]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: update bundled http2
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 12 Jul 2018 19:12:38 +0000 (19:12 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 12 Jul 2018 21:49:56 +0000 (21:49 +0000)
Updates bundled x/net/http2 to git rev d0887baf81f4 for:

    http2: ignore unknown 1xx responses like HTTP/1
    https://golang.org/cl/123615

    http2: fix bug in earlier CL 123615
    https://golang.org/cl/123675

Also along for the ride, but without any effect:

    http2: export a field of an internal type for use by net/http
    https://golang.org/cl/123656

Fixes #26189
Updates #17739

Change-Id: I1955d844d74113efbcbbdaa7d7a7faebb2225b45
Reviewed-on: https://go-review.googlesource.com/123676
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/http/h2_bundle.go

index 154287dbd6bf37671c38a4faa5fe0ae3316f24e9..7fc8937125ba4780370b01f080f106d7cdb8d2fc 100644 (file)
@@ -999,7 +999,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 
 // registerHTTPSProtocol calls Transport.RegisterProtocol but
 // converting panics into errors.
-func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
+func http2registerHTTPSProtocol(t *Transport, rt http2noDialH2RoundTripper) (err error) {
        defer func() {
                if e := recover(); e != nil {
                        err = fmt.Errorf("%v", e)
@@ -1011,10 +1011,12 @@ func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
 
 // noDialH2RoundTripper is a RoundTripper which only tries to complete the request
 // if there's already has a cached connection to the host.
-type http2noDialH2RoundTripper struct{ t *http2Transport }
+// (The field is exported so it can be accessed via reflect from net/http; tested
+// by TestNoDialH2RoundTripperType)
+type http2noDialH2RoundTripper struct{ *http2Transport }
 
 func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) {
-       res, err := rt.t.RoundTrip(req)
+       res, err := rt.http2Transport.RoundTrip(req)
        if http2isNoCachedConnError(err) {
                return nil, ErrSkipAltProtocol
        }
@@ -2897,6 +2899,13 @@ func http2traceWroteHeaderField(trace *http2clientTrace, k, v string) {
        }
 }
 
+func http2traceGot1xxResponseFunc(trace *http2clientTrace) func(int, textproto.MIMEHeader) error {
+       if trace != nil {
+               return trace.Got1xxResponse
+       }
+       return nil
+}
+
 func http2transportExpectContinueTimeout(t1 *Transport) time.Duration {
        return t1.ExpectContinueTimeout
 }
@@ -6815,9 +6824,10 @@ type http2clientStream struct {
        done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
 
        // owned by clientConnReadLoop:
-       firstByte    bool // got the first response byte
-       pastHeaders  bool // got first MetaHeadersFrame (actual headers)
-       pastTrailers bool // got optional second MetaHeadersFrame (trailers)
+       firstByte    bool  // got the first response byte
+       pastHeaders  bool  // got first MetaHeadersFrame (actual headers)
+       pastTrailers bool  // got optional second MetaHeadersFrame (trailers)
+       num1xx       uint8 // number of 1xx responses seen
 
        trailer    Header  // accumulated trailers
        resTrailer *Header // client's Response.Trailer
@@ -6841,6 +6851,17 @@ func http2awaitRequestCancel(req *Request, done <-chan struct{}) error {
        }
 }
 
+var http2got1xxFuncForTests func(int, textproto.MIMEHeader) error
+
+// get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func,
+// if any. It returns nil if not set or if the Go version is too old.
+func (cs *http2clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error {
+       if fn := http2got1xxFuncForTests; fn != nil {
+               return fn
+       }
+       return http2traceGot1xxResponseFunc(cs.trace)
+}
+
 // awaitRequestCancel waits for the user to cancel a request, its context to
 // expire, or for the request to be done (any way it might be removed from the
 // cc.streams map: peer reset, successful completion, TCP connection breakage,
@@ -8338,8 +8359,7 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
 // is the detail.
 //
 // As a special case, handleResponse may return (nil, nil) to skip the
-// frame (currently only used for 100 expect continue). This special
-// case is going away after Issue 13851 is fixed.
+// frame (currently only used for 1xx responses).
 func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http2MetaHeadersFrame) (*Response, error) {
        if f.Truncated {
                return nil, http2errResponseHeaderListSize
@@ -8354,15 +8374,6 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
                return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
        }
 
-       if statusCode == 100 {
-               http2traceGot100Continue(cs.trace)
-               if cs.on100 != nil {
-                       cs.on100() // forces any write delay timer to fire
-               }
-               cs.pastHeaders = false // do it all again
-               return nil, nil
-       }
-
        header := make(Header)
        res := &Response{
                Proto:      "HTTP/2.0",
@@ -8387,6 +8398,27 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
                }
        }
 
+       if statusCode >= 100 && statusCode <= 199 {
+               cs.num1xx++
+               const max1xxResponses = 5 // arbitrary bound on number of informational responses, same as net/http
+               if cs.num1xx > max1xxResponses {
+                       return nil, errors.New("http2: too many 1xx informational responses")
+               }
+               if fn := cs.get1xxTraceFunc(); fn != nil {
+                       if err := fn(statusCode, textproto.MIMEHeader(header)); err != nil {
+                               return nil, err
+                       }
+               }
+               if statusCode == 100 {
+                       http2traceGot100Continue(cs.trace)
+                       if cs.on100 != nil {
+                               cs.on100() // forces any write delay timer to fire
+                       }
+               }
+               cs.pastHeaders = false // do it all again
+               return nil, nil
+       }
+
        streamEnded := f.StreamEnded()
        isHead := cs.req.Method == "HEAD"
        if !streamEnded || isHead {