Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(660)

Delta Between Two Patch Sets: src/pkg/net/http/server.go

Issue 9432046: code review 9432046: net/http: fewer allocations in the server path (Closed)
Left Patch Set: diff -r 0d28fd55e721 https://go.googlecode.com/hg/ Created 10 years, 10 months ago
Right Patch Set: diff -r 53b012eb5e17 https://go.googlecode.com/hg/ Created 10 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/net/http/serve_test.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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
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
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b