http: assume ContentLength 0 on GET requests
Incremental step in fix for issue 1999
R=golang-dev, kevlar
CC=golang-dev
https://golang.org/cl/4667041
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
index 0b92b79..0df6d21 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/http/readrequest_test.go
@@ -69,6 +69,31 @@
"abcdef\n",
},
+ // GET request with no body (the normal case)
+ {
+ "GET / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n\r\n",
+
+ Request{
+ Method: "GET",
+ RawURL: "/",
+ URL: &URL{
+ Raw: "/",
+ Path: "/",
+ RawPath: "/",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: false,
+ ContentLength: 0,
+ Host: "foo.com",
+ Form: Values{},
+ },
+
+ "",
+ },
+
// Tests that we don't parse a path that looks like a
// scheme-relative URI as a scheme-relative URI.
{
@@ -94,7 +119,7 @@
ProtoMinor: 1,
Header: Header{},
Close: false,
- ContentLength: -1,
+ ContentLength: 0,
Host: "test",
Form: Values{},
},
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index b54508e..609a5f7 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -195,6 +195,7 @@
t := &transferReader{}
// Unify input
+ isResponse := false
switch rr := msg.(type) {
case *Response:
t.Header = rr.Header
@@ -203,6 +204,7 @@
t.ProtoMajor = rr.ProtoMajor
t.ProtoMinor = rr.ProtoMinor
t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+ isResponse = true
case *Request:
t.Header = rr.Header
t.ProtoMajor = rr.ProtoMajor
@@ -211,6 +213,8 @@
// Responses with status code 200, responding to a GET method
t.StatusCode = 200
t.RequestMethod = "GET"
+ default:
+ panic("unexpected type")
}
// Default to HTTP/1.1
@@ -224,7 +228,7 @@
return err
}
- t.ContentLength, err = fixLength(t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+ t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
if err != nil {
return err
}
@@ -265,9 +269,6 @@
// Persistent connection (i.e. HTTP/1.1)
t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
}
- // TODO(petar): It may be a good idea, for extra robustness, to
- // assume ContentLength=0 for GET requests (and other special
- // cases?). This logic should be in fixLength().
}
// Unify output
@@ -345,7 +346,7 @@
// Determine the expected body length, using RFC 2616 Section 4.4. This
// function is not a method, because ultimately it should be shared by
// ReadResponse and ReadRequest.
-func fixLength(status int, requestMethod string, header Header, te []string) (int64, os.Error) {
+func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, os.Error) {
// Logic based on response type or status
if noBodyExpected(requestMethod) {
@@ -376,6 +377,14 @@
header.Del("Content-Length")
}
+ if !isResponse && requestMethod == "GET" {
+ // RFC 2616 doesn't explicitly permit nor forbid an
+ // entity-body on a GET request so we permit one if
+ // declared, but we default to 0 here (not -1 below)
+ // if there's no mention of a body.
+ return 0, nil
+ }
+
// Logic based on media type. The purpose of the following code is just
// to detect whether the unsupported "multipart/byteranges" is being
// used. A proper Content-Type parser is needed in the future.