aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2011-06-02 12:00:26 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2011-06-02 12:00:26 -0700
commit2a8ea0d1b598938d344edec9428acc4a2d2e8e4e (patch)
treeff37e43459172867e8c50845165e2e840daab26f
parent191a6bfc5e99911f905cb582b676b5502c7b5aad (diff)
downloadgo-2a8ea0d1b598938d344edec9428acc4a2d2e8e4e.tar.xz
http: catch panics
R=rsc CC=golang-dev https://golang.org/cl/4559067
-rw-r--r--src/pkg/http/serve_test.go18
-rw-r--r--src/pkg/http/server.go30
2 files changed, 47 insertions, 1 deletions
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 0acec226d5..c923c8a76d 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -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) {
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index ffeac034ef..93d9d2ff4f 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -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 {