Commit e16b7407 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

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
parent e0e28d2b
...@@ -69,6 +69,31 @@ var reqTests = []reqTest{ ...@@ -69,6 +69,31 @@ var reqTests = []reqTest{
"abcdef\n", "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 // Tests that we don't parse a path that looks like a
// scheme-relative URI as a scheme-relative URI. // scheme-relative URI as a scheme-relative URI.
{ {
...@@ -94,7 +119,7 @@ var reqTests = []reqTest{ ...@@ -94,7 +119,7 @@ var reqTests = []reqTest{
ProtoMinor: 1, ProtoMinor: 1,
Header: Header{}, Header: Header{},
Close: false, Close: false,
ContentLength: -1, ContentLength: 0,
Host: "test", Host: "test",
Form: Values{}, Form: Values{},
}, },
......
...@@ -195,6 +195,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -195,6 +195,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
t := &transferReader{} t := &transferReader{}
// Unify input // Unify input
isResponse := false
switch rr := msg.(type) { switch rr := msg.(type) {
case *Response: case *Response:
t.Header = rr.Header t.Header = rr.Header
...@@ -203,6 +204,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -203,6 +204,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
t.ProtoMajor = rr.ProtoMajor t.ProtoMajor = rr.ProtoMajor
t.ProtoMinor = rr.ProtoMinor t.ProtoMinor = rr.ProtoMinor
t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header) t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
isResponse = true
case *Request: case *Request:
t.Header = rr.Header t.Header = rr.Header
t.ProtoMajor = rr.ProtoMajor t.ProtoMajor = rr.ProtoMajor
...@@ -211,6 +213,8 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -211,6 +213,8 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Responses with status code 200, responding to a GET method // Responses with status code 200, responding to a GET method
t.StatusCode = 200 t.StatusCode = 200
t.RequestMethod = "GET" t.RequestMethod = "GET"
default:
panic("unexpected type")
} }
// Default to HTTP/1.1 // Default to HTTP/1.1
...@@ -224,7 +228,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -224,7 +228,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
return err 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 { if err != nil {
return err return err
} }
...@@ -265,9 +269,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -265,9 +269,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Persistent connection (i.e. HTTP/1.1) // Persistent connection (i.e. HTTP/1.1)
t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close} 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 // Unify output
...@@ -345,7 +346,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro ...@@ -345,7 +346,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
// Determine the expected body length, using RFC 2616 Section 4.4. This // Determine the expected body length, using RFC 2616 Section 4.4. This
// function is not a method, because ultimately it should be shared by // function is not a method, because ultimately it should be shared by
// ReadResponse and ReadRequest. // 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 // Logic based on response type or status
if noBodyExpected(requestMethod) { if noBodyExpected(requestMethod) {
...@@ -376,6 +377,14 @@ func fixLength(status int, requestMethod string, header Header, te []string) (in ...@@ -376,6 +377,14 @@ func fixLength(status int, requestMethod string, header Header, te []string) (in
header.Del("Content-Length") 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 // Logic based on media type. The purpose of the following code is just
// to detect whether the unsupported "multipart/byteranges" is being // to detect whether the unsupported "multipart/byteranges" is being
// used. A proper Content-Type parser is needed in the future. // used. A proper Content-Type parser is needed in the future.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment