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