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