diff options
Diffstat (limited to 'vendor/golang.org/x/net/http2')
| -rw-r--r-- | vendor/golang.org/x/net/http2/h2c/h2c.go | 6 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/headermap.go | 18 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/hpack/encode.go | 5 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/hpack/static_table.go | 188 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/hpack/tables.go | 78 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/server.go | 236 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/http2/transport.go | 113 | 
7 files changed, 487 insertions, 157 deletions
| diff --git a/vendor/golang.org/x/net/http2/h2c/h2c.go b/vendor/golang.org/x/net/http2/h2c/h2c.go index 2b77ffdaf..a72bbed1b 100644 --- a/vendor/golang.org/x/net/http2/h2c/h2c.go +++ b/vendor/golang.org/x/net/http2/h2c/h2c.go @@ -109,6 +109,7 @@ func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {  			if http2VerboseLogs {  				log.Printf("h2c: error h2c upgrade: %v", err)  			} +			w.WriteHeader(http.StatusInternalServerError)  			return  		}  		defer conn.Close() @@ -167,7 +168,10 @@ func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []  		return nil, nil, errors.New("h2c: connection does not support Hijack")  	} -	body, _ := io.ReadAll(r.Body) +	body, err := io.ReadAll(r.Body) +	if err != nil { +		return nil, nil, err +	}  	r.Body = io.NopCloser(bytes.NewBuffer(body))  	conn, rw, err := hijacker.Hijack() diff --git a/vendor/golang.org/x/net/http2/headermap.go b/vendor/golang.org/x/net/http2/headermap.go index 9e12941da..149b3dd20 100644 --- a/vendor/golang.org/x/net/http2/headermap.go +++ b/vendor/golang.org/x/net/http2/headermap.go @@ -27,7 +27,14 @@ func buildCommonHeaderMaps() {  		"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", @@ -53,6 +60,7 @@ func buildCommonHeaderMaps() {  		"link",  		"location",  		"max-forwards", +		"origin",  		"proxy-authenticate",  		"proxy-authorization",  		"range", @@ -68,6 +76,8 @@ func buildCommonHeaderMaps() {  		"vary",  		"via",  		"www-authenticate", +		"x-forwarded-for", +		"x-forwarded-proto",  	}  	commonLowerHeader = make(map[string]string, len(common))  	commonCanonHeader = make(map[string]string, len(common)) @@ -85,3 +95,11 @@ func lowerHeader(v string) (lower string, ascii bool) {  	}  	return asciiToLower(v)  } + +func canonicalHeader(v string) string { +	buildCommonHeaderMapsOnce() +	if s, ok := commonCanonHeader[v]; ok { +		return s +	} +	return http.CanonicalHeaderKey(v) +} diff --git a/vendor/golang.org/x/net/http2/hpack/encode.go b/vendor/golang.org/x/net/http2/hpack/encode.go index 6886dc163..46219da2b 100644 --- a/vendor/golang.org/x/net/http2/hpack/encode.go +++ b/vendor/golang.org/x/net/http2/hpack/encode.go @@ -116,6 +116,11 @@ func (e *Encoder) SetMaxDynamicTableSize(v uint32) {  	e.dynTab.setMaxSize(v)  } +// MaxDynamicTableSize returns the current dynamic header table size. +func (e *Encoder) MaxDynamicTableSize() (v uint32) { +	return e.dynTab.maxSize +} +  // SetMaxDynamicTableSizeLimit changes the maximum value that can be  // specified in SetMaxDynamicTableSize to v. By default, it is set to  // 4096, which is the same size of the default dynamic header table diff --git a/vendor/golang.org/x/net/http2/hpack/static_table.go b/vendor/golang.org/x/net/http2/hpack/static_table.go new file mode 100644 index 000000000..754a1eb91 --- /dev/null +++ b/vendor/golang.org/x/net/http2/hpack/static_table.go @@ -0,0 +1,188 @@ +// go generate gen.go +// Code generated by the command above; DO NOT EDIT. + +package hpack + +var staticTable = &headerFieldTable{ +	evictCount: 0, +	byName: map[string]uint64{ +		":authority":                  1, +		":method":                     3, +		":path":                       5, +		":scheme":                     7, +		":status":                     14, +		"accept-charset":              15, +		"accept-encoding":             16, +		"accept-language":             17, +		"accept-ranges":               18, +		"accept":                      19, +		"access-control-allow-origin": 20, +		"age":                         21, +		"allow":                       22, +		"authorization":               23, +		"cache-control":               24, +		"content-disposition":         25, +		"content-encoding":            26, +		"content-language":            27, +		"content-length":              28, +		"content-location":            29, +		"content-range":               30, +		"content-type":                31, +		"cookie":                      32, +		"date":                        33, +		"etag":                        34, +		"expect":                      35, +		"expires":                     36, +		"from":                        37, +		"host":                        38, +		"if-match":                    39, +		"if-modified-since":           40, +		"if-none-match":               41, +		"if-range":                    42, +		"if-unmodified-since":         43, +		"last-modified":               44, +		"link":                        45, +		"location":                    46, +		"max-forwards":                47, +		"proxy-authenticate":          48, +		"proxy-authorization":         49, +		"range":                       50, +		"referer":                     51, +		"refresh":                     52, +		"retry-after":                 53, +		"server":                      54, +		"set-cookie":                  55, +		"strict-transport-security":   56, +		"transfer-encoding":           57, +		"user-agent":                  58, +		"vary":                        59, +		"via":                         60, +		"www-authenticate":            61, +	}, +	byNameValue: map[pairNameValue]uint64{ +		{name: ":authority", value: ""}:                   1, +		{name: ":method", value: "GET"}:                   2, +		{name: ":method", value: "POST"}:                  3, +		{name: ":path", value: "/"}:                       4, +		{name: ":path", value: "/index.html"}:             5, +		{name: ":scheme", value: "http"}:                  6, +		{name: ":scheme", value: "https"}:                 7, +		{name: ":status", value: "200"}:                   8, +		{name: ":status", value: "204"}:                   9, +		{name: ":status", value: "206"}:                   10, +		{name: ":status", value: "304"}:                   11, +		{name: ":status", value: "400"}:                   12, +		{name: ":status", value: "404"}:                   13, +		{name: ":status", value: "500"}:                   14, +		{name: "accept-charset", value: ""}:               15, +		{name: "accept-encoding", value: "gzip, deflate"}: 16, +		{name: "accept-language", value: ""}:              17, +		{name: "accept-ranges", value: ""}:                18, +		{name: "accept", value: ""}:                       19, +		{name: "access-control-allow-origin", value: ""}:  20, +		{name: "age", value: ""}:                          21, +		{name: "allow", value: ""}:                        22, +		{name: "authorization", value: ""}:                23, +		{name: "cache-control", value: ""}:                24, +		{name: "content-disposition", value: ""}:          25, +		{name: "content-encoding", value: ""}:             26, +		{name: "content-language", value: ""}:             27, +		{name: "content-length", value: ""}:               28, +		{name: "content-location", value: ""}:             29, +		{name: "content-range", value: ""}:                30, +		{name: "content-type", value: ""}:                 31, +		{name: "cookie", value: ""}:                       32, +		{name: "date", value: ""}:                         33, +		{name: "etag", value: ""}:                         34, +		{name: "expect", value: ""}:                       35, +		{name: "expires", value: ""}:                      36, +		{name: "from", value: ""}:                         37, +		{name: "host", value: ""}:                         38, +		{name: "if-match", value: ""}:                     39, +		{name: "if-modified-since", value: ""}:            40, +		{name: "if-none-match", value: ""}:                41, +		{name: "if-range", value: ""}:                     42, +		{name: "if-unmodified-since", value: ""}:          43, +		{name: "last-modified", value: ""}:                44, +		{name: "link", value: ""}:                         45, +		{name: "location", value: ""}:                     46, +		{name: "max-forwards", value: ""}:                 47, +		{name: "proxy-authenticate", value: ""}:           48, +		{name: "proxy-authorization", value: ""}:          49, +		{name: "range", value: ""}:                        50, +		{name: "referer", value: ""}:                      51, +		{name: "refresh", value: ""}:                      52, +		{name: "retry-after", value: ""}:                  53, +		{name: "server", value: ""}:                       54, +		{name: "set-cookie", value: ""}:                   55, +		{name: "strict-transport-security", value: ""}:    56, +		{name: "transfer-encoding", value: ""}:            57, +		{name: "user-agent", value: ""}:                   58, +		{name: "vary", value: ""}:                         59, +		{name: "via", value: ""}:                          60, +		{name: "www-authenticate", value: ""}:             61, +	}, +	ents: []HeaderField{ +		{Name: ":authority", Value: "", Sensitive: false}, +		{Name: ":method", Value: "GET", Sensitive: false}, +		{Name: ":method", Value: "POST", Sensitive: false}, +		{Name: ":path", Value: "/", Sensitive: false}, +		{Name: ":path", Value: "/index.html", Sensitive: false}, +		{Name: ":scheme", Value: "http", Sensitive: false}, +		{Name: ":scheme", Value: "https", Sensitive: false}, +		{Name: ":status", Value: "200", Sensitive: false}, +		{Name: ":status", Value: "204", Sensitive: false}, +		{Name: ":status", Value: "206", Sensitive: false}, +		{Name: ":status", Value: "304", Sensitive: false}, +		{Name: ":status", Value: "400", Sensitive: false}, +		{Name: ":status", Value: "404", Sensitive: false}, +		{Name: ":status", Value: "500", Sensitive: false}, +		{Name: "accept-charset", Value: "", Sensitive: false}, +		{Name: "accept-encoding", Value: "gzip, deflate", Sensitive: false}, +		{Name: "accept-language", Value: "", Sensitive: false}, +		{Name: "accept-ranges", Value: "", Sensitive: false}, +		{Name: "accept", Value: "", Sensitive: false}, +		{Name: "access-control-allow-origin", Value: "", Sensitive: false}, +		{Name: "age", Value: "", Sensitive: false}, +		{Name: "allow", Value: "", Sensitive: false}, +		{Name: "authorization", Value: "", Sensitive: false}, +		{Name: "cache-control", Value: "", Sensitive: false}, +		{Name: "content-disposition", Value: "", Sensitive: false}, +		{Name: "content-encoding", Value: "", Sensitive: false}, +		{Name: "content-language", Value: "", Sensitive: false}, +		{Name: "content-length", Value: "", Sensitive: false}, +		{Name: "content-location", Value: "", Sensitive: false}, +		{Name: "content-range", Value: "", Sensitive: false}, +		{Name: "content-type", Value: "", Sensitive: false}, +		{Name: "cookie", Value: "", Sensitive: false}, +		{Name: "date", Value: "", Sensitive: false}, +		{Name: "etag", Value: "", Sensitive: false}, +		{Name: "expect", Value: "", Sensitive: false}, +		{Name: "expires", Value: "", Sensitive: false}, +		{Name: "from", Value: "", Sensitive: false}, +		{Name: "host", Value: "", Sensitive: false}, +		{Name: "if-match", Value: "", Sensitive: false}, +		{Name: "if-modified-since", Value: "", Sensitive: false}, +		{Name: "if-none-match", Value: "", Sensitive: false}, +		{Name: "if-range", Value: "", Sensitive: false}, +		{Name: "if-unmodified-since", Value: "", Sensitive: false}, +		{Name: "last-modified", Value: "", Sensitive: false}, +		{Name: "link", Value: "", Sensitive: false}, +		{Name: "location", Value: "", Sensitive: false}, +		{Name: "max-forwards", Value: "", Sensitive: false}, +		{Name: "proxy-authenticate", Value: "", Sensitive: false}, +		{Name: "proxy-authorization", Value: "", Sensitive: false}, +		{Name: "range", Value: "", Sensitive: false}, +		{Name: "referer", Value: "", Sensitive: false}, +		{Name: "refresh", Value: "", Sensitive: false}, +		{Name: "retry-after", Value: "", Sensitive: false}, +		{Name: "server", Value: "", Sensitive: false}, +		{Name: "set-cookie", Value: "", Sensitive: false}, +		{Name: "strict-transport-security", Value: "", Sensitive: false}, +		{Name: "transfer-encoding", Value: "", Sensitive: false}, +		{Name: "user-agent", Value: "", Sensitive: false}, +		{Name: "vary", Value: "", Sensitive: false}, +		{Name: "via", Value: "", Sensitive: false}, +		{Name: "www-authenticate", Value: "", Sensitive: false}, +	}, +} diff --git a/vendor/golang.org/x/net/http2/hpack/tables.go b/vendor/golang.org/x/net/http2/hpack/tables.go index a66cfbea6..8cbdf3f01 100644 --- a/vendor/golang.org/x/net/http2/hpack/tables.go +++ b/vendor/golang.org/x/net/http2/hpack/tables.go @@ -96,8 +96,7 @@ func (t *headerFieldTable) evictOldest(n int) {  // meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic  // table, the return value i actually refers to the entry t.ents[t.len()-i].  // -// All tables are assumed to be a dynamic tables except for the global -// staticTable pointer. +// All tables are assumed to be a dynamic tables except for the global staticTable.  //  // See Section 2.3.3.  func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) { @@ -125,81 +124,6 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 {  	return k + 1  } -// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B -var staticTable = newStaticTable() -var staticTableEntries = [...]HeaderField{ -	{Name: ":authority"}, -	{Name: ":method", Value: "GET"}, -	{Name: ":method", Value: "POST"}, -	{Name: ":path", Value: "/"}, -	{Name: ":path", Value: "/index.html"}, -	{Name: ":scheme", Value: "http"}, -	{Name: ":scheme", Value: "https"}, -	{Name: ":status", Value: "200"}, -	{Name: ":status", Value: "204"}, -	{Name: ":status", Value: "206"}, -	{Name: ":status", Value: "304"}, -	{Name: ":status", Value: "400"}, -	{Name: ":status", Value: "404"}, -	{Name: ":status", Value: "500"}, -	{Name: "accept-charset"}, -	{Name: "accept-encoding", Value: "gzip, deflate"}, -	{Name: "accept-language"}, -	{Name: "accept-ranges"}, -	{Name: "accept"}, -	{Name: "access-control-allow-origin"}, -	{Name: "age"}, -	{Name: "allow"}, -	{Name: "authorization"}, -	{Name: "cache-control"}, -	{Name: "content-disposition"}, -	{Name: "content-encoding"}, -	{Name: "content-language"}, -	{Name: "content-length"}, -	{Name: "content-location"}, -	{Name: "content-range"}, -	{Name: "content-type"}, -	{Name: "cookie"}, -	{Name: "date"}, -	{Name: "etag"}, -	{Name: "expect"}, -	{Name: "expires"}, -	{Name: "from"}, -	{Name: "host"}, -	{Name: "if-match"}, -	{Name: "if-modified-since"}, -	{Name: "if-none-match"}, -	{Name: "if-range"}, -	{Name: "if-unmodified-since"}, -	{Name: "last-modified"}, -	{Name: "link"}, -	{Name: "location"}, -	{Name: "max-forwards"}, -	{Name: "proxy-authenticate"}, -	{Name: "proxy-authorization"}, -	{Name: "range"}, -	{Name: "referer"}, -	{Name: "refresh"}, -	{Name: "retry-after"}, -	{Name: "server"}, -	{Name: "set-cookie"}, -	{Name: "strict-transport-security"}, -	{Name: "transfer-encoding"}, -	{Name: "user-agent"}, -	{Name: "vary"}, -	{Name: "via"}, -	{Name: "www-authenticate"}, -} - -func newStaticTable() *headerFieldTable { -	t := &headerFieldTable{} -	t.init() -	for _, e := range staticTableEntries[:] { -		t.addEntry(e) -	} -	return t -} -  var huffmanCodes = [256]uint32{  	0x1ff8,  	0x7fffd8, diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index 43cc2a34a..4eb7617fa 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -98,6 +98,19 @@ type Server struct {  	// the HTTP/2 spec's recommendations.  	MaxConcurrentStreams uint32 +	// MaxDecoderHeaderTableSize optionally specifies the http2 +	// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It +	// informs the remote endpoint of the maximum size of the header compression +	// table used to decode header blocks, in octets. If zero, the default value +	// of 4096 is used. +	MaxDecoderHeaderTableSize uint32 + +	// MaxEncoderHeaderTableSize optionally specifies an upper limit for the +	// header compression table used for encoding request headers. Received +	// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero, +	// the default value of 4096 is used. +	MaxEncoderHeaderTableSize uint32 +  	// MaxReadFrameSize optionally specifies the largest frame  	// this server is willing to read. A valid value is between  	// 16k and 16M, inclusive. If zero or otherwise invalid, a @@ -170,6 +183,20 @@ func (s *Server) maxConcurrentStreams() uint32 {  	return defaultMaxStreams  } +func (s *Server) maxDecoderHeaderTableSize() uint32 { +	if v := s.MaxDecoderHeaderTableSize; v > 0 { +		return v +	} +	return initialHeaderTableSize +} + +func (s *Server) maxEncoderHeaderTableSize() uint32 { +	if v := s.MaxEncoderHeaderTableSize; v > 0 { +		return v +	} +	return initialHeaderTableSize +} +  // maxQueuedControlFrames is the maximum number of control frames like  // SETTINGS, PING and RST_STREAM that will be queued for writing before  // the connection is closed to prevent memory exhaustion attacks. @@ -394,7 +421,6 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {  		advMaxStreams:               s.maxConcurrentStreams(),  		initialStreamSendWindowSize: initialWindowSize,  		maxFrameSize:                initialMaxFrameSize, -		headerTableSize:             initialHeaderTableSize,  		serveG:                      newGoroutineLock(),  		pushEnabled:                 true,  		sawClientPreface:            opts.SawClientPreface, @@ -424,12 +450,13 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {  	sc.flow.add(initialWindowSize)  	sc.inflow.add(initialWindowSize)  	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) +	sc.hpackEncoder.SetMaxDynamicTableSizeLimit(s.maxEncoderHeaderTableSize())  	fr := NewFramer(sc.bw, c)  	if s.CountError != nil {  		fr.countError = s.CountError  	} -	fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) +	fr.ReadMetaHeaders = hpack.NewDecoder(s.maxDecoderHeaderTableSize(), nil)  	fr.MaxHeaderListSize = sc.maxHeaderListSize()  	fr.SetMaxReadFrameSize(s.maxReadFrameSize())  	sc.framer = fr @@ -559,9 +586,9 @@ type serverConn struct {  	streams                     map[uint32]*stream  	initialStreamSendWindowSize int32  	maxFrameSize                int32 -	headerTableSize             uint32  	peerMaxHeaderListSize       uint32            // zero means unknown (default)  	canonHeader                 map[string]string // http2-lower-case -> Go-Canonical-Case +	canonHeaderKeysSize         int               // canonHeader keys size in bytes  	writingFrame                bool              // started writing a frame (on serve goroutine or separate)  	writingFrameAsync           bool              // started a frame on its own goroutine but haven't heard back on wroteFrameCh  	needsFrameFlush             bool              // last frame write wasn't a flush @@ -622,7 +649,9 @@ type stream struct {  	resetQueued      bool        // RST_STREAM queued for write; set by sc.resetStream  	gotTrailerHeader bool        // HEADER frame for trailers was seen  	wroteHeaders     bool        // whether we wrote headers (not status 100) +	readDeadline     *time.Timer // nil if unused  	writeDeadline    *time.Timer // nil if unused +	closeErr         error       // set before cw is closed  	trailer    http.Header // accumulated trailers  	reqTrailer http.Header // handler's Request.Trailer @@ -738,6 +767,13 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {  	}  } +// maxCachedCanonicalHeadersKeysSize is an arbitrarily-chosen limit on the size +// of the entries in the canonHeader cache. +// This should be larger than the size of unique, uncommon header keys likely to +// be sent by the peer, while not so high as to permit unreasonable memory usage +// if the peer sends an unbounded number of unique header keys. +const maxCachedCanonicalHeadersKeysSize = 2048 +  func (sc *serverConn) canonicalHeader(v string) string {  	sc.serveG.check()  	buildCommonHeaderMapsOnce() @@ -753,14 +789,10 @@ func (sc *serverConn) canonicalHeader(v string) string {  		sc.canonHeader = make(map[string]string)  	}  	cv = http.CanonicalHeaderKey(v) -	// maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of -	// entries in the canonHeader cache. This should be larger than the number -	// of unique, uncommon header keys likely to be sent by the peer, while not -	// so high as to permit unreasonable memory usage if the peer sends an unbounded -	// number of unique header keys. -	const maxCachedCanonicalHeaders = 32 -	if len(sc.canonHeader) < maxCachedCanonicalHeaders { +	size := 100 + len(v)*2 // 100 bytes of map overhead + key + value +	if sc.canonHeaderKeysSize+size <= maxCachedCanonicalHeadersKeysSize {  		sc.canonHeader[v] = cv +		sc.canonHeaderKeysSize += size  	}  	return cv  } @@ -862,6 +894,7 @@ func (sc *serverConn) serve() {  			{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},  			{SettingMaxConcurrentStreams, sc.advMaxStreams},  			{SettingMaxHeaderListSize, sc.maxHeaderListSize()}, +			{SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()},  			{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},  		},  	}) @@ -869,7 +902,9 @@ func (sc *serverConn) serve() {  	// Each connection starts with initialWindowSize inflow tokens.  	// If a higher value is configured, we add more tokens. -	sc.sendWindowUpdate(nil) +	if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 { +		sc.sendWindowUpdate(nil, int(diff)) +	}  	if err := sc.readPreface(); err != nil {  		sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err) @@ -946,6 +981,8 @@ func (sc *serverConn) serve() {  				}  			case *startPushRequest:  				sc.startPush(v) +			case func(*serverConn): +				v(sc)  			default:  				panic(fmt.Sprintf("unexpected type %T", v))  			} @@ -1459,6 +1496,21 @@ func (sc *serverConn) processFrame(f Frame) error {  		sc.sawFirstSettings = true  	} +	// Discard frames for streams initiated after the identified last +	// stream sent in a GOAWAY, or all frames after sending an error. +	// We still need to return connection-level flow control for DATA frames. +	// RFC 9113 Section 6.8. +	if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || f.Header().StreamID > sc.maxClientStreamID) { + +		if f, ok := f.(*DataFrame); ok { +			if sc.inflow.available() < int32(f.Length) { +				return sc.countError("data_flow", streamError(f.Header().StreamID, ErrCodeFlowControl)) +			} +			sc.sendWindowUpdate(nil, int(f.Length)) // conn-level +		} +		return nil +	} +  	switch f := f.(type) {  	case *SettingsFrame:  		return sc.processSettings(f) @@ -1501,9 +1553,6 @@ func (sc *serverConn) processPing(f *PingFrame) error {  		// PROTOCOL_ERROR."  		return sc.countError("ping_on_stream", ConnectionError(ErrCodeProtocol))  	} -	if sc.inGoAway && sc.goAwayCode != ErrCodeNo { -		return nil -	}  	sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})  	return nil  } @@ -1565,6 +1614,9 @@ func (sc *serverConn) closeStream(st *stream, err error) {  		panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))  	}  	st.state = stateClosed +	if st.readDeadline != nil { +		st.readDeadline.Stop() +	}  	if st.writeDeadline != nil {  		st.writeDeadline.Stop()  	} @@ -1586,10 +1638,18 @@ func (sc *serverConn) closeStream(st *stream, err error) {  	if p := st.body; p != nil {  		// Return any buffered unread bytes worth of conn-level flow control.  		// See golang.org/issue/16481 -		sc.sendWindowUpdate(nil) +		sc.sendWindowUpdate(nil, p.Len())  		p.CloseWithError(err)  	} +	if e, ok := err.(StreamError); ok { +		if e.Cause != nil { +			err = e.Cause +		} else { +			err = errStreamClosed +		} +	} +	st.closeErr = err  	st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc  	sc.writeSched.CloseStream(st.id)  } @@ -1632,7 +1692,6 @@ func (sc *serverConn) processSetting(s Setting) error {  	}  	switch s.ID {  	case SettingHeaderTableSize: -		sc.headerTableSize = s.Val  		sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)  	case SettingEnablePush:  		sc.pushEnabled = s.Val != 0 @@ -1686,16 +1745,6 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {  func (sc *serverConn) processData(f *DataFrame) error {  	sc.serveG.check()  	id := f.Header().StreamID -	if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) { -		// Discard all DATA frames if the GOAWAY is due to an -		// error, or: -		// -		// Section 6.8: After sending a GOAWAY frame, the sender -		// can discard frames for streams initiated by the -		// receiver with identifiers higher than the identified -		// last stream. -		return nil -	}  	data := f.Data()  	state, st := sc.state(id) @@ -1734,7 +1783,7 @@ func (sc *serverConn) processData(f *DataFrame) error {  		// sendWindowUpdate, which also schedules sending the  		// frames.  		sc.inflow.take(int32(f.Length)) -		sc.sendWindowUpdate(nil) // conn-level +		sc.sendWindowUpdate(nil, int(f.Length)) // conn-level  		if st != nil && st.resetQueued {  			// Already have a stream error in flight. Don't send another. @@ -1752,7 +1801,7 @@ func (sc *serverConn) processData(f *DataFrame) error {  			return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))  		}  		sc.inflow.take(int32(f.Length)) -		sc.sendWindowUpdate(nil) // conn-level +		sc.sendWindowUpdate(nil, int(f.Length)) // conn-level  		st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))  		// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the @@ -1770,7 +1819,7 @@ func (sc *serverConn) processData(f *DataFrame) error {  		if len(data) > 0 {  			wrote, err := st.body.Write(data)  			if err != nil { -				sc.sendWindowUpdate32(nil, int32(f.Length)-int32(wrote)) +				sc.sendWindowUpdate(nil, int(f.Length)-wrote)  				return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))  			}  			if wrote != len(data) { @@ -1838,19 +1887,27 @@ func (st *stream) copyTrailersToHandlerRequest() {  	}  } +// onReadTimeout is run on its own goroutine (from time.AfterFunc) +// when the stream's ReadTimeout has fired. +func (st *stream) onReadTimeout() { +	// Wrap the ErrDeadlineExceeded to avoid callers depending on us +	// returning the bare error. +	st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded)) +} +  // onWriteTimeout is run on its own goroutine (from time.AfterFunc)  // when the stream's WriteTimeout has fired.  func (st *stream) onWriteTimeout() { -	st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)}) +	st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{ +		StreamID: st.id, +		Code:     ErrCodeInternal, +		Cause:    os.ErrDeadlineExceeded, +	}})  }  func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {  	sc.serveG.check()  	id := f.StreamID -	if sc.inGoAway { -		// Ignore. -		return nil -	}  	// http://tools.ietf.org/html/rfc7540#section-5.1.1  	// Streams initiated by a client MUST use odd-numbered stream  	// identifiers. [...] An endpoint that receives an unexpected @@ -1953,6 +2010,9 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {  	// (in Go 1.8), though. That's a more sane option anyway.  	if sc.hs.ReadTimeout != 0 {  		sc.conn.SetReadDeadline(time.Time{}) +		if st.body != nil { +			st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout) +		}  	}  	go sc.runHandler(rw, req, handler) @@ -2021,9 +2081,6 @@ func (sc *serverConn) checkPriority(streamID uint32, p PriorityParam) error {  }  func (sc *serverConn) processPriority(f *PriorityFrame) error { -	if sc.inGoAway { -		return nil -	}  	if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {  		return err  	} @@ -2322,39 +2379,24 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {  func (sc *serverConn) noteBodyRead(st *stream, n int) {  	sc.serveG.check() -	sc.sendWindowUpdate(nil) // conn-level +	sc.sendWindowUpdate(nil, n) // conn-level  	if st.state != stateHalfClosedRemote && st.state != stateClosed {  		// Don't send this WINDOW_UPDATE if the stream is closed  		// remotely. -		sc.sendWindowUpdate(st) +		sc.sendWindowUpdate(st, n)  	}  }  // st may be nil for conn-level -func (sc *serverConn) sendWindowUpdate(st *stream) { +func (sc *serverConn) sendWindowUpdate(st *stream, n int) {  	sc.serveG.check() - -	var n int32 -	if st == nil { -		if avail, windowSize := sc.inflow.available(), sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 { -			return -		} else { -			n = windowSize - avail -		} -	} else { -		if avail, windowSize := st.inflow.available(), sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 { -			return -		} else { -			n = windowSize - avail -		} -	}  	// "The legal range for the increment to the flow control  	// window is 1 to 2^31-1 (2,147,483,647) octets."  	// A Go Read call on 64-bit machines could in theory read  	// a larger Read than this. Very unlikely, but we handle it here  	// rather than elsewhere for now.  	const maxUint31 = 1<<31 - 1 -	for n >= maxUint31 { +	for n > maxUint31 {  		sc.sendWindowUpdate32(st, maxUint31)  		n -= maxUint31  	} @@ -2474,7 +2516,15 @@ type responseWriterState struct {  type chunkWriter struct{ rws *responseWriterState } -func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) } +func (cw chunkWriter) Write(p []byte) (n int, err error) { +	n, err = cw.rws.writeChunk(p) +	if err == errStreamClosed { +		// If writing failed because the stream has been closed, +		// return the reason it was closed. +		err = cw.rws.stream.closeErr +	} +	return n, err +}  func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 } @@ -2668,23 +2718,85 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {  	}  } +func (w *responseWriter) SetReadDeadline(deadline time.Time) error { +	st := w.rws.stream +	if !deadline.IsZero() && deadline.Before(time.Now()) { +		// If we're setting a deadline in the past, reset the stream immediately +		// so writes after SetWriteDeadline returns will fail. +		st.onReadTimeout() +		return nil +	} +	w.rws.conn.sendServeMsg(func(sc *serverConn) { +		if st.readDeadline != nil { +			if !st.readDeadline.Stop() { +				// Deadline already exceeded, or stream has been closed. +				return +			} +		} +		if deadline.IsZero() { +			st.readDeadline = nil +		} else if st.readDeadline == nil { +			st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout) +		} else { +			st.readDeadline.Reset(deadline.Sub(time.Now())) +		} +	}) +	return nil +} + +func (w *responseWriter) SetWriteDeadline(deadline time.Time) error { +	st := w.rws.stream +	if !deadline.IsZero() && deadline.Before(time.Now()) { +		// If we're setting a deadline in the past, reset the stream immediately +		// so writes after SetWriteDeadline returns will fail. +		st.onWriteTimeout() +		return nil +	} +	w.rws.conn.sendServeMsg(func(sc *serverConn) { +		if st.writeDeadline != nil { +			if !st.writeDeadline.Stop() { +				// Deadline already exceeded, or stream has been closed. +				return +			} +		} +		if deadline.IsZero() { +			st.writeDeadline = nil +		} else if st.writeDeadline == nil { +			st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout) +		} else { +			st.writeDeadline.Reset(deadline.Sub(time.Now())) +		} +	}) +	return nil +} +  func (w *responseWriter) Flush() { +	w.FlushError() +} + +func (w *responseWriter) FlushError() error {  	rws := w.rws  	if rws == nil {  		panic("Header called after Handler finished")  	} +	var err error  	if rws.bw.Buffered() > 0 { -		if err := rws.bw.Flush(); err != nil { -			// Ignore the error. The frame writer already knows. -			return -		} +		err = rws.bw.Flush()  	} else {  		// The bufio.Writer won't call chunkWriter.Write  		// (writeChunk with zero bytes, so we have to do it  		// ourselves to force the HTTP response header and/or  		// final DATA frame (with END_STREAM) to be sent. -		rws.writeChunk(nil) +		_, err = chunkWriter{rws}.Write(nil) +		if err == nil { +			select { +			case <-rws.stream.cw: +				err = rws.stream.closeErr +			default: +			} +		}  	} +	return err  }  func (w *responseWriter) CloseNotify() <-chan bool { diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index c5d005bba..30f706e6c 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -16,6 +16,7 @@ import (  	"errors"  	"fmt"  	"io" +	"io/fs"  	"log"  	"math"  	mathrand "math/rand" @@ -117,6 +118,28 @@ type Transport struct {  	// to mean no limit.  	MaxHeaderListSize uint32 +	// MaxReadFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the +	// initial settings frame. It is the size in bytes of the largest frame +	// payload that the sender is willing to receive. If 0, no setting is +	// sent, and the value is provided by the peer, which should be 16384 +	// according to the spec: +	// https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2. +	// Values are bounded in the range 16k to 16M. +	MaxReadFrameSize uint32 + +	// MaxDecoderHeaderTableSize optionally specifies the http2 +	// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It +	// informs the remote endpoint of the maximum size of the header compression +	// table used to decode header blocks, in octets. If zero, the default value +	// of 4096 is used. +	MaxDecoderHeaderTableSize uint32 + +	// MaxEncoderHeaderTableSize optionally specifies an upper limit for the +	// header compression table used for encoding request headers. Received +	// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero, +	// the default value of 4096 is used. +	MaxEncoderHeaderTableSize uint32 +  	// StrictMaxConcurrentStreams controls whether the server's  	// SETTINGS_MAX_CONCURRENT_STREAMS should be respected  	// globally. If false, new TCP connections are created to the @@ -170,6 +193,19 @@ func (t *Transport) maxHeaderListSize() uint32 {  	return t.MaxHeaderListSize  } +func (t *Transport) maxFrameReadSize() uint32 { +	if t.MaxReadFrameSize == 0 { +		return 0 // use the default provided by the peer +	} +	if t.MaxReadFrameSize < minMaxFrameSize { +		return minMaxFrameSize +	} +	if t.MaxReadFrameSize > maxFrameSize { +		return maxFrameSize +	} +	return t.MaxReadFrameSize +} +  func (t *Transport) disableCompression() bool {  	return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)  } @@ -292,10 +328,11 @@ type ClientConn struct {  	lastActive      time.Time  	lastIdle        time.Time // time last idle  	// Settings from peer: (also guarded by wmu) -	maxFrameSize          uint32 -	maxConcurrentStreams  uint32 -	peerMaxHeaderListSize uint64 -	initialWindowSize     uint32 +	maxFrameSize           uint32 +	maxConcurrentStreams   uint32 +	peerMaxHeaderListSize  uint64 +	peerMaxHeaderTableSize uint32 +	initialWindowSize      uint32  	// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.  	// Write to reqHeaderMu to lock it, read from it to unlock. @@ -501,6 +538,15 @@ func authorityAddr(scheme string, authority string) (addr string) {  	return net.JoinHostPort(host, port)  } +var retryBackoffHook func(time.Duration) *time.Timer + +func backoffNewTimer(d time.Duration) *time.Timer { +	if retryBackoffHook != nil { +		return retryBackoffHook(d) +	} +	return time.NewTimer(d) +} +  // RoundTripOpt is like RoundTrip, but takes options.  func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {  	if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) { @@ -526,11 +572,14 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res  				}  				backoff := float64(uint(1) << (uint(retry) - 1))  				backoff += backoff * (0.1 * mathrand.Float64()) +				d := time.Second * time.Duration(backoff) +				timer := backoffNewTimer(d)  				select { -				case <-time.After(time.Second * time.Duration(backoff)): +				case <-timer.C:  					t.vlogf("RoundTrip retrying after failure: %v", err)  					continue  				case <-req.Context().Done(): +					timer.Stop()  					err = req.Context().Err()  				}  			} @@ -668,6 +717,20 @@ func (t *Transport) expectContinueTimeout() time.Duration {  	return t.t1.ExpectContinueTimeout  } +func (t *Transport) maxDecoderHeaderTableSize() uint32 { +	if v := t.MaxDecoderHeaderTableSize; v > 0 { +		return v +	} +	return initialHeaderTableSize +} + +func (t *Transport) maxEncoderHeaderTableSize() uint32 { +	if v := t.MaxEncoderHeaderTableSize; v > 0 { +		return v +	} +	return initialHeaderTableSize +} +  func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {  	return t.newClientConn(c, t.disableKeepAlives())  } @@ -708,15 +771,19 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro  	})  	cc.br = bufio.NewReader(c)  	cc.fr = NewFramer(cc.bw, cc.br) +	if t.maxFrameReadSize() != 0 { +		cc.fr.SetMaxReadFrameSize(t.maxFrameReadSize()) +	}  	if t.CountError != nil {  		cc.fr.countError = t.CountError  	} -	cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) +	maxHeaderTableSize := t.maxDecoderHeaderTableSize() +	cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil)  	cc.fr.MaxHeaderListSize = t.maxHeaderListSize() -	// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on -	// henc in response to SETTINGS frames?  	cc.henc = hpack.NewEncoder(&cc.hbuf) +	cc.henc.SetMaxDynamicTableSizeLimit(t.maxEncoderHeaderTableSize()) +	cc.peerMaxHeaderTableSize = initialHeaderTableSize  	if t.AllowHTTP {  		cc.nextStreamID = 3 @@ -731,9 +798,15 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro  		{ID: SettingEnablePush, Val: 0},  		{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},  	} +	if max := t.maxFrameReadSize(); max != 0 { +		initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: max}) +	}  	if max := t.maxHeaderListSize(); max != 0 {  		initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})  	} +	if maxHeaderTableSize != initialHeaderTableSize { +		initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: maxHeaderTableSize}) +	}  	cc.bw.Write(clientPreface)  	cc.fr.WriteSettings(initialSettings...) @@ -1075,7 +1148,7 @@ var errRequestCanceled = errors.New("net/http: request canceled")  func commaSeparatedTrailers(req *http.Request) (string, error) {  	keys := make([]string, 0, len(req.Trailer))  	for k := range req.Trailer { -		k = http.CanonicalHeaderKey(k) +		k = canonicalHeader(k)  		switch k {  		case "Transfer-Encoding", "Trailer", "Content-Length":  			return "", fmt.Errorf("invalid Trailer key %q", k) @@ -1612,7 +1685,7 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {  	var sawEOF bool  	for !sawEOF { -		n, err := body.Read(buf[:len(buf)]) +		n, err := body.Read(buf)  		if hasContentLen {  			remainLen -= int64(n)  			if remainLen == 0 && err == nil { @@ -1915,7 +1988,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail  	// Header list size is ok. Write the headers.  	enumerateHeaders(func(name, value string) { -		name, ascii := asciiToLower(name) +		name, ascii := lowerHeader(name)  		if !ascii {  			// 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). @@ -1968,7 +2041,7 @@ func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {  	}  	for k, vv := range trailer { -		lowKey, ascii := asciiToLower(k) +		lowKey, ascii := lowerHeader(k)  		if !ascii {  			// 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). @@ -2301,7 +2374,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra  		Status:     status + " " + http.StatusText(statusCode),  	}  	for _, hf := range regularFields { -		key := http.CanonicalHeaderKey(hf.Name) +		key := canonicalHeader(hf.Name)  		if key == "Trailer" {  			t := res.Trailer  			if t == nil { @@ -2309,7 +2382,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra  				res.Trailer = t  			}  			foreachHeaderElement(hf.Value, func(v string) { -				t[http.CanonicalHeaderKey(v)] = nil +				t[canonicalHeader(v)] = nil  			})  		} else {  			vv := header[key] @@ -2414,7 +2487,7 @@ func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFr  	trailer := make(http.Header)  	for _, hf := range f.RegularFields() { -		key := http.CanonicalHeaderKey(hf.Name) +		key := canonicalHeader(hf.Name)  		trailer[key] = append(trailer[key], hf.Value)  	}  	cs.trailer = trailer @@ -2760,8 +2833,10 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {  			cc.cond.Broadcast()  			cc.initialWindowSize = s.Val +		case SettingHeaderTableSize: +			cc.henc.SetMaxDynamicTableSize(s.Val) +			cc.peerMaxHeaderTableSize = s.Val  		default: -			// TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably.  			cc.vlogf("Unhandled Setting: %v", s)  		}  		return nil @@ -2985,7 +3060,11 @@ func (gz *gzipReader) Read(p []byte) (n int, err error) {  }  func (gz *gzipReader) Close() error { -	return gz.body.Close() +	if err := gz.body.Close(); err != nil { +		return err +	} +	gz.zerr = fs.ErrClosed +	return nil  }  type errorReader struct{ err error } | 
