Skip to content

Commit d1bef43

Browse files
artyomtombergan
authored andcommitted
net/http: make TimeoutHandler recover child handler panics
Fixes #22084. Change-Id: If405ffdc57fcf81de3c0e8473c45fc504db735bc Reviewed-on: https://go-review.googlesource.com/67410 Run-TryBot: Tom Bergan <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Tom Bergan <[email protected]>
1 parent c4d63a0 commit d1bef43

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

src/net/http/serve_test.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,6 +2438,14 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) {
24382438
}
24392439
}
24402440

2441+
// https://golang.org/issues/22084
2442+
func TestTimeoutHandlerPanicRecovery(t *testing.T) {
2443+
wrapper := func(h Handler) Handler {
2444+
return TimeoutHandler(h, time.Second, "")
2445+
}
2446+
testHandlerPanic(t, false, false, wrapper, "intentional death for testing")
2447+
}
2448+
24412449
func TestRedirectBadPath(t *testing.T) {
24422450
// This used to crash. It's not valid input (bad path), but it
24432451
// shouldn't crash.
@@ -2551,22 +2559,22 @@ func testZeroLengthPostAndResponse(t *testing.T, h2 bool) {
25512559
}
25522560
}
25532561

2554-
func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil) }
2555-
func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil) }
2562+
func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil, nil) }
2563+
func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil, nil) }
25562564

25572565
func TestHandlerPanic_h1(t *testing.T) {
2558-
testHandlerPanic(t, false, h1Mode, "intentional death for testing")
2566+
testHandlerPanic(t, false, h1Mode, nil, "intentional death for testing")
25592567
}
25602568
func TestHandlerPanic_h2(t *testing.T) {
2561-
testHandlerPanic(t, false, h2Mode, "intentional death for testing")
2569+
testHandlerPanic(t, false, h2Mode, nil, "intentional death for testing")
25622570
}
25632571

25642572
func TestHandlerPanicWithHijack(t *testing.T) {
25652573
// Only testing HTTP/1, and our http2 server doesn't support hijacking.
2566-
testHandlerPanic(t, true, h1Mode, "intentional death for testing")
2574+
testHandlerPanic(t, true, h1Mode, nil, "intentional death for testing")
25672575
}
25682576

2569-
func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) {
2577+
func testHandlerPanic(t *testing.T, withHijack, h2 bool, wrapper func(Handler) Handler, panicValue interface{}) {
25702578
defer afterTest(t)
25712579
// Unlike the other tests that set the log output to ioutil.Discard
25722580
// to quiet the output, this test uses a pipe. The pipe serves three
@@ -2589,7 +2597,7 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
25892597
defer log.SetOutput(os.Stderr)
25902598
defer pw.Close()
25912599

2592-
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
2600+
var handler Handler = HandlerFunc(func(w ResponseWriter, r *Request) {
25932601
if withHijack {
25942602
rwc, _, err := w.(Hijacker).Hijack()
25952603
if err != nil {
@@ -2598,7 +2606,11 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
25982606
defer rwc.Close()
25992607
}
26002608
panic(panicValue)
2601-
}))
2609+
})
2610+
if wrapper != nil {
2611+
handler = wrapper(handler)
2612+
}
2613+
cst := newClientServerTest(t, h2, handler)
26022614
defer cst.close()
26032615

26042616
// Do a blocking read on the log output pipe so its logging

src/net/http/server.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3081,11 +3081,19 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
30813081
w: w,
30823082
h: make(Header),
30833083
}
3084+
panicChan := make(chan interface{}, 1)
30843085
go func() {
3086+
defer func() {
3087+
if p := recover(); p != nil {
3088+
panicChan <- p
3089+
}
3090+
}()
30853091
h.handler.ServeHTTP(tw, r)
30863092
close(done)
30873093
}()
30883094
select {
3095+
case p := <-panicChan:
3096+
panic(p)
30893097
case <-done:
30903098
tw.mu.Lock()
30913099
defer tw.mu.Unlock()

0 commit comments

Comments
 (0)