// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
//go:generate bundle -prefix= -o=httpcommon.go golang.org/x/net/internal/httpcommon

package httpcommon

import (
	
	
	
	
	
	
	
	
	
	

	
	
)

// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
// otherwise be unsafe and could introduce vulnerabilities if used improperly.

// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
// are equal, ASCII-case-insensitively.
func asciiEqualFold(,  string) bool {
	if len() != len() {
		return false
	}
	for  := 0;  < len(); ++ {
		if lower([]) != lower([]) {
			return false
		}
	}
	return true
}

// lower returns the ASCII lowercase version of b.
func lower( byte) byte {
	if 'A' <=  &&  <= 'Z' {
		return  + ('a' - 'A')
	}
	return 
}

// isASCIIPrint returns whether s is ASCII and printable according to
// https://tools.ietf.org/html/rfc20#section-4.2.
func isASCIIPrint( string) bool {
	for  := 0;  < len(); ++ {
		if [] < ' ' || [] > '~' {
			return false
		}
	}
	return true
}

// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func asciiToLower( string) ( string,  bool) {
	if !isASCIIPrint() {
		return "", false
	}
	return strings.ToLower(), true
}

var (
	commonBuildOnce   sync.Once
	commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
	commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
)

func buildCommonHeaderMapsOnce() {
	commonBuildOnce.Do(buildCommonHeaderMaps)
}

func buildCommonHeaderMaps() {
	 := []string{
		"accept",
		"accept-charset",
		"accept-encoding",
		"accept-language",
		"accept-ranges",
		"age",
		"access-control-allow-credentials",
		"access-control-allow-headers",
		"access-control-allow-methods",
		"access-control-allow-origin",
		"access-control-expose-headers",
		"access-control-max-age",
		"access-control-request-headers",
		"access-control-request-method",
		"allow",
		"authorization",
		"cache-control",
		"content-disposition",
		"content-encoding",
		"content-language",
		"content-length",
		"content-location",
		"content-range",
		"content-type",
		"cookie",
		"date",
		"etag",
		"expect",
		"expires",
		"from",
		"host",
		"if-match",
		"if-modified-since",
		"if-none-match",
		"if-unmodified-since",
		"last-modified",
		"link",
		"location",
		"max-forwards",
		"origin",
		"proxy-authenticate",
		"proxy-authorization",
		"range",
		"referer",
		"refresh",
		"retry-after",
		"server",
		"set-cookie",
		"strict-transport-security",
		"trailer",
		"transfer-encoding",
		"user-agent",
		"vary",
		"via",
		"www-authenticate",
		"x-forwarded-for",
		"x-forwarded-proto",
	}
	commonLowerHeader = make(map[string]string, len())
	commonCanonHeader = make(map[string]string, len())
	for ,  := range  {
		 := textproto.CanonicalMIMEHeaderKey()
		commonLowerHeader[] = 
		commonCanonHeader[] = 
	}
}

// LowerHeader returns the lowercase form of a header name,
// used on the wire for HTTP/2 and HTTP/3 requests.
func ( string) ( string,  bool) {
	buildCommonHeaderMapsOnce()
	if ,  := commonLowerHeader[];  {
		return , true
	}
	return asciiToLower()
}

// CanonicalHeader canonicalizes a header name. (For example, "host" becomes "Host".)
func ( string) string {
	buildCommonHeaderMapsOnce()
	if ,  := commonCanonHeader[];  {
		return 
	}
	return textproto.CanonicalMIMEHeaderKey()
}

// CachedCanonicalHeader returns the canonical form of a well-known header name.
func ( string) (string, bool) {
	buildCommonHeaderMapsOnce()
	,  := commonCanonHeader[]
	return , 
}

var (
	ErrRequestHeaderListSize = errors.New("request header list larger than peer's advertised limit")
)

// Request is a subset of http.Request.
// It'd be simpler to pass an *http.Request, of course, but we can't depend on net/http
// without creating a dependency cycle.
type Request struct {
	URL                 *url.URL
	Method              string
	Host                string
	Header              map[string][]string
	Trailer             map[string][]string
	ActualContentLength int64 // 0 means 0, -1 means unknown
}

// EncodeHeadersParam is parameters to EncodeHeaders.
type EncodeHeadersParam struct {
	Request Request

	// AddGzipHeader indicates that an "accept-encoding: gzip" header should be
	// added to the request.
	AddGzipHeader bool

	// PeerMaxHeaderListSize, when non-zero, is the peer's MAX_HEADER_LIST_SIZE setting.
	PeerMaxHeaderListSize uint64

	// DefaultUserAgent is the User-Agent header to send when the request
	// neither contains a User-Agent nor disables it.
	DefaultUserAgent string
}

// EncodeHeadersParam is the result of EncodeHeaders.
type EncodeHeadersResult struct {
	HasBody     bool
	HasTrailers bool
}

// EncodeHeaders constructs request headers common to HTTP/2 and HTTP/3.
// It validates a request and calls headerf with each pseudo-header and header
// for the request.
// The headerf function is called with the validated, canonicalized header name.
func ( context.Context,  EncodeHeadersParam,  func(,  string)) ( EncodeHeadersResult,  error) {
	 := .Request

	// Check for invalid connection-level headers.
	if  := checkConnHeaders(.Header);  != nil {
		return , 
	}

	if .URL == nil {
		return , errors.New("Request.URL is nil")
	}

	 := .Host
	if  == "" {
		 = .URL.Host
	}
	,  := httpguts.PunycodeHostPort()
	if  != nil {
		return , 
	}
	if !httpguts.ValidHostHeader() {
		return , errors.New("invalid Host header")
	}

	// isNormalConnect is true if this is a non-extended CONNECT request.
	 := false
	var  string
	if  := .Header[":protocol"]; len() > 0 {
		 = [0]
	}
	if .Method == "CONNECT" &&  == "" {
		 = true
	} else if  != "" && .Method != "CONNECT" {
		return , errors.New("invalid :protocol header in non-CONNECT request")
	}

	// Validate the path, except for non-extended CONNECT requests which have no path.
	var  string
	if ! {
		 = .URL.RequestURI()
		if !validPseudoPath() {
			 := 
			 = strings.TrimPrefix(, .URL.Scheme+"://"+)
			if !validPseudoPath() {
				if .URL.Opaque != "" {
					return , fmt.Errorf("invalid request :path %q from URL.Opaque = %q", , .URL.Opaque)
				} else {
					return , fmt.Errorf("invalid request :path %q", )
				}
			}
		}
	}

	// Check for any invalid headers+trailers and return an error before we
	// potentially pollute our hpack state. (We want to be able to
	// continue to reuse the hpack encoder for future requests)
	if  := validateHeaders(.Header);  != "" {
		return , fmt.Errorf("invalid HTTP header %s", )
	}
	if  := validateHeaders(.Trailer);  != "" {
		return , fmt.Errorf("invalid HTTP trailer %s", )
	}

	,  := commaSeparatedTrailers(.Trailer)
	if  != nil {
		return , 
	}

	 := func( func(,  string)) {
		// 8.1.2.3 Request Pseudo-Header Fields
		// The :path pseudo-header field includes the path and query parts of the
		// target URI (the path-absolute production and optionally a '?' character
		// followed by the query production, see Sections 3.3 and 3.4 of
		// [RFC3986]).
		(":authority", )
		 := .Method
		if  == "" {
			 = "GET"
		}
		(":method", )
		if ! {
			(":path", )
			(":scheme", .URL.Scheme)
		}
		if  != "" {
			(":protocol", )
		}
		if  != "" {
			("trailer", )
		}

		var  bool
		for ,  := range .Header {
			if asciiEqualFold(, "host") || asciiEqualFold(, "content-length") {
				// Host is :authority, already sent.
				// Content-Length is automatic, set below.
				continue
			} else if asciiEqualFold(, "connection") ||
				asciiEqualFold(, "proxy-connection") ||
				asciiEqualFold(, "transfer-encoding") ||
				asciiEqualFold(, "upgrade") ||
				asciiEqualFold(, "keep-alive") {
				// Per 8.1.2.2 Connection-Specific Header
				// Fields, don't send connection-specific
				// fields. We have already checked if any
				// are error-worthy so just ignore the rest.
				continue
			} else if asciiEqualFold(, "user-agent") {
				// Match Go's http1 behavior: at most one
				// User-Agent. If set to nil or empty string,
				// then omit it. Otherwise if not mentioned,
				// include the default (below).
				 = true
				if len() < 1 {
					continue
				}
				 = [:1]
				if [0] == "" {
					continue
				}
			} else if asciiEqualFold(, "cookie") {
				// Per 8.1.2.5 To allow for better compression efficiency, the
				// Cookie header field MAY be split into separate header fields,
				// each with one or more cookie-pairs.
				for ,  := range  {
					for {
						 := strings.IndexByte(, ';')
						if  < 0 {
							break
						}
						("cookie", [:])
						++
						// strip space after semicolon if any.
						for +1 <= len() && [] == ' ' {
							++
						}
						 = [:]
					}
					if len() > 0 {
						("cookie", )
					}
				}
				continue
			} else if  == ":protocol" {
				// :protocol pseudo-header was already sent above.
				continue
			}

			for ,  := range  {
				(, )
			}
		}
		if shouldSendReqContentLength(.Method, .ActualContentLength) {
			("content-length", strconv.FormatInt(.ActualContentLength, 10))
		}
		if .AddGzipHeader {
			("accept-encoding", "gzip")
		}
		if ! {
			("user-agent", .DefaultUserAgent)
		}
	}

	// Do a first pass over the headers counting bytes to ensure
	// we don't exceed cc.peerMaxHeaderListSize. This is done as a
	// separate pass before encoding the headers to prevent
	// modifying the hpack state.
	if .PeerMaxHeaderListSize > 0 {
		 := uint64(0)
		(func(,  string) {
			 := hpack.HeaderField{Name: , Value: }
			 += uint64(.Size())
		})

		if  > .PeerMaxHeaderListSize {
			return , ErrRequestHeaderListSize
		}
	}

	 := httptrace.ContextClientTrace()

	// Header list size is ok. Write the headers.
	(func(,  string) {
		,  := LowerHeader()
		if ! {
			// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
			// field names have to be ASCII characters (just as in HTTP/1.x).
			return
		}

		(, )

		if  != nil && .WroteHeaderField != nil {
			.WroteHeaderField(, []string{})
		}
	})

	.HasBody = .ActualContentLength != 0
	.HasTrailers =  != ""
	return , nil
}

// IsRequestGzip reports whether we should add an Accept-Encoding: gzip header
// for a request.
func ( string,  map[string][]string,  bool) bool {
	// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
	if ! &&
		len(["Accept-Encoding"]) == 0 &&
		len(["Range"]) == 0 &&
		 != "HEAD" {
		// Request gzip only, not deflate. Deflate is ambiguous and
		// not as universally supported anyway.
		// See: https://zlib.net/zlib_faq.html#faq39
		//
		// Note that we don't request this for HEAD requests,
		// due to a bug in nginx:
		//   http://trac.nginx.org/nginx/ticket/358
		//   https://golang.org/issue/5522
		//
		// We don't request gzip if the request is for a range, since
		// auto-decoding a portion of a gzipped document will just fail
		// anyway. See https://golang.org/issue/8923
		return true
	}
	return false
}

// checkConnHeaders checks whether req has any invalid connection-level headers.
//
// https://www.rfc-editor.org/rfc/rfc9114.html#section-4.2-3
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.2-1
//
// Certain headers are special-cased as okay but not transmitted later.
// For example, we allow "Transfer-Encoding: chunked", but drop the header when encoding.
func checkConnHeaders( map[string][]string) error {
	if  := ["Upgrade"]; len() > 0 && ([0] != "" && [0] != "chunked") {
		return fmt.Errorf("invalid Upgrade request header: %q", )
	}
	if  := ["Transfer-Encoding"]; len() > 0 && (len() > 1 || [0] != "" && [0] != "chunked") {
		return fmt.Errorf("invalid Transfer-Encoding request header: %q", )
	}
	if  := ["Connection"]; len() > 0 && (len() > 1 || [0] != "" && !asciiEqualFold([0], "close") && !asciiEqualFold([0], "keep-alive")) {
		return fmt.Errorf("invalid Connection request header: %q", )
	}
	return nil
}

func commaSeparatedTrailers( map[string][]string) (string, error) {
	 := make([]string, 0, len())
	for  := range  {
		 = CanonicalHeader()
		switch  {
		case "Transfer-Encoding", "Trailer", "Content-Length":
			return "", fmt.Errorf("invalid Trailer key %q", )
		}
		 = append(, )
	}
	if len() > 0 {
		sort.Strings()
		return strings.Join(, ","), nil
	}
	return "", nil
}

// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
//   - a non-empty string starting with '/'
//   - the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath( string) bool {
	return (len() > 0 && [0] == '/') ||  == "*"
}

func validateHeaders( map[string][]string) string {
	for ,  := range  {
		if !httpguts.ValidHeaderFieldName() &&  != ":protocol" {
			return fmt.Sprintf("name %q", )
		}
		for ,  := range  {
			if !httpguts.ValidHeaderFieldValue() {
				// Don't include the value in the error,
				// because it may be sensitive.
				return fmt.Sprintf("value for header %q", )
			}
		}
	}
	return ""
}

// shouldSendReqContentLength reports whether we should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength( string,  int64) bool {
	if  > 0 {
		return true
	}
	if  < 0 {
		return false
	}
	// For zero bodies, whether we send a content-length depends on the method.
	// It also kinda doesn't matter for http2 either way, with END_STREAM.
	switch  {
	case "POST", "PUT", "PATCH":
		return true
	default:
		return false
	}
}

// ServerRequestParam is parameters to NewServerRequest.
type ServerRequestParam struct {
	Method                  string
	Scheme, Authority, Path string
	Protocol                string
	Header                  map[string][]string
}

// ServerRequestResult is the result of NewServerRequest.
type ServerRequestResult struct {
	// Various http.Request fields.
	URL        *url.URL
	RequestURI string
	Trailer    map[string][]string

	NeedsContinue bool // client provided an "Expect: 100-continue" header

	// If the request should be rejected, this is a short string suitable for passing
	// to the http2 package's CountError function.
	// It might be a bit odd to return errors this way rather than returing an error,
	// but this ensures we don't forget to include a CountError reason.
	InvalidReason string
}

func ( ServerRequestParam) ServerRequestResult {
	 := httpguts.HeaderValuesContainsToken(.Header["Expect"], "100-continue")
	if  {
		delete(.Header, "Expect")
	}
	// Merge Cookie headers into one "; "-delimited value.
	if  := .Header["Cookie"]; len() > 1 {
		.Header["Cookie"] = []string{strings.Join(, "; ")}
	}

	// Setup Trailers
	var  map[string][]string
	for ,  := range .Header["Trailer"] {
		for ,  := range strings.Split(, ",") {
			 = textproto.CanonicalMIMEHeaderKey(textproto.TrimString())
			switch  {
			case "Transfer-Encoding", "Trailer", "Content-Length":
				// Bogus. (copy of http1 rules)
				// Ignore.
			default:
				if  == nil {
					 = make(map[string][]string)
				}
				[] = nil
			}
		}
	}
	delete(.Header, "Trailer")

	// "':authority' MUST NOT include the deprecated userinfo subcomponent
	// for "http" or "https" schemed URIs."
	// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.8
	if strings.IndexByte(.Authority, '@') != -1 && (.Scheme == "http" || .Scheme == "https") {
		return ServerRequestResult{
			InvalidReason: "userinfo_in_authority",
		}
	}

	var  *url.URL
	var  string
	if .Method == "CONNECT" && .Protocol == "" {
		 = &url.URL{Host: .Authority}
		 = .Authority // mimic HTTP/1 server behavior
	} else {
		var  error
		,  = url.ParseRequestURI(.Path)
		if  != nil {
			return ServerRequestResult{
				InvalidReason: "bad_path",
			}
		}
		 = .Path
	}

	return ServerRequestResult{
		URL:           ,
		NeedsContinue: ,
		RequestURI:    ,
		Trailer:       ,
	}
}