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