1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
21 type errorReader
struct {
25 func (r
*errorReader
) Read(p
[]byte) (n
int, err error
) {
29 // transferWriter inspects the fields of a user-supplied Request or Response,
30 // sanitizes them without changing the user object and provides methods for
31 // writing the respective header, body and trailer in wire format.
32 type transferWriter
struct {
37 ContentLength
int64 // -1 means unknown, 0 means exactly none
39 TransferEncoding
[]string
43 func newTransferWriter(r
interface{}) (t
*transferWriter
, err error
) {
46 // Extract relevant fields
47 atLeastHTTP11
:= false
48 switch rr
:= r
.(type) {
50 if rr
.ContentLength
!= 0 && rr
.Body
== nil {
51 return nil, fmt
.Errorf("http: Request.ContentLength=%d with nil Body", rr
.ContentLength
)
55 t
.BodyCloser
= rr
.Body
56 t
.ContentLength
= rr
.ContentLength
58 t
.TransferEncoding
= rr
.TransferEncoding
59 t
.Trailer
= rr
.Trailer
60 atLeastHTTP11
= rr
.ProtoAtLeast(1, 1)
61 if t
.Body
!= nil && len(t
.TransferEncoding
) == 0 && atLeastHTTP11
{
62 if t
.ContentLength
== 0 {
63 // Test to see if it's actually zero or just unset.
65 n
, rerr
:= io
.ReadFull(t
.Body
, buf
[:])
66 if rerr
!= nil && rerr
!= io
.EOF
{
68 t
.Body
= &errorReader
{rerr
}
70 // Oh, guess there is data in this Body Reader after all.
71 // The ContentLength field just wasn't set.
72 // Stich the Body back together again, re-attaching our
75 t
.Body
= io
.MultiReader(bytes
.NewReader(buf
[:]), t
.Body
)
77 // Body is actually empty.
82 if t
.ContentLength
< 0 {
83 t
.TransferEncoding
= []string{"chunked"}
87 if rr
.Request
!= nil {
88 t
.Method
= rr
.Request
.Method
91 t
.BodyCloser
= rr
.Body
92 t
.ContentLength
= rr
.ContentLength
94 t
.TransferEncoding
= rr
.TransferEncoding
95 t
.Trailer
= rr
.Trailer
96 atLeastHTTP11
= rr
.ProtoAtLeast(1, 1)
97 t
.ResponseToHEAD
= noBodyExpected(t
.Method
)
100 // Sanitize Body,ContentLength,TransferEncoding
101 if t
.ResponseToHEAD
{
103 if chunked(t
.TransferEncoding
) {
107 if !atLeastHTTP11 || t
.Body
== nil {
108 t
.TransferEncoding
= nil
110 if chunked(t
.TransferEncoding
) {
112 } else if t
.Body
== nil { // no chunking, no body
118 if !chunked(t
.TransferEncoding
) {
125 func noBodyExpected(requestMethod
string) bool {
126 return requestMethod
== "HEAD"
129 func (t
*transferWriter
) shouldSendContentLength() bool {
130 if chunked(t
.TransferEncoding
) {
133 if t
.ContentLength
> 0 {
136 // Many servers expect a Content-Length for these methods
137 if t
.Method
== "POST" || t
.Method
== "PUT" {
140 if t
.ContentLength
== 0 && isIdentity(t
.TransferEncoding
) {
147 func (t
*transferWriter
) WriteHeader(w io
.Writer
) error
{
149 if _
, err
:= io
.WriteString(w
, "Connection: close\r\n"); err
!= nil {
154 // Write Content-Length and/or Transfer-Encoding whose values are a
155 // function of the sanitized field triple (Body, ContentLength,
157 if t
.shouldSendContentLength() {
158 if _
, err
:= io
.WriteString(w
, "Content-Length: "); err
!= nil {
161 if _
, err
:= io
.WriteString(w
, strconv
.FormatInt(t
.ContentLength
, 10)+"\r\n"); err
!= nil {
164 } else if chunked(t
.TransferEncoding
) {
165 if _
, err
:= io
.WriteString(w
, "Transfer-Encoding: chunked\r\n"); err
!= nil {
170 // Write Trailer header
171 if t
.Trailer
!= nil {
172 keys
:= make([]string, 0, len(t
.Trailer
))
173 for k
:= range t
.Trailer
{
174 k
= CanonicalHeaderKey(k
)
176 case "Transfer-Encoding", "Trailer", "Content-Length":
177 return &badStringError
{"invalid Trailer key", k
}
179 keys
= append(keys
, k
)
183 // TODO: could do better allocation-wise here, but trailers are rare,
184 // so being lazy for now.
185 if _
, err
:= io
.WriteString(w
, "Trailer: "+strings
.Join(keys
, ",")+"\r\n"); err
!= nil {
194 func (t
*transferWriter
) WriteBody(w io
.Writer
) error
{
200 if chunked(t
.TransferEncoding
) {
201 cw
:= newChunkedWriter(w
)
202 _
, err
= io
.Copy(cw
, t
.Body
)
206 } else if t
.ContentLength
== -1 {
207 ncopy
, err
= io
.Copy(w
, t
.Body
)
209 ncopy
, err
= io
.Copy(w
, io
.LimitReader(t
.Body
, t
.ContentLength
))
214 nextra
, err
= io
.Copy(ioutil
.Discard
, t
.Body
)
220 if err
= t
.BodyCloser
.Close(); err
!= nil {
225 if !t
.ResponseToHEAD
&& t
.ContentLength
!= -1 && t
.ContentLength
!= ncopy
{
226 return fmt
.Errorf("http: Request.ContentLength=%d with Body length %d",
227 t
.ContentLength
, ncopy
)
230 // TODO(petar): Place trailer writer code here.
231 if chunked(t
.TransferEncoding
) {
232 // Write Trailer header
233 if t
.Trailer
!= nil {
234 if err
:= t
.Trailer
.Write(w
); err
!= nil {
238 // Last chunk, empty trailer
239 _
, err
= io
.WriteString(w
, "\r\n")
244 type transferReader
struct {
254 TransferEncoding
[]string
259 // bodyAllowedForStatus reports whether a given response status code
260 // permits a body. See RFC2616, section 4.4.
261 func bodyAllowedForStatus(status
int) bool {
263 case status
>= 100 && status
<= 199:
274 suppressedHeaders304
= []string{"Content-Type", "Content-Length", "Transfer-Encoding"}
275 suppressedHeadersNoBody
= []string{"Content-Length", "Transfer-Encoding"}
278 func suppressedHeaders(status
int) []string {
281 // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
282 return suppressedHeaders304
283 case !bodyAllowedForStatus(status
):
284 return suppressedHeadersNoBody
289 // msg is *Request or *Response.
290 func readTransfer(msg
interface{}, r
*bufio
.Reader
) (err error
) {
291 t
:= &transferReader
{RequestMethod
: "GET"}
295 switch rr
:= msg
.(type) {
298 t
.StatusCode
= rr
.StatusCode
299 t
.ProtoMajor
= rr
.ProtoMajor
300 t
.ProtoMinor
= rr
.ProtoMinor
301 t
.Close
= shouldClose(t
.ProtoMajor
, t
.ProtoMinor
, t
.Header
)
303 if rr
.Request
!= nil {
304 t
.RequestMethod
= rr
.Request
.Method
308 t
.ProtoMajor
= rr
.ProtoMajor
309 t
.ProtoMinor
= rr
.ProtoMinor
310 // Transfer semantics for Requests are exactly like those for
311 // Responses with status code 200, responding to a GET method
314 panic("unexpected type")
317 // Default to HTTP/1.1
318 if t
.ProtoMajor
== 0 && t
.ProtoMinor
== 0 {
319 t
.ProtoMajor
, t
.ProtoMinor
= 1, 1
322 // Transfer encoding, content length
323 t
.TransferEncoding
, err
= fixTransferEncoding(t
.RequestMethod
, t
.Header
)
328 realLength
, err
:= fixLength(isResponse
, t
.StatusCode
, t
.RequestMethod
, t
.Header
, t
.TransferEncoding
)
332 if isResponse
&& t
.RequestMethod
== "HEAD" {
333 if n
, err
:= parseContentLength(t
.Header
.get("Content-Length")); err
!= nil {
339 t
.ContentLength
= realLength
343 t
.Trailer
, err
= fixTrailer(t
.Header
, t
.TransferEncoding
)
348 // If there is no Content-Length or chunked Transfer-Encoding on a *Response
349 // and the status is not 1xx, 204 or 304, then the body is unbounded.
350 // See RFC2616, section 4.4.
353 if realLength
== -1 &&
354 !chunked(t
.TransferEncoding
) &&
355 bodyAllowedForStatus(t
.StatusCode
) {
361 // Prepare body reader. ContentLength < 0 means chunked encoding
362 // or close connection when finished, since multipart is not supported yet
364 case chunked(t
.TransferEncoding
):
365 if noBodyExpected(t
.RequestMethod
) {
368 t
.Body
= &body
{src
: newChunkedReader(r
), hdr
: msg
, r
: r
, closing
: t
.Close
}
370 case realLength
== 0:
373 t
.Body
= &body
{src
: io
.LimitReader(r
, realLength
), closing
: t
.Close
}
375 // realLength < 0, i.e. "Content-Length" not mentioned in header
377 // Close semantics (i.e. HTTP/1.0)
378 t
.Body
= &body
{src
: r
, closing
: t
.Close
}
380 // Persistent connection (i.e. HTTP/1.1)
386 switch rr
:= msg
.(type) {
389 rr
.ContentLength
= t
.ContentLength
390 rr
.TransferEncoding
= t
.TransferEncoding
392 rr
.Trailer
= t
.Trailer
395 rr
.ContentLength
= t
.ContentLength
396 rr
.TransferEncoding
= t
.TransferEncoding
398 rr
.Trailer
= t
.Trailer
404 // Checks whether chunked is part of the encodings stack
405 func chunked(te
[]string) bool { return len(te
) > 0 && te
[0] == "chunked" }
407 // Checks whether the encoding is explicitly "identity".
408 func isIdentity(te
[]string) bool { return len(te
) == 1 && te
[0] == "identity" }
410 // Sanitize transfer encoding
411 func fixTransferEncoding(requestMethod
string, header Header
) ([]string, error
) {
412 raw
, present
:= header
["Transfer-Encoding"]
417 delete(header
, "Transfer-Encoding")
419 encodings
:= strings
.Split(raw
[0], ",")
420 te
:= make([]string, 0, len(encodings
))
421 // TODO: Even though we only support "identity" and "chunked"
422 // encodings, the loop below is designed with foresight. One
423 // invariant that must be maintained is that, if present,
424 // chunked encoding must always come first.
425 for _
, encoding
:= range encodings
{
426 encoding
= strings
.ToLower(strings
.TrimSpace(encoding
))
427 // "identity" encoding is not recorded
428 if encoding
== "identity" {
431 if encoding
!= "chunked" {
432 return nil, &badStringError
{"unsupported transfer encoding", encoding
}
434 te
= te
[0 : len(te
)+1]
435 te
[len(te
)-1] = encoding
438 return nil, &badStringError
{"too many transfer encodings", strings
.Join(te
, ",")}
441 // Chunked encoding trumps Content-Length. See RFC 2616
442 // Section 4.4. Currently len(te) > 0 implies chunked
444 delete(header
, "Content-Length")
451 // Determine the expected body length, using RFC 2616 Section 4.4. This
452 // function is not a method, because ultimately it should be shared by
453 // ReadResponse and ReadRequest.
454 func fixLength(isResponse
bool, status
int, requestMethod
string, header Header
, te
[]string) (int64, error
) {
456 // Logic based on response type or status
457 if noBodyExpected(requestMethod
) {
468 // Logic based on Transfer-Encoding
473 // Logic based on Content-Length
474 cl
:= strings
.TrimSpace(header
.get("Content-Length"))
476 n
, err
:= parseContentLength(cl
)
482 header
.Del("Content-Length")
485 if !isResponse
&& requestMethod
== "GET" {
486 // RFC 2616 doesn't explicitly permit nor forbid an
487 // entity-body on a GET request so we permit one if
488 // declared, but we default to 0 here (not -1 below)
489 // if there's no mention of a body.
493 // Body-EOF logic based on other methods (like closing, or chunked coding)
497 // Determine whether to hang up after sending a request and body, or
498 // receiving a response and body
499 // 'header' is the request headers
500 func shouldClose(major
, minor
int, header Header
) bool {
503 } else if major
== 1 && minor
== 0 {
504 if !strings
.Contains(strings
.ToLower(header
.get("Connection")), "keep-alive") {
509 // TODO: Should split on commas, toss surrounding white space,
510 // and check each field.
511 if strings
.ToLower(header
.get("Connection")) == "close" {
512 header
.Del("Connection")
519 // Parse the trailer header
520 func fixTrailer(header Header
, te
[]string) (Header
, error
) {
521 raw
:= header
.get("Trailer")
526 header
.Del("Trailer")
527 trailer
:= make(Header
)
528 keys
:= strings
.Split(raw
, ",")
529 for _
, key
:= range keys
{
530 key
= CanonicalHeaderKey(strings
.TrimSpace(key
))
532 case "Transfer-Encoding", "Trailer", "Content-Length":
533 return nil, &badStringError
{"bad trailer key", key
}
537 if len(trailer
) == 0 {
541 // Trailer and no chunking
542 return nil, ErrUnexpectedTrailer
547 // body turns a Reader into a ReadCloser.
548 // Close ensures that the body has been fully read
549 // and then reads the trailer if necessary.
552 hdr
interface{} // non-nil (Response or Request) value means read trailer
553 r
*bufio
.Reader
// underlying wire-format reader for the trailer
554 closing
bool // is the connection to be closed after reading body?
556 mu sync
.Mutex
// guards closed, and calls to Read and Close
560 // ErrBodyReadAfterClose is returned when reading a Request or Response
561 // Body after the body has been closed. This typically happens when the body is
562 // read after an HTTP Handler calls WriteHeader or Write on its
564 var ErrBodyReadAfterClose
= errors
.New("http: invalid Read on closed Body")
566 func (b
*body
) Read(p
[]byte) (n
int, err error
) {
570 return 0, ErrBodyReadAfterClose
572 return b
.readLocked(p
)
576 func (b
*body
) readLocked(p
[]byte) (n
int, err error
) {
577 n
, err
= b
.src
.Read(p
)
580 // Chunked case. Read the trailer.
582 if e
:= b
.readTrailer(); e
!= nil {
587 // If the server declared the Content-Length, our body is a LimitedReader
588 // and we need to check whether this EOF arrived early.
589 if lr
, ok
:= b
.src
.(*io
.LimitedReader
); ok
&& lr
.N
> 0 {
590 err
= io
.ErrUnexpectedEOF
595 // If we can return an EOF here along with the read data, do
596 // so. This is optional per the io.Reader contract, but doing
597 // so helps the HTTP transport code recycle its connection
598 // earlier (since it will see this EOF itself), even if the
599 // client doesn't do future reads or Close.
600 if err
== nil && n
> 0 {
601 if lr
, ok
:= b
.src
.(*io
.LimitedReader
); ok
&& lr
.N
== 0 {
610 singleCRLF
= []byte("\r\n")
611 doubleCRLF
= []byte("\r\n\r\n")
614 func seeUpcomingDoubleCRLF(r
*bufio
.Reader
) bool {
615 for peekSize
:= 4; ; peekSize
++ {
616 // This loop stops when Peek returns an error,
617 // which it does when r's buffer has been filled.
618 buf
, err
:= r
.Peek(peekSize
)
619 if bytes
.HasSuffix(buf
, doubleCRLF
) {
629 var errTrailerEOF
= errors
.New("http: unexpected EOF reading trailer")
631 func (b
*body
) readTrailer() error
{
632 // The common case, since nobody uses trailers.
633 buf
, err
:= b
.r
.Peek(2)
634 if bytes
.Equal(buf
, singleCRLF
) {
646 // Make sure there's a header terminator coming up, to prevent
647 // a DoS with an unbounded size Trailer. It's not easy to
648 // slip in a LimitReader here, as textproto.NewReader requires
649 // a concrete *bufio.Reader. Also, we can't get all the way
650 // back up to our conn's LimitedReader that *might* be backing
651 // this bufio.Reader. Instead, a hack: we iteratively Peek up
652 // to the bufio.Reader's max size, looking for a double CRLF.
653 // This limits the trailer to the underlying buffer size, typically 4kB.
654 if !seeUpcomingDoubleCRLF(b
.r
) {
655 return errors
.New("http: suspiciously long trailer after chunked body")
658 hdr
, err
:= textproto
.NewReader(b
.r
).ReadMIMEHeader()
665 switch rr
:= b
.hdr
.(type) {
667 mergeSetHeader(&rr
.Trailer
, Header(hdr
))
669 mergeSetHeader(&rr
.Trailer
, Header(hdr
))
674 func mergeSetHeader(dst
*Header
, src Header
) {
679 for k
, vv
:= range src
{
684 func (b
*body
) Close() error
{
692 case b
.hdr
== nil && b
.closing
:
693 // no trailer and closing the connection next.
694 // no point in reading to EOF.
696 // Fully consume the body, which will also lead to us reading
697 // the trailer headers after the body, if present.
698 _
, err
= io
.Copy(ioutil
.Discard
, bodyLocked
{b
})
704 // bodyLocked is a io.Reader reading from a *body when its mutex is
706 type bodyLocked
struct {
710 func (bl bodyLocked
) Read(p
[]byte) (n
int, err error
) {
712 return 0, ErrBodyReadAfterClose
714 return bl
.b
.readLocked(p
)
717 // parseContentLength trims whitespace from s and returns -1 if no value
718 // is set, or the value if it's >= 0.
719 func parseContentLength(cl
string) (int64, error
) {
720 cl
= strings
.TrimSpace(cl
)
724 n
, err
:= strconv
.ParseInt(cl
, 10, 64)
725 if err
!= nil || n
< 0 {
726 return 0, &badStringError
{"bad Content-Length", cl
}