http: consume request bodies before replying
This fixes our http behavior (even if Handlers forget to
consume a request body, we do it for them before we send
their response header), fixes the racy TestServerExpect,
and adds TestServerConsumesRequestBody.
With GOMAXPROCS>1, the http tests now seem race-free.
R=rsc
CC=golang-dev
https://golang.org/cl/4419042
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 0142dea..eb1ecfd 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -588,7 +588,7 @@
sendf := func(format string, args ...interface{}) {
_, err := fmt.Fprintf(conn, format, args...)
if err != nil {
- t.Fatalf("Error writing %q: %v", format, err)
+ t.Fatalf("On test %#v, error writing %q: %v", test, format, err)
}
}
go func() {
@@ -616,3 +616,49 @@
runTest(test)
}
}
+
+func TestServerConsumesRequestBody(t *testing.T) {
+ log := make(chan string, 100)
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ log <- "got_request"
+ w.WriteHeader(StatusOK)
+ log <- "wrote_header"
+ }))
+ defer ts.Close()
+
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer conn.Close()
+
+ bufr := bufio.NewReader(conn)
+ gotres := make(chan bool)
+ go func() {
+ line, err := bufr.ReadString('\n')
+ if err != nil {
+ t.Fatal(err)
+ }
+ log <- line
+ gotres <- true
+ }()
+
+ size := 1 << 20
+ log <- "writing_request"
+ fmt.Fprintf(conn, "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n", size)
+ time.Sleep(25e6) // give server chance to misbehave & speak out of turn
+ log <- "slept_after_req_headers"
+ conn.Write([]byte(strings.Repeat("a", size)))
+
+ <-gotres
+ expected := []string{
+ "writing_request", "got_request",
+ "slept_after_req_headers", "wrote_header",
+ "HTTP/1.0 200 OK\r\n"}
+ for step, e := range expected {
+ if g := <-log; e != g {
+ t.Errorf("on step %d expected %q, got %q", step, e, g)
+ }
+ }
+}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 3291de1..aa4dc29 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -141,9 +141,13 @@
type expectContinueReader struct {
resp *response
readCloser io.ReadCloser
+ closed bool
}
func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+ if ecr.closed {
+ return 0, os.NewError("http: Read after Close on request Body")
+ }
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
ecr.resp.wroteContinue = true
io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
@@ -153,6 +157,7 @@
}
func (ecr *expectContinueReader) Close() os.Error {
+ ecr.closed = true
return ecr.readCloser.Close()
}
@@ -196,6 +201,16 @@
log.Print("http: multiple response.WriteHeader calls")
return
}
+
+ // Per RFC 2616, we should consume the request body before
+ // replying, if the handler hasn't already done so.
+ if w.req.ContentLength != 0 {
+ ecr, isExpecter := w.req.Body.(*expectContinueReader)
+ if !isExpecter || ecr.resp.wroteContinue {
+ w.req.Body.Close()
+ }
+ }
+
w.wroteHeader = true
w.status = code
if code == StatusNotModified {