aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pkg/http/request.go11
-rw-r--r--src/pkg/http/requestwrite_test.go36
-rw-r--r--src/pkg/http/transfer.go8
3 files changed, 49 insertions, 6 deletions
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 2ff3160a95..bdc3a7e4fb 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -238,9 +238,9 @@ const defaultUserAgent = "Go http package"
// TransferEncoding
// Body
//
-// If Body is present but Content-Length is <= 0, Write adds
-// "Transfer-Encoding: chunked" to the header. Body is closed after
-// it is sent.
+// If Body is present, Content-Length is <= 0 and TransferEncoding
+// hasn't been set to "identity", Write adds "Transfer-Encoding:
+// chunked" to the header. Body is closed after it is sent.
func (req *Request) Write(w io.Writer) os.Error {
return req.write(w, false)
}
@@ -488,6 +488,11 @@ func NewRequest(method, url string, body io.Reader) (*Request, os.Error) {
default:
req.ContentLength = -1 // chunked
}
+ if req.ContentLength == 0 {
+ // To prevent chunking and disambiguate this
+ // from the default ContentLength zero value.
+ req.TransferEncoding = []string{"identity"}
+ }
}
return req, nil
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
index 2889048a94..98fbcf459b 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/http/requestwrite_test.go
@@ -274,13 +274,45 @@ func (rc *closeChecker) Close() os.Error {
// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
-// inside a NopCloser.
+// inside a NopCloser, and that it serializes it correctly.
func TestRequestWriteClosesBody(t *testing.T) {
rc := &closeChecker{Reader: strings.NewReader("my body")}
- req, _ := NewRequest("GET", "http://foo.com/", rc)
+ req, _ := NewRequest("POST", "http://foo.com/", rc)
+ if g, e := req.ContentLength, int64(-1); g != e {
+ t.Errorf("got req.ContentLength %d, want %d", g, e)
+ }
buf := new(bytes.Buffer)
req.Write(buf)
if !rc.closed {
t.Error("body not closed after write")
}
+ if g, e := buf.String(), "POST / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n7\r\nmy body\r\n0\r\n\r\n"; g != e {
+ t.Errorf("write:\n got: %s\nwant: %s", g, e)
+ }
+}
+
+func TestZeroLengthNewRequest(t *testing.T) {
+ var buf bytes.Buffer
+
+ // Writing with default identity encoding
+ req, _ := NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
+ if len(req.TransferEncoding) == 0 || req.TransferEncoding[0] != "identity" {
+ t.Fatalf("got req.TransferEncoding of %v, want %v", req.TransferEncoding, []string{"identity"})
+ }
+ if g, e := req.ContentLength, int64(0); g != e {
+ t.Errorf("got req.ContentLength %d, want %d", g, e)
+ }
+ req.Write(&buf)
+ if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nContent-Length: 0\r\n\r\n"; g != e {
+ t.Errorf("identity write:\n got: %s\nwant: %s", g, e)
+ }
+
+ // Overriding identity encoding and forcing chunked.
+ req, _ = NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
+ req.TransferEncoding = nil
+ buf.Reset()
+ req.Write(&buf)
+ if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"; g != e {
+ t.Errorf("chunked write:\n got: %s\nwant: %s", g, e)
+ }
}
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index 062e7a0ff7..b54508e7ad 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -38,6 +38,9 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ if t.Body != nil && t.ContentLength <= 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+ t.TransferEncoding = []string{"chunked"}
+ }
case *Response:
t.Body = rr.Body
t.ContentLength = rr.ContentLength
@@ -95,7 +98,7 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
if err != nil {
return
}
- } else if t.ContentLength > 0 || t.ResponseToHEAD {
+ } 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")
if err != nil {
@@ -289,6 +292,9 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Checks whether chunked is part of the encodings stack
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+// Checks whether the encoding is explicitly "identity".
+func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
+
// Sanitize transfer encoding
func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
raw, present := header["Transfer-Encoding"]