]> Cypherpunks repositories - gostls13.git/commitdiff
http: catch panics
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 2 Jun 2011 19:00:26 +0000 (12:00 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 2 Jun 2011 19:00:26 +0000 (12:00 -0700)
R=rsc
CC=golang-dev
https://golang.org/cl/4559067

src/pkg/http/serve_test.go
src/pkg/http/server.go

index 0acec226d5f38b14bf4d567bbb517e51f8c7ca10..c923c8a76d0fc167530afcc150cef8d45dc3751f 100644 (file)
@@ -13,6 +13,7 @@ import (
        . "http"
        "http/httptest"
        "io/ioutil"
+       "log"
        "os"
        "net"
        "reflect"
@@ -432,6 +433,9 @@ func TestSetsRemoteAddr(t *testing.T) {
 }
 
 func TestChunkedResponseHeaders(t *testing.T) {
+       log.SetOutput(ioutil.Discard) // is noisy otherwise
+       defer log.SetOutput(os.Stderr)
+
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
                fmt.Fprintf(w, "I am a chunked response.")
@@ -755,6 +759,20 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
        }
 }
 
+func TestHandlerPanic(t *testing.T) {
+       log.SetOutput(ioutil.Discard) // is noisy otherwise
+       defer log.SetOutput(os.Stderr)
+
+       ts := httptest.NewServer(HandlerFunc(func(ResponseWriter, *Request) {
+               panic("intentional death for testing")
+       }))
+       defer ts.Close()
+       _, err := Get(ts.URL)
+       if err == nil {
+               t.Logf("expected an error")
+       }
+}
+
 func BenchmarkClientServer(b *testing.B) {
        b.StopTimer()
        ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
index ffeac034ef89245b4a79aeef46a0fb4e6050877c..93d9d2ff4f4015cec2f41541569b6b70f88f8e4c 100644 (file)
@@ -6,12 +6,12 @@
 
 // TODO(rsc):
 //     logging
-//     post support
 
 package http
 
 import (
        "bufio"
+       "bytes"
        "crypto/rand"
        "crypto/tls"
        "fmt"
@@ -20,6 +20,7 @@ import (
        "net"
        "os"
        "path"
+       "runtime"
        "strconv"
        "strings"
        "sync"
@@ -475,6 +476,33 @@ func (c *conn) close() {
 
 // Serve a new connection.
 func (c *conn) serve() {
+       defer func() {
+               err := recover()
+               if err == nil {
+                       return
+               }
+               c.rwc.Close()
+
+               // TODO(rsc,bradfitz): this is boilerplate. move it to runtime.Stack()
+               var buf bytes.Buffer
+               fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
+               for i := 1; i < 20; i++ {
+                       pc, file, line, ok := runtime.Caller(i)
+                       if !ok {
+                               break
+                       }
+                       var name string
+                       f := runtime.FuncForPC(pc)
+                       if f != nil {
+                               name = f.Name()
+                       } else {
+                               name = fmt.Sprintf("%#x", pc)
+                       }
+                       fmt.Fprintf(&buf, "  %s %s:%d\n", name, file, line)
+               }
+               log.Print(buf.String())
+       }()
+
        for {
                w, err := c.readRequest()
                if err != nil {