Commit a0e6f03a authored by Petar Maymounkov's avatar Petar Maymounkov Committed by Russ Cox

Cosmetic bug or compliance fixes in http.Response.

(1) http.Response must close resp.Body after writing.
(2) Case when resp.Body != nil and resp.ContentLength = 0 should not be
treated as an error in Response.Write, because this is what
ReadResponse often returns.
(3) Changed body.th to body.hdr for readability.

R=rsc
CC=golang-dev
https://golang.org/cl/194084
parent d53b426f
...@@ -574,7 +574,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) { ...@@ -574,7 +574,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
// A message body exists when either Content-Length or Transfer-Encoding // A message body exists when either Content-Length or Transfer-Encoding
// headers are present. Transfer-Encoding trumps Content-Length. // headers are present. Transfer-Encoding trumps Content-Length.
if v, present := req.Header["Transfer-Encoding"]; present && v == "chunked" { if v, present := req.Header["Transfer-Encoding"]; present && v == "chunked" {
req.Body = &body{Reader: newChunkedReader(b), th: req, r: b, closing: req.Close} req.Body = &body{Reader: newChunkedReader(b), hdr: req, r: b, closing: req.Close}
} else if v, present := req.Header["Content-Length"]; present { } else if v, present := req.Header["Content-Length"]; present {
length, err := strconv.Btoi64(v, 10) length, err := strconv.Btoi64(v, 10)
if err != nil { if err != nil {
......
...@@ -112,6 +112,7 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os ...@@ -112,6 +112,7 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
fixPragmaCacheControl(resp.Header) fixPragmaCacheControl(resp.Header)
// Transfer encoding, content length
resp.TransferEncoding, err = fixTransferEncoding(resp.Header) resp.TransferEncoding, err = fixTransferEncoding(resp.Header)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -123,8 +124,10 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os ...@@ -123,8 +124,10 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
return nil, err return nil, err
} }
// Closing
resp.Close = shouldClose(resp.ProtoMajor, resp.ProtoMinor, resp.Header) resp.Close = shouldClose(resp.ProtoMajor, resp.ProtoMinor, resp.Header)
// Trailer
resp.Trailer, err = fixTrailer(resp.Header, resp.TransferEncoding) resp.Trailer, err = fixTrailer(resp.Header, resp.TransferEncoding)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -134,7 +137,7 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os ...@@ -134,7 +137,7 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
// or close connection when finished, since multipart is not supported yet // or close connection when finished, since multipart is not supported yet
switch { switch {
case chunked(resp.TransferEncoding): case chunked(resp.TransferEncoding):
resp.Body = &body{Reader: newChunkedReader(r), th: resp, r: r, closing: resp.Close} resp.Body = &body{Reader: newChunkedReader(r), hdr: resp, r: r, closing: resp.Close}
case resp.ContentLength >= 0: case resp.ContentLength >= 0:
resp.Body = &body{Reader: io.LimitReader(r, resp.ContentLength), closing: resp.Close} resp.Body = &body{Reader: io.LimitReader(r, resp.ContentLength), closing: resp.Close}
default: default:
...@@ -149,13 +152,13 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os ...@@ -149,13 +152,13 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
// and then reads the trailer if necessary. // and then reads the trailer if necessary.
type body struct { type body struct {
io.Reader io.Reader
th interface{} // non-nil (Response or Request) value means read trailer hdr interface{} // non-nil (Response or Request) value means read trailer
r *bufio.Reader // underlying wire-format reader for the trailer r *bufio.Reader // underlying wire-format reader for the trailer
closing bool // is the connection to be closed after reading body? closing bool // is the connection to be closed after reading body?
} }
func (b *body) Close() os.Error { func (b *body) Close() os.Error {
if b.th == nil && b.closing { if b.hdr == nil && b.closing {
// no trailer and closing the connection next. // no trailer and closing the connection next.
// no point in reading to EOF. // no point in reading to EOF.
return nil return nil
...@@ -172,7 +175,7 @@ func (b *body) Close() os.Error { ...@@ -172,7 +175,7 @@ func (b *body) Close() os.Error {
} }
return err return err
} }
if b.th == nil { // not reading trailer if b.hdr == nil { // not reading trailer
return nil return nil
} }
...@@ -378,7 +381,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool { ...@@ -378,7 +381,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
// //
func (resp *Response) Write(w io.Writer) os.Error { func (resp *Response) Write(w io.Writer) os.Error {
// RequestMethod should be lower-case // RequestMethod should be upper-case
resp.RequestMethod = strings.ToUpper(resp.RequestMethod) resp.RequestMethod = strings.ToUpper(resp.RequestMethod)
// Status line // Status line
...@@ -404,13 +407,7 @@ func (resp *Response) Write(w io.Writer) os.Error { ...@@ -404,13 +407,7 @@ func (resp *Response) Write(w io.Writer) os.Error {
} }
if chunked(resp.TransferEncoding) { if chunked(resp.TransferEncoding) {
resp.ContentLength = -1 resp.ContentLength = -1
} else if resp.Body != nil { } else if resp.Body == nil { // no chunking, no body
// For safety, consider sending a 0-length body an
// error
if resp.ContentLength <= 0 {
return &ProtocolError{"zero body length"}
}
} else { // no chunking, no body
resp.ContentLength = 0 resp.ContentLength = 0
} }
} }
...@@ -421,8 +418,10 @@ func (resp *Response) Write(w io.Writer) os.Error { ...@@ -421,8 +418,10 @@ func (resp *Response) Write(w io.Writer) os.Error {
if chunked(resp.TransferEncoding) { if chunked(resp.TransferEncoding) {
io.WriteString(w, "Transfer-Encoding: chunked\r\n") io.WriteString(w, "Transfer-Encoding: chunked\r\n")
} else { } else {
io.WriteString(w, "Content-Length: ") if resp.ContentLength > 0 || resp.RequestMethod == "HEAD" {
io.WriteString(w, strconv.Itoa64(resp.ContentLength)+"\r\n") io.WriteString(w, "Content-Length: ")
io.WriteString(w, strconv.Itoa64(resp.ContentLength)+"\r\n")
}
} }
if resp.Header != nil { if resp.Header != nil {
resp.Header["Content-Length"] = "", false resp.Header["Content-Length"] = "", false
...@@ -478,6 +477,9 @@ func (resp *Response) Write(w io.Writer) os.Error { ...@@ -478,6 +477,9 @@ func (resp *Response) Write(w io.Writer) os.Error {
if err != nil { if err != nil {
return err return err
} }
if err = resp.Body.Close(); err != nil {
return err
}
} }
// TODO(petar): Place trailer writer code here. // TODO(petar): Place trailer writer code here.
......
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