diff options
author | Harrison Healey <harrisonmhealey@gmail.com> | 2018-01-16 12:03:31 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-16 12:03:31 -0500 |
commit | 2fa7c464f019f67c5c0494aaf5ac0f5ecc1ee7a7 (patch) | |
tree | e08ff912e1924c06939f314168c3362d6f1ec0de /vendor/golang.org/x/net/http2 | |
parent | f5c8a71698d0a7a16c68be220e49fe64bfee7f5c (diff) | |
download | chat-2fa7c464f019f67c5c0494aaf5ac0f5ecc1ee7a7.tar.gz chat-2fa7c464f019f67c5c0494aaf5ac0f5ecc1ee7a7.tar.bz2 chat-2fa7c464f019f67c5c0494aaf5ac0f5ecc1ee7a7.zip |
Updated dependencies and added avct/uasurfer (#8089)
* Updated dependencies and added avct/uasurfer
* Added uasurfer to NOTICE.txt
Diffstat (limited to 'vendor/golang.org/x/net/http2')
-rw-r--r-- | vendor/golang.org/x/net/http2/go19_test.go | 1 | ||||
-rw-r--r-- | vendor/golang.org/x/net/http2/server.go | 32 | ||||
-rw-r--r-- | vendor/golang.org/x/net/http2/server_test.go | 3 | ||||
-rw-r--r-- | vendor/golang.org/x/net/http2/transport.go | 62 | ||||
-rw-r--r-- | vendor/golang.org/x/net/http2/transport_test.go | 51 |
5 files changed, 109 insertions, 40 deletions
diff --git a/vendor/golang.org/x/net/http2/go19_test.go b/vendor/golang.org/x/net/http2/go19_test.go index 1675d248f..22b000667 100644 --- a/vendor/golang.org/x/net/http2/go19_test.go +++ b/vendor/golang.org/x/net/http2/go19_test.go @@ -46,7 +46,6 @@ func TestServerGracefulShutdown(t *testing.T) { wanth := [][2]string{ {":status", "200"}, {"x-foo", "bar"}, - {"content-type", "text/plain; charset=utf-8"}, {"content-length", "0"}, } if !reflect.DeepEqual(goth, wanth) { diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index 3e705a01c..460ede03b 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -652,7 +652,7 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) { if err == nil { return } - if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) { + if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout { // Boring, expected errors. sc.vlogf(format, args...) } else { @@ -897,8 +897,11 @@ func (sc *serverConn) sendServeMsg(msg interface{}) { } } -// readPreface reads the ClientPreface greeting from the peer -// or returns an error on timeout or an invalid greeting. +var errPrefaceTimeout = errors.New("timeout waiting for client preface") + +// readPreface reads the ClientPreface greeting from the peer or +// returns errPrefaceTimeout on timeout, or an error if the greeting +// is invalid. func (sc *serverConn) readPreface() error { errc := make(chan error, 1) go func() { @@ -916,7 +919,7 @@ func (sc *serverConn) readPreface() error { defer timer.Stop() select { case <-timer.C: - return errors.New("timeout waiting for client preface") + return errPrefaceTimeout case err := <-errc: if err == nil { if VerboseLogs { @@ -2319,7 +2322,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { clen = strconv.Itoa(len(p)) } _, hasContentType := rws.snapHeader["Content-Type"] - if !hasContentType && bodyAllowedForStatus(rws.status) { + if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 { ctype = http.DetectContentType(p) } var date string @@ -2487,6 +2490,24 @@ func (w *responseWriter) Header() http.Header { return rws.handlerHeader } +// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode. +func checkWriteHeaderCode(code int) { + // Issue 22880: require valid WriteHeader status codes. + // For now we only enforce that it's three digits. + // In the future we might block things over 599 (600 and above aren't defined + // at http://httpwg.org/specs/rfc7231.html#status.codes) + // and we might block under 200 (once we have more mature 1xx support). + // But for now any three digits. + // + // We used to send "HTTP/1.1 000 0" on the wire in responses but there's + // no equivalent bogus thing we can realistically send in HTTP/2, + // so we'll consistently panic instead and help people find their bugs + // early. (We can't return an error from WriteHeader even if we wanted to.) + if code < 100 || code > 999 { + panic(fmt.Sprintf("invalid WriteHeader code %v", code)) + } +} + func (w *responseWriter) WriteHeader(code int) { rws := w.rws if rws == nil { @@ -2497,6 +2518,7 @@ func (w *responseWriter) WriteHeader(code int) { func (rws *responseWriterState) writeHeader(code int) { if !rws.wroteHeader { + checkWriteHeaderCode(code) rws.wroteHeader = true rws.status = code if len(rws.handlerHeader) > 0 { diff --git a/vendor/golang.org/x/net/http2/server_test.go b/vendor/golang.org/x/net/http2/server_test.go index 91db6a2c5..bd1ba20d0 100644 --- a/vendor/golang.org/x/net/http2/server_test.go +++ b/vendor/golang.org/x/net/http2/server_test.go @@ -1718,7 +1718,6 @@ func TestServer_Response_NoData_Header_FooBar(t *testing.T) { wanth := [][2]string{ {":status", "200"}, {"foo-bar", "some-value"}, - {"content-type", "text/plain; charset=utf-8"}, {"content-length", "0"}, } if !reflect.DeepEqual(goth, wanth) { @@ -2953,7 +2952,6 @@ func TestServerDoesntWriteInvalidHeaders(t *testing.T) { wanth := [][2]string{ {":status", "200"}, {"ok1", "x"}, - {"content-type", "text/plain; charset=utf-8"}, {"content-length", "0"}, } if !reflect.DeepEqual(goth, wanth) { @@ -3266,7 +3264,6 @@ func TestServerNoAutoContentLengthOnHead(t *testing.T) { headers := st.decodeHeader(h.HeaderBlockFragment()) want := [][2]string{ {":status", "200"}, - {"content-type", "text/plain; charset=utf-8"}, } if !reflect.DeepEqual(headers, want) { t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 4392a09f8..c65f1a397 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -811,7 +811,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf cc.wmu.Lock() endStream := !hasBody && !hasTrailers - werr := cc.writeHeaders(cs.ID, endStream, hdrs) + werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) cc.wmu.Unlock() traceWroteHeaders(cs.trace) cc.mu.Unlock() @@ -964,13 +964,12 @@ func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error { } // requires cc.wmu be held -func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error { +func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error { first := true // first frame written (HEADERS is first, then CONTINUATION) - frameSize := int(cc.maxFrameSize) for len(hdrs) > 0 && cc.werr == nil { chunk := hdrs - if len(chunk) > frameSize { - chunk = chunk[:frameSize] + if len(chunk) > maxFrameSize { + chunk = chunk[:maxFrameSize] } hdrs = hdrs[len(chunk):] endHeaders := len(hdrs) == 0 @@ -1087,13 +1086,17 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( } } + cc.mu.Lock() + maxFrameSize := int(cc.maxFrameSize) + cc.mu.Unlock() + cc.wmu.Lock() defer cc.wmu.Unlock() // Two ways to send END_STREAM: either with trailers, or // with an empty DATA frame. if len(trls) > 0 { - err = cc.writeHeaders(cs.ID, true, trls) + err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls) } else { err = cc.fr.WriteData(cs.ID, true, nil) } @@ -1373,17 +1376,12 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream { // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. type clientConnReadLoop struct { cc *ClientConn - activeRes map[uint32]*clientStream // keyed by streamID closeWhenIdle bool } // readLoop runs in its own goroutine and reads and dispatches frames. func (cc *ClientConn) readLoop() { - rl := &clientConnReadLoop{ - cc: cc, - activeRes: make(map[uint32]*clientStream), - } - + rl := &clientConnReadLoop{cc: cc} defer rl.cleanup() cc.readerErr = rl.run() if ce, ok := cc.readerErr.(ConnectionError); ok { @@ -1438,10 +1436,8 @@ func (rl *clientConnReadLoop) cleanup() { } else if err == io.EOF { err = io.ErrUnexpectedEOF } - for _, cs := range rl.activeRes { - cs.bufPipe.CloseWithError(err) - } for _, cs := range cc.streams { + cs.bufPipe.CloseWithError(err) // no-op if already closed select { case cs.resc <- resAndError{err: err}: default: @@ -1519,7 +1515,7 @@ func (rl *clientConnReadLoop) run() error { } return err } - if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 { + if rl.closeWhenIdle && gotReply && maybeIdle { cc.closeIfIdle() } } @@ -1527,6 +1523,13 @@ func (rl *clientConnReadLoop) run() error { func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { cc := rl.cc + cs := cc.streamByID(f.StreamID, false) + if cs == nil { + // We'd get here if we canceled a request while the + // server had its response still in flight. So if this + // was just something we canceled, ignore it. + return nil + } if f.StreamEnded() { // Issue 20521: If the stream has ended, streamByID() causes // clientStream.done to be closed, which causes the request's bodyWriter @@ -1535,14 +1538,15 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { // Deferring stream closure allows the header processing to occur first. // clientConn.RoundTrip may still receive the bodyWriter error first, but // the fix for issue 16102 prioritises any response. - defer cc.streamByID(f.StreamID, true) - } - cs := cc.streamByID(f.StreamID, false) - if cs == nil { - // We'd get here if we canceled a request while the - // server had its response still in flight. So if this - // was just something we canceled, ignore it. - return nil + // + // Issue 22413: If there is no request body, we should close the + // stream before writing to cs.resc so that the stream is closed + // immediately once RoundTrip returns. + if cs.req.Body != nil { + defer cc.forgetStreamID(f.StreamID) + } else { + cc.forgetStreamID(f.StreamID) + } } if !cs.firstByte { if cs.trace != nil { @@ -1567,6 +1571,7 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { } // Any other error type is a stream error. cs.cc.writeStreamReset(f.StreamID, ErrCodeProtocol, err) + cc.forgetStreamID(cs.ID) cs.resc <- resAndError{err: err} return nil // return nil from process* funcs to keep conn alive } @@ -1574,9 +1579,6 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { // (nil, nil) special case. See handleResponse docs. return nil } - if res.Body != noBody { - rl.activeRes[cs.ID] = cs - } cs.resTrailer = &res.Trailer cs.resc <- resAndError{res: res} return nil @@ -1596,11 +1598,11 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra status := f.PseudoValue("status") if status == "" { - return nil, errors.New("missing status pseudo header") + return nil, errors.New("malformed response from server: missing status pseudo header") } statusCode, err := strconv.Atoi(status) if err != nil { - return nil, errors.New("malformed non-numeric status pseudo header") + return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header") } if statusCode == 100 { @@ -1915,7 +1917,6 @@ func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) { rl.closeWhenIdle = true } cs.bufPipe.closeWithErrorAndCode(err, code) - delete(rl.activeRes, cs.ID) select { case cs.resc <- resAndError{err: err}: @@ -2042,7 +2043,6 @@ func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error { cs.bufPipe.CloseWithError(err) cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl } - delete(rl.activeRes, cs.ID) return nil } diff --git a/vendor/golang.org/x/net/http2/transport_test.go b/vendor/golang.org/x/net/http2/transport_test.go index 30d7b5de0..adee48cd3 100644 --- a/vendor/golang.org/x/net/http2/transport_test.go +++ b/vendor/golang.org/x/net/http2/transport_test.go @@ -13,6 +13,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "math/rand" "net" "net/http" @@ -2291,6 +2292,11 @@ func TestTransportReadHeadResponse(t *testing.T) { } func TestTransportReadHeadResponseWithBody(t *testing.T) { + // This test use not valid response format. + // Discarding logger output to not spam tests output. + log.SetOutput(ioutil.Discard) + defer log.SetOutput(os.Stderr) + response := "redirecting to /elsewhere" ct := newClientTester(t) clientDone := make(chan struct{}) @@ -3383,6 +3389,11 @@ func TestTransportRetryHasLimit(t *testing.T) { } func TestTransportResponseDataBeforeHeaders(t *testing.T) { + // This test use not valid response format. + // Discarding logger output to not spam tests output. + log.SetOutput(ioutil.Discard) + defer log.SetOutput(os.Stderr) + ct := newClientTester(t) ct.client = func() error { defer ct.cc.(*net.TCPConn).CloseWrite() @@ -3788,6 +3799,46 @@ func TestTransportResponseAndResetWithoutConsumingBodyRace(t *testing.T) { } } +// Verify transport doesn't crash when receiving bogus response lacking a :status header. +// Issue 22880. +func TestTransportHandlesInvalidStatuslessResponse(t *testing.T) { + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + _, err := ct.tr.RoundTrip(req) + const substr = "malformed response from server: missing status pseudo header" + if !strings.Contains(fmt.Sprint(err), substr) { + return fmt.Errorf("RoundTrip error = %v; want substring %q", err, substr) + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + switch f := f.(type) { + case *HeadersFrame: + enc.WriteField(hpack.HeaderField{Name: "content-type", Value: "text/html"}) // no :status header + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: false, // we'll send some DATA to try to crash the transport + BlockFragment: buf.Bytes(), + }) + ct.fr.WriteData(f.StreamID, true, []byte("payload")) + return nil + } + } + } + ct.run() +} + func BenchmarkClientRequestHeaders(b *testing.B) { b.Run(" 0 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0) }) b.Run(" 10 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 10) }) |