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