87
87
// Sanitize Body,ContentLength,TransferEncoding
88
88
if t.ResponseToHEAD {
90
t.TransferEncoding = nil
91
// ContentLength is expected to hold Content-Length
92
if t.ContentLength < 0 {
93
return nil, ErrMissingContentLength
90
if chunked(t.TransferEncoding) {
96
94
if !atLeastHTTP11 || t.Body == nil {
199
194
ncopy, err = io.Copy(w, t.Body)
201
196
ncopy, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
202
nextra, err := io.Copy(ioutil.Discard, t.Body)
201
nextra, err = io.Copy(ioutil.Discard, t.Body)
297
t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
293
realLength, err := fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
297
if isResponse && t.RequestMethod == "HEAD" {
298
if n, err := parseContentLength(t.Header.get("Content-Length")); err != nil {
304
t.ContentLength = realLength
303
308
t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
322
327
// or close connection when finished, since multipart is not supported yet
324
329
case chunked(t.TransferEncoding):
325
t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
326
case t.ContentLength >= 0:
327
// TODO: limit the Content-Length. This is an easy DoS vector.
328
t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
330
if noBodyExpected(t.RequestMethod) {
331
t.Body = &body{Reader: eofReader, closing: t.Close}
333
t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
335
case realLength == 0:
336
t.Body = &body{Reader: eofReader, closing: t.Close}
338
t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
330
// t.ContentLength < 0, i.e. "Content-Length" not mentioned in header
340
// realLength < 0, i.e. "Content-Length" not mentioned in header
332
342
// Close semantics (i.e. HTTP/1.0)
333
343
t.Body = &body{Reader: r, closing: t.Close}
335
345
// Persistent connection (i.e. HTTP/1.1)
336
t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
346
t.Body = &body{Reader: eofReader, closing: t.Close}
372
382
delete(header, "Transfer-Encoding")
374
// Head responses have no bodies, so the transfer encoding
375
// should be ignored.
376
if requestMethod == "HEAD" {
380
384
encodings := strings.Split(raw[0], ",")
381
385
te := make([]string, 0, len(encodings))
382
386
// TODO: Even though we only support "identity" and "chunked"
434
438
// Logic based on Content-Length
435
cl := strings.TrimSpace(header.Get("Content-Length"))
439
cl := strings.TrimSpace(header.get("Content-Length"))
437
n, err := strconv.ParseInt(cl, 10, 64)
438
if err != nil || n < 0 {
439
return -1, &badStringError{"bad Content-Length", cl}
441
n, err := parseContentLength(cl)
454
// Logic based on media type. The purpose of the following code is just
455
// to detect whether the unsupported "multipart/byteranges" is being
456
// used. A proper Content-Type parser is needed in the future.
457
if strings.Contains(strings.ToLower(header.Get("Content-Type")), "multipart/byteranges") {
458
return -1, ErrNotSupported
461
458
// Body-EOF logic based on other methods (like closing, or chunked coding)
471
468
} else if major == 1 && minor == 0 {
472
if !strings.Contains(strings.ToLower(header.Get("Connection")), "keep-alive") {
469
if !strings.Contains(strings.ToLower(header.get("Connection")), "keep-alive") {
477
474
// TODO: Should split on commas, toss surrounding white space,
478
475
// and check each field.
479
if strings.ToLower(header.Get("Connection")) == "close" {
476
if strings.ToLower(header.get("Connection")) == "close" {
480
477
header.Del("Connection")
487
484
// Parse the trailer header
488
485
func fixTrailer(header Header, te []string) (Header, error) {
489
raw := header.Get("Trailer")
486
raw := header.get("Trailer")
525
522
res *response // response writer for server requests, else nil
528
// ErrBodyReadAfterClose is returned when reading a Request Body after
529
// the body has been closed. This typically happens when the body is
525
// ErrBodyReadAfterClose is returned when reading a Request or Response
526
// Body after the body has been closed. This typically happens when the body is
530
527
// read after an HTTP Handler calls WriteHeader or Write on its
531
528
// ResponseWriter.
532
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed request Body")
529
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
534
531
func (b *body) Read(p []byte) (n int, err error) {
567
var errTrailerEOF = errors.New("http: unexpected EOF reading trailer")
570
569
func (b *body) readTrailer() error {
571
570
// The common case, since nobody uses trailers.
572
buf, _ := b.r.Peek(2)
571
buf, err := b.r.Peek(2)
573
572
if bytes.Equal(buf, singleCRLF) {
579
584
// Make sure there's a header terminator coming up, to prevent
580
585
// a DoS with an unbounded size Trailer. It's not easy to
611
if b.hdr == nil && b.closing {
618
case b.hdr == nil && b.closing:
612
619
// no trailer and closing the connection next.
613
620
// no point in reading to EOF.
617
// In a server request, don't continue reading from the client
618
// if we've already hit the maximum body size set by the
619
// handler. If this is set, that also means the TCP connection
620
// is about to be closed, so getting to the next HTTP request
621
// in the stream is not necessary.
622
if b.res != nil && b.res.requestBodyLimitHit {
626
// Fully consume the body, which will also lead to us reading
627
// the trailer headers after the body, if present.
628
if _, err := io.Copy(ioutil.Discard, b); err != nil {
621
case b.res != nil && b.res.requestBodyLimitHit:
622
// In a server request, don't continue reading from the client
623
// if we've already hit the maximum body size set by the
624
// handler. If this is set, that also means the TCP connection
625
// is about to be closed, so getting to the next HTTP request
626
// in the stream is not necessary.
627
case b.Reader == eofReader:
628
// Nothing to read. No need to io.Copy from it.
630
// Fully consume the body, which will also lead to us reading
631
// the trailer headers after the body, if present.
632
_, err = io.Copy(ioutil.Discard, b)
638
// parseContentLength trims whitespace from s and returns -1 if no value
639
// is set, or the value if it's >= 0.
640
func parseContentLength(cl string) (int64, error) {
641
cl = strings.TrimSpace(cl)
645
n, err := strconv.ParseInt(cl, 10, 64)
646
if err != nil || n < 0 {
647
return 0, &badStringError{"bad Content-Length", cl}