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