mirror of
https://github.com/golang/go
synced 2024-11-18 00:54:45 -07:00
net/http: updated bundled http2 copy, enable some tests
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>
This commit is contained in:
parent
9b1068ad2f
commit
d4df6f4874
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user