mirror of https://github.com/golang/go.git
net/http: regenerate h2_bundle.go
Done with: go generate -run=bundle std After CL 452096 updated the x/net version. Change-Id: I1c1cd76d4ec9e14f45dc66c945c74e41ff689a30 Reviewed-on: https://go-review.googlesource.com/c/go/+/452195 Reviewed-by: Roland Shoemaker <roland@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org> Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
04d6aa6514
commit
4f0d3bcd6d
|
|
@ -30,6 +30,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"math"
|
||||
mathrand "math/rand"
|
||||
|
|
@ -3185,7 +3186,14 @@ func http2buildCommonHeaderMaps() {
|
|||
"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",
|
||||
|
|
@ -3211,6 +3219,7 @@ func http2buildCommonHeaderMaps() {
|
|||
"link",
|
||||
"location",
|
||||
"max-forwards",
|
||||
"origin",
|
||||
"proxy-authenticate",
|
||||
"proxy-authorization",
|
||||
"range",
|
||||
|
|
@ -3226,6 +3235,8 @@ func http2buildCommonHeaderMaps() {
|
|||
"vary",
|
||||
"via",
|
||||
"www-authenticate",
|
||||
"x-forwarded-for",
|
||||
"x-forwarded-proto",
|
||||
}
|
||||
http2commonLowerHeader = make(map[string]string, len(common))
|
||||
http2commonCanonHeader = make(map[string]string, len(common))
|
||||
|
|
@ -3244,6 +3255,14 @@ func http2lowerHeader(v string) (lower string, ascii bool) {
|
|||
return http2asciiToLower(v)
|
||||
}
|
||||
|
||||
func http2canonicalHeader(v string) string {
|
||||
http2buildCommonHeaderMapsOnce()
|
||||
if s, ok := http2commonCanonHeader[v]; ok {
|
||||
return s
|
||||
}
|
||||
return CanonicalHeaderKey(v)
|
||||
}
|
||||
|
||||
var (
|
||||
http2VerboseLogs bool
|
||||
http2logFrameWrites bool
|
||||
|
|
@ -4342,7 +4361,9 @@ type http2stream 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 Header // accumulated trailers
|
||||
reqTrailer Header // handler's Request.Trailer
|
||||
|
|
@ -4592,7 +4613,9 @@ func (sc *http2serverConn) 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() - http2initialWindowSize; 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)
|
||||
|
|
@ -4669,6 +4692,8 @@ func (sc *http2serverConn) serve() {
|
|||
}
|
||||
case *http2startPushRequest:
|
||||
sc.startPush(v)
|
||||
case func(*http2serverConn):
|
||||
v(sc)
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected type %T", v))
|
||||
}
|
||||
|
|
@ -5184,6 +5209,21 @@ func (sc *http2serverConn) processFrame(f http2Frame) 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 != http2ErrCodeNo || f.Header().StreamID > sc.maxClientStreamID) {
|
||||
|
||||
if f, ok := f.(*http2DataFrame); ok {
|
||||
if sc.inflow.available() < int32(f.Length) {
|
||||
return sc.countError("data_flow", http2streamError(f.Header().StreamID, http2ErrCodeFlowControl))
|
||||
}
|
||||
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f := f.(type) {
|
||||
case *http2SettingsFrame:
|
||||
return sc.processSettings(f)
|
||||
|
|
@ -5226,9 +5266,6 @@ func (sc *http2serverConn) processPing(f *http2PingFrame) error {
|
|||
// PROTOCOL_ERROR."
|
||||
return sc.countError("ping_on_stream", http2ConnectionError(http2ErrCodeProtocol))
|
||||
}
|
||||
if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
|
||||
return nil
|
||||
}
|
||||
sc.writeFrame(http2FrameWriteRequest{write: http2writePingAck{f}})
|
||||
return nil
|
||||
}
|
||||
|
|
@ -5290,6 +5327,9 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
|
|||
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
|
||||
}
|
||||
st.state = http2stateClosed
|
||||
if st.readDeadline != nil {
|
||||
st.readDeadline.Stop()
|
||||
}
|
||||
if st.writeDeadline != nil {
|
||||
st.writeDeadline.Stop()
|
||||
}
|
||||
|
|
@ -5311,10 +5351,18 @@ func (sc *http2serverConn) closeStream(st *http2stream, 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.(http2StreamError); ok {
|
||||
if e.Cause != nil {
|
||||
err = e.Cause
|
||||
} else {
|
||||
err = http2errStreamClosed
|
||||
}
|
||||
}
|
||||
st.closeErr = err
|
||||
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
|
||||
sc.writeSched.CloseStream(st.id)
|
||||
}
|
||||
|
|
@ -5411,16 +5459,6 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
|
|||
func (sc *http2serverConn) processData(f *http2DataFrame) error {
|
||||
sc.serveG.check()
|
||||
id := f.Header().StreamID
|
||||
if sc.inGoAway && (sc.goAwayCode != http2ErrCodeNo || 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)
|
||||
|
|
@ -5459,7 +5497,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) 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.
|
||||
|
|
@ -5477,7 +5515,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
|
|||
return sc.countError("data_flow", http2streamError(id, http2ErrCodeFlowControl))
|
||||
}
|
||||
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
|
||||
|
|
@ -5495,7 +5533,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) 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", http2streamError(id, http2ErrCodeStreamClosed))
|
||||
}
|
||||
if wrote != len(data) {
|
||||
|
|
@ -5563,19 +5601,27 @@ func (st *http2stream) copyTrailersToHandlerRequest() {
|
|||
}
|
||||
}
|
||||
|
||||
// onReadTimeout is run on its own goroutine (from time.AfterFunc)
|
||||
// when the stream's ReadTimeout has fired.
|
||||
func (st *http2stream) 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 *http2stream) onWriteTimeout() {
|
||||
st.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2streamError(st.id, http2ErrCodeInternal)})
|
||||
st.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2StreamError{
|
||||
StreamID: st.id,
|
||||
Code: http2ErrCodeInternal,
|
||||
Cause: os.ErrDeadlineExceeded,
|
||||
}})
|
||||
}
|
||||
|
||||
func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) 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
|
||||
|
|
@ -5678,6 +5724,9 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) 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)
|
||||
|
|
@ -5746,9 +5795,6 @@ func (sc *http2serverConn) checkPriority(streamID uint32, p http2PriorityParam)
|
|||
}
|
||||
|
||||
func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
|
||||
if sc.inGoAway {
|
||||
return nil
|
||||
}
|
||||
if err := sc.checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -6047,39 +6093,24 @@ func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err e
|
|||
|
||||
func (sc *http2serverConn) noteBodyRead(st *http2stream, n int) {
|
||||
sc.serveG.check()
|
||||
sc.sendWindowUpdate(nil) // conn-level
|
||||
sc.sendWindowUpdate(nil, n) // conn-level
|
||||
if st.state != http2stateHalfClosedRemote && st.state != http2stateClosed {
|
||||
// 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 *http2serverConn) sendWindowUpdate(st *http2stream) {
|
||||
func (sc *http2serverConn) sendWindowUpdate(st *http2stream, 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
|
||||
}
|
||||
|
|
@ -6199,7 +6230,15 @@ type http2responseWriterState struct {
|
|||
|
||||
type http2chunkWriter struct{ rws *http2responseWriterState }
|
||||
|
||||
func (cw http2chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
|
||||
func (cw http2chunkWriter) Write(p []byte) (n int, err error) {
|
||||
n, err = cw.rws.writeChunk(p)
|
||||
if err == http2errStreamClosed {
|
||||
// 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 *http2responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
|
||||
|
||||
|
|
@ -6393,23 +6432,85 @@ func (rws *http2responseWriterState) promoteUndeclaredTrailers() {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *http2responseWriter) 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 *http2serverConn) {
|
||||
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 *http2responseWriter) 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 *http2serverConn) {
|
||||
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 *http2responseWriter) Flush() {
|
||||
w.FlushError()
|
||||
}
|
||||
|
||||
func (w *http2responseWriter) 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 = http2chunkWriter{rws}.Write(nil)
|
||||
if err == nil {
|
||||
select {
|
||||
case <-rws.stream.cw:
|
||||
err = rws.stream.closeErr
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *http2responseWriter) CloseNotify() <-chan bool {
|
||||
|
|
@ -7329,6 +7430,15 @@ func http2authorityAddr(scheme string, authority string) (addr string) {
|
|||
return net.JoinHostPort(host, port)
|
||||
}
|
||||
|
||||
var http2retryBackoffHook func(time.Duration) *time.Timer
|
||||
|
||||
func http2backoffNewTimer(d time.Duration) *time.Timer {
|
||||
if http2retryBackoffHook != nil {
|
||||
return http2retryBackoffHook(d)
|
||||
}
|
||||
return time.NewTimer(d)
|
||||
}
|
||||
|
||||
// RoundTripOpt is like RoundTrip, but takes options.
|
||||
func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
|
||||
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
|
||||
|
|
@ -7354,11 +7464,14 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res
|
|||
}
|
||||
backoff := float64(uint(1) << (uint(retry) - 1))
|
||||
backoff += backoff * (0.1 * mathrand.Float64())
|
||||
d := time.Second * time.Duration(backoff)
|
||||
timer := http2backoffNewTimer(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()
|
||||
}
|
||||
}
|
||||
|
|
@ -7903,7 +8016,7 @@ var http2errRequestCanceled = errors.New("net/http: request canceled")
|
|||
func http2commaSeparatedTrailers(req *Request) (string, error) {
|
||||
keys := make([]string, 0, len(req.Trailer))
|
||||
for k := range req.Trailer {
|
||||
k = CanonicalHeaderKey(k)
|
||||
k = http2canonicalHeader(k)
|
||||
switch k {
|
||||
case "Transfer-Encoding", "Trailer", "Content-Length":
|
||||
return "", fmt.Errorf("invalid Trailer key %q", k)
|
||||
|
|
@ -8440,7 +8553,7 @@ func (cs *http2clientStream) writeRequestBody(req *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 {
|
||||
|
|
@ -8743,7 +8856,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
|
|||
|
||||
// Header list size is ok. Write the headers.
|
||||
enumerateHeaders(func(name, value string) {
|
||||
name, ascii := http2asciiToLower(name)
|
||||
name, ascii := http2lowerHeader(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).
|
||||
|
|
@ -8796,7 +8909,7 @@ func (cc *http2ClientConn) encodeTrailers(trailer Header) ([]byte, error) {
|
|||
}
|
||||
|
||||
for k, vv := range trailer {
|
||||
lowKey, ascii := http2asciiToLower(k)
|
||||
lowKey, ascii := http2lowerHeader(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).
|
||||
|
|
@ -9129,7 +9242,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
|
|||
Status: status + " " + StatusText(statusCode),
|
||||
}
|
||||
for _, hf := range regularFields {
|
||||
key := CanonicalHeaderKey(hf.Name)
|
||||
key := http2canonicalHeader(hf.Name)
|
||||
if key == "Trailer" {
|
||||
t := res.Trailer
|
||||
if t == nil {
|
||||
|
|
@ -9137,7 +9250,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
|
|||
res.Trailer = t
|
||||
}
|
||||
http2foreachHeaderElement(hf.Value, func(v string) {
|
||||
t[CanonicalHeaderKey(v)] = nil
|
||||
t[http2canonicalHeader(v)] = nil
|
||||
})
|
||||
} else {
|
||||
vv := header[key]
|
||||
|
|
@ -9242,7 +9355,7 @@ func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *htt
|
|||
|
||||
trailer := make(Header)
|
||||
for _, hf := range f.RegularFields() {
|
||||
key := CanonicalHeaderKey(hf.Name)
|
||||
key := http2canonicalHeader(hf.Name)
|
||||
trailer[key] = append(trailer[key], hf.Value)
|
||||
}
|
||||
cs.trailer = trailer
|
||||
|
|
@ -9816,7 +9929,11 @@ func (gz *http2gzipReader) Read(p []byte) (n int, err error) {
|
|||
}
|
||||
|
||||
func (gz *http2gzipReader) Close() error {
|
||||
return gz.body.Close()
|
||||
if err := gz.body.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
gz.zerr = fs.ErrClosed
|
||||
return nil
|
||||
}
|
||||
|
||||
type http2errorReader struct{ err error }
|
||||
|
|
|
|||
Loading…
Reference in New Issue