@@ -47,6 +47,7 @@ import (
47
47
"net"
48
48
"net/http"
49
49
"net/url"
50
+ "runtime"
50
51
"strconv"
51
52
"strings"
52
53
"sync"
@@ -615,6 +616,7 @@ func (sc *serverConn) stopShutdownTimer() {
615
616
}
616
617
617
618
func (sc * serverConn ) notePanic () {
619
+ // Note: this is for serverConn.serve panicking, not http.Handler code.
618
620
if testHookOnPanicMu != nil {
619
621
testHookOnPanicMu .Lock ()
620
622
defer testHookOnPanicMu .Unlock ()
@@ -837,6 +839,11 @@ func (sc *serverConn) startFrameWrite(wm frameWriteMsg) {
837
839
go sc .writeFrameAsync (wm )
838
840
}
839
841
842
+ // errHandlerPanicked is the error given to any callers blocked in a read from
843
+ // Request.Body when the main goroutine panics. Since most handlers read in the
844
+ // the main ServeHTTP goroutine, this will show up rarely.
845
+ var errHandlerPanicked = errors .New ("http2: handler panicked" )
846
+
840
847
// wroteFrame is called on the serve goroutine with the result of
841
848
// whatever happened on writeFrameAsync.
842
849
func (sc * serverConn ) wroteFrame (res frameWriteResult ) {
@@ -851,6 +858,10 @@ func (sc *serverConn) wroteFrame(res frameWriteResult) {
851
858
852
859
closeStream := endsStream (wm .write )
853
860
861
+ if _ , ok := wm .write .(handlerPanicRST ); ok {
862
+ sc .closeStream (st , errHandlerPanicked )
863
+ }
864
+
854
865
// Reply (if requested) to the blocked ServeHTTP goroutine.
855
866
if ch := wm .done ; ch != nil {
856
867
select {
@@ -1530,9 +1541,25 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
1530
1541
1531
1542
// Run on its own goroutine.
1532
1543
func (sc * serverConn ) runHandler (rw * responseWriter , req * http.Request , handler func (http.ResponseWriter , * http.Request )) {
1533
- defer rw .handlerDone ()
1534
- // TODO: catch panics like net/http.Server
1544
+ didPanic := true
1545
+ defer func () {
1546
+ if didPanic {
1547
+ e := recover ()
1548
+ // Same as net/http:
1549
+ const size = 64 << 10
1550
+ buf := make ([]byte , size )
1551
+ buf = buf [:runtime .Stack (buf , false )]
1552
+ sc .writeFrameFromHandler (frameWriteMsg {
1553
+ write : handlerPanicRST {rw .rws .stream .id },
1554
+ stream : rw .rws .stream ,
1555
+ })
1556
+ sc .logf ("http2: panic serving %v: %v\n %s" , sc .conn .RemoteAddr (), e , buf )
1557
+ return
1558
+ }
1559
+ rw .handlerDone ()
1560
+ }()
1535
1561
handler (rw , req )
1562
+ didPanic = false
1536
1563
}
1537
1564
1538
1565
func handleHeaderListTooLong (w http.ResponseWriter , r * http.Request ) {
@@ -1920,9 +1947,6 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int,
1920
1947
1921
1948
func (w * responseWriter ) handlerDone () {
1922
1949
rws := w .rws
1923
- if rws == nil {
1924
- panic ("handlerDone called twice" )
1925
- }
1926
1950
rws .handlerDone = true
1927
1951
w .Flush ()
1928
1952
w .rws = nil
0 commit comments