github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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 = 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 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 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 closed, 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 } 629 630 // ErrBodyReadAfterClose is returned when reading a Request or Response 631 // Body after the body has been closed. This typically happens when the body is 632 // read after an HTTP Handler calls WriteHeader or Write on its 633 // ResponseWriter. 634 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body") 635 636 func (b *body) Read(p []byte) (n int, err error) { 637 b.mu.Lock() 638 defer b.mu.Unlock() 639 if b.closed { 640 return 0, ErrBodyReadAfterClose 641 } 642 return b.readLocked(p) 643 } 644 645 // Must hold b.mu. 646 func (b *body) readLocked(p []byte) (n int, err error) { 647 if b.sawEOF { 648 return 0, io.EOF 649 } 650 n, err = b.src.Read(p) 651 652 if err == io.EOF { 653 b.sawEOF = true 654 // Chunked case. Read the trailer. 655 if b.hdr != nil { 656 if e := b.readTrailer(); e != nil { 657 err = e 658 // Something went wrong in the trailer, we must not allow any 659 // further reads of any kind to succeed from body, nor any 660 // subsequent requests on the server connection. See 661 // golang.org/issue/12027 662 b.sawEOF = false 663 b.closed = true 664 } 665 b.hdr = nil 666 } else { 667 // If the server declared the Content-Length, our body is a LimitedReader 668 // and we need to check whether this EOF arrived early. 669 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 { 670 err = io.ErrUnexpectedEOF 671 } 672 } 673 } 674 675 // If we can return an EOF here along with the read data, do 676 // so. This is optional per the io.Reader contract, but doing 677 // so helps the HTTP transport code recycle its connection 678 // earlier (since it will see this EOF itself), even if the 679 // client doesn't do future reads or Close. 680 if err == nil && n > 0 { 681 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 { 682 err = io.EOF 683 b.sawEOF = true 684 } 685 } 686 687 return n, err 688 } 689 690 var ( 691 singleCRLF = []byte("\r\n") 692 doubleCRLF = []byte("\r\n\r\n") 693 ) 694 695 func seeUpcomingDoubleCRLF(r *bufio.Reader) bool { 696 for peekSize := 4; ; peekSize++ { 697 // This loop stops when Peek returns an error, 698 // which it does when r's buffer has been filled. 699 buf, err := r.Peek(peekSize) 700 if bytes.HasSuffix(buf, doubleCRLF) { 701 return true 702 } 703 if err != nil { 704 break 705 } 706 } 707 return false 708 } 709 710 var errTrailerEOF = errors.New("http: unexpected EOF reading trailer") 711 712 func (b *body) readTrailer() error { 713 // The common case, since nobody uses trailers. 714 buf, err := b.r.Peek(2) 715 if bytes.Equal(buf, singleCRLF) { 716 b.r.Discard(2) 717 return nil 718 } 719 if len(buf) < 2 { 720 return errTrailerEOF 721 } 722 if err != nil { 723 return err 724 } 725 726 // Make sure there's a header terminator coming up, to prevent 727 // a DoS with an unbounded size Trailer. It's not easy to 728 // slip in a LimitReader here, as textproto.NewReader requires 729 // a concrete *bufio.Reader. Also, we can't get all the way 730 // back up to our conn's LimitedReader that *might* be backing 731 // this bufio.Reader. Instead, a hack: we iteratively Peek up 732 // to the bufio.Reader's max size, looking for a double CRLF. 733 // This limits the trailer to the underlying buffer size, typically 4kB. 734 if !seeUpcomingDoubleCRLF(b.r) { 735 return errors.New("http: suspiciously long trailer after chunked body") 736 } 737 738 hdr, err := textproto.NewReader(b.r).ReadMIMEHeader() 739 if err != nil { 740 if err == io.EOF { 741 return errTrailerEOF 742 } 743 return err 744 } 745 switch rr := b.hdr.(type) { 746 case *Request: 747 mergeSetHeader(&rr.Trailer, Header(hdr)) 748 case *Response: 749 mergeSetHeader(&rr.Trailer, Header(hdr)) 750 } 751 return nil 752 } 753 754 func mergeSetHeader(dst *Header, src Header) { 755 if *dst == nil { 756 *dst = src 757 return 758 } 759 for k, vv := range src { 760 (*dst)[k] = vv 761 } 762 } 763 764 // unreadDataSizeLocked returns the number of bytes of unread input. 765 // It returns -1 if unknown. 766 // b.mu must be held. 767 func (b *body) unreadDataSizeLocked() int64 { 768 if lr, ok := b.src.(*io.LimitedReader); ok { 769 return lr.N 770 } 771 return -1 772 } 773 774 func (b *body) Close() error { 775 b.mu.Lock() 776 defer b.mu.Unlock() 777 if b.closed { 778 return nil 779 } 780 var err error 781 switch { 782 case b.sawEOF: 783 // Already saw EOF, so no need going to look for it. 784 case b.hdr == nil && b.closing: 785 // no trailer and closing the connection next. 786 // no point in reading to EOF. 787 case b.doEarlyClose: 788 // Read up to maxPostHandlerReadBytes bytes of the body, looking for 789 // for EOF (and trailers), so we can re-use this connection. 790 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes { 791 // There was a declared Content-Length, and we have more bytes remaining 792 // than our maxPostHandlerReadBytes tolerance. So, give up. 793 b.earlyClose = true 794 } else { 795 var n int64 796 // Consume the body, or, which will also lead to us reading 797 // the trailer headers after the body, if present. 798 n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes) 799 if err == io.EOF { 800 err = nil 801 } 802 if n == maxPostHandlerReadBytes { 803 b.earlyClose = true 804 } 805 } 806 default: 807 // Fully consume the body, which will also lead to us reading 808 // the trailer headers after the body, if present. 809 _, err = io.Copy(ioutil.Discard, bodyLocked{b}) 810 } 811 b.closed = true 812 return err 813 } 814 815 func (b *body) didEarlyClose() bool { 816 b.mu.Lock() 817 defer b.mu.Unlock() 818 return b.earlyClose 819 } 820 821 // bodyLocked is a io.Reader reading from a *body when its mutex is 822 // already held. 823 type bodyLocked struct { 824 b *body 825 } 826 827 func (bl bodyLocked) Read(p []byte) (n int, err error) { 828 if bl.b.closed { 829 return 0, ErrBodyReadAfterClose 830 } 831 return bl.b.readLocked(p) 832 } 833 834 // parseContentLength trims whitespace from s and returns -1 if no value 835 // is set, or the value if it's >= 0. 836 func parseContentLength(cl string) (int64, error) { 837 cl = strings.TrimSpace(cl) 838 if cl == "" { 839 return -1, nil 840 } 841 n, err := strconv.ParseInt(cl, 10, 64) 842 if err != nil || n < 0 { 843 return 0, &badStringError{"bad Content-Length", cl} 844 } 845 return n, nil 846 847 }