]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: updated bundled http2 copy, enable some tests
authorBrad Fitzpatrick <bradfitz@golang.org>
Tue, 15 Dec 2015 00:52:58 +0000 (00:52 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 15 Dec 2015 05:05:00 +0000 (05:05 +0000)
Updates bundled copy of x/net/http2 to include
https://golang.org/cl/17823 (catching panics in Handlers)

Fixes #13555

Change-Id: I08e4e38e736a8d93f5ec200e8041c143fc6eafce
Reviewed-on: https://go-review.googlesource.com/17824
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/http/h2_bundle.go
src/net/http/serve_test.go

index 216b8232148a6d0740ebc31dcb524007a7084b21..155796af14f0112b77396f6bfacf9cc2a255dd8f 100644 (file)
@@ -1473,6 +1473,8 @@ type http2headersEnder interface {
        HeadersEnded() bool
 }
 
+func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel }
+
 var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
 
 type http2goroutineLock uint64
@@ -2545,6 +2547,7 @@ func (sc *http2serverConn) stopShutdownTimer() {
 }
 
 func (sc *http2serverConn) notePanic() {
+
        if http2testHookOnPanicMu != nil {
                http2testHookOnPanicMu.Lock()
                defer http2testHookOnPanicMu.Unlock()
@@ -2752,6 +2755,11 @@ func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
        go sc.writeFrameAsync(wm)
 }
 
+// errHandlerPanicked is the error given to any callers blocked in a read from
+// Request.Body when the main goroutine panics. Since most handlers read in the
+// the main ServeHTTP goroutine, this will show up rarely.
+var http2errHandlerPanicked = errors.New("http2: handler panicked")
+
 // wroteFrame is called on the serve goroutine with the result of
 // whatever happened on writeFrameAsync.
 func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
@@ -2766,6 +2774,10 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
 
        closeStream := http2endsStream(wm.write)
 
+       if _, ok := wm.write.(http2handlerPanicRST); ok {
+               sc.closeStream(st, http2errHandlerPanicked)
+       }
+
        if ch := wm.done; ch != nil {
                select {
                case ch <- res.err:
@@ -3360,9 +3372,25 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
 
 // Run on its own goroutine.
 func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
-       defer rw.handlerDone()
-
+       didPanic := true
+       defer func() {
+               if didPanic {
+                       e := recover()
+                       // Same as net/http:
+                       const size = 64 << 10
+                       buf := make([]byte, size)
+                       buf = buf[:runtime.Stack(buf, false)]
+                       sc.writeFrameFromHandler(http2frameWriteMsg{
+                               write:  http2handlerPanicRST{rw.rws.stream.id},
+                               stream: rw.rws.stream,
+                       })
+                       sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+                       return
+               }
+               rw.handlerDone()
+       }()
        handler(rw, req)
+       didPanic = false
 }
 
 func http2handleHeaderListTooLong(w ResponseWriter, r *Request) {
@@ -3743,9 +3771,6 @@ func (w *http2responseWriter) write(lenData int, dataB []byte, dataS string) (n
 
 func (w *http2responseWriter) handlerDone() {
        rws := w.rws
-       if rws == nil {
-               panic("handlerDone called twice")
-       }
        rws.handlerDone = true
        w.Flush()
        w.rws = nil
@@ -4279,9 +4304,11 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
                        res.Request = req
                        res.TLS = cc.tlsState
                        return res, nil
-               case <-req.Cancel:
+               case <-http2requestCancel(req):
                        cs.abortRequestBodyWrite()
                        return nil, http2errRequestCanceled
+               case <-cs.peerReset:
+                       return nil, cs.resetErr
                case err := <-bodyCopyErrc:
                        if err != nil {
                                return nil, err
@@ -4630,7 +4657,7 @@ func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, strea
                cs.bufPipe = http2pipe{b: buf}
                cs.bytesRemain = res.ContentLength
                res.Body = http2transportResponseBody{cs}
-               go cs.awaitRequestCancel(cs.req.Cancel)
+               go cs.awaitRequestCancel(http2requestCancel(cs.req))
 
                if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
                        res.Header.Del("Content-Encoding")
@@ -5016,6 +5043,16 @@ func (w *http2writeData) writeFrame(ctx http2writeContext) error {
        return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
 }
 
+// handlerPanicRST is the message sent from handler goroutines when
+// the handler panics.
+type http2handlerPanicRST struct {
+       StreamID uint32
+}
+
+func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal)
+}
+
 func (se http2StreamError) writeFrame(ctx http2writeContext) error {
        return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
 }
index 5a0706e06e744a0a3b5cada2de359534b37b044e..a98a4ccf3b1b2fac7ebbcfbfffe1ff154440ff32 100644 (file)
@@ -1926,16 +1926,12 @@ func testZeroLengthPostAndResponse(t *testing.T, h2 bool) {
 }
 
 func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil) }
-func TestHandlerPanicNil_h2(t *testing.T) {
-       t.Skip("known failure; golang.org/issue/13555")
-       testHandlerPanic(t, false, h2Mode, nil)
-}
+func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil) }
 
 func TestHandlerPanic_h1(t *testing.T) {
        testHandlerPanic(t, false, h1Mode, "intentional death for testing")
 }
 func TestHandlerPanic_h2(t *testing.T) {
-       t.Skip("known failure; golang.org/issue/13555")
        testHandlerPanic(t, false, h2Mode, "intentional death for testing")
 }