]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: don't write body for HEAD responses in Response.Write
authorDamien Neil <dneil@google.com>
Fri, 26 Jul 2024 22:34:03 +0000 (15:34 -0700)
committerDamien Neil <dneil@google.com>
Mon, 29 Jul 2024 21:26:22 +0000 (21:26 +0000)
Fixes #62015

Change-Id: I88c5427f85e740d5b956942bb1c2727dac2935ea
Reviewed-on: https://go-review.googlesource.com/c/go/+/601238
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/net/http/response_test.go
src/net/http/transfer.go

index a63aac95ac1f691961f6f80e2666f708a02d965a..3ccbb9b0f2d4b1621eaeb3a96b9444e9bad98545 100644 (file)
@@ -21,9 +21,10 @@ import (
 )
 
 type respTest struct {
-       Raw  string
-       Resp Response
-       Body string
+       Raw    string
+       RawOut string
+       Resp   Response
+       Body   string
 }
 
 func dummyReq(method string) *Request {
@@ -42,6 +43,11 @@ var respTests = []respTest{
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -66,6 +72,11 @@ var respTests = []respTest{
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:        "200 OK",
                        StatusCode:    200,
@@ -87,6 +98,9 @@ var respTests = []respTest{
                        "\r\n" +
                        "Body should not be read!\n",
 
+               "HTTP/1.1 204 No Content\r\n" +
+                       "\r\n",
+
                Response{
                        Status:        "204 No Content",
                        StatusCode:    204,
@@ -110,6 +124,12 @@ var respTests = []respTest{
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -140,6 +160,14 @@ var respTests = []respTest{
                        "0\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Transfer-Encoding: chunked\r\n" +
+                       "\r\n" +
+                       "13\r\n" +
+                       "Body here\ncontinued\r\n" +
+                       "0\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -165,6 +193,12 @@ var respTests = []respTest{
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -195,6 +229,14 @@ var respTests = []respTest{
                        "0\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Transfer-Encoding: chunked\r\n" +
+                       "\r\n" +
+                       "a\r\n" +
+                       "Body here\n\r\n" +
+                       "0\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -217,6 +259,10 @@ var respTests = []respTest{
                        "Transfer-Encoding: chunked\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Transfer-Encoding: chunked\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -239,6 +285,11 @@ var respTests = []respTest{
                        "Content-Length: 256\r\n" +
                        "\r\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Length: 256\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -261,6 +312,10 @@ var respTests = []respTest{
                        "Content-Length: 256\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Content-Length: 256\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -282,6 +337,10 @@ var respTests = []respTest{
                "HTTP/1.0 200 OK\r\n" +
                        "\r\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n",
+
                Response{
                        Status:           "200 OK",
                        StatusCode:       200,
@@ -304,6 +363,10 @@ var respTests = []respTest{
                        "Content-Length: 0\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Content-Length: 0\r\n" +
+                       "\r\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -325,6 +388,11 @@ var respTests = []respTest{
        // (permitted by RFC 7230, section 3.1.2)
        {
                "HTTP/1.0 303 \r\n\r\n",
+
+               "HTTP/1.0 303 \r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n",
+
                Response{
                        Status:        "303 ",
                        StatusCode:    303,
@@ -344,6 +412,11 @@ var respTests = []respTest{
        // (not permitted by RFC 7230, but we'll accept it anyway)
        {
                "HTTP/1.0 303\r\n\r\n",
+
+               "HTTP/1.0 303 303\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n",
+
                Response{
                        Status:        "303",
                        StatusCode:    303,
@@ -366,6 +439,13 @@ Connection: close
 Content-Type: multipart/byteranges; boundary=18a75608c8f47cef
 
 some body`,
+
+               "HTTP/1.1 206 Partial Content\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Type: multipart/byteranges; boundary=18a75608c8f47cef\r\n" +
+                       "\r\n" +
+                       "some body",
+
                Response{
                        Status:     "206 Partial Content",
                        StatusCode: 206,
@@ -390,6 +470,11 @@ some body`,
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -415,6 +500,14 @@ some body`,
                        "Content-Length: 6\r\n\r\n" +
                        "foobar",
 
+               "HTTP/1.1 206 Partial Content\r\n" +
+                       "Content-Length: 6\r\n" +
+                       "Accept-Ranges: bytes\r\n" +
+                       "Content-Range: bytes 0-5/1862\r\n" +
+                       "Content-Type: text/plain; charset=utf-8\r\n" +
+                       "\r\n" +
+                       "foobar",
+
                Response{
                        Status:     "206 Partial Content",
                        StatusCode: 206,
@@ -441,6 +534,11 @@ some body`,
                        "Connection: keep-alive, close\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Length: 256\r\n" +
+                       "\r\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -467,6 +565,11 @@ some body`,
                        "Connection: close\r\n" +
                        "\r\n",
 
+               "HTTP/1.1 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Length: 256\r\n" +
+                       "\r\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -493,6 +596,11 @@ some body`,
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:        "200 OK",
                        StatusCode:    200,
@@ -517,6 +625,12 @@ some body`,
                        "\r\n" +
                        "Body here\n",
 
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -541,6 +655,14 @@ some body`,
                        "Connection: keep-alive\r\n" +
                        "Keep-Alive: timeout=7200\r\n\r\n" +
                        "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+
+               "HTTP/1.1 200 OK\r\n" +
+                       "Content-Length: 23\r\n" +
+                       "Connection: keep-alive\r\n" +
+                       "Content-Encoding: gzip\r\n" +
+                       "Keep-Alive: timeout=7200\r\n\r\n" +
+                       "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+
                Response{
                        Status:     "200 OK",
                        StatusCode: 200,
@@ -566,6 +688,14 @@ some body`,
                        "Content-type: text/html\r\n" +
                        "WWW-Authenticate: Basic realm=\"\"\r\n\r\n" +
                        "Your Authentication failed.\r\n",
+
+               "HTTP/1.0 401 Unauthorized\r\n" +
+                       "Connection: close\r\n" +
+                       "Content-Type: text/html\r\n" +
+                       "Www-Authenticate: Basic realm=\"\"\r\n" +
+                       "\r\n" +
+                       "Your Authentication failed.\r\n",
+
                Response{
                        Status:     "401 Unauthorized",
                        StatusCode: 401,
@@ -619,11 +749,18 @@ func TestWriteResponse(t *testing.T) {
                        t.Errorf("#%d: %v", i, err)
                        continue
                }
-               err = resp.Write(io.Discard)
+               var buf bytes.Buffer
+               err = resp.Write(&buf)
                if err != nil {
                        t.Errorf("#%d: %v", i, err)
                        continue
                }
+               if got, want := buf.String(), tt.RawOut; got != want {
+                       t.Errorf("#%d: response differs; got:\n----\n%v\n----\nwant:\n----\n%v\n----\n",
+                               i,
+                               strings.ReplaceAll(got, "\r", "\\r"),
+                               strings.ReplaceAll(want, "\r", "\\r"))
+               }
        }
 }
 
index 5a3c6ceff5780832728f214b4caed10241e4cfb7..f7eef6475e6bffc6768a285d1dea192f6b8cf789 100644 (file)
@@ -350,7 +350,7 @@ func (t *transferWriter) writeBody(w io.Writer) (err error) {
        // nopCloser or readTrackingBody. This is to ensure that we can take advantage of
        // OS-level optimizations in the event that the body is an
        // *os.File.
-       if t.Body != nil {
+       if !t.ResponseToHEAD && t.Body != nil {
                var body = t.unwrapBody()
                if chunked(t.TransferEncoding) {
                        if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
@@ -392,7 +392,7 @@ func (t *transferWriter) writeBody(w io.Writer) (err error) {
                        t.ContentLength, ncopy)
        }
 
-       if chunked(t.TransferEncoding) {
+       if !t.ResponseToHEAD && chunked(t.TransferEncoding) {
                // Write Trailer header
                if t.Trailer != nil {
                        if err := t.Trailer.Write(w); err != nil {