]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: don't validate WriteHeader code if header's already been sent
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 4 Jan 2018 22:26:20 +0000 (22:26 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 5 Jan 2018 01:36:15 +0000 (01:36 +0000)
Also vendors x/net/http git rev 42fe2e1c for:

    http2: don't check WriteHeader status if we've already sent the header
    https://golang.org/cl/86255

Fixes #23010

Change-Id: I4f3dd63acb52d5a34a0350aaf847a7a376d6968f
Reviewed-on: https://go-review.googlesource.com/86275
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/http/clientserver_test.go
src/net/http/h2_bundle.go
src/net/http/server.go

index 238297f945ca2084cc37887ae169b8161c42266c..b894be0813da1cd075f0704c84a0979c19c6168a 100644 (file)
@@ -1424,3 +1424,59 @@ func testWriteHeader0(t *testing.T, h2 bool) {
                t.Error("expected panic in handler")
        }
 }
+
+// Issue 23010: don't be super strict checking WriteHeader's code if
+// it's not even valid to call WriteHeader then anyway.
+func TestWriteHeaderNoCodeCheck_h1(t *testing.T)       { testWriteHeaderAfterWrite(t, h1Mode, false) }
+func TestWriteHeaderNoCodeCheck_h1hijack(t *testing.T) { testWriteHeaderAfterWrite(t, h1Mode, true) }
+func TestWriteHeaderNoCodeCheck_h2(t *testing.T)       { testWriteHeaderAfterWrite(t, h2Mode, false) }
+func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
+       setParallel(t)
+       defer afterTest(t)
+
+       var errorLog lockedBytesBuffer
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               if hijack {
+                       conn, _, _ := w.(Hijacker).Hijack()
+                       defer conn.Close()
+                       conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nfoo"))
+                       w.WriteHeader(0) // verify this doesn't panic if there's already output; Issue 23010
+                       conn.Write([]byte("bar"))
+                       return
+               }
+               io.WriteString(w, "foo")
+               w.(Flusher).Flush()
+               w.WriteHeader(0) // verify this doesn't panic if there's already output; Issue 23010
+               io.WriteString(w, "bar")
+       }), func(ts *httptest.Server) {
+               ts.Config.ErrorLog = log.New(&errorLog, "", 0)
+       })
+       defer cst.close()
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer res.Body.Close()
+       body, err := ioutil.ReadAll(res.Body)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if got, want := string(body), "foobar"; got != want {
+               t.Errorf("got = %q; want %q", got, want)
+       }
+
+       // Also check the stderr output:
+       if h2 {
+               // TODO: also emit this log message for HTTP/2?
+               // We historically haven't, so don't check.
+               return
+       }
+       gotLog := strings.TrimSpace(errorLog.String())
+       wantLog := "http: multiple response.WriteHeader calls"
+       if hijack {
+               wantLog = "http: response.WriteHeader on hijacked connection"
+       }
+       if gotLog != wantLog {
+               t.Errorf("stderr output = %q; want %q", gotLog, wantLog)
+       }
+}
index e6e164467d83c54abe2c5bb70d91bd3bf666bae5..161a1ed1372d87a4eada4c672f654d22227881fa 100644 (file)
@@ -6204,7 +6204,6 @@ func http2checkWriteHeaderCode(code int) {
 }
 
 func (w *http2responseWriter) WriteHeader(code int) {
-       http2checkWriteHeaderCode(code)
        rws := w.rws
        if rws == nil {
                panic("WriteHeader called after Handler finished")
@@ -6214,6 +6213,7 @@ func (w *http2responseWriter) WriteHeader(code int) {
 
 func (rws *http2responseWriterState) writeHeader(code int) {
        if !rws.wroteHeader {
+               http2checkWriteHeaderCode(code)
                rws.wroteHeader = true
                rws.status = code
                if len(rws.handlerHeader) > 0 {
index e1698ccfa323128eca408fb9f1c76f913757b986..ceb1a047cf57667741e4aec2d62b7be4b0378c52 100644 (file)
@@ -1072,7 +1072,6 @@ func checkWriteHeaderCode(code int) {
 }
 
 func (w *response) WriteHeader(code int) {
-       checkWriteHeaderCode(code)
        if w.conn.hijacked() {
                w.conn.server.logf("http: response.WriteHeader on hijacked connection")
                return
@@ -1081,6 +1080,7 @@ func (w *response) WriteHeader(code int) {
                w.conn.server.logf("http: multiple response.WriteHeader calls")
                return
        }
+       checkWriteHeaderCode(code)
        w.wroteHeader = true
        w.status = code