github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/net/http/transfer.go (about) 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. 4 5 package http 6 7 import ( 8 "bufio" 9 "bytes" 10 "errors" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "net/http/internal" 15 "net/textproto" 16 "sort" 17 "strconv" 18 "strings" 19 "sync" 20 ) 21 22 // ErrLineTooLong is returned when reading request or response bodies 23 // with malformed chunked encoding. 24 var ErrLineTooLong = internal.ErrLineTooLong 25 26 type errorReader struct { 27 err error 28 } 29 30 func (r errorReader) Read(p []byte) (n int, err error) { 31 return 0, r.err 32 } 33 34 // transferWriter inspects the fields of a user-supplied Request or Response, 35 // sanitizes them without changing the user object and provides methods for 36 // writing the respective header, body and trailer in wire format. 37 type transferWriter struct { 38 Method string 39 Body io.Reader 40 BodyCloser io.Closer 41 ResponseToHEAD bool 42 ContentLength int64 // -1 means unknown, 0 means exactly none 43 Close bool 44 TransferEncoding []string 45 Trailer Header 46 IsResponse bool 47 } 48 49 func newTransferWriter(r interface{}) (t *transferWriter, err error) { 50 t = &transferWriter{} 51 52 // Extract relevant fields 53 atLeastHTTP11 := false 54 switch rr := r.(type) { 55 case *Request: 56 if rr.ContentLength != 0 && rr.Body == nil { 57 return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength) 58 } 59 t.Method = rr.Method 60 t.Body = rr.Body 61 t.BodyCloser = rr.Body 62 t.ContentLength = rr.ContentLength 63 t.Close = rr.Close 64 t.TransferEncoding = rr.TransferEncoding 65 t.Trailer = rr.Trailer 66 atLeastHTTP11 = rr.ProtoAtLeast(1, 1) 67 if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 { 68 if t.ContentLength == 0 { 69 // Test to see if it's actually zero or just unset. 70 var buf [1]byte 71 n, rerr := io.ReadFull(t.Body, buf[:]) 72 if rerr != nil && rerr != io.EOF { 73 t.ContentLength = -1 74 t.Body = errorReader{rerr} 75 } else if n == 1 { 76 // Oh, guess there is data in this Body Reader after all. 77 // The ContentLength field just wasn't set. 78 // Stich the Body back together again, re-attaching our 79 // consumed byte. 80 t.ContentLength = -1 81 t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body) 82 } else { 83 // Body is actually empty. 84 t.Body = nil 85 t.BodyCloser = nil 86 } 87 } 88 if t.ContentLength < 0 { 89 t.TransferEncoding = []string{"chunked"} 90 } 91 } 92 case *Response: 93 t.IsResponse = true 94 if rr.Request != nil { 95 t.Method = rr.Request.Method 96 } 97 t.Body = rr.Body 98 t.BodyCloser = rr.Body 99 t.ContentLength = rr.ContentLength 100 t.Close = rr.Close 101 t.TransferEncoding = rr.TransferEncoding 102 t.Trailer = rr.Trailer 103 atLeastHTTP11 = rr.ProtoAtLeast(1, 1) 104 t.ResponseToHEAD = noBodyExpected(t.Method) 105 } 106 107 // Sanitize Body,ContentLength,TransferEncoding 108 if t.ResponseToHEAD { 109 t.Body = nil 110 if chunked(t.TransferEncoding) { 111 t.ContentLength = -1 112 } 113 } else { 114 if !atLeastHTTP11 || t.Body == nil { 115 t.TransferEncoding = nil 116 } 117 if chunked(t.TransferEncoding) { 118 t.ContentLength = -1 119 } else if t.Body == nil { // no chunking, no body 120 t.ContentLength = 0 121 } 122 } 123 124 // Sanitize Trailer 125 if !chunked(t.TransferEncoding) { 126 t.Trailer = nil 127 } 128 129 return t, nil 130 } 131 132 func noBodyExpected(requestMethod string) bool { 133 return requestMethod == "HEAD" 134 } 135 136 func (t *transferWriter) shouldSendContentLength() bool { 137 if chunked(t.TransferEncoding) { 138 return false 139 } 140 if t.ContentLength > 0 { 141 return true 142 } 143 if t.ContentLength < 0 { 144 return false 145 } 146 // Many servers expect a Content-Length for these methods 147 if t.Method == "POST" || t.Method == "PUT" { 148 return true 149 } 150 if t.ContentLength == 0 && isIdentity(t.TransferEncoding) { 151 if t.Method == "GET" || t.Method == "HEAD" { 152 return false 153 } 154 return true 155 } 156 157 return false 158 } 159 160 func (t *transferWriter) WriteHeader(w io.Writer) error { 161 if t.Close { 162 if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil { 163 return err 164 } 165 } 166 167 // Write Content-Length and/or Transfer-Encoding whose values are a 168 // function of the sanitized field triple (Body, ContentLength, 169 // TransferEncoding) 170 if t.shouldSendContentLength() { 171 if _, err := io.WriteString(w, "Content-Length: "); err != nil { 172 return err 173 } 174 if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil { 175 return err 176 } 177 } else if chunked(t.TransferEncoding) { 178 if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil { 179 return err 180 } 181 } 182 183 // Write Trailer header 184 if t.Trailer != nil { 185 keys := make([]string, 0, len(t.Trailer)) 186 for k := range t.Trailer { 187 k = CanonicalHeaderKey(k) 188 switch k { 189 case "Transfer-Encoding", "Trailer", "Content-Length": 190 return &badStringError{"invalid Trailer key", k} 191 } 192 keys = append(keys, k) 193 } 194 if len(keys) > 0 { 195 sort.Strings(keys) 196 // TODO: could do better allocation-wise here, but trailers are rare, 197 // so being lazy for now. 198 if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil { 199 return err 200 } 201 } 202 } 203 204 return nil 205 } 206 207 func (t *transferWriter) WriteBody(w io.Writer) error { 208 var err error 209 var ncopy int64 210 211 // Write body 212 if t.Body != nil { 213 if chunked(t.TransferEncoding) { 214 if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse { 215 w = &internal.FlushAfterChunkWriter{bw} 216 } 217 cw := internal.NewChunkedWriter(w) 218 _, err = io.Copy(cw, t.Body) 219 if err == nil { 220 err = cw.Close() 221 } 222 } else if t.ContentLength == -1 { 223 ncopy, err = io.Copy(w, t.Body) 224 } else { 225 ncopy, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength)) 226 if err != nil { 227 return err 228 } 229 var nextra int64 230 nextra, err = io.Copy(ioutil.Discard, t.Body) 231 ncopy += nextra 232 } 233 if err != nil { 234 return err 235 } 236 if err = t.BodyCloser.Close(); err != nil { 237 return err 238 } 239 } 240 241 if !t.ResponseToHEAD && t.ContentLength != -1 && t.ContentLength != ncopy { 242 return fmt.Errorf("http: ContentLength=%d with Body length %d", 243 t.ContentLength, ncopy) 244 } 245 246 if chunked(t.TransferEncoding) { 247 // Write Trailer header 248 if t.Trailer != nil { 249 if err := t.Trailer.Write(w); err != nil { 250 return err 251 } 252 } 253 // Last chunk, empty trailer 254 _, err = io.WriteString(w, "\r\n") 255 } 256 return err 257 } 258 259 type transferReader struct { 260 // Input 261 Header Header 262 StatusCode int 263 RequestMethod string 264 ProtoMajor int 265 ProtoMinor int 266 // Output 267 Body io.ReadCloser 268 ContentLength int64 269 TransferEncoding []string 270 Close bool 271 Trailer Header 272 } 273 274 func (t *transferReader) protoAtLeast(m, n int) bool { 275 return t.ProtoMajor > m || (t.ProtoMajor == m && t.ProtoMinor >= n) 276 } 277 278 // bodyAllowedForStatus reports whether a given response status code 279 // permits a body. See RFC2616, section 4.4. 280 func bodyAllowedForStatus(status int) bool { 281 switch { 282 case status >= 100 && status <= 199: 283 return false 284 case status == 204: 285 return false 286 case status == 304: 287 return false 288 } 289 return true 290 } 291 292 var ( 293 suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"} 294 suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"} 295 ) 296 297 func suppressedHeaders(status int) []string { 298 switch { 299 case status == 304: 300 // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers" 301 return suppressedHeaders304 302 case !bodyAllowedForStatus(status): 303 return suppressedHeadersNoBody 304 } 305 return nil 306 } 307 308 // msg is *Request or *Response. 309 func readTransfer(msg interface{}, r *bufio.Reader) (err error) { 310 t := &transferReader{RequestMethod: "GET"} 311 312 // Unify input 313 isResponse := false 314 switch rr := msg.(type) { 315 case *Response: 316 t.Header = rr.Header 317 t.StatusCode = rr.StatusCode 318 t.ProtoMajor = rr.ProtoMajor 319 t.ProtoMinor = rr.ProtoMinor 320 t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header, true) 321 isResponse = true 322 if rr.Request != nil { 323 t.RequestMethod = rr.Request.Method 324 } 325 case *Request: 326 t.Header = rr.Header 327 t.RequestMethod = rr.Method 328 t.ProtoMajor = rr.ProtoMajor 329 t.ProtoMinor = rr.ProtoMinor 330 // Transfer semantics for Requests are exactly like those for 331 // Responses with status code 200, responding to a GET method 332 t.StatusCode = 200 333 t.Close = rr.Close 334 default: 335 panic("unexpected type") 336 } 337 338 // Default to HTTP/1.1 339 if t.ProtoMajor == 0 && t.ProtoMinor == 0 { 340 t.ProtoMajor, t.ProtoMinor = 1, 1 341 } 342 343 // Transfer encoding, content length 344 err = t.fixTransferEncoding() 345 if err != nil { 346 return err 347 } 348 349 realLength, err := fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding) 350 if err != nil { 351 return err 352 } 353 if isResponse && t.RequestMethod == "HEAD" { 354 if n, err := parseContentLength(t.Header.get("Content-Length")); err != nil { 355 return err 356 } else { 357 t.ContentLength = n 358 } 359 } else { 360 t.ContentLength = realLength 361 } 362 363 // Trailer 364 t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding) 365 if err != nil { 366 return err 367 } 368 369 // If there is no Content-Length or chunked Transfer-Encoding on a *Response 370 // and the status is not 1xx, 204 or 304, then the body is unbounded. 371 // See RFC2616, section 4.4. 372 switch msg.(type) { 373 case *Response: 374 if realLength == -1 && 375 !chunked(t.TransferEncoding) && 376 bodyAllowedForStatus(t.StatusCode) { 377 // Unbounded body. 378 t.Close = true 379 } 380 } 381 382 // Prepare body reader. ContentLength < 0 means chunked encoding 383 // or close connection when finished, since multipart is not supported yet 384 switch { 385 case chunked(t.TransferEncoding): 386 if noBodyExpected(t.RequestMethod) { 387 t.Body = eofReader 388 } else { 389 t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close} 390 } 391 case realLength == 0: 392 t.Body = eofReader 393 case realLength > 0: 394 t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close} 395 default: 396 // realLength < 0, i.e. "Content-Length" not mentioned in header 397 if t.Close { 398 // Close semantics (i.e. HTTP/1.0) 399 t.Body = &body{src: r, closing: t.Close} 400 } else { 401 // Persistent connection (i.e. HTTP/1.1) 402 t.Body = eofReader 403 } 404 } 405 406 // Unify output 407 switch rr := msg.(type) { 408 case *Request: 409 rr.Body = t.Body 410 rr.ContentLength = t.ContentLength 411 rr.TransferEncoding = t.TransferEncoding 412 rr.Close = t.Close 413 rr.Trailer = t.Trailer 414 case *Response: 415 rr.Body = t.Body 416 rr.ContentLength = t.ContentLength 417 rr.TransferEncoding = t.TransferEncoding 418 rr.Close = t.Close 419 rr.Trailer = t.Trailer 420 } 421 422 return nil 423 } 424 425 // Checks whether chunked is part of the encodings stack 426 func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } 427 428 // Checks whether the encoding is explicitly "identity". 429 func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } 430 431 // fixTransferEncoding sanitizes t.TransferEncoding, if needed. 432 func (t *transferReader) fixTransferEncoding() error { 433 raw, present := t.Header["Transfer-Encoding"] 434 if !present { 435 return nil 436 } 437 delete(t.Header, "Transfer-Encoding") 438 439 // Issue 12785; ignore Transfer-Encoding on HTTP/1.0 requests. 440 if !t.protoAtLeast(1, 1) { 441 return nil 442 } 443 444 encodings := strings.Split(raw[0], ",") 445 te := make([]string, 0, len(encodings)) 446 // TODO: Even though we only support "identity" and "chunked" 447 // encodings, the loop below is designed with foresight. One 448 // invariant that must be maintained is that, if present, 449 // chunked encoding must always come first. 450 for _, encoding := range encodings { 451 encoding = strings.ToLower(strings.TrimSpace(encoding)) 452 // "identity" encoding is not recorded 453 if encoding == "identity" { 454 break 455 } 456 if encoding != "chunked" { 457 return &badStringError{"unsupported transfer encoding", encoding} 458 } 459 te = te[0 : len(te)+1] 460 te[len(te)-1] = encoding 461 } 462 if len(te) > 1 { 463 return &badStringError{"too many transfer encodings", strings.Join(te, ",")} 464 } 465 if len(te) > 0 { 466 // RFC 7230 3.3.2 says "A sender MUST NOT send a 467 // Content-Length header field in any message that 468 // contains a Transfer-Encoding header field." 469 // 470 // but also: 471 // "If a message is received with both a 472 // Transfer-Encoding and a Content-Length header 473 // field, the Transfer-Encoding overrides the 474 // Content-Length. Such a message might indicate an 475 // attempt to perform request smuggling (Section 9.5) 476 // or response splitting (Section 9.4) and ought to be 477 // handled as an error. A sender MUST remove the 478 // received Content-Length field prior to forwarding 479 // such a message downstream." 480 // 481 // Reportedly, these appear in the wild. 482 delete(t.Header, "Content-Length") 483 t.TransferEncoding = te 484 return nil 485 } 486 487 return nil 488 } 489 490 // Determine the expected body length, using RFC 2616 Section 4.4. This 491 // function is not a method, because ultimately it should be shared by 492 // ReadResponse and ReadRequest. 493 func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) { 494 contentLens := header["Content-Length"] 495 isRequest := !isResponse 496 // Logic based on response type or status 497 if noBodyExpected(requestMethod) { 498 // For HTTP requests, as part of hardening against request 499 // smuggling (RFC 7230), don't allow a Content-Length header for 500 // methods which don't permit bodies. As an exception, allow 501 // exactly one Content-Length header if its value is "0". 502 if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") { 503 return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens) 504 } 505 return 0, nil 506 } 507 if status/100 == 1 { 508 return 0, nil 509 } 510 switch status { 511 case 204, 304: 512 return 0, nil 513 } 514 515 if len(contentLens) > 1 { 516 // harden against HTTP request smuggling. See RFC 7230. 517 return 0, errors.New("http: message cannot contain multiple Content-Length headers") 518 } 519 520 // Logic based on Transfer-Encoding 521 if chunked(te) { 522 return -1, nil 523 } 524 525 // Logic based on Content-Length 526 var cl string 527 if len(contentLens) == 1 { 528 cl = strings.TrimSpace(contentLens[0]) 529 } 530 if cl != "" { 531 n, err := parseContentLength(cl) 532 if err != nil { 533 return -1, err 534 } 535 return n, nil 536 } else { 537 header.Del("Content-Length") 538 } 539 540 if !isResponse { 541 // RFC 2616 neither explicitly permits nor forbids an 542 // entity-body on a GET request so we permit one if 543 // declared, but we default to 0 here (not -1 below) 544 // if there's no mention of a body. 545 // Likewise, all other request methods are assumed to have 546 // no body if neither Transfer-Encoding chunked nor a 547 // Content-Length are set. 548 return 0, nil 549 } 550 551 // Body-EOF logic based on other methods (like closing, or chunked coding) 552 return -1, nil 553 } 554 555 // Determine whether to hang up after sending a request and body, or 556 // receiving a response and body 557 // 'header' is the request headers 558 func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool { 559 if major < 1 { 560 return true 561 } else if major == 1 && minor == 0 { 562 vv := header["Connection"] 563 if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") { 564 return true 565 } 566 return false 567 } else { 568 if headerValuesContainsToken(header["Connection"], "close") { 569 if removeCloseHeader { 570 header.Del("Connection") 571 } 572 return true 573 } 574 } 575 return false 576 } 577 578 // Parse the trailer header 579 func fixTrailer(header Header, te []string) (Header, error) { 580 raw := header.get("Trailer") 581 if raw == "" { 582 return nil, nil 583 } 584 585 header.Del("Trailer") 586 trailer := make(Header) 587 keys := strings.Split(raw, ",") 588 for _, key := range keys { 589 key = CanonicalHeaderKey(strings.TrimSpace(key)) 590 switch key { 591 case "Transfer-Encoding", "Trailer", "Content-Length": 592 return nil, &badStringError{"bad trailer key", key} 593 } 594 trailer[key] = nil 595 } 596 if len(trailer) == 0 { 597 return nil, nil 598 } 599 if !chunked(te) { 600 // Trailer and no chunking 601 return nil, ErrUnexpectedTrailer 602 } 603 return trailer, nil 604 } 605 606 // body turns a Reader into a ReadCloser. 607 // Close ensures that the body has been fully read 608 // and then reads the trailer if necessary. 609 type body struct { 610 src io.Reader 611 hdr interface{} // non-nil (Response or Request) value means read trailer 612 r *bufio.Reader // underlying wire-format reader for the trailer 613 closing bool // is the connection to be closed after reading body? 614 doEarlyClose bool // whether Close should stop early 615 616 mu sync.Mutex // guards closed, and calls to Read and Close 617 sawEOF bool 618 closed bool 619 earlyClose bool // Close called and we didn't read to the end of src 620 } 621 622 // ErrBodyReadAfterClose is returned when reading a Request or Response 623 // Body after the body has been closed. This typically happens when the body is 624 // read after an HTTP Handler calls WriteHeader or Write on its 625 // ResponseWriter. 626 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body") 627 628 func (b *body) Read(p []byte) (n int, err error) { 629 b.mu.Lock() 630 defer b.mu.Unlock() 631 if b.closed { 632 return 0, ErrBodyReadAfterClose 633 } 634 return b.readLocked(p) 635 } 636 637 // Must hold b.mu. 638 func (b *body) readLocked(p []byte) (n int, err error) { 639 if b.sawEOF { 640 return 0, io.EOF 641 } 642 n, err = b.src.Read(p) 643 644 if err == io.EOF { 645 b.sawEOF = true 646 // Chunked case. Read the trailer. 647 if b.hdr != nil { 648 if e := b.readTrailer(); e != nil { 649 err = e 650 // Something went wrong in the trailer, we must not allow any 651 // further reads of any kind to succeed from body, nor any 652 // subsequent requests on the server connection. See 653 // golang.org/issue/12027 654 b.sawEOF = false 655 b.closed = true 656 } 657 b.hdr = nil 658 } else { 659 // If the server declared the Content-Length, our body is a LimitedReader 660 // and we need to check whether this EOF arrived early. 661 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 { 662 err = io.ErrUnexpectedEOF 663 } 664 } 665 } 666 667 // If we can return an EOF here along with the read data, do 668 // so. This is optional per the io.Reader contract, but doing 669 // so helps the HTTP transport code recycle its connection 670 // earlier (since it will see this EOF itself), even if the 671 // client doesn't do future reads or Close. 672 if err == nil && n > 0 { 673 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 { 674 err = io.EOF 675 b.sawEOF = true 676 } 677 } 678 679 return n, err 680 } 681 682 var ( 683 singleCRLF = []byte("\r\n") 684 doubleCRLF = []byte("\r\n\r\n") 685 ) 686 687 func seeUpcomingDoubleCRLF(r *bufio.Reader) bool { 688 for peekSize := 4; ; peekSize++ { 689 // This loop stops when Peek returns an error, 690 // which it does when r's buffer has been filled. 691 buf, err := r.Peek(peekSize) 692 if bytes.HasSuffix(buf, doubleCRLF) { 693 return true 694 } 695 if err != nil { 696 break 697 } 698 } 699 return false 700 } 701 702 var errTrailerEOF = errors.New("http: unexpected EOF reading trailer") 703 704 func (b *body) readTrailer() error { 705 // The common case, since nobody uses trailers. 706 buf, err := b.r.Peek(2) 707 if bytes.Equal(buf, singleCRLF) { 708 b.r.Discard(2) 709 return nil 710 } 711 if len(buf) < 2 { 712 return errTrailerEOF 713 } 714 if err != nil { 715 return err 716 } 717 718 // Make sure there's a header terminator coming up, to prevent 719 // a DoS with an unbounded size Trailer. It's not easy to 720 // slip in a LimitReader here, as textproto.NewReader requires 721 // a concrete *bufio.Reader. Also, we can't get all the way 722 // back up to our conn's LimitedReader that *might* be backing 723 // this bufio.Reader. Instead, a hack: we iteratively Peek up 724 // to the bufio.Reader's max size, looking for a double CRLF. 725 // This limits the trailer to the underlying buffer size, typically 4kB. 726 if !seeUpcomingDoubleCRLF(b.r) { 727 return errors.New("http: suspiciously long trailer after chunked body") 728 } 729 730 hdr, err := textproto.NewReader(b.r).ReadMIMEHeader() 731 if err != nil { 732 if err == io.EOF { 733 return errTrailerEOF 734 } 735 return err 736 } 737 switch rr := b.hdr.(type) { 738 case *Request: 739 mergeSetHeader(&rr.Trailer, Header(hdr)) 740 case *Response: 741 mergeSetHeader(&rr.Trailer, Header(hdr)) 742 } 743 return nil 744 } 745 746 func mergeSetHeader(dst *Header, src Header) { 747 if *dst == nil { 748 *dst = src 749 return 750 } 751 for k, vv := range src { 752 (*dst)[k] = vv 753 } 754 } 755 756 // unreadDataSizeLocked returns the number of bytes of unread input. 757 // It returns -1 if unknown. 758 // b.mu must be held. 759 func (b *body) unreadDataSizeLocked() int64 { 760 if lr, ok := b.src.(*io.LimitedReader); ok { 761 return lr.N 762 } 763 return -1 764 } 765 766 func (b *body) Close() error { 767 b.mu.Lock() 768 defer b.mu.Unlock() 769 if b.closed { 770 return nil 771 } 772 var err error 773 switch { 774 case b.sawEOF: 775 // Already saw EOF, so no need going to look for it. 776 case b.hdr == nil && b.closing: 777 // no trailer and closing the connection next. 778 // no point in reading to EOF. 779 case b.doEarlyClose: 780 // Read up to maxPostHandlerReadBytes bytes of the body, looking for 781 // for EOF (and trailers), so we can re-use this connection. 782 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes { 783 // There was a declared Content-Length, and we have more bytes remaining 784 // than our maxPostHandlerReadBytes tolerance. So, give up. 785 b.earlyClose = true 786 } else { 787 var n int64 788 // Consume the body, or, which will also lead to us reading 789 // the trailer headers after the body, if present. 790 n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes) 791 if err == io.EOF { 792 err = nil 793 } 794 if n == maxPostHandlerReadBytes { 795 b.earlyClose = true 796 } 797 } 798 default: 799 // Fully consume the body, which will also lead to us reading 800 // the trailer headers after the body, if present. 801 _, err = io.Copy(ioutil.Discard, bodyLocked{b}) 802 } 803 b.closed = true 804 return err 805 } 806 807 func (b *body) didEarlyClose() bool { 808 b.mu.Lock() 809 defer b.mu.Unlock() 810 return b.earlyClose 811 } 812 813 // bodyLocked is a io.Reader reading from a *body when its mutex is 814 // already held. 815 type bodyLocked struct { 816 b *body 817 } 818 819 func (bl bodyLocked) Read(p []byte) (n int, err error) { 820 if bl.b.closed { 821 return 0, ErrBodyReadAfterClose 822 } 823 return bl.b.readLocked(p) 824 } 825 826 // parseContentLength trims whitespace from s and returns -1 if no value 827 // is set, or the value if it's >= 0. 828 func parseContentLength(cl string) (int64, error) { 829 cl = strings.TrimSpace(cl) 830 if cl == "" { 831 return -1, nil 832 } 833 n, err := strconv.ParseInt(cl, 10, 64) 834 if err != nil || n < 0 { 835 return 0, &badStringError{"bad Content-Length", cl} 836 } 837 return n, nil 838 839 }