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 5package http 6 7import ( 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. 24var ErrLineTooLong = internal.ErrLineTooLong 25 26type errorReader struct { 27 err error 28} 29 30func (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. 37type 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 49func 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 = valueOrDefault(rr.Method, "GET") 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 132func noBodyExpected(requestMethod string) bool { 133 return requestMethod == "HEAD" 134} 135 136func (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 160func (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 207func (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 259type 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 274func (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. 280func 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 292var ( 293 suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"} 294 suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"} 295) 296 297func 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. 309func 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 426func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } 427 428// Checks whether the encoding is explicitly "identity". 429func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } 430 431// fixTransferEncoding sanitizes t.TransferEncoding, if needed. 432func (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. 493func 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 558func 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 579func 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. 617type 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. 635var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body") 636 637func (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. 647func (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 695var ( 696 singleCRLF = []byte("\r\n") 697 doubleCRLF = []byte("\r\n\r\n") 698) 699 700func 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 715var errTrailerEOF = errors.New("http: unexpected EOF reading trailer") 716 717func (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 759func 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. 772func (b *body) unreadDataSizeLocked() int64 { 773 if lr, ok := b.src.(*io.LimitedReader); ok { 774 return lr.N 775 } 776 return -1 777} 778 779func (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 820func (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. 828func (b *body) bodyRemains() bool { 829 b.mu.Lock() 830 defer b.mu.Unlock() 831 return !b.sawEOF 832} 833 834func (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. 842type bodyLocked struct { 843 b *body 844} 845 846func (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. 855func 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} 867