1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:07:58 -07:00

http: always include Content-Length header, even for 0

fixes #2221

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/4952052
This commit is contained in:
Dave Grijalva 2011-09-19 11:41:09 -07:00 committed by Brad Fitzpatrick
parent ab596cae9e
commit 80700eb817
2 changed files with 34 additions and 6 deletions

View File

@ -246,14 +246,19 @@ var reqWriteTests = []reqWriteTest{
Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) }, 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" + WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" + "Host: example.com\r\n" +
"User-Agent: Go http package\r\n" + "User-Agent: Go http package\r\n" +
"Content-Length: 0\r\n" +
"\r\n", "\r\n",
WantProxy: "POST / HTTP/1.1\r\n" + WantProxy: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" + "Host: example.com\r\n" +
"User-Agent: Go http package\r\n" + "User-Agent: Go http package\r\n" +
"Content-Length: 0\r\n" +
"\r\n", "\r\n",
}, },

View File

@ -19,6 +19,7 @@ import (
// sanitizes them without changing the user object and provides methods for // sanitizes them without changing the user object and provides methods for
// writing the respective header, body and trailer in wire format. // writing the respective header, body and trailer in wire format.
type transferWriter struct { type transferWriter struct {
Method string
Body io.Reader Body io.Reader
BodyCloser io.Closer BodyCloser io.Closer
ResponseToHEAD bool ResponseToHEAD bool
@ -38,7 +39,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
if rr.ContentLength != 0 && rr.Body == nil { if rr.ContentLength != 0 && rr.Body == nil {
return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength) return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
} }
t.Method = rr.Method
t.Body = rr.Body t.Body = rr.Body
t.BodyCloser = rr.Body t.BodyCloser = rr.Body
t.ContentLength = rr.ContentLength t.ContentLength = rr.ContentLength
@ -69,6 +70,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
} }
} }
case *Response: case *Response:
t.Method = rr.Request.Method
t.Body = rr.Body t.Body = rr.Body
t.BodyCloser = rr.Body t.BodyCloser = rr.Body
t.ContentLength = rr.ContentLength t.ContentLength = rr.ContentLength
@ -110,6 +112,27 @@ func noBodyExpected(requestMethod string) bool {
return requestMethod == "HEAD" 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) { func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
if t.Close { if t.Close {
_, err = io.WriteString(w, "Connection: close\r\n") _, 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 // Write Content-Length and/or Transfer-Encoding whose values are a
// function of the sanitized field triple (Body, ContentLength, // function of the sanitized field triple (Body, ContentLength,
// TransferEncoding) // TransferEncoding)
if chunked(t.TransferEncoding) { if t.shouldSendContentLength() {
_, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n") io.WriteString(w, "Content-Length: ")
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
if err != nil { if err != nil {
return return
} }
} else if t.ContentLength > 0 || t.ResponseToHEAD || (t.ContentLength == 0 && isIdentity(t.TransferEncoding)) { } else if chunked(t.TransferEncoding) {
io.WriteString(w, "Content-Length: ") _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
if err != nil { if err != nil {
return return
} }