LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // HTTP server. See RFC 2616. | 5 // HTTP server. See RFC 2616. |
6 | 6 |
7 package http | 7 package http |
8 | 8 |
9 import ( | 9 import ( |
10 "bufio" | 10 "bufio" |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 // requestBodyLimitHit is set by requestTooLarge when | 313 // requestBodyLimitHit is set by requestTooLarge when |
314 // maxBytesReader hits its max size. It is checked in | 314 // maxBytesReader hits its max size. It is checked in |
315 // WriteHeader, to make sure we don't consume the | 315 // WriteHeader, to make sure we don't consume the |
316 // remaining request body to try to advance to the next HTTP | 316 // remaining request body to try to advance to the next HTTP |
317 // request. Instead, when this is set, we stop reading | 317 // request. Instead, when this is set, we stop reading |
318 // subsequent requests on this connection and stop reading | 318 // subsequent requests on this connection and stop reading |
319 // input from it. | 319 // input from it. |
320 requestBodyLimitHit bool | 320 requestBodyLimitHit bool |
321 | 321 |
322 handlerDone bool // set true when the handler exits | 322 handlerDone bool // set true when the handler exits |
| 323 |
| 324 // Buffers for Date and Content-Length |
| 325 dateBuf [len(TimeFormat)]byte |
| 326 clenBuf [10]byte |
323 } | 327 } |
324 | 328 |
325 // requestTooLarge is called by maxBytesReader when too much input has | 329 // requestTooLarge is called by maxBytesReader when too much input has |
326 // been read from the client. | 330 // been read from the client. |
327 func (w *response) requestTooLarge() { | 331 func (w *response) requestTooLarge() { |
328 w.closeAfterReply = true | 332 w.closeAfterReply = true |
329 w.requestBodyLimitHit = true | 333 w.requestBodyLimitHit = true |
330 if !w.wroteHeader { | 334 if !w.wroteHeader { |
331 w.Header().Set("Connection", "close") | 335 w.Header().Set("Connection", "close") |
332 } | 336 } |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 ecr.closed = true | 522 ecr.closed = true |
519 return ecr.readCloser.Close() | 523 return ecr.readCloser.Close() |
520 } | 524 } |
521 | 525 |
522 // TimeFormat is the time format to use with | 526 // TimeFormat is the time format to use with |
523 // time.Parse and time.Time.Format when parsing | 527 // time.Parse and time.Time.Format when parsing |
524 // or generating times in HTTP headers. | 528 // or generating times in HTTP headers. |
525 // It is like time.RFC1123 but hard codes GMT as the time zone. | 529 // It is like time.RFC1123 but hard codes GMT as the time zone. |
526 const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" | 530 const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" |
527 | 531 |
| 532 // appendTime is a non-allocating version of []byte(time.Now().UTC().Format(Time
Format)) |
| 533 func appendTime(b []byte, t time.Time) []byte { |
| 534 const days = "SunMonTueWedThuFriSat" |
| 535 const months = "JanFebMarAprMayJunJulAugSepOctNovDec" |
| 536 |
| 537 yy, mm, dd := t.Date() |
| 538 hh, mn, ss := t.Clock() |
| 539 day := days[3*t.Weekday():] |
| 540 mon := months[3*(mm-1):] |
| 541 |
| 542 return append(b, |
| 543 day[0], day[1], day[2], ',', ' ', |
| 544 byte('0'+dd/10), byte('0'+dd%10), ' ', |
| 545 mon[0], mon[1], mon[2], ' ', |
| 546 byte('0'+yy/1000), byte('0'+(yy/100)%10), byte('0'+(yy/10)%10),
byte('0'+yy%10), ' ', |
| 547 byte('0'+hh/10), byte('0'+hh%10), ':', |
| 548 byte('0'+mn/10), byte('0'+mn%10), ':', |
| 549 byte('0'+ss/10), byte('0'+ss%10), ' ', |
| 550 'G', 'M', 'T') |
| 551 } |
| 552 |
528 var errTooLarge = errors.New("http: request too large") | 553 var errTooLarge = errors.New("http: request too large") |
529 | 554 |
530 // Read next request from connection. | 555 // Read next request from connection. |
531 func (c *conn) readRequest() (w *response, err error) { | 556 func (c *conn) readRequest() (w *response, err error) { |
532 if c.hijacked() { | 557 if c.hijacked() { |
533 return nil, ErrHijacked | 558 return nil, ErrHijacked |
534 } | 559 } |
535 | 560 |
536 if d := c.server.ReadTimeout; d != 0 { | 561 if d := c.server.ReadTimeout; d != 0 { |
537 c.rwc.SetReadDeadline(time.Now().Add(d)) | 562 c.rwc.SetReadDeadline(time.Now().Add(d)) |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 } | 640 } |
616 } | 641 } |
617 | 642 |
618 // extraHeader is the set of headers sometimes added by chunkWriter.writeHeader. | 643 // extraHeader is the set of headers sometimes added by chunkWriter.writeHeader. |
619 // This type is used to avoid extra allocations from cloning and/or populating | 644 // This type is used to avoid extra allocations from cloning and/or populating |
620 // the response Header map and all its 1-element slices. | 645 // the response Header map and all its 1-element slices. |
621 type extraHeader struct { | 646 type extraHeader struct { |
622 contentType string | 647 contentType string |
623 connection string | 648 connection string |
624 transferEncoding string | 649 transferEncoding string |
625 » date bool // if true, write current date | 650 » date []byte // written if not nil |
626 » contentLength int | 651 » contentLength []byte // written if not nil |
627 » setContentLength bool // if true, write contentLength | |
628 } | 652 } |
629 | 653 |
630 // Sorted the same as extraHeader.Write's loop. | 654 // Sorted the same as extraHeader.Write's loop. |
631 var extraHeaderKeys = [][]byte{ | 655 var extraHeaderKeys = [][]byte{ |
632 []byte("Content-Type"), | 656 []byte("Content-Type"), |
633 []byte("Connection"), | 657 []byte("Connection"), |
634 []byte("Transfer-Encoding"), | 658 []byte("Transfer-Encoding"), |
635 } | 659 } |
636 | 660 |
637 var ( | 661 var ( |
638 » headerDate = []byte("Date: ") | 662 » headerContentLength = []byte("Content-Length: ") |
639 » headerContentLen = []byte("Content-Length: ") | 663 » headerDate = []byte("Date: ") |
640 ) | 664 ) |
641 | 665 |
642 // writeBytes writes p to w, without p escaping to the writer. | 666 // Write writes the headers described in h to w. |
643 func writeBytes(w *bufio.Writer, p []byte) { | 667 // |
644 » // Effectively the same as w.Write(p), but that adds an allocation. | 668 // This method has a value receiver, despite the somewhat large size |
645 » // Compare using go test -v -run=none -bench=BenchmarkServerHandlerNoHea
der$ | 669 // of h, because it prevents an allocation. The escape analysis isn't |
646 » for _, b := range p { | 670 // smart enough to realize this function doesn't mutate h. |
647 » » w.WriteByte(b) | |
648 » } | |
649 } | |
650 | |
651 // The value receiver, despite copying 5 strings to the stack, | |
652 // prevents an extra allocation. The escape analysis isn't smart | |
653 // enough to realize this doesn't mutate h. | |
654 func (h extraHeader) Write(w *bufio.Writer) { | 671 func (h extraHeader) Write(w *bufio.Writer) { |
655 » var buf [30]byte // enough for TimeFormat | 672 » if h.date != nil { |
656 » if h.date { | |
657 w.Write(headerDate) | 673 w.Write(headerDate) |
658 » » writeBytes(w, time.Now().UTC().FormatAppend(TimeFormat, buf[:0])
) | 674 » » w.Write(h.date) |
659 w.Write(crlf) | 675 w.Write(crlf) |
660 } | 676 } |
661 » if h.setContentLength { | 677 » if h.contentLength != nil { |
662 » » w.Write(headerContentLen) | 678 » » w.Write(headerContentLength) |
663 » » writeBytes(w, strconv.AppendInt(buf[:0], int64(h.contentLength),
10)) | 679 » » w.Write(h.contentLength) |
664 w.Write(crlf) | 680 w.Write(crlf) |
665 } | 681 } |
666 for i, v := range []string{h.contentType, h.connection, h.transferEncodi
ng} { | 682 for i, v := range []string{h.contentType, h.connection, h.transferEncodi
ng} { |
667 if v != "" { | 683 if v != "" { |
668 w.Write(extraHeaderKeys[i]) | 684 w.Write(extraHeaderKeys[i]) |
669 w.Write(colonSpace) | 685 w.Write(colonSpace) |
670 w.WriteString(v) | 686 w.WriteString(v) |
671 w.Write(crlf) | 687 w.Write(crlf) |
672 } | 688 } |
673 } | 689 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 excludeHeader[key] = true | 730 excludeHeader[key] = true |
715 } | 731 } |
716 var setHeader extraHeader | 732 var setHeader extraHeader |
717 | 733 |
718 // If the handler is done but never sent a Content-Length | 734 // If the handler is done but never sent a Content-Length |
719 // response header and this is our first (and last) write, set | 735 // response header and this is our first (and last) write, set |
720 // it, even to zero. This helps HTTP/1.0 clients keep their | 736 // it, even to zero. This helps HTTP/1.0 clients keep their |
721 // "keep-alive" connections alive. | 737 // "keep-alive" connections alive. |
722 if w.handlerDone && header.get("Content-Length") == "" && w.req.Method !
= "HEAD" { | 738 if w.handlerDone && header.get("Content-Length") == "" && w.req.Method !
= "HEAD" { |
723 w.contentLength = int64(len(p)) | 739 w.contentLength = int64(len(p)) |
724 » » setHeader.contentLength = len(p) | 740 » » setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0],
int64(len(p)), 10) |
725 » » setHeader.setContentLength = true | |
726 } | 741 } |
727 | 742 |
728 // If this was an HTTP/1.0 request with keep-alive and we sent a | 743 // If this was an HTTP/1.0 request with keep-alive and we sent a |
729 // Content-Length back, we can make this a keep-alive response ... | 744 // Content-Length back, we can make this a keep-alive response ... |
730 if w.req.wantsHttp10KeepAlive() { | 745 if w.req.wantsHttp10KeepAlive() { |
731 sentLength := header.get("Content-Length") != "" | 746 sentLength := header.get("Content-Length") != "" |
732 if sentLength && header.get("Connection") == "keep-alive" { | 747 if sentLength && header.get("Connection") == "keep-alive" { |
733 w.closeAfterReply = false | 748 w.closeAfterReply = false |
734 } | 749 } |
735 } | 750 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 delHeader(k) | 791 delHeader(k) |
777 } | 792 } |
778 } else { | 793 } else { |
779 // If no content type, apply sniffing algorithm to body. | 794 // If no content type, apply sniffing algorithm to body. |
780 if header.get("Content-Type") == "" && w.req.Method != "HEAD" { | 795 if header.get("Content-Type") == "" && w.req.Method != "HEAD" { |
781 setHeader.contentType = DetectContentType(p) | 796 setHeader.contentType = DetectContentType(p) |
782 } | 797 } |
783 } | 798 } |
784 | 799 |
785 if _, ok := header["Date"]; !ok { | 800 if _, ok := header["Date"]; !ok { |
786 » » setHeader.date = true | 801 » » setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) |
787 } | 802 } |
788 | 803 |
789 te := header.get("Transfer-Encoding") | 804 te := header.get("Transfer-Encoding") |
790 hasTE := te != "" | 805 hasTE := te != "" |
791 if hasCL && hasTE && te != "identity" { | 806 if hasCL && hasTE && te != "identity" { |
792 // TODO: return an error if WriteHeader gets a return parameter | 807 // TODO: return an error if WriteHeader gets a return parameter |
793 // For now just ignore the Content-Length. | 808 // For now just ignore the Content-Length. |
794 log.Printf("http: WriteHeader called with both Transfer-Encoding
of %q and a Content-Length of %d", | 809 log.Printf("http: WriteHeader called with both Transfer-Encoding
of %q and a Content-Length of %d", |
795 te, w.contentLength) | 810 te, w.contentLength) |
796 delHeader("Content-Length") | 811 delHeader("Content-Length") |
(...skipping 1060 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1857 log.Printf("%s.Read(%d) = %d, %v", c.name, len(p), n, err) | 1872 log.Printf("%s.Read(%d) = %d, %v", c.name, len(p), n, err) |
1858 return | 1873 return |
1859 } | 1874 } |
1860 | 1875 |
1861 func (c *loggingConn) Close() (err error) { | 1876 func (c *loggingConn) Close() (err error) { |
1862 log.Printf("%s.Close() = ...", c.name) | 1877 log.Printf("%s.Close() = ...", c.name) |
1863 err = c.Conn.Close() | 1878 err = c.Conn.Close() |
1864 log.Printf("%s.Close() = %v", c.name, err) | 1879 log.Printf("%s.Close() = %v", c.name, err) |
1865 return | 1880 return |
1866 } | 1881 } |
LEFT | RIGHT |