aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net/http/server.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2016-02-03 21:58:02 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-02-03 21:58:02 +0000
commitf98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch)
tree2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/net/http/server.go
parentb081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff)
downloadgcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.zip
gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.gz
gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.bz2
libgo: Update to go1.6rc1.
Reviewed-on: https://go-review.googlesource.com/19200 From-SVN: r233110
Diffstat (limited to 'libgo/go/net/http/server.go')
-rw-r--r--libgo/go/net/http/server.go729
1 files changed, 514 insertions, 215 deletions
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index a3e4355..004a1f9 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -8,6 +8,7 @@ package http
import (
"bufio"
+ "bytes"
"crypto/tls"
"errors"
"fmt"
@@ -35,26 +36,33 @@ var (
ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length")
)
-// Objects implementing the Handler interface can be
-// registered to serve a particular path or subtree
-// in the HTTP server.
+// A Handler responds to an HTTP request.
//
// ServeHTTP should write reply headers and data to the ResponseWriter
-// and then return. Returning signals that the request is finished
-// and that the HTTP server can move on to the next request on
-// the connection.
+// and then return. Returning signals that the request is finished; it
+// is not valid to use the ResponseWriter or read from the
+// Request.Body after or concurrently with the completion of the
+// ServeHTTP call.
+//
+// Depending on the HTTP client software, HTTP protocol version, and
+// any intermediaries between the client and the Go server, it may not
+// be possible to read from the Request.Body after writing to the
+// ResponseWriter. Cautious handlers should read the Request.Body
+// first, and then reply.
//
// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
// that the effect of the panic was isolated to the active request.
// It recovers the panic, logs a stack trace to the server error log,
// and hangs up the connection.
-//
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// A ResponseWriter interface is used by an HTTP handler to
// construct an HTTP response.
+//
+// A ResponseWriter may not be used after the Handler.ServeHTTP method
+// has returned.
type ResponseWriter interface {
// Header returns the header map that will be sent by
// WriteHeader. Changing the header after a call to
@@ -114,28 +122,76 @@ type Hijacker interface {
// This mechanism can be used to cancel long operations on the server
// if the client has disconnected before the response is ready.
type CloseNotifier interface {
- // CloseNotify returns a channel that receives a single value
- // when the client connection has gone away.
+ // CloseNotify returns a channel that receives at most a
+ // single value (true) when the client connection has gone
+ // away.
+ //
+ // CloseNotify may wait to notify until Request.Body has been
+ // fully read.
+ //
+ // After the Handler has returned, there is no guarantee
+ // that the channel receives a value.
+ //
+ // If the protocol is HTTP/1.1 and CloseNotify is called while
+ // processing an idempotent request (such a GET) while
+ // HTTP/1.1 pipelining is in use, the arrival of a subsequent
+ // pipelined request may cause a value to be sent on the
+ // returned channel. In practice HTTP/1.1 pipelining is not
+ // enabled in browsers and not seen often in the wild. If this
+ // is a problem, use HTTP/2 or only use CloseNotify on methods
+ // such as POST.
CloseNotify() <-chan bool
}
// A conn represents the server side of an HTTP connection.
type conn struct {
- remoteAddr string // network address of remote side
- server *Server // the Server on which the connection arrived
- rwc net.Conn // i/o connection
- w io.Writer // checkConnErrorWriter's copy of wrc, not zeroed on Hijack
- werr error // any errors writing to w
- sr liveSwitchReader // where the LimitReader reads from; usually the rwc
- lr *io.LimitedReader // io.LimitReader(sr)
- buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
- tlsState *tls.ConnectionState // or nil when not using TLS
- lastMethod string // method of previous request, or ""
-
- mu sync.Mutex // guards the following
- clientGone bool // if client has disconnected mid-request
- closeNotifyc chan bool // made lazily
- hijackedv bool // connection has been hijacked by handler
+ // server is the server on which the connection arrived.
+ // Immutable; never nil.
+ server *Server
+
+ // rwc is the underlying network connection.
+ // This is never wrapped by other types and is the value given out
+ // to CloseNotifier callers. It is usually of type *net.TCPConn or
+ // *tls.Conn.
+ rwc net.Conn
+
+ // remoteAddr is rwc.RemoteAddr().String(). It is not populated synchronously
+ // inside the Listener's Accept goroutine, as some implementations block.
+ // It is populated immediately inside the (*conn).serve goroutine.
+ // This is the value of a Handler's (*Request).RemoteAddr.
+ remoteAddr string
+
+ // tlsState is the TLS connection state when using TLS.
+ // nil means not TLS.
+ tlsState *tls.ConnectionState
+
+ // werr is set to the first write error to rwc.
+ // It is set via checkConnErrorWriter{w}, where bufw writes.
+ werr error
+
+ // r is bufr's read source. It's a wrapper around rwc that provides
+ // io.LimitedReader-style limiting (while reading request headers)
+ // and functionality to support CloseNotifier. See *connReader docs.
+ r *connReader
+
+ // bufr reads from r.
+ // Users of bufr must hold mu.
+ bufr *bufio.Reader
+
+ // bufw writes to checkConnErrorWriter{c}, which populates werr on error.
+ bufw *bufio.Writer
+
+ // lastMethod is the method of the most recent request
+ // on this connection, if any.
+ lastMethod string
+
+ // mu guards hijackedv, use of bufr, (*response).closeNotifyCh.
+ mu sync.Mutex
+
+ // hijackedv is whether this connection has been hijacked
+ // by a Handler with the Hijacker interface.
+ // It is guarded by mu.
+ hijackedv bool
}
func (c *conn) hijacked() bool {
@@ -144,81 +200,18 @@ func (c *conn) hijacked() bool {
return c.hijackedv
}
-func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
- c.mu.Lock()
- defer c.mu.Unlock()
+// c.mu must be held.
+func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if c.hijackedv {
return nil, nil, ErrHijacked
}
- if c.closeNotifyc != nil {
- return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier")
- }
c.hijackedv = true
rwc = c.rwc
- buf = c.buf
- c.rwc = nil
- c.buf = nil
+ buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
c.setState(rwc, StateHijacked)
return
}
-func (c *conn) closeNotify() <-chan bool {
- c.mu.Lock()
- defer c.mu.Unlock()
- if c.closeNotifyc == nil {
- c.closeNotifyc = make(chan bool, 1)
- if c.hijackedv {
- // to obey the function signature, even though
- // it'll never receive a value.
- return c.closeNotifyc
- }
- pr, pw := io.Pipe()
-
- readSource := c.sr.r
- c.sr.Lock()
- c.sr.r = pr
- c.sr.Unlock()
- go func() {
- _, err := io.Copy(pw, readSource)
- if err == nil {
- err = io.EOF
- }
- pw.CloseWithError(err)
- c.noteClientGone()
- }()
- }
- return c.closeNotifyc
-}
-
-func (c *conn) noteClientGone() {
- c.mu.Lock()
- defer c.mu.Unlock()
- if c.closeNotifyc != nil && !c.clientGone {
- c.closeNotifyc <- true
- }
- c.clientGone = true
-}
-
-// A switchWriter can have its Writer changed at runtime.
-// It's not safe for concurrent Writes and switches.
-type switchWriter struct {
- io.Writer
-}
-
-// A liveSwitchReader can have its Reader changed at runtime. It's
-// safe for concurrent reads and switches, if its mutex is held.
-type liveSwitchReader struct {
- sync.Mutex
- r io.Reader
-}
-
-func (sr *liveSwitchReader) Read(p []byte) (n int, err error) {
- sr.Lock()
- r := sr.r
- sr.Unlock()
- return r.Read(p)
-}
-
// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 2048
@@ -265,15 +258,15 @@ func (cw *chunkWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
if cw.chunking {
- _, err = fmt.Fprintf(cw.res.conn.buf, "%x\r\n", len(p))
+ _, err = fmt.Fprintf(cw.res.conn.bufw, "%x\r\n", len(p))
if err != nil {
cw.res.conn.rwc.Close()
return
}
}
- n, err = cw.res.conn.buf.Write(p)
+ n, err = cw.res.conn.bufw.Write(p)
if cw.chunking && err == nil {
- _, err = cw.res.conn.buf.Write(crlf)
+ _, err = cw.res.conn.bufw.Write(crlf)
}
if err != nil {
cw.res.conn.rwc.Close()
@@ -285,7 +278,7 @@ func (cw *chunkWriter) flush() {
if !cw.wroteHeader {
cw.writeHeader(nil)
}
- cw.res.conn.buf.Flush()
+ cw.res.conn.bufw.Flush()
}
func (cw *chunkWriter) close() {
@@ -293,7 +286,7 @@ func (cw *chunkWriter) close() {
cw.writeHeader(nil)
}
if cw.chunking {
- bw := cw.res.conn.buf // conn's bufio writer
+ bw := cw.res.conn.bufw // conn's bufio writer
// zero chunk to mark EOF
bw.WriteString("0\r\n")
if len(cw.res.trailers) > 0 {
@@ -315,12 +308,12 @@ func (cw *chunkWriter) close() {
type response struct {
conn *conn
req *Request // request for this response
- wroteHeader bool // reply header has been (logically) written
- wroteContinue bool // 100 Continue response was written
+ reqBody io.ReadCloser
+ wroteHeader bool // reply header has been (logically) written
+ wroteContinue bool // 100 Continue response was written
w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter
- sw *switchWriter // of the bufio.Writer, for return to putBufioWriter
// handlerHeader is the Header that Handlers get access to,
// which may be retained and mutated even after WriteHeader.
@@ -354,13 +347,22 @@ type response struct {
// written.
trailers []string
- handlerDone bool // set true when the handler exits
+ handlerDone atomicBool // set true when the handler exits
// Buffers for Date and Content-Length
dateBuf [len(TimeFormat)]byte
clenBuf [10]byte
+
+ // closeNotifyCh is non-nil once CloseNotify is called.
+ // Guarded by conn.mu
+ closeNotifyCh <-chan bool
}
+type atomicBool int32
+
+func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
+func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
+
// declareTrailer is called for each Trailer header when the
// response header is written. It notes that a header will need to be
// written in the trailers at the end of the response.
@@ -423,7 +425,9 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return 0, err
}
if !ok || !regFile {
- return io.Copy(writerOnly{w}, src)
+ bufp := copyBufPool.Get().(*[]byte)
+ defer copyBufPool.Put(bufp)
+ return io.CopyBuffer(writerOnly{w}, src, *bufp)
}
// sendfile path:
@@ -456,29 +460,88 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return n, err
}
-// noLimit is an effective infinite upper bound for io.LimitedReader
-const noLimit int64 = (1 << 63) - 1
-
// debugServerConnections controls whether all server connections are wrapped
// with a verbose logging wrapper.
const debugServerConnections = false
// Create new connection from rwc.
-func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
- c = new(conn)
- c.remoteAddr = rwc.RemoteAddr().String()
- c.server = srv
- c.rwc = rwc
- c.w = rwc
+func (srv *Server) newConn(rwc net.Conn) *conn {
+ c := &conn{
+ server: srv,
+ rwc: rwc,
+ }
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
- c.sr.r = c.rwc
- c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
- br := newBufioReader(c.lr)
- bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
- c.buf = bufio.NewReadWriter(br, bw)
- return c, nil
+ return c
+}
+
+type readResult struct {
+ n int
+ err error
+ b byte // byte read, if n == 1
+}
+
+// connReader is the io.Reader wrapper used by *conn. It combines a
+// selectively-activated io.LimitedReader (to bound request header
+// read sizes) with support for selectively keeping an io.Reader.Read
+// call blocked in a background goroutine to wait for activity and
+// trigger a CloseNotifier channel.
+type connReader struct {
+ r io.Reader
+ remain int64 // bytes remaining
+
+ // ch is non-nil if a background read is in progress.
+ // It is guarded by conn.mu.
+ ch chan readResult
+}
+
+func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain }
+func (cr *connReader) setInfiniteReadLimit() { cr.remain = 1<<63 - 1 }
+func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 }
+
+func (cr *connReader) Read(p []byte) (n int, err error) {
+ if cr.hitReadLimit() {
+ return 0, io.EOF
+ }
+ if len(p) == 0 {
+ return
+ }
+ if int64(len(p)) > cr.remain {
+ p = p[:cr.remain]
+ }
+
+ // Is a background read (started by CloseNotifier) already in
+ // flight? If so, wait for it and use its result.
+ ch := cr.ch
+ if ch != nil {
+ cr.ch = nil
+ res := <-ch
+ if res.n == 1 {
+ p[0] = res.b
+ cr.remain -= 1
+ }
+ return res.n, res.err
+ }
+ n, err = cr.r.Read(p)
+ cr.remain -= int64(n)
+ return
+}
+
+func (cr *connReader) startBackgroundRead(onReadComplete func()) {
+ if cr.ch != nil {
+ // Background read already started.
+ return
+ }
+ cr.ch = make(chan readResult, 1)
+ go cr.closeNotifyAwaitActivityRead(cr.ch, onReadComplete)
+}
+
+func (cr *connReader) closeNotifyAwaitActivityRead(ch chan<- readResult, onReadComplete func()) {
+ var buf [1]byte
+ n, err := cr.r.Read(buf[:1])
+ onReadComplete()
+ ch <- readResult{n, err, buf[0]}
}
var (
@@ -487,6 +550,13 @@ var (
bufioWriter4kPool sync.Pool
)
+var copyBufPool = sync.Pool{
+ New: func() interface{} {
+ b := make([]byte, 32*1024)
+ return &b
+ },
+}
+
func bufioWriterPool(size int) *sync.Pool {
switch size {
case 2 << 10:
@@ -544,7 +614,7 @@ func (srv *Server) maxHeaderBytes() int {
return DefaultMaxHeaderBytes
}
-func (srv *Server) initialLimitedReaderSize() int64 {
+func (srv *Server) initialReadLimitSize() int64 {
return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
}
@@ -563,8 +633,8 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
}
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() {
ecr.resp.wroteContinue = true
- ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
- ecr.resp.conn.buf.Flush()
+ ecr.resp.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
+ ecr.resp.conn.bufw.Flush()
}
n, err = ecr.readCloser.Read(p)
if err == io.EOF {
@@ -578,10 +648,12 @@ func (ecr *expectContinueReader) Close() error {
return ecr.readCloser.Close()
}
-// TimeFormat is the time format to use with
-// time.Parse and time.Time.Format when parsing
-// or generating times in HTTP headers.
-// It is like time.RFC1123 but hard codes GMT as the time zone.
+// TimeFormat is the time format to use when generating times in HTTP
+// headers. It is like time.RFC1123 but hard-codes GMT as the time
+// zone. The time being formatted must be in UTC for Format to
+// generate the correct format.
+//
+// For parsing this time format, see ParseTime.
const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
// appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat))
@@ -623,21 +695,45 @@ func (c *conn) readRequest() (w *response, err error) {
}()
}
- c.lr.N = c.server.initialLimitedReaderSize()
+ c.r.setReadLimit(c.server.initialReadLimitSize())
+ c.mu.Lock() // while using bufr
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
- peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below
- c.buf.Reader.Discard(numLeadingCRorLF(peek))
+ peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
+ c.bufr.Discard(numLeadingCRorLF(peek))
}
- var req *Request
- if req, err = ReadRequest(c.buf.Reader); err != nil {
- if c.lr.N == 0 {
+ req, err := readRequest(c.bufr, keepHostHeader)
+ c.mu.Unlock()
+ if err != nil {
+ if c.r.hitReadLimit() {
return nil, errTooLarge
}
return nil, err
}
- c.lr.N = noLimit
c.lastMethod = req.Method
+ c.r.setInfiniteReadLimit()
+
+ hosts, haveHost := req.Header["Host"]
+ if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
+ return nil, badRequestError("missing required Host header")
+ }
+ if len(hosts) > 1 {
+ return nil, badRequestError("too many Host headers")
+ }
+ if len(hosts) == 1 && !validHostHeader(hosts[0]) {
+ return nil, badRequestError("malformed Host header")
+ }
+ for k, vv := range req.Header {
+ if !validHeaderName(k) {
+ return nil, badRequestError("invalid header name")
+ }
+ for _, v := range vv {
+ if !validHeaderValue(v) {
+ return nil, badRequestError("invalid header value")
+ }
+ }
+ }
+ delete(req.Header, "Host")
req.RemoteAddr = c.remoteAddr
req.TLS = c.tlsState
@@ -648,6 +744,7 @@ func (c *conn) readRequest() (w *response, err error) {
w = &response{
conn: c,
req: req,
+ reqBody: req.Body,
handlerHeader: make(Header),
contentLength: -1,
}
@@ -755,7 +852,7 @@ func (h extraHeader) Write(w *bufio.Writer) {
}
// writeHeader finalizes the header sent to the client and writes it
-// to cw.res.conn.buf.
+// to cw.res.conn.bufw.
//
// p is not written by writeHeader, but is the first chunk of the body
// that will be written. It is sniffed for a Content-Type if none is
@@ -821,7 +918,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// send a Content-Length header.
// Further, we don't send an automatic Content-Length if they
// set a Transfer-Encoding, because they're generally incompatible.
- if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+ if w.handlerDone.isSet() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
w.contentLength = int64(len(p))
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
}
@@ -898,7 +995,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
if discard {
- _, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
+ _, err := io.CopyN(ioutil.Discard, w.reqBody, maxPostHandlerReadBytes+1)
switch err {
case nil:
// There must be even more data left over.
@@ -907,7 +1004,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// Body was already consumed and closed.
case io.EOF:
// The remaining body was just consumed, close it.
- err = w.req.Body.Close()
+ err = w.reqBody.Close()
if err != nil {
w.closeAfterReply = true
}
@@ -996,10 +1093,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
}
- w.conn.buf.WriteString(statusLine(w.req, code))
- cw.header.WriteSubset(w.conn.buf, excludeHeader)
- setHeader.Write(w.conn.buf.Writer)
- w.conn.buf.Write(crlf)
+ w.conn.bufw.WriteString(statusLine(w.req, code))
+ cw.header.WriteSubset(w.conn.bufw, excludeHeader)
+ setHeader.Write(w.conn.bufw)
+ w.conn.bufw.Write(crlf)
}
// foreachHeaderElement splits v according to the "#rule" construction
@@ -1144,7 +1241,7 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
}
func (w *response) finishRequest() {
- w.handlerDone = true
+ w.handlerDone.setTrue()
if !w.wroteHeader {
w.WriteHeader(StatusOK)
@@ -1153,11 +1250,11 @@ func (w *response) finishRequest() {
w.w.Flush()
putBufioWriter(w.w)
w.cw.close()
- w.conn.buf.Flush()
+ w.conn.bufw.Flush()
// Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely.
- w.req.Body.Close()
+ w.reqBody.Close()
if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll()
@@ -1206,28 +1303,26 @@ func (w *response) Flush() {
}
func (c *conn) finalFlush() {
- if c.buf != nil {
- c.buf.Flush()
-
+ if c.bufr != nil {
// Steal the bufio.Reader (~4KB worth of memory) and its associated
// reader for a future connection.
- putBufioReader(c.buf.Reader)
+ putBufioReader(c.bufr)
+ c.bufr = nil
+ }
+ if c.bufw != nil {
+ c.bufw.Flush()
// Steal the bufio.Writer (~4KB worth of memory) and its associated
// writer for a future connection.
- putBufioWriter(c.buf.Writer)
-
- c.buf = nil
+ putBufioWriter(c.bufw)
+ c.bufw = nil
}
}
// Close the connection.
func (c *conn) close() {
c.finalFlush()
- if c.rwc != nil {
- c.rwc.Close()
- c.rwc = nil
- }
+ c.rwc.Close()
}
// rstAvoidanceDelay is the amount of time we sleep after closing the
@@ -1277,9 +1372,16 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
}
}
+// badRequestError is a literal string (used by in the server in HTML,
+// unescaped) to tell the user why their request was bad. It should
+// be plain text without user info or other embeddded errors.
+type badRequestError string
+
+func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
+
// Serve a new connection.
func (c *conn) serve() {
- origConn := c.rwc // copy it before it's set nil on Close or Hijack
+ c.remoteAddr = c.rwc.RemoteAddr().String()
defer func() {
if err := recover(); err != nil {
const size = 64 << 10
@@ -1289,7 +1391,7 @@ func (c *conn) serve() {
}
if !c.hijacked() {
c.close()
- c.setState(origConn, StateClosed)
+ c.setState(c.rwc, StateClosed)
}
}()
@@ -1315,9 +1417,13 @@ func (c *conn) serve() {
}
}
+ c.r = &connReader{r: c.rwc}
+ c.bufr = newBufioReader(c.r)
+ c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
+
for {
w, err := c.readRequest()
- if c.lr.N != c.server.initialLimitedReaderSize() {
+ if c.r.remain != c.server.initialReadLimitSize() {
// If we read any bytes off the wire, we're active.
c.setState(c.rwc, StateActive)
}
@@ -1328,16 +1434,22 @@ func (c *conn) serve() {
// responding to them and hanging up
// while they're still writing their
// request. Undefined behavior.
- io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n")
+ io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")
c.closeWriteAndWait()
- break
- } else if err == io.EOF {
- break // Don't reply
- } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
- break // Don't reply
+ return
}
- io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n")
- break
+ if err == io.EOF {
+ return // don't reply
+ }
+ if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ return // don't reply
+ }
+ var publicErr string
+ if v, ok := err.(badRequestError); ok {
+ publicErr = ": " + string(v)
+ }
+ io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)
+ return
}
// Expect 100 Continue support
@@ -1347,10 +1459,9 @@ func (c *conn) serve() {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
- req.Header.Del("Expect")
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
- break
+ return
}
// HTTP cannot have multiple simultaneous active requests.[*]
@@ -1367,7 +1478,7 @@ func (c *conn) serve() {
if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
c.closeWriteAndWait()
}
- break
+ return
}
c.setState(c.rwc, StateIdle)
}
@@ -1394,12 +1505,24 @@ func (w *response) sendExpectationFailed() {
// Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter
// and a Hijacker.
func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
+ if w.handlerDone.isSet() {
+ panic("net/http: Hijack called after ServeHTTP finished")
+ }
if w.wroteHeader {
w.cw.flush()
}
+
+ c := w.conn
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if w.closeNotifyCh != nil {
+ return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier in same ServeHTTP call")
+ }
+
// Release the bufioWriter that writes to the chunk writer, it is not
// used after a connection has been hijacked.
- rwc, buf, err = w.conn.hijack()
+ rwc, buf, err = c.hijackLocked()
if err == nil {
putBufioWriter(w.w)
w.w = nil
@@ -1408,13 +1531,86 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
}
func (w *response) CloseNotify() <-chan bool {
- return w.conn.closeNotify()
+ if w.handlerDone.isSet() {
+ panic("net/http: CloseNotify called after ServeHTTP finished")
+ }
+ c := w.conn
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if w.closeNotifyCh != nil {
+ return w.closeNotifyCh
+ }
+ ch := make(chan bool, 1)
+ w.closeNotifyCh = ch
+
+ if w.conn.hijackedv {
+ // CloseNotify is undefined after a hijack, but we have
+ // no place to return an error, so just return a channel,
+ // even though it'll never receive a value.
+ return ch
+ }
+
+ var once sync.Once
+ notify := func() { once.Do(func() { ch <- true }) }
+
+ if requestBodyRemains(w.reqBody) {
+ // They're still consuming the request body, so we
+ // shouldn't notify yet.
+ registerOnHitEOF(w.reqBody, func() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ startCloseNotifyBackgroundRead(c, notify)
+ })
+ } else {
+ startCloseNotifyBackgroundRead(c, notify)
+ }
+ return ch
+}
+
+// c.mu must be held.
+func startCloseNotifyBackgroundRead(c *conn, notify func()) {
+ if c.bufr.Buffered() > 0 {
+ // They've consumed the request body, so anything
+ // remaining is a pipelined request, which we
+ // document as firing on.
+ notify()
+ } else {
+ c.r.startBackgroundRead(notify)
+ }
+}
+
+func registerOnHitEOF(rc io.ReadCloser, fn func()) {
+ switch v := rc.(type) {
+ case *expectContinueReader:
+ registerOnHitEOF(v.readCloser, fn)
+ case *body:
+ v.registerOnHitEOF(fn)
+ default:
+ panic("unexpected type " + fmt.Sprintf("%T", rc))
+ }
+}
+
+// requestBodyRemains reports whether future calls to Read
+// on rc might yield more data.
+func requestBodyRemains(rc io.ReadCloser) bool {
+ if rc == eofReader {
+ return false
+ }
+ switch v := rc.(type) {
+ case *expectContinueReader:
+ return requestBodyRemains(v.readCloser)
+ case *body:
+ return v.bodyRemains()
+ default:
+ panic("unexpected type " + fmt.Sprintf("%T", rc))
+ }
}
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
-// Handler object that calls f.
+// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
@@ -1461,6 +1657,9 @@ func StripPrefix(prefix string, h Handler) Handler {
// Redirect replies to the request with a redirect to url,
// which may be a path relative to the request path.
+//
+// The provided code should be in the 3xx range and is usually
+// StatusMovedPermanently, StatusFound or StatusSeeOther.
func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
if u, err := url.Parse(urlStr); err == nil {
// If url was relative, make absolute by
@@ -1479,11 +1678,12 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
// Because of this problem, no one pays attention
// to the RFC; they all send back just a new path.
// So do we.
- oldpath := r.URL.Path
- if oldpath == "" { // should not happen, but avoid a crash if it does
- oldpath = "/"
- }
- if u.Scheme == "" {
+ if u.Scheme == "" && u.Host == "" {
+ oldpath := r.URL.Path
+ if oldpath == "" { // should not happen, but avoid a crash if it does
+ oldpath = "/"
+ }
+
// no leading http://server
if urlStr == "" || urlStr[0] != '/' {
// make relative path absolute
@@ -1545,6 +1745,9 @@ func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
// RedirectHandler returns a request handler that redirects
// each request it receives to the given url using the given
// status code.
+//
+// The provided code should be in the 3xx range and is usually
+// StatusMovedPermanently, StatusFound or StatusSeeOther.
func RedirectHandler(url string, code int) Handler {
return &redirectHandler{url, code}
}
@@ -1567,6 +1770,14 @@ func RedirectHandler(url string, code int) Handler {
// the pattern "/" matches all paths not matched by other registered
// patterns, not just the URL with Path == "/".
//
+// If a subtree has been registered and a request is received naming the
+// subtree root without its trailing slash, ServeMux redirects that
+// request to the subtree root (adding the trailing slash). This behavior can
+// be overridden with a separate registration for the path without
+// the trailing slash. For example, registering "/images/" causes ServeMux
+// to redirect a request for "/images" to "/images/", unless "/images" has
+// been registered separately.
+//
// Patterns may optionally begin with a host name, restricting matches to
// URLs on that host only. Host-specific patterns take precedence over
// general patterns, so that a handler might register for the two patterns
@@ -1574,8 +1785,8 @@ func RedirectHandler(url string, code int) Handler {
// requests for "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path,
-// redirecting any request containing . or .. elements to an
-// equivalent .- and ..-free URL.
+// redirecting any request containing . or .. elements or repeated slashes
+// to an equivalent, cleaner URL.
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
@@ -1782,6 +1993,7 @@ type Server struct {
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
+ // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
@@ -1795,7 +2007,9 @@ type Server struct {
// standard logger.
ErrorLog *log.Logger
- disableKeepAlives int32 // accessed atomically.
+ disableKeepAlives int32 // accessed atomically.
+ nextProtoOnce sync.Once // guards initialization of TLSNextProto in Serve
+ nextProtoErr error
}
// A ConnState represents the state of a client connection to a server.
@@ -1815,6 +2029,11 @@ const (
// and doesn't fire again until the request has been
// handled. After the request is handled, the state
// transitions to StateClosed, StateHijacked, or StateIdle.
+ // For HTTP/2, StateActive fires on the transition from zero
+ // to one active request, and only transitions away once all
+ // active requests are complete. That means that ConnState
+ // can not be used to do per-request work; ConnState only notes
+ // the overall state of the connection.
StateActive
// StateIdle represents a connection that has finished
@@ -1863,8 +2082,10 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
}
// ListenAndServe listens on the TCP network address srv.Addr and then
-// calls Serve to handle requests on incoming connections. If
-// srv.Addr is blank, ":http" is used.
+// calls Serve to handle requests on incoming connections.
+// Accepted connections are configured to enable TCP keep-alives.
+// If srv.Addr is blank, ":http" is used.
+// ListenAndServe always returns a non-nil error.
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == "" {
@@ -1877,12 +2098,21 @@ func (srv *Server) ListenAndServe() error {
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
+var testHookServerServe func(*Server, net.Listener) // used if non-nil
+
// Serve accepts incoming connections on the Listener l, creating a
-// new service goroutine for each. The service goroutines read requests and
+// new service goroutine for each. The service goroutines read requests and
// then call srv.Handler to reply to them.
+// Serve always returns a non-nil error.
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
+ if fn := testHookServerServe; fn != nil {
+ fn(srv, l)
+ }
var tempDelay time.Duration // how long to sleep on accept failure
+ if err := srv.setupHTTP2(); err != nil {
+ return err
+ }
for {
rw, e := l.Accept()
if e != nil {
@@ -1902,10 +2132,7 @@ func (srv *Server) Serve(l net.Listener) error {
return e
}
tempDelay = 0
- c, err := srv.newConn(rw)
- if err != nil {
- continue
- }
+ c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
}
@@ -1937,8 +2164,10 @@ func (s *Server) logf(format string, args ...interface{}) {
// ListenAndServe listens on the TCP network address addr
// and then calls Serve with handler to handle requests
-// on incoming connections. Handler is typically nil,
-// in which case the DefaultServeMux is used.
+// on incoming connections.
+// Accepted connections are configured to enable TCP keep-alives.
+// Handler is typically nil, in which case the DefaultServeMux is
+// used.
//
// A trivial example server is:
//
@@ -1957,11 +2186,10 @@ func (s *Server) logf(format string, args ...interface{}) {
//
// func main() {
// http.HandleFunc("/hello", HelloServer)
-// err := http.ListenAndServe(":12345", nil)
-// if err != nil {
-// log.Fatal("ListenAndServe: ", err)
-// }
+// log.Fatal(http.ListenAndServe(":12345", nil))
// }
+//
+// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
@@ -1989,19 +2217,20 @@ func ListenAndServe(addr string, handler Handler) error {
// http.HandleFunc("/", handler)
// log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
// err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
-// if err != nil {
-// log.Fatal(err)
-// }
+// log.Fatal(err)
// }
//
// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
-func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error {
+//
+// ListenAndServeTLS always returns a non-nil error.
+func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServeTLS(certFile, keyFile)
}
// ListenAndServeTLS listens on the TCP network address srv.Addr and
// then calls Serve to handle requests on incoming TLS connections.
+// Accepted connections are configured to enable TCP keep-alives.
//
// Filenames containing a certificate and matching private key for the
// server must be provided if the Server's TLSConfig.Certificates is
@@ -2010,14 +2239,23 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
// certificate, any intermediates, and the CA's certificate.
//
// If srv.Addr is blank, ":https" is used.
+//
+// ListenAndServeTLS always returns a non-nil error.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
+
+ // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
+ // before we clone it and create the TLS Listener.
+ if err := srv.setupHTTP2(); err != nil {
+ return err
+ }
+
config := cloneTLSConfig(srv.TLSConfig)
- if config.NextProtos == nil {
- config.NextProtos = []string{"http/1.1"}
+ if !strSliceContains(config.NextProtos, "http/1.1") {
+ config.NextProtos = append(config.NextProtos, "http/1.1")
}
if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
@@ -2038,6 +2276,25 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return srv.Serve(tlsListener)
}
+func (srv *Server) setupHTTP2() error {
+ srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
+ return srv.nextProtoErr
+}
+
+// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
+// configured otherwise. (by setting srv.TLSNextProto non-nil)
+// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2).
+func (srv *Server) onceSetNextProtoDefaults() {
+ if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
+ return
+ }
+ // Enable HTTP/2 by default if the user hasn't otherwise
+ // configured their TLSNextProto map.
+ if srv.TLSNextProto == nil {
+ srv.nextProtoErr = http2ConfigureServer(srv, nil)
+ }
+}
+
// TimeoutHandler returns a Handler that runs h with the given time limit.
//
// The new Handler calls h.ServeHTTP to handle each request, but if a
@@ -2046,11 +2303,20 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
// (If msg is empty, a suitable default message will be sent.)
// After such a timeout, writes by h to its ResponseWriter will return
// ErrHandlerTimeout.
+//
+// TimeoutHandler buffers all Handler writes to memory and does not
+// support the Hijacker or Flusher interfaces.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
- f := func() <-chan time.Time {
- return time.After(dt)
+ t := time.NewTimer(dt)
+ return &timeoutHandler{
+ handler: h,
+ body: msg,
+
+ // Effectively storing a *time.Timer, but decomposed
+ // for testing:
+ timeout: func() <-chan time.Time { return t.C },
+ cancelTimer: t.Stop,
}
- return &timeoutHandler{h, f, msg}
}
// ErrHandlerTimeout is returned on ResponseWriter Write calls
@@ -2059,8 +2325,13 @@ var ErrHandlerTimeout = errors.New("http: Handler timeout")
type timeoutHandler struct {
handler Handler
- timeout func() <-chan time.Time // returns channel producing a timeout
body string
+
+ // timeout returns the channel of a *time.Timer and
+ // cancelTimer cancels it. They're stored separately for
+ // testing purposes.
+ timeout func() <-chan time.Time // returns channel producing a timeout
+ cancelTimer func() bool // optional
}
func (h *timeoutHandler) errorBody() string {
@@ -2071,46 +2342,61 @@ func (h *timeoutHandler) errorBody() string {
}
func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
- done := make(chan bool, 1)
- tw := &timeoutWriter{w: w}
+ done := make(chan struct{})
+ tw := &timeoutWriter{
+ w: w,
+ h: make(Header),
+ }
go func() {
h.handler.ServeHTTP(tw, r)
- done <- true
+ close(done)
}()
select {
case <-done:
- return
- case <-h.timeout():
tw.mu.Lock()
defer tw.mu.Unlock()
- if !tw.wroteHeader {
- tw.w.WriteHeader(StatusServiceUnavailable)
- tw.w.Write([]byte(h.errorBody()))
+ dst := w.Header()
+ for k, vv := range tw.h {
+ dst[k] = vv
+ }
+ w.WriteHeader(tw.code)
+ w.Write(tw.wbuf.Bytes())
+ if h.cancelTimer != nil {
+ h.cancelTimer()
}
+ case <-h.timeout():
+ tw.mu.Lock()
+ defer tw.mu.Unlock()
+ w.WriteHeader(StatusServiceUnavailable)
+ io.WriteString(w, h.errorBody())
tw.timedOut = true
+ return
}
}
type timeoutWriter struct {
- w ResponseWriter
+ w ResponseWriter
+ h Header
+ wbuf bytes.Buffer
mu sync.Mutex
timedOut bool
wroteHeader bool
+ code int
}
-func (tw *timeoutWriter) Header() Header {
- return tw.w.Header()
-}
+func (tw *timeoutWriter) Header() Header { return tw.h }
func (tw *timeoutWriter) Write(p []byte) (int, error) {
tw.mu.Lock()
defer tw.mu.Unlock()
- tw.wroteHeader = true // implicitly at least
if tw.timedOut {
return 0, ErrHandlerTimeout
}
- return tw.w.Write(p)
+ if !tw.wroteHeader {
+ tw.writeHeader(StatusOK)
+ }
+ return tw.wbuf.Write(p)
}
func (tw *timeoutWriter) WriteHeader(code int) {
@@ -2119,8 +2405,12 @@ func (tw *timeoutWriter) WriteHeader(code int) {
if tw.timedOut || tw.wroteHeader {
return
}
+ tw.writeHeader(code)
+}
+
+func (tw *timeoutWriter) writeHeader(code int) {
tw.wroteHeader = true
- tw.w.WriteHeader(code)
+ tw.code = code
}
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
@@ -2247,7 +2537,7 @@ type checkConnErrorWriter struct {
}
func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
- n, err = w.c.w.Write(p) // c.w == c.rwc, except after a hijack, when rwc is nil.
+ n, err = w.c.rwc.Write(p)
if err != nil && w.c.werr == nil {
w.c.werr = err
}
@@ -2265,3 +2555,12 @@ func numLeadingCRorLF(v []byte) (n int) {
return
}
+
+func strSliceContains(ss []string, s string) bool {
+ for _, v := range ss {
+ if v == s {
+ return true
+ }
+ }
+ return false
+}