]> Cypherpunks repositories - gostls13.git/commitdiff
http: always include Content-Length header, even for 0
authorDave Grijalva <dgrijalva@ngmoco.com>
Mon, 19 Sep 2011 18:41:09 +0000 (11:41 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 19 Sep 2011 18:41:09 +0000 (11:41 -0700)
fixes #2221

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/4952052

src/pkg/http/requestwrite_test.go
src/pkg/http/transfer.go

index a8cb75a597558431d069a1846ac6b0da1c06013c..8c29c44f49820a48eaf2383c53b68931b25dbbe9 100644 (file)
@@ -246,14 +246,19 @@ var reqWriteTests = []reqWriteTest{
 
                Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
 
+               // RFC 2616 Section 14.13 says Content-Length should be specified
+               // unless body is prohibited by the request method.
+               // Also, nginx expects it for POST and PUT.
                WantWrite: "POST / HTTP/1.1\r\n" +
                        "Host: example.com\r\n" +
                        "User-Agent: Go http package\r\n" +
+                       "Content-Length: 0\r\n" +
                        "\r\n",
 
                WantProxy: "POST / HTTP/1.1\r\n" +
                        "Host: example.com\r\n" +
                        "User-Agent: Go http package\r\n" +
+                       "Content-Length: 0\r\n" +
                        "\r\n",
        },
 
index 8b12447acc924e3e2b9a3313baf83bed88ebd380..300c7a88d5eedc8d950db8e770232302e037d58c 100644 (file)
@@ -19,6 +19,7 @@ import (
 // sanitizes them without changing the user object and provides methods for
 // writing the respective header, body and trailer in wire format.
 type transferWriter struct {
+       Method           string
        Body             io.Reader
        BodyCloser       io.Closer
        ResponseToHEAD   bool
@@ -38,7 +39,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
                if rr.ContentLength != 0 && rr.Body == nil {
                        return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
                }
-
+               t.Method = rr.Method
                t.Body = rr.Body
                t.BodyCloser = rr.Body
                t.ContentLength = rr.ContentLength
@@ -69,6 +70,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
                        }
                }
        case *Response:
+               t.Method = rr.Request.Method
                t.Body = rr.Body
                t.BodyCloser = rr.Body
                t.ContentLength = rr.ContentLength
@@ -110,6 +112,27 @@ func noBodyExpected(requestMethod string) bool {
        return requestMethod == "HEAD"
 }
 
+func (t *transferWriter) shouldSendContentLength() bool {
+       if chunked(t.TransferEncoding) {
+               return false
+       }
+       if t.ContentLength > 0 {
+               return true
+       }
+       if t.ResponseToHEAD {
+               return true
+       }
+       // Many servers expect a Content-Length for these methods
+       if t.Method == "POST" || t.Method == "PUT" {
+               return true
+       }
+       if t.ContentLength == 0 && isIdentity(t.TransferEncoding) {
+               return true
+       }
+
+       return false
+}
+
 func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
        if t.Close {
                _, err = io.WriteString(w, "Connection: close\r\n")
@@ -121,14 +144,14 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
        // Write Content-Length and/or Transfer-Encoding whose values are a
        // function of the sanitized field triple (Body, ContentLength,
        // TransferEncoding)
-       if chunked(t.TransferEncoding) {
-               _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
+       if t.shouldSendContentLength() {
+               io.WriteString(w, "Content-Length: ")
+               _, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
                if err != nil {
                        return
                }
-       } else if t.ContentLength > 0 || t.ResponseToHEAD || (t.ContentLength == 0 && isIdentity(t.TransferEncoding)) {
-               io.WriteString(w, "Content-Length: ")
-               _, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
+       } else if chunked(t.TransferEncoding) {
+               _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
                if err != nil {
                        return
                }