Source File
server.go
Belonging Package
net/http
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// HTTP server. See RFC 7230 through 7235.
package http
import (
urlpkg
_ // for linkname
)
// Errors used by the HTTP server.
var (
// ErrBodyNotAllowed is returned by ResponseWriter.Write calls
// when the HTTP method or response code does not permit a
// body.
ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
// ErrHijacked is returned by ResponseWriter.Write calls when
// the underlying connection has been hijacked using the
// Hijacker interface. A zero-byte write on a hijacked
// connection will return ErrHijacked without any other side
// effects.
ErrHijacked = errors.New("http: connection has been hijacked")
// ErrContentLength is returned by ResponseWriter.Write calls
// when a Handler set a Content-Length response header with a
// declared size and then attempted to write more bytes than
// declared.
ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
// Deprecated: ErrWriteAfterFlush is no longer returned by
// anything in the net/http package. Callers should not
// compare errors against this variable.
ErrWriteAfterFlush = errors.New("unused")
)
// A Handler responds to an HTTP request.
//
// [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter]
// 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.
//
// Except for reading the body, handlers should not modify the
// provided Request.
//
// 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 either closes the network connection or sends an HTTP/2
// RST_STREAM, depending on the HTTP protocol. To abort a handler so
// the client sees an interrupted response but the server doesn't log
// an error, panic with the value [ErrAbortHandler].
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 [Handler.ServeHTTP] has returned.
type ResponseWriter interface {
// Header returns the header map that will be sent by
// [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which
// [Handler] implementations can set HTTP trailers.
//
// Changing the header map after a call to [ResponseWriter.WriteHeader] (or
// [ResponseWriter.Write]) has no effect unless the HTTP status code was of the
// 1xx class or the modified headers are trailers.
//
// There are two ways to set Trailers. The preferred way is to
// predeclare in the headers which trailers you will later
// send by setting the "Trailer" header to the names of the
// trailer keys which will come later. In this case, those
// keys of the Header map are treated as if they were
// trailers. See the example. The second way, for trailer
// keys not known to the [Handler] until after the first [ResponseWriter.Write],
// is to prefix the [Header] map keys with the [TrailerPrefix]
// constant value.
//
// To suppress automatic response headers (such as "Date"), set
// their value to nil.
Header() Header
// Write writes the data to the connection as part of an HTTP reply.
//
// If [ResponseWriter.WriteHeader] has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data. If the Header
// does not contain a Content-Type line, Write adds a Content-Type set
// to the result of passing the initial 512 bytes of written data to
// [DetectContentType]. Additionally, if the total size of all written
// data is under a few KB and there are no Flush calls, the
// Content-Length header is added automatically.
//
// Depending on the HTTP protocol version and the client, calling
// Write or WriteHeader may prevent future reads on the
// Request.Body. For HTTP/1.x requests, handlers should read any
// needed request body data before writing the response. Once the
// headers have been flushed (due to either an explicit Flusher.Flush
// call or writing enough data to trigger a flush), the request body
// may be unavailable. For HTTP/2 requests, the Go HTTP server permits
// handlers to continue to read the request body while concurrently
// writing the response. However, such behavior may not be supported
// by all HTTP/2 clients. Handlers should read before writing if
// possible to maximize compatibility.
Write([]byte) (int, error)
// WriteHeader sends an HTTP response header with the provided
// status code.
//
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes or 1xx informational responses.
//
// The provided code must be a valid HTTP 1xx-5xx status code.
// Any number of 1xx headers may be written, followed by at most
// one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx
// headers may be buffered. Use the Flusher interface to send
// buffered data. The header map is cleared when 2xx-5xx headers are
// sent, but not with 1xx headers.
//
// The server will automatically send a 100 (Continue) header
// on the first read from the request body if the request has
// an "Expect: 100-continue" header.
WriteHeader(statusCode int)
}
// The Flusher interface is implemented by ResponseWriters that allow
// an HTTP handler to flush buffered data to the client.
//
// The default HTTP/1.x and HTTP/2 [ResponseWriter] implementations
// support [Flusher], but ResponseWriter wrappers may not. Handlers
// should always test for this ability at runtime.
//
// Note that even for ResponseWriters that support Flush,
// if the client is connected through an HTTP proxy,
// the buffered data may not reach the client until the response
// completes.
type Flusher interface {
// Flush sends any buffered data to the client.
Flush()
}
// The Hijacker interface is implemented by ResponseWriters that allow
// an HTTP handler to take over the connection.
//
// The default [ResponseWriter] for HTTP/1.x connections supports
// Hijacker, but HTTP/2 connections intentionally do not.
// ResponseWriter wrappers may also not support Hijacker. Handlers
// should always test for this ability at runtime.
type Hijacker interface {
// Hijack lets the caller take over the connection.
// After a call to Hijack the HTTP server library
// will not do anything else with the connection.
//
// It becomes the caller's responsibility to manage
// and close the connection.
//
// The returned net.Conn may have read or write deadlines
// already set, depending on the configuration of the
// Server. It is the caller's responsibility to set
// or clear those deadlines as needed.
//
// The returned bufio.Reader may contain unprocessed buffered
// data from the client.
//
// After a call to Hijack, the original Request.Body must not
// be used. The original Request's Context remains valid and
// is not canceled until the Request's ServeHTTP method
// returns.
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
// The CloseNotifier interface is implemented by ResponseWriters which
// allow detecting when the underlying connection has gone away.
//
// This mechanism can be used to cancel long operations on the server
// if the client has disconnected before the response is ready.
//
// Deprecated: the CloseNotifier interface predates Go's context package.
// New code should use [Request.Context] instead.
type CloseNotifier interface {
// 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 as 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
}
var (
// ServerContextKey is a context key. It can be used in HTTP
// handlers with Context.Value to access the server that
// started the handler. The associated value will be of
// type *Server.
ServerContextKey = &contextKey{"http-server"}
// LocalAddrContextKey is a context key. It can be used in
// HTTP handlers with Context.Value to access the local
// address the connection arrived on.
// The associated value will be of type net.Addr.
LocalAddrContextKey = &contextKey{"local-addr"}
)
// A conn represents the server side of an HTTP connection.
type conn struct {
// server is the server on which the connection arrived.
// Immutable; never nil.
server *Server
// cancelCtx cancels the connection-level context.
cancelCtx context.CancelFunc
// 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.
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
curReq atomic.Pointer[response] // (which has a Request in it)
curState atomic.Uint64 // packed (unixtime<<8|uint8(ConnState))
// mu guards hijackedv
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 ( *conn) () bool {
.mu.Lock()
defer .mu.Unlock()
return .hijackedv
}
// c.mu must be held.
func ( *conn) () ( net.Conn, *bufio.ReadWriter, error) {
if .hijackedv {
return nil, nil, ErrHijacked
}
.r.abortPendingRead()
.hijackedv = true
= .rwc
.SetDeadline(time.Time{})
= bufio.NewReadWriter(.bufr, bufio.NewWriter())
if .r.hasByte {
if , := .bufr.Peek(.bufr.Buffered() + 1); != nil {
return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", )
}
}
.setState(, StateHijacked, runHooks)
return
}
// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 2048
// chunkWriter writes to a response's conn buffer, and is the writer
// wrapped by the response.w buffered writer.
//
// chunkWriter also is responsible for finalizing the Header, including
// conditionally setting the Content-Type and setting a Content-Length
// in cases where the handler's final output is smaller than the buffer
// size. It also conditionally adds chunk headers, when in chunking mode.
//
// See the comment above (*response).Write for the entire write flow.
type chunkWriter struct {
res *response
// header is either nil or a deep clone of res.handlerHeader
// at the time of res.writeHeader, if res.writeHeader is
// called and extra buffering is being done to calculate
// Content-Type and/or Content-Length.
header Header
// wroteHeader tells whether the header's been written to "the
// wire" (or rather: w.conn.buf). this is unlike
// (*response).wroteHeader, which tells only whether it was
// logically written.
wroteHeader bool
// set by the writeHeader method:
chunking bool // using chunked transfer encoding for reply body
}
var (
crlf = []byte("\r\n")
colonSpace = []byte(": ")
)
func ( *chunkWriter) ( []byte) ( int, error) {
if !.wroteHeader {
.writeHeader()
}
if .res.req.Method == "HEAD" {
// Eat writes.
return len(), nil
}
if .chunking {
_, = fmt.Fprintf(.res.conn.bufw, "%x\r\n", len())
if != nil {
.res.conn.rwc.Close()
return
}
}
, = .res.conn.bufw.Write()
if .chunking && == nil {
_, = .res.conn.bufw.Write(crlf)
}
if != nil {
.res.conn.rwc.Close()
}
return
}
func ( *chunkWriter) () error {
if !.wroteHeader {
.writeHeader(nil)
}
return .res.conn.bufw.Flush()
}
func ( *chunkWriter) () {
if !.wroteHeader {
.writeHeader(nil)
}
if .chunking {
:= .res.conn.bufw // conn's bufio writer
// zero chunk to mark EOF
.WriteString("0\r\n")
if := .res.finalTrailers(); != nil {
.Write() // the writer handles noting errors
}
// final blank line after the trailers (whether
// present or not)
.WriteString("\r\n")
}
}
// A response represents the server side of an HTTP response.
type response struct {
conn *conn
req *Request // request for this response
reqBody io.ReadCloser
cancelCtx context.CancelFunc // when ServeHTTP exits
wroteHeader bool // a non-1xx header has been (logically) written
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
wantsClose bool // HTTP request has Connection "close"
// canWriteContinue is an atomic boolean that says whether or
// not a 100 Continue header can be written to the
// connection.
// writeContinueMu must be held while writing the header.
// These two fields together synchronize the body reader (the
// expectContinueReader, which wants to write 100 Continue)
// against the main writer.
writeContinueMu sync.Mutex
canWriteContinue atomic.Bool
w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter
// handlerHeader is the Header that Handlers get access to,
// which may be retained and mutated even after WriteHeader.
// handlerHeader is copied into cw.header at WriteHeader
// time, and privately mutated thereafter.
handlerHeader Header
calledHeader bool // handler accessed handlerHeader via Header
written int64 // number of bytes written in body
contentLength int64 // explicitly-declared Content-Length; or -1
status int // status code passed to WriteHeader
// close connection after this reply. set on request and
// updated after response from handler if there's a
// "Connection: keep-alive" response header and a
// Content-Length.
closeAfterReply bool
// When fullDuplex is false (the default), we consume any remaining
// request body before starting to write a response.
fullDuplex bool
// requestBodyLimitHit is set by requestTooLarge when
// maxBytesReader hits its max size. It is checked in
// WriteHeader, to make sure we don't consume the
// remaining request body to try to advance to the next HTTP
// request. Instead, when this is set, we stop reading
// subsequent requests on this connection and stop reading
// input from it.
requestBodyLimitHit bool
// trailers are the headers to be sent after the handler
// finishes writing the body. This field is initialized from
// the Trailer response header when the response header is
// written.
trailers []string
handlerDone atomic.Bool // set true when the handler exits
// Buffers for Date, Content-Length, and status code
dateBuf [len(TimeFormat)]byte
clenBuf [10]byte
statusBuf [3]byte
// closeNotifyCh is the channel returned by CloseNotify.
// TODO(bradfitz): this is currently (for Go 1.8) always
// non-nil. Make this lazily-created again as it used to be?
closeNotifyCh chan bool
didCloseNotify atomic.Bool // atomic (only false->true winner should send)
}
func ( *response) ( time.Time) error {
return .conn.rwc.SetReadDeadline()
}
func ( *response) ( time.Time) error {
return .conn.rwc.SetWriteDeadline()
}
func ( *response) () error {
.fullDuplex = true
return nil
}
// TrailerPrefix is a magic prefix for [ResponseWriter.Header] map keys
// that, if present, signals that the map entry is actually for
// the response trailers, and not the response headers. The prefix
// is stripped after the ServeHTTP call finishes and the values are
// sent in the trailers.
//
// This mechanism is intended only for trailers that are not known
// prior to the headers being written. If the set of trailers is fixed
// or known before the header is written, the normal Go trailers mechanism
// is preferred:
//
// https://pkg.go.dev/net/http#ResponseWriter
// https://pkg.go.dev/net/http#example-ResponseWriter-Trailers
const TrailerPrefix = "Trailer:"
// finalTrailers is called after the Handler exits and returns a non-nil
// value if the Handler set any trailers.
func ( *response) () Header {
var Header
for , := range .handlerHeader {
if , := strings.CutPrefix(, TrailerPrefix); {
if == nil {
= make(Header)
}
[] =
}
}
for , := range .trailers {
if == nil {
= make(Header)
}
for , := range .handlerHeader[] {
.Add(, )
}
}
return
}
// 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.
func ( *response) ( string) {
= CanonicalHeaderKey()
if !httpguts.ValidTrailerHeader() {
// Forbidden by RFC 7230, section 4.1.2
return
}
.trailers = append(.trailers, )
}
// requestTooLarge is called by maxBytesReader when too much input has
// been read from the client.
func ( *response) () {
.closeAfterReply = true
.requestBodyLimitHit = true
if !.wroteHeader {
.Header().Set("Connection", "close")
}
}
// disableWriteContinue stops Request.Body.Read from sending an automatic 100-Continue.
// If a 100-Continue is being written, it waits for it to complete before continuing.
func ( *response) () {
.writeContinueMu.Lock()
.canWriteContinue.Store(false)
.writeContinueMu.Unlock()
}
// writerOnly hides an io.Writer value's optional ReadFrom method
// from io.Copy.
type writerOnly struct {
io.Writer
}
// ReadFrom is here to optimize copying from an [*os.File] regular file
// to a [*net.TCPConn] with sendfile, or from a supported src type such
// as a *net.TCPConn on Linux with splice.
func ( *response) ( io.Reader) ( int64, error) {
:= getCopyBuf()
defer putCopyBuf()
// Our underlying w.conn.rwc is usually a *TCPConn (with its
// own ReadFrom method). If not, just fall back to the normal
// copy method.
, := .conn.rwc.(io.ReaderFrom)
if ! {
return io.CopyBuffer(writerOnly{}, , )
}
// Copy the first sniffLen bytes before switching to ReadFrom.
// This ensures we don't start writing the response before the
// source is available (see golang.org/issue/5660) and provides
// enough bytes to perform Content-Type sniffing when required.
if !.cw.wroteHeader {
, := io.CopyBuffer(writerOnly{}, io.LimitReader(, sniffLen), )
+=
if != nil || < sniffLen {
return ,
}
}
.w.Flush() // get rid of any previous writes
.cw.flush() // make sure Header is written; flush data to rwc
// Now that cw has been flushed, its chunking field is guaranteed initialized.
if !.cw.chunking && .bodyAllowed() && .req.Method != "HEAD" {
, := .ReadFrom()
+=
.written +=
return ,
}
, := io.CopyBuffer(writerOnly{}, , )
+=
return ,
}
// debugServerConnections controls whether all server connections are wrapped
// with a verbose logging wrapper.
const debugServerConnections = false
// Create new connection from rwc.
func ( *Server) ( net.Conn) *conn {
:= &conn{
server: ,
rwc: ,
}
if debugServerConnections {
.rwc = newLoggingConn("server", .rwc)
}
return
}
type readResult struct {
_ incomparable
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 {
conn *conn
mu sync.Mutex // guards following
hasByte bool
byteBuf [1]byte
cond *sync.Cond
inRead bool
aborted bool // set true before conn.rwc deadline is set to past
remain int64 // bytes remaining
}
func ( *connReader) () {
.mu.Lock()
if .cond == nil {
.cond = sync.NewCond(&.mu)
}
}
func ( *connReader) () { .mu.Unlock() }
func ( *connReader) () {
.lock()
defer .unlock()
if .inRead {
panic("invalid concurrent Body.Read call")
}
if .hasByte {
return
}
.inRead = true
.conn.rwc.SetReadDeadline(time.Time{})
go .backgroundRead()
}
func ( *connReader) () {
, := .conn.rwc.Read(.byteBuf[:])
.lock()
if == 1 {
.hasByte = true
// We were past the end of the previous request's body already
// (since we wouldn't be in a background read otherwise), so
// this is a pipelined HTTP request. Prior to Go 1.11 we used to
// send on the CloseNotify channel and cancel the context here,
// but the behavior was documented as only "may", and we only
// did that because that's how CloseNotify accidentally behaved
// in very early Go releases prior to context support. Once we
// added context support, people used a Handler's
// Request.Context() and passed it along. Having that context
// cancel on pipelined HTTP requests caused problems.
// Fortunately, almost nothing uses HTTP/1.x pipelining.
// Unfortunately, apt-get does, or sometimes does.
// New Go 1.11 behavior: don't fire CloseNotify or cancel
// contexts on pipelined requests. Shouldn't affect people, but
// fixes cases like Issue 23921. This does mean that a client
// closing their TCP connection after sending a pipelined
// request won't cancel the context, but we'll catch that on any
// write failure (in checkConnErrorWriter.Write).
// If the server never writes, yes, there are still contrived
// server & client behaviors where this fails to ever cancel the
// context, but that's kinda why HTTP/1.x pipelining died
// anyway.
}
if , := .(net.Error); && .aborted && .Timeout() {
// Ignore this error. It's the expected error from
// another goroutine calling abortPendingRead.
} else if != nil {
.handleReadError()
}
.aborted = false
.inRead = false
.unlock()
.cond.Broadcast()
}
func ( *connReader) () {
.lock()
defer .unlock()
if !.inRead {
return
}
.aborted = true
.conn.rwc.SetReadDeadline(aLongTimeAgo)
for .inRead {
.cond.Wait()
}
.conn.rwc.SetReadDeadline(time.Time{})
}
func ( *connReader) ( int64) { .remain = }
func ( *connReader) () { .remain = maxInt64 }
func ( *connReader) () bool { return .remain <= 0 }
// handleReadError is called whenever a Read from the client returns a
// non-nil error.
//
// The provided non-nil err is almost always io.EOF or a "use of
// closed network connection". In any case, the error is not
// particularly interesting, except perhaps for debugging during
// development. Any error means the connection is dead and we should
// down its context.
//
// It may be called from multiple goroutines.
func ( *connReader) ( error) {
.conn.cancelCtx()
.closeNotify()
}
// may be called from multiple goroutines.
func ( *connReader) () {
:= .conn.curReq.Load()
if != nil && !.didCloseNotify.Swap(true) {
.closeNotifyCh <- true
}
}
func ( *connReader) ( []byte) ( int, error) {
.lock()
if .inRead {
.unlock()
if .conn.hijacked() {
panic("invalid Body.Read call. After hijacked, the original Request must not be used")
}
panic("invalid concurrent Body.Read call")
}
if .hitReadLimit() {
.unlock()
return 0, io.EOF
}
if len() == 0 {
.unlock()
return 0, nil
}
if int64(len()) > .remain {
= [:.remain]
}
if .hasByte {
[0] = .byteBuf[0]
.hasByte = false
.unlock()
return 1, nil
}
.inRead = true
.unlock()
, = .conn.rwc.Read()
.lock()
.inRead = false
if != nil {
.handleReadError()
}
.remain -= int64()
.unlock()
.cond.Broadcast()
return ,
}
var (
bufioReaderPool sync.Pool
bufioWriter2kPool sync.Pool
bufioWriter4kPool sync.Pool
)
const copyBufPoolSize = 32 * 1024
var copyBufPool = sync.Pool{New: func() any { return new([copyBufPoolSize]byte) }}
func getCopyBuf() []byte {
return copyBufPool.Get().(*[copyBufPoolSize]byte)[:]
}
func putCopyBuf( []byte) {
if len() != copyBufPoolSize {
panic("trying to put back buffer of the wrong size in the copyBufPool")
}
copyBufPool.Put((*[copyBufPoolSize]byte)())
}
func bufioWriterPool( int) *sync.Pool {
switch {
case 2 << 10:
return &bufioWriter2kPool
case 4 << 10:
return &bufioWriter4kPool
}
return nil
}
// newBufioReader should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/gobwas/ws
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname newBufioReader
func newBufioReader( io.Reader) *bufio.Reader {
if := bufioReaderPool.Get(); != nil {
:= .(*bufio.Reader)
.Reset()
return
}
// Note: if this reader size is ever changed, update
// TestHandlerBodyClose's assumptions.
return bufio.NewReader()
}
// putBufioReader should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/gobwas/ws
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname putBufioReader
func putBufioReader( *bufio.Reader) {
.Reset(nil)
bufioReaderPool.Put()
}
// newBufioWriterSize should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/gobwas/ws
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname newBufioWriterSize
func newBufioWriterSize( io.Writer, int) *bufio.Writer {
:= bufioWriterPool()
if != nil {
if := .Get(); != nil {
:= .(*bufio.Writer)
.Reset()
return
}
}
return bufio.NewWriterSize(, )
}
// putBufioWriter should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/gobwas/ws
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname putBufioWriter
func putBufioWriter( *bufio.Writer) {
.Reset(nil)
if := bufioWriterPool(.Available()); != nil {
.Put()
}
}
// DefaultMaxHeaderBytes is the maximum permitted size of the headers
// in an HTTP request.
// This can be overridden by setting [Server.MaxHeaderBytes].
const DefaultMaxHeaderBytes = 1 << 20 // 1 MB
func ( *Server) () int {
if .MaxHeaderBytes > 0 {
return .MaxHeaderBytes
}
return DefaultMaxHeaderBytes
}
func ( *Server) () int64 {
return int64(.maxHeaderBytes()) + 4096 // bufio slop
}
// tlsHandshakeTimeout returns the time limit permitted for the TLS
// handshake, or zero for unlimited.
//
// It returns the minimum of any positive ReadHeaderTimeout,
// ReadTimeout, or WriteTimeout.
func ( *Server) () time.Duration {
var time.Duration
for , := range [...]time.Duration{
.ReadHeaderTimeout,
.ReadTimeout,
.WriteTimeout,
} {
if <= 0 {
continue
}
if == 0 || < {
=
}
}
return
}
// wrapper around io.ReadCloser which on first read, sends an
// HTTP/1.1 100 Continue header
type expectContinueReader struct {
resp *response
readCloser io.ReadCloser
closed atomic.Bool
sawEOF atomic.Bool
}
func ( *expectContinueReader) ( []byte) ( int, error) {
if .closed.Load() {
return 0, ErrBodyReadAfterClose
}
:= .resp
if .canWriteContinue.Load() {
.writeContinueMu.Lock()
if .canWriteContinue.Load() {
.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
.conn.bufw.Flush()
.canWriteContinue.Store(false)
}
.writeContinueMu.Unlock()
}
, = .readCloser.Read()
if == io.EOF {
.sawEOF.Store(true)
}
return
}
func ( *expectContinueReader) () error {
.closed.Store(true)
return .readCloser.Close()
}
// 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))
func appendTime( []byte, time.Time) []byte {
const = "SunMonTueWedThuFriSat"
const = "JanFebMarAprMayJunJulAugSepOctNovDec"
= .UTC()
, , := .Date()
, , := .Clock()
:= [3*.Weekday():]
:= [3*(-1):]
return append(,
[0], [1], [2], ',', ' ',
byte('0'+/10), byte('0'+%10), ' ',
[0], [1], [2], ' ',
byte('0'+/1000), byte('0'+(/100)%10), byte('0'+(/10)%10), byte('0'+%10), ' ',
byte('0'+/10), byte('0'+%10), ':',
byte('0'+/10), byte('0'+%10), ':',
byte('0'+/10), byte('0'+%10), ' ',
'G', 'M', 'T')
}
var errTooLarge = errors.New("http: request too large")
// Read next request from connection.
func ( *conn) ( context.Context) ( *response, error) {
if .hijacked() {
return nil, ErrHijacked
}
var (
time.Time // or zero if none
time.Time // or zero if none
)
:= time.Now()
if := .server.readHeaderTimeout(); > 0 {
= .Add()
}
if := .server.ReadTimeout; > 0 {
= .Add()
}
.rwc.SetReadDeadline()
if := .server.WriteTimeout; > 0 {
defer func() {
.rwc.SetWriteDeadline(time.Now().Add())
}()
}
.r.setReadLimit(.server.initialReadLimitSize())
if .lastMethod == "POST" {
// RFC 7230 section 3 tolerance for old buggy clients.
, := .bufr.Peek(4) // ReadRequest will get err below
.bufr.Discard(numLeadingCRorLF())
}
, := readRequest(.bufr)
if != nil {
if .r.hitReadLimit() {
return nil, errTooLarge
}
return nil,
}
if !http1ServerSupportsRequest() {
return nil, statusError{StatusHTTPVersionNotSupported, "unsupported protocol version"}
}
.lastMethod = .Method
.r.setInfiniteReadLimit()
, := .Header["Host"]
:= .isH2Upgrade()
if .ProtoAtLeast(1, 1) && (! || len() == 0) && ! && .Method != "CONNECT" {
return nil, badRequestError("missing required Host header")
}
if len() == 1 && !httpguts.ValidHostHeader([0]) {
return nil, badRequestError("malformed Host header")
}
for , := range .Header {
if !httpguts.ValidHeaderFieldName() {
return nil, badRequestError("invalid header name")
}
for , := range {
if !httpguts.ValidHeaderFieldValue() {
return nil, badRequestError("invalid header value")
}
}
}
delete(.Header, "Host")
, := context.WithCancel()
.ctx =
.RemoteAddr = .remoteAddr
.TLS = .tlsState
if , := .Body.(*body); {
.doEarlyClose = true
}
// Adjust the read deadline if necessary.
if !.Equal() {
.rwc.SetReadDeadline()
}
= &response{
conn: ,
cancelCtx: ,
req: ,
reqBody: .Body,
handlerHeader: make(Header),
contentLength: -1,
closeNotifyCh: make(chan bool, 1),
// We populate these ahead of time so we're not
// reading from req.Header after their Handler starts
// and maybe mutates it (Issue 14940)
wants10KeepAlive: .wantsHttp10KeepAlive(),
wantsClose: .wantsClose(),
}
if {
.closeAfterReply = true
}
.cw.res =
.w = newBufioWriterSize(&.cw, bufferBeforeChunkingSize)
return , nil
}
// http1ServerSupportsRequest reports whether Go's HTTP/1.x server
// supports the given request.
func http1ServerSupportsRequest( *Request) bool {
if .ProtoMajor == 1 {
return true
}
// Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can
// wire up their own HTTP/2 upgrades.
if .ProtoMajor == 2 && .ProtoMinor == 0 &&
.Method == "PRI" && .RequestURI == "*" {
return true
}
// Reject HTTP/0.x, and all other HTTP/2+ requests (which
// aren't encoded in ASCII anyway).
return false
}
func ( *response) () Header {
if .cw.header == nil && .wroteHeader && !.cw.wroteHeader {
// Accessing the header between logically writing it
// and physically writing it means we need to allocate
// a clone to snapshot the logically written state.
.cw.header = .handlerHeader.Clone()
}
.calledHeader = true
return .handlerHeader
}
// maxPostHandlerReadBytes is the max number of Request.Body bytes not
// consumed by a handler that the server will read from the client
// in order to keep a connection alive. If there are more bytes
// than this, the server, to be paranoid, instead sends a
// "Connection close" response.
//
// This number is approximately what a typical machine's TCP buffer
// size is anyway. (if we have the bytes on the machine, we might as
// well read them)
const maxPostHandlerReadBytes = 256 << 10
func checkWriteHeaderCode( int) {
// Issue 22880: require valid WriteHeader status codes.
// For now we only enforce that it's three digits.
// In the future we might block things over 599 (600 and above aren't defined
// at https://httpwg.org/specs/rfc7231.html#status.codes).
// But for now any three digits.
//
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's
// no equivalent bogus thing we can realistically send in HTTP/2,
// so we'll consistently panic instead and help people find their bugs
// early. (We can't return an error from WriteHeader even if we wanted to.)
if < 100 || > 999 {
panic(fmt.Sprintf("invalid WriteHeader code %v", ))
}
}
// relevantCaller searches the call stack for the first function outside of net/http.
// The purpose of this function is to provide more helpful error messages.
func relevantCaller() runtime.Frame {
:= make([]uintptr, 16)
:= runtime.Callers(1, )
:= runtime.CallersFrames([:])
var runtime.Frame
for {
, := .Next()
if !strings.HasPrefix(.Function, "net/http.") {
return
}
if ! {
break
}
}
return
}
func ( *response) ( int) {
if .conn.hijacked() {
:= relevantCaller()
.conn.server.logf("http: response.WriteHeader on hijacked connection from %s (%s:%d)", .Function, path.Base(.File), .Line)
return
}
if .wroteHeader {
:= relevantCaller()
.conn.server.logf("http: superfluous response.WriteHeader call from %s (%s:%d)", .Function, path.Base(.File), .Line)
return
}
checkWriteHeaderCode()
if < 101 || > 199 {
// Sending a 100 Continue or any non-1xx header disables the
// automatically-sent 100 Continue from Request.Body.Read.
.disableWriteContinue()
}
// Handle informational headers.
//
// We shouldn't send any further headers after 101 Switching Protocols,
// so it takes the non-informational path.
if >= 100 && <= 199 && != StatusSwitchingProtocols {
writeStatusLine(.conn.bufw, .req.ProtoAtLeast(1, 1), , .statusBuf[:])
// Per RFC 8297 we must not clear the current header map
.handlerHeader.WriteSubset(.conn.bufw, excludedHeadersNoBody)
.conn.bufw.Write(crlf)
.conn.bufw.Flush()
return
}
.wroteHeader = true
.status =
if .calledHeader && .cw.header == nil {
.cw.header = .handlerHeader.Clone()
}
if := .handlerHeader.get("Content-Length"); != "" {
, := strconv.ParseInt(, 10, 64)
if == nil && >= 0 {
.contentLength =
} else {
.conn.server.logf("http: invalid Content-Length of %q", )
.handlerHeader.Del("Content-Length")
}
}
}
// extraHeader is the set of headers sometimes added by chunkWriter.writeHeader.
// This type is used to avoid extra allocations from cloning and/or populating
// the response Header map and all its 1-element slices.
type extraHeader struct {
contentType string
connection string
transferEncoding string
date []byte // written if not nil
contentLength []byte // written if not nil
}
// Sorted the same as extraHeader.Write's loop.
var extraHeaderKeys = [][]byte{
[]byte("Content-Type"),
[]byte("Connection"),
[]byte("Transfer-Encoding"),
}
var (
headerContentLength = []byte("Content-Length: ")
headerDate = []byte("Date: ")
)
// Write writes the headers described in h to w.
//
// This method has a value receiver, despite the somewhat large size
// of h, because it prevents an allocation. The escape analysis isn't
// smart enough to realize this function doesn't mutate h.
func ( extraHeader) ( *bufio.Writer) {
if .date != nil {
.Write(headerDate)
.Write(.date)
.Write(crlf)
}
if .contentLength != nil {
.Write(headerContentLength)
.Write(.contentLength)
.Write(crlf)
}
for , := range []string{.contentType, .connection, .transferEncoding} {
if != "" {
.Write(extraHeaderKeys[])
.Write(colonSpace)
.WriteString()
.Write(crlf)
}
}
}
// writeHeader finalizes the header sent to the client and writes it
// 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
// set explicitly. It's also used to set the Content-Length, if the
// total body size was small and the handler has already finished
// running.
func ( *chunkWriter) ( []byte) {
if .wroteHeader {
return
}
.wroteHeader = true
:= .res
:= .conn.server.doKeepAlives()
:= .req.Method == "HEAD"
// header is written out to w.conn.buf below. Depending on the
// state of the handler, we either own the map or not. If we
// don't own it, the exclude map is created lazily for
// WriteSubset to remove headers. The setHeader struct holds
// headers we need to add.
:= .header
:= != nil
if ! {
= .handlerHeader
}
var map[string]bool
:= func( string) {
if {
.Del()
return
}
if , := []; ! {
return
}
if == nil {
= make(map[string]bool)
}
[] = true
}
var extraHeader
// Don't write out the fake "Trailer:foo" keys. See TrailerPrefix.
:= false
for := range .header {
if strings.HasPrefix(, TrailerPrefix) {
if == nil {
= make(map[string]bool)
}
[] = true
= true
}
}
for , := range .header["Trailer"] {
= true
foreachHeaderElement(, .res.declareTrailer)
}
:= .get("Transfer-Encoding")
:= != ""
// If the handler is done but never sent a Content-Length
// response header and this is our first (and last) write, set
// it, even to zero. This helps HTTP/1.0 clients keep their
// "keep-alive" connections alive.
// Exceptions: 304/204/1xx responses never get Content-Length, and if
// it was a HEAD request, we don't know the difference between
// 0 actual bytes and 0 bytes because the handler noticed it
// was a HEAD request and chose not to write anything. So for
// HEAD, the handler should either write the Content-Length or
// write non-zero bytes. If it's actually 0 bytes and the
// handler never looked at the Request.Method, we just don't
// 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 .handlerDone.Load() && ! && ! && bodyAllowedForStatus(.status) && !.has("Content-Length") && (! || len() > 0) {
.contentLength = int64(len())
.contentLength = strconv.AppendInt(.res.clenBuf[:0], int64(len()), 10)
}
// If this was an HTTP/1.0 request with keep-alive and we sent a
// Content-Length back, we can make this a keep-alive response ...
if .wants10KeepAlive && {
:= .get("Content-Length") != ""
if && .get("Connection") == "keep-alive" {
.closeAfterReply = false
}
}
// Check for an explicit (and valid) Content-Length header.
:= .contentLength != -1
if .wants10KeepAlive && ( || || !bodyAllowedForStatus(.status)) {
, := ["Connection"]
if ! {
.connection = "keep-alive"
}
} else if !.req.ProtoAtLeast(1, 1) || .wantsClose {
.closeAfterReply = true
}
if .get("Connection") == "close" || ! {
.closeAfterReply = true
}
// If the client wanted a 100-continue but we never sent it to
// them (or, more strictly: we never finished reading their
// request body), don't reuse this connection.
//
// This behavior was first added on the theory that we don't know
// if the next bytes on the wire are going to be the remainder of
// the request body or the subsequent request (see issue 11549),
// but that's not correct: If we keep using the connection,
// the client is required to send the request body whether we
// asked for it or not.
//
// We probably do want to skip reusing the connection in most cases,
// however. If the client is offering a large request body that we
// don't intend to use, then it's better to close the connection
// than to read the body. For now, assume that if we're sending
// headers, the handler is done reading the body and we should
// drop the connection if we haven't seen EOF.
if , := .req.Body.(*expectContinueReader); && !.sawEOF.Load() {
.closeAfterReply = true
}
// We do this by default because there are a number of clients that
// send a full request before starting to read the response, and they
// can deadlock if we start writing the response with unconsumed body
// remaining. See Issue 15527 for some history.
//
// If full duplex mode has been enabled with ResponseController.EnableFullDuplex,
// then leave the request body alone.
//
// We don't take this path when w.closeAfterReply is set.
// We may not need to consume the request to get ready for the next one
// (since we're closing the conn), but a client which sends a full request
// before reading a response may deadlock in this case.
// This behavior has been present since CL 5268043 (2011), however,
// so it doesn't seem to be causing problems.
if .req.ContentLength != 0 && !.closeAfterReply && !.fullDuplex {
var , bool
switch bdy := .req.Body.(type) {
case *expectContinueReader:
// We only get here if we have already fully consumed the request body
// (see above).
case *body:
.mu.Lock()
switch {
case .closed:
if !.sawEOF {
// Body was closed in handler with non-EOF error.
.closeAfterReply = true
}
case .unreadDataSizeLocked() >= maxPostHandlerReadBytes:
= true
default:
= true
}
.mu.Unlock()
default:
= true
}
if {
, := io.CopyN(io.Discard, .reqBody, maxPostHandlerReadBytes+1)
switch {
case nil:
// There must be even more data left over.
= true
case ErrBodyReadAfterClose:
// Body was already consumed and closed.
case io.EOF:
// The remaining body was just consumed, close it.
= .reqBody.Close()
if != nil {
.closeAfterReply = true
}
default:
// Some other kind of error occurred, like a read timeout, or
// corrupt chunked encoding. In any case, whatever remains
// on the wire must not be parsed as another HTTP request.
.closeAfterReply = true
}
}
if {
.requestTooLarge()
("Connection")
.connection = "close"
}
}
:= .status
if bodyAllowedForStatus() {
// If no content type, apply sniffing algorithm to body.
, := ["Content-Type"]
// If the Content-Encoding was set and is non-blank,
// we shouldn't sniff the body. See Issue 31753.
:= .Get("Content-Encoding")
:= len() > 0
if ! && ! && ! && len() > 0 {
.contentType = DetectContentType()
}
} else {
for , := range suppressedHeaders() {
()
}
}
if !.has("Date") {
.date = appendTime(.res.dateBuf[:0], time.Now())
}
if && && != "identity" {
// TODO: return an error if WriteHeader gets a return parameter
// For now just ignore the Content-Length.
.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
, .contentLength)
("Content-Length")
= false
}
if .req.Method == "HEAD" || !bodyAllowedForStatus() || == StatusNoContent {
// Response has no body.
("Transfer-Encoding")
} else if {
// Content-Length has been provided, so no chunking is to be done.
("Transfer-Encoding")
} else if .req.ProtoAtLeast(1, 1) {
// HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no
// content-length has been provided. The connection must be closed after the
// reply is written, and no chunking is to be done. This is the setup
// recommended in the Server-Sent Events candidate recommendation 11,
// section 8.
if && == "identity" {
.chunking = false
.closeAfterReply = true
("Transfer-Encoding")
} else {
// HTTP/1.1 or greater: use chunked transfer encoding
// to avoid closing the connection at EOF.
.chunking = true
.transferEncoding = "chunked"
if && == "chunked" {
// We will send the chunked Transfer-Encoding header later.
("Transfer-Encoding")
}
}
} else {
// HTTP version < 1.1: cannot do chunked transfer
// encoding and we don't know the Content-Length so
// signal EOF by closing connection.
.closeAfterReply = true
("Transfer-Encoding") // in case already set
}
// Cannot use Content-Length with non-identity Transfer-Encoding.
if .chunking {
("Content-Length")
}
if !.req.ProtoAtLeast(1, 0) {
return
}
// Only override the Connection header if it is not a successful
// protocol switch response and if KeepAlives are not enabled.
// See https://golang.org/issue/36381.
:= .closeAfterReply &&
(! || !hasToken(.header.get("Connection"), "close")) &&
!isProtocolSwitchResponse(.status, )
if {
("Connection")
if .req.ProtoAtLeast(1, 1) {
.connection = "close"
}
}
writeStatusLine(.conn.bufw, .req.ProtoAtLeast(1, 1), , .statusBuf[:])
.header.WriteSubset(.conn.bufw, )
.Write(.conn.bufw)
.conn.bufw.Write(crlf)
}
// foreachHeaderElement splits v according to the "#rule" construction
// in RFC 7230 section 7 and calls fn for each non-empty element.
func foreachHeaderElement( string, func(string)) {
= textproto.TrimString()
if == "" {
return
}
if !strings.Contains(, ",") {
()
return
}
for , := range strings.Split(, ",") {
if = textproto.TrimString(); != "" {
()
}
}
}
// writeStatusLine writes an HTTP/1.x Status-Line (RFC 7230 Section 3.1.2)
// to bw. is11 is whether the HTTP request is HTTP/1.1. false means HTTP/1.0.
// code is the response status code.
// scratch is an optional scratch buffer. If it has at least capacity 3, it's used.
func writeStatusLine( *bufio.Writer, bool, int, []byte) {
if {
.WriteString("HTTP/1.1 ")
} else {
.WriteString("HTTP/1.0 ")
}
if := StatusText(); != "" {
.Write(strconv.AppendInt([:0], int64(), 10))
.WriteByte(' ')
.WriteString()
.WriteString("\r\n")
} else {
// don't worry about performance
fmt.Fprintf(, "%03d status code %d\r\n", , )
}
}
// bodyAllowed reports whether a Write is allowed for this response type.
// It's illegal to call this before the header has been flushed.
func ( *response) () bool {
if !.wroteHeader {
panic("")
}
return bodyAllowedForStatus(.status)
}
// The Life Of A Write is like this:
//
// Handler starts. No header has been sent. The handler can either
// write a header, or just start writing. Writing before sending a header
// sends an implicitly empty 200 OK header.
//
// If the handler didn't declare a Content-Length up front, we either
// go into chunking mode or, if the handler finishes running before
// the chunking buffer size, we compute a Content-Length and send that
// in the header instead.
//
// Likewise, if the handler didn't set a Content-Type, we sniff that
// from the initial chunk of output.
//
// The Writers are wired together like:
//
// 1. *response (the ResponseWriter) ->
// 2. (*response).w, a [*bufio.Writer] of bufferBeforeChunkingSize bytes ->
// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type)
// and which writes the chunk headers, if needed ->
// 4. conn.bufw, a *bufio.Writer of default (4kB) bytes, writing to ->
// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write
// and populates c.werr with it if so, but otherwise writes to ->
// 6. the rwc, the [net.Conn].
//
// TODO(bradfitz): short-circuit some of the buffering when the
// initial header contains both a Content-Type and Content-Length.
// Also short-circuit in (1) when the header's been sent and not in
// chunking mode, writing directly to (4) instead, if (2) has no
// buffered data. More generally, we could short-circuit from (1) to
// (3) even in chunking mode if the write size from (1) is over some
// threshold and nothing is in (2). The answer might be mostly making
// bufferBeforeChunkingSize smaller and having bufio's fast-paths deal
// with this instead.
func ( *response) ( []byte) ( int, error) {
return .write(len(), , "")
}
func ( *response) ( string) ( int, error) {
return .write(len(), nil, )
}
// either dataB or dataS is non-zero.
func ( *response) ( int, []byte, string) ( int, error) {
if .conn.hijacked() {
if > 0 {
:= relevantCaller()
.conn.server.logf("http: response.Write on hijacked connection from %s (%s:%d)", .Function, path.Base(.File), .Line)
}
return 0, ErrHijacked
}
if .canWriteContinue.Load() {
// Body reader wants to write 100 Continue but hasn't yet. Tell it not to.
.disableWriteContinue()
}
if !.wroteHeader {
.WriteHeader(StatusOK)
}
if == 0 {
return 0, nil
}
if !.bodyAllowed() {
return 0, ErrBodyNotAllowed
}
.written += int64() // ignoring errors, for errorKludge
if .contentLength != -1 && .written > .contentLength {
return 0, ErrContentLength
}
if != nil {
return .w.Write()
} else {
return .w.WriteString()
}
}
func ( *response) () {
.handlerDone.Store(true)
if !.wroteHeader {
.WriteHeader(StatusOK)
}
.w.Flush()
putBufioWriter(.w)
.cw.close()
.conn.bufw.Flush()
.conn.r.abortPendingRead()
// Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely.
.reqBody.Close()
if .req.MultipartForm != nil {
.req.MultipartForm.RemoveAll()
}
}
// shouldReuseConnection reports whether the underlying TCP connection can be reused.
// It must only be called after the handler is done executing.
func ( *response) () bool {
if .closeAfterReply {
// The request or something set while executing the
// handler indicated we shouldn't reuse this
// connection.
return false
}
if .req.Method != "HEAD" && .contentLength != -1 && .bodyAllowed() && .contentLength != .written {
// Did not write enough. Avoid getting out of sync.
return false
}
// There was some error writing to the underlying connection
// during the request, so don't re-use this conn.
if .conn.werr != nil {
return false
}
if .closedRequestBodyEarly() {
return false
}
return true
}
func ( *response) () bool {
, := .req.Body.(*body)
return && .didEarlyClose()
}
func ( *response) () {
.FlushError()
}
func ( *response) () error {
if !.wroteHeader {
.WriteHeader(StatusOK)
}
:= .w.Flush()
:= .cw.flush()
if == nil {
=
}
return
}
func ( *conn) () {
if .bufr != nil {
// Steal the bufio.Reader (~4KB worth of memory) and its associated
// reader for a future connection.
putBufioReader(.bufr)
.bufr = nil
}
if .bufw != nil {
.bufw.Flush()
// Steal the bufio.Writer (~4KB worth of memory) and its associated
// writer for a future connection.
putBufioWriter(.bufw)
.bufw = nil
}
}
// Close the connection.
func ( *conn) () {
.finalFlush()
.rwc.Close()
}
// rstAvoidanceDelay is the amount of time we sleep after closing the
// write side of a TCP connection before closing the entire socket.
// By sleeping, we increase the chances that the client sees our FIN
// and processes its final data before they process the subsequent RST
// from closing a connection with known unread data.
// This RST seems to occur mostly on BSD systems. (And Windows?)
// This timeout is somewhat arbitrary (~latency around the planet),
// and may be modified by tests.
//
// TODO(bcmills): This should arguably be a server configuration parameter,
// not a hard-coded value.
var rstAvoidanceDelay = 500 * time.Millisecond
type closeWriter interface {
CloseWrite() error
}
var _ closeWriter = (*net.TCPConn)(nil)
// closeWriteAndWait flushes any outstanding data and sends a FIN packet (if
// client is connected via TCP), signaling that we're done. We then
// pause for a bit, hoping the client processes it before any
// subsequent RST.
//
// See https://golang.org/issue/3595
func ( *conn) () {
.finalFlush()
if , := .rwc.(closeWriter); {
.CloseWrite()
}
// When we return from closeWriteAndWait, the caller will fully close the
// connection. If client is still writing to the connection, this will cause
// the write to fail with ECONNRESET or similar. Unfortunately, many TCP
// implementations will also drop unread packets from the client's read buffer
// when a write fails, causing our final response to be truncated away too.
//
// As a result, https://www.rfc-editor.org/rfc/rfc7230#section-6.6 recommends
// that “[t]he server … continues to read from the connection until it
// receives a corresponding close by the client, or until the server is
// reasonably certain that its own TCP stack has received the client's
// acknowledgement of the packet(s) containing the server's last response.”
//
// Unfortunately, we have no straightforward way to be “reasonably certain”
// that we have received the client's ACK, and at any rate we don't want to
// allow a misbehaving client to soak up server connections indefinitely by
// withholding an ACK, nor do we want to go through the complexity or overhead
// of using low-level APIs to figure out when a TCP round-trip has completed.
//
// Instead, we declare that we are “reasonably certain” that we received the
// ACK if maxRSTAvoidanceDelay has elapsed.
time.Sleep(rstAvoidanceDelay)
}
// validNextProto reports whether the proto is a valid ALPN protocol name.
// Everything is valid except the empty string and built-in protocol types,
// so that those can't be overridden with alternate implementations.
func validNextProto( string) bool {
switch {
case "", "http/1.1", "http/1.0":
return false
}
return true
}
const (
runHooks = true
skipHooks = false
)
func ( *conn) ( net.Conn, ConnState, bool) {
:= .server
switch {
case StateNew:
.trackConn(, true)
case StateHijacked, StateClosed:
.trackConn(, false)
}
if > 0xff || < 0 {
panic("internal error")
}
:= uint64(time.Now().Unix()<<8) | uint64()
.curState.Store()
if ! {
return
}
if := .ConnState; != nil {
(, )
}
}
func ( *conn) () ( ConnState, int64) {
:= .curState.Load()
return ConnState( & 0xff), int64( >> 8)
}
// 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 embedded errors.
func badRequestError( string) error { return statusError{StatusBadRequest, } }
// statusError is an error used to respond to a request with an HTTP status.
// The text should be plain text without user info or other embedded errors.
type statusError struct {
code int
text string
}
func ( statusError) () string { return StatusText(.code) + ": " + .text }
// ErrAbortHandler is a sentinel panic value to abort a handler.
// While any panic from ServeHTTP aborts the response to the client,
// panicking with ErrAbortHandler also suppresses logging of a stack
// trace to the server's error log.
var ErrAbortHandler = errors.New("net/http: abort Handler")
// isCommonNetReadError reports whether err is a common error
// encountered during reading a request off the network when the
// client has gone away or had its read fail somehow. This is used to
// determine which logs are interesting enough to log about.
func isCommonNetReadError( error) bool {
if == io.EOF {
return true
}
if , := .(net.Error); && .Timeout() {
return true
}
if , := .(*net.OpError); && .Op == "read" {
return true
}
return false
}
// Serve a new connection.
func ( *conn) ( context.Context) {
if := .rwc.RemoteAddr(); != nil {
.remoteAddr = .String()
}
= context.WithValue(, LocalAddrContextKey, .rwc.LocalAddr())
var *response
defer func() {
if := recover(); != nil && != ErrAbortHandler {
const = 64 << 10
:= make([]byte, )
= [:runtime.Stack(, false)]
.server.logf("http: panic serving %v: %v\n%s", .remoteAddr, , )
}
if != nil {
.cancelCtx()
.disableWriteContinue()
}
if !.hijacked() {
if != nil {
.conn.r.abortPendingRead()
.reqBody.Close()
}
.close()
.setState(.rwc, StateClosed, runHooks)
}
}()
if , := .rwc.(*tls.Conn); {
:= .server.tlsHandshakeTimeout()
if > 0 {
:= time.Now().Add()
.rwc.SetReadDeadline()
.rwc.SetWriteDeadline()
}
if := .HandshakeContext(); != nil {
// If the handshake failed due to the client not speaking
// TLS, assume they're speaking plaintext HTTP and write a
// 400 response on the TLS conn's underlying net.Conn.
var string
if , := .(tls.RecordHeaderError); && .Conn != nil && tlsRecordHeaderLooksLikeHTTP(.RecordHeader) {
io.WriteString(.Conn, "HTTP/1.0 400 Bad Request\r\n\r\nClient sent an HTTP request to an HTTPS server.\n")
.Conn.Close()
= "client sent an HTTP request to an HTTPS server"
} else {
= .Error()
}
.server.logf("http: TLS handshake error from %s: %v", .rwc.RemoteAddr(), )
return
}
// Restore Conn-level deadlines.
if > 0 {
.rwc.SetReadDeadline(time.Time{})
.rwc.SetWriteDeadline(time.Time{})
}
.tlsState = new(tls.ConnectionState)
*.tlsState = .ConnectionState()
if := .tlsState.NegotiatedProtocol; validNextProto() {
if := .server.TLSNextProto[]; != nil {
:= initALPNRequest{, , serverHandler{.server}}
// Mark freshly created HTTP/2 as active and prevent any server state hooks
// from being run on these connections. This prevents closeIdleConns from
// closing such connections. See issue https://golang.org/issue/39776.
.setState(.rwc, StateActive, skipHooks)
(.server, , )
}
return
}
}
// HTTP/1.x from here on.
, := context.WithCancel()
.cancelCtx =
defer ()
.r = &connReader{conn: }
.bufr = newBufioReader(.r)
.bufw = newBufioWriterSize(checkConnErrorWriter{}, 4<<10)
:= .server.protocols()
if .tlsState == nil && .UnencryptedHTTP2() {
if .maybeServeUnencryptedHTTP2() {
return
}
}
if !.HTTP1() {
return
}
for {
, := .readRequest()
if .r.remain != .server.initialReadLimitSize() {
// If we read any bytes off the wire, we're active.
.setState(.rwc, StateActive, runHooks)
}
if != nil {
const = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n"
switch {
case == errTooLarge:
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
// request. Undefined behavior.
const = "431 Request Header Fields Too Large"
fmt.Fprintf(.rwc, "HTTP/1.1 "+++)
.closeWriteAndWait()
return
case isUnsupportedTEError():
// Respond as per RFC 7230 Section 3.3.1 which says,
// A server that receives a request message with a
// transfer coding it does not understand SHOULD
// respond with 501 (Unimplemented).
:= StatusNotImplemented
// We purposefully aren't echoing back the transfer-encoding's value,
// so as to mitigate the risk of cross side scripting by an attacker.
fmt.Fprintf(.rwc, "HTTP/1.1 %d %s%sUnsupported transfer encoding", , StatusText(), )
return
case isCommonNetReadError():
return // don't reply
default:
if , := .(statusError); {
fmt.Fprintf(.rwc, "HTTP/1.1 %d %s: %s%s%d %s: %s", .code, StatusText(.code), .text, , .code, StatusText(.code), .text)
return
}
const = "400 Bad Request"
fmt.Fprintf(.rwc, "HTTP/1.1 "+++)
return
}
}
// Expect 100 Continue support
:= .req
if .expectsContinue() {
if .ProtoAtLeast(1, 1) && .ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
.Body = &expectContinueReader{readCloser: .Body, resp: }
.canWriteContinue.Store(true)
}
} else if .Header.get("Expect") != "" {
.sendExpectationFailed()
return
}
.curReq.Store()
if requestBodyRemains(.Body) {
registerOnHitEOF(.Body, .conn.r.startBackgroundRead)
} else {
.conn.r.startBackgroundRead()
}
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
=
serverHandler{.server}.ServeHTTP(, .req)
= nil
.cancelCtx()
if .hijacked() {
return
}
.finishRequest()
.rwc.SetWriteDeadline(time.Time{})
if !.shouldReuseConnection() {
if .requestBodyLimitHit || .closedRequestBodyEarly() {
.closeWriteAndWait()
}
return
}
.setState(.rwc, StateIdle, runHooks)
.curReq.Store(nil)
if !.conn.server.doKeepAlives() {
// We're in shutdown mode. We might've replied
// to the user without "Connection: close" and
// they might think they can send another
// request, but such is life with HTTP/1.1.
return
}
if := .server.idleTimeout(); > 0 {
.rwc.SetReadDeadline(time.Now().Add())
} else {
.rwc.SetReadDeadline(time.Time{})
}
// Wait for the connection to become readable again before trying to
// read the next request. This prevents a ReadHeaderTimeout or
// ReadTimeout from starting until the first bytes of the next request
// have been received.
if , := .bufr.Peek(4); != nil {
return
}
.rwc.SetReadDeadline(time.Time{})
}
}
// unencryptedHTTP2Request is an HTTP handler that initializes
// certain uninitialized fields in its *Request.
//
// It's the unencrypted version of initALPNRequest.
type unencryptedHTTP2Request struct {
ctx context.Context
c net.Conn
h serverHandler
}
func ( unencryptedHTTP2Request) () context.Context { return .ctx }
func ( unencryptedHTTP2Request) ( ResponseWriter, *Request) {
if .Body == nil {
.Body = NoBody
}
if .RemoteAddr == "" {
.RemoteAddr = .c.RemoteAddr().String()
}
.h.ServeHTTP(, )
}
// unencryptedNetConnInTLSConn is used to pass an unencrypted net.Conn to
// functions that only accept a *tls.Conn.
type unencryptedNetConnInTLSConn struct {
net.Conn // panic on all net.Conn methods
conn net.Conn
}
func ( unencryptedNetConnInTLSConn) () net.Conn {
return .conn
}
func unencryptedTLSConn( net.Conn) *tls.Conn {
return tls.Client(unencryptedNetConnInTLSConn{conn: }, nil)
}
// TLSNextProto key to use for unencrypted HTTP/2 connections.
// Not actually a TLS-negotiated protocol.
const nextProtoUnencryptedHTTP2 = "unencrypted_http2"
func ( *conn) ( context.Context) bool {
, := .server.TLSNextProto[nextProtoUnencryptedHTTP2]
if ! {
return false
}
:= func( *conn, []byte) bool {
.r.setReadLimit(int64(len()) - int64(.bufr.Buffered()))
, := .bufr.Peek(len())
.r.setInfiniteReadLimit()
return == nil && bytes.Equal(, )
}
if !(, []byte("PRI * HTTP/2.0")) {
return false
}
if !(, []byte("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")) {
return false
}
.setState(.rwc, StateActive, skipHooks)
:= unencryptedHTTP2Request{, .rwc, serverHandler{.server}}
(.server, unencryptedTLSConn(.rwc), )
return true
}
func ( *response) () {
// TODO(bradfitz): let ServeHTTP handlers handle
// requests with non-standard expectation[s]? Seems
// theoretical at best, and doesn't fit into the
// current ServeHTTP model anyway. We'd need to
// make the ResponseWriter an optional
// "ExpectReplier" interface or something.
//
// For now we'll just obey RFC 7231 5.1.1 which says
// "A server that receives an Expect field-value other
// than 100-continue MAY respond with a 417 (Expectation
// Failed) status code to indicate that the unexpected
// expectation cannot be met."
.Header().Set("Connection", "close")
.WriteHeader(StatusExpectationFailed)
.finishRequest()
}
// Hijack implements the [Hijacker.Hijack] method. Our response is both a [ResponseWriter]
// and a [Hijacker].
func ( *response) () ( net.Conn, *bufio.ReadWriter, error) {
if .handlerDone.Load() {
panic("net/http: Hijack called after ServeHTTP finished")
}
.disableWriteContinue()
if .wroteHeader {
.cw.flush()
}
:= .conn
.mu.Lock()
defer .mu.Unlock()
// Release the bufioWriter that writes to the chunk writer, it is not
// used after a connection has been hijacked.
, , = .hijackLocked()
if == nil {
putBufioWriter(.w)
.w = nil
}
return , ,
}
func ( *response) () <-chan bool {
if .handlerDone.Load() {
panic("net/http: CloseNotify called after ServeHTTP finished")
}
return .closeNotifyCh
}
func registerOnHitEOF( io.ReadCloser, func()) {
switch v := .(type) {
case *expectContinueReader:
(.readCloser, )
case *body:
.registerOnHitEOF()
default:
panic("unexpected type " + fmt.Sprintf("%T", ))
}
}
// requestBodyRemains reports whether future calls to Read
// on rc might yield more data.
func requestBodyRemains( io.ReadCloser) bool {
if == NoBody {
return false
}
switch v := .(type) {
case *expectContinueReader:
return (.readCloser)
case *body:
return .bodyRemains()
default:
panic("unexpected type " + fmt.Sprintf("%T", ))
}
}
// 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] that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func ( HandlerFunc) ( ResponseWriter, *Request) {
(, )
}
// Helper handlers
// Error replies to the request with the specified error message and HTTP code.
// It does not otherwise end the request; the caller should ensure no further
// writes are done to w.
// The error message should be plain text.
//
// Error deletes the Content-Length header,
// sets Content-Type to “text/plain; charset=utf-8”,
// and sets X-Content-Type-Options to “nosniff”.
// This configures the header properly for the error message,
// in case the caller had set it up expecting a successful output.
func ( ResponseWriter, string, int) {
:= .Header()
// Delete the Content-Length header, which might be for some other content.
// Assuming the error string fits in the writer's buffer, we'll figure
// out the correct Content-Length for it later.
//
// We don't delete Content-Encoding, because some middleware sets
// Content-Encoding: gzip and wraps the ResponseWriter to compress on-the-fly.
// See https://go.dev/issue/66343.
.Del("Content-Length")
// There might be content type already set, but we reset it to
// text/plain for the error message.
.Set("Content-Type", "text/plain; charset=utf-8")
.Set("X-Content-Type-Options", "nosniff")
.WriteHeader()
fmt.Fprintln(, )
}
// NotFound replies to the request with an HTTP 404 not found error.
func ( ResponseWriter, *Request) { Error(, "404 page not found", StatusNotFound) }
// NotFoundHandler returns a simple request handler
// that replies to each request with a “404 page not found” reply.
func () Handler { return HandlerFunc(NotFound) }
// StripPrefix returns a handler that serves HTTP requests by removing the
// given prefix from the request URL's Path (and RawPath if set) and invoking
// the handler h. StripPrefix handles a request for a path that doesn't begin
// with prefix by replying with an HTTP 404 not found error. The prefix must
// match exactly: if the prefix in the request contains escaped characters
// the reply is also an HTTP 404 not found error.
func ( string, Handler) Handler {
if == "" {
return
}
return HandlerFunc(func( ResponseWriter, *Request) {
:= strings.TrimPrefix(.URL.Path, )
:= strings.TrimPrefix(.URL.RawPath, )
if len() < len(.URL.Path) && (.URL.RawPath == "" || len() < len(.URL.RawPath)) {
:= new(Request)
* = *
.URL = new(url.URL)
*.URL = *.URL
.URL.Path =
.URL.RawPath =
.ServeHTTP(, )
} else {
NotFound(, )
}
})
}
// 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].
//
// If the Content-Type header has not been set, [Redirect] sets it
// to "text/html; charset=utf-8" and writes a small HTML body.
// Setting the Content-Type header to any value, including nil,
// disables that behavior.
func ( ResponseWriter, *Request, string, int) {
if , := urlpkg.Parse(); == nil {
// If url was relative, make its path absolute by
// combining with request path.
// The client would probably do this for us,
// but doing it ourselves is more reliable.
// See RFC 7231, section 7.1.2
if .Scheme == "" && .Host == "" {
:= .URL.Path
if == "" { // should not happen, but avoid a crash if it does
= "/"
}
// no leading http://server
if == "" || [0] != '/' {
// make relative path absolute
, := path.Split()
= +
}
var string
if := strings.Index(, "?"); != -1 {
, = [:], [:]
}
// clean up but preserve trailing slash
:= strings.HasSuffix(, "/")
= path.Clean()
if && !strings.HasSuffix(, "/") {
+= "/"
}
+=
}
}
:= .Header()
// RFC 7231 notes that a short HTML body is usually included in
// the response because older user agents may not understand 301/307.
// Do it only if the request didn't already have a Content-Type header.
, := ["Content-Type"]
.Set("Location", hexEscapeNonASCII())
if ! && (.Method == "GET" || .Method == "HEAD") {
.Set("Content-Type", "text/html; charset=utf-8")
}
.WriteHeader()
// Shouldn't send the body for POST or HEAD; that leaves GET.
if ! && .Method == "GET" {
:= "<a href=\"" + htmlEscape() + "\">" + StatusText() + "</a>.\n"
fmt.Fprintln(, )
}
}
var htmlReplacer = strings.NewReplacer(
"&", "&",
"<", "<",
">", ">",
// """ is shorter than """.
`"`, """,
// "'" is shorter than "'" and apos was not in HTML until HTML5.
"'", "'",
)
func htmlEscape( string) string {
return htmlReplacer.Replace()
}
// Redirect to a fixed URL
type redirectHandler struct {
url string
code int
}
func ( *redirectHandler) ( ResponseWriter, *Request) {
Redirect(, , .url, .code)
}
// 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 ( string, int) Handler {
return &redirectHandler{, }
}
// ServeMux is an HTTP request multiplexer.
// It matches the URL of each incoming request against a list of registered
// patterns and calls the handler for the pattern that
// most closely matches the URL.
//
// # Patterns
//
// Patterns can match the method, host and path of a request.
// Some examples:
//
// - "/index.html" matches the path "/index.html" for any host and method.
// - "GET /static/" matches a GET request whose path begins with "/static/".
// - "example.com/" matches any request to the host "example.com".
// - "example.com/{$}" matches requests with host "example.com" and path "/".
// - "/b/{bucket}/o/{objectname...}" matches paths whose first segment is "b"
// and whose third segment is "o". The name "bucket" denotes the second
// segment and "objectname" denotes the remainder of the path.
//
// In general, a pattern looks like
//
// [METHOD ][HOST]/[PATH]
//
// All three parts are optional; "/" is a valid pattern.
// If METHOD is present, it must be followed by at least one space or tab.
//
// Literal (that is, non-wildcard) parts of a pattern match
// the corresponding parts of a request case-sensitively.
//
// A pattern with no method matches every method. A pattern
// with the method GET matches both GET and HEAD requests.
// Otherwise, the method must match exactly.
//
// A pattern with no host matches every host.
// A pattern with a host matches URLs on that host only.
//
// A path can include wildcard segments of the form {NAME} or {NAME...}.
// For example, "/b/{bucket}/o/{objectname...}".
// The wildcard name must be a valid Go identifier.
// Wildcards must be full path segments: they must be preceded by a slash and followed by
// either a slash or the end of the string.
// For example, "/b_{bucket}" is not a valid pattern.
//
// Normally a wildcard matches only a single path segment,
// ending at the next literal slash (not %2F) in the request URL.
// But if the "..." is present, then the wildcard matches the remainder of the URL path, including slashes.
// (Therefore it is invalid for a "..." wildcard to appear anywhere but at the end of a pattern.)
// The match for a wildcard can be obtained by calling [Request.PathValue] with the wildcard's name.
// A trailing slash in a path acts as an anonymous "..." wildcard.
//
// The special wildcard {$} matches only the end of the URL.
// For example, the pattern "/{$}" matches only the path "/",
// whereas the pattern "/" matches every path.
//
// For matching, both pattern paths and incoming request paths are unescaped segment by segment.
// So, for example, the path "/a%2Fb/100%25" is treated as having two segments, "a/b" and "100%".
// The pattern "/a%2fb/" matches it, but the pattern "/a/b/" does not.
//
// # Precedence
//
// If two or more patterns match a request, then the most specific pattern takes precedence.
// A pattern P1 is more specific than P2 if P1 matches a strict subset of P2’s requests;
// that is, if P2 matches all the requests of P1 and more.
// If neither is more specific, then the patterns conflict.
// There is one exception to this rule, for backwards compatibility:
// if two patterns would otherwise conflict and one has a host while the other does not,
// then the pattern with the host takes precedence.
// If a pattern passed to [ServeMux.Handle] or [ServeMux.HandleFunc] conflicts with
// another pattern that is already registered, those functions panic.
//
// As an example of the general rule, "/images/thumbnails/" is more specific than "/images/",
// so both can be registered.
// The former matches paths beginning with "/images/thumbnails/"
// and the latter will match any other path in the "/images/" subtree.
//
// As another example, consider the patterns "GET /" and "/index.html":
// both match a GET request for "/index.html", but the former pattern
// matches all other GET and HEAD requests, while the latter matches any
// request for "/index.html" that uses a different method.
// The patterns conflict.
//
// # Trailing-slash redirection
//
// Consider a [ServeMux] with a handler for a subtree, registered using a trailing slash or "..." wildcard.
// If the ServeMux receives a request for the subtree root without a trailing slash,
// it redirects the request by adding the trailing slash.
// This behavior can be overridden with a separate registration for the path without
// the trailing slash or "..." wildcard. For example, registering "/images/" causes ServeMux
// to redirect a request for "/images" to "/images/", unless "/images" has
// been registered separately.
//
// # Request sanitizing
//
// ServeMux also takes care of sanitizing the URL request path and the Host
// header, stripping the port number and redirecting any request containing . or
// .. segments or repeated slashes to an equivalent, cleaner URL.
// Escaped path elements such as "%2e" for "." and "%2f" for "/" are preserved
// and aren't considered separators for request routing.
//
// # Compatibility
//
// The pattern syntax and matching behavior of ServeMux changed significantly
// in Go 1.22. To restore the old behavior, set the GODEBUG environment variable
// to "httpmuxgo121=1". This setting is read once, at program startup; changes
// during execution will be ignored.
//
// The backwards-incompatible changes include:
// - Wildcards are just ordinary literal path segments in 1.21.
// For example, the pattern "/{x}" will match only that path in 1.21,
// but will match any one-segment path in 1.22.
// - In 1.21, no pattern was rejected, unless it was empty or conflicted with an existing pattern.
// In 1.22, syntactically invalid patterns will cause [ServeMux.Handle] and [ServeMux.HandleFunc] to panic.
// For example, in 1.21, the patterns "/{" and "/a{x}" match themselves,
// but in 1.22 they are invalid and will cause a panic when registered.
// - In 1.22, each segment of a pattern is unescaped; this was not done in 1.21.
// For example, in 1.22 the pattern "/%61" matches the path "/a" ("%61" being the URL escape sequence for "a"),
// but in 1.21 it would match only the path "/%2561" (where "%25" is the escape for the percent sign).
// - When matching patterns to paths, in 1.22 each segment of the path is unescaped; in 1.21, the entire path is unescaped.
// This change mostly affects how paths with %2F escapes adjacent to slashes are treated.
// See https://go.dev/issue/21955 for details.
type ServeMux struct {
mu sync.RWMutex
tree routingNode
index routingIndex
mux121 serveMux121 // used only when GODEBUG=httpmuxgo121=1
}
// NewServeMux allocates and returns a new [ServeMux].
func () *ServeMux {
return &ServeMux{}
}
// DefaultServeMux is the default [ServeMux] used by [Serve].
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
// cleanPath returns the canonical path for p, eliminating . and .. elements.
func cleanPath( string) string {
if == "" {
return "/"
}
if [0] != '/' {
= "/" +
}
:= path.Clean()
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if [len()-1] == '/' && != "/" {
// Fast path for common case of p being the string we want:
if len() == len()+1 && strings.HasPrefix(, ) {
=
} else {
+= "/"
}
}
return
}
// stripHostPort returns h without any trailing ":<port>".
func stripHostPort( string) string {
// If no port on host, return unchanged
if !strings.Contains(, ":") {
return
}
, , := net.SplitHostPort()
if != nil {
return // on error, return unchanged
}
return
}
// Handler returns the handler to use for the given request,
// consulting r.Method, r.Host, and r.URL.Path. It always returns
// a non-nil handler. If the path is not in its canonical form, the
// handler will be an internally-generated handler that redirects
// to the canonical path. If the host contains a port, it is ignored
// when matching handlers.
//
// The path and host are used unchanged for CONNECT requests.
//
// Handler also returns the registered pattern that matches the
// request or, in the case of internally-generated redirects,
// the path that will match after following the redirect.
//
// If there is no registered handler that applies to the request,
// Handler returns a “page not found” handler and an empty pattern.
func ( *ServeMux) ( *Request) ( Handler, string) {
if use121 {
return .mux121.findHandler()
}
, , , := .findHandler()
return ,
}
// findHandler finds a handler for a request.
// If there is a matching handler, it returns it and the pattern that matched.
// Otherwise it returns a Redirect or NotFound handler with the path that would match
// after the redirect.
func ( *ServeMux) ( *Request) ( Handler, string, *pattern, []string) {
var *routingNode
:= .URL.Host
:= .URL.EscapedPath()
:=
// CONNECT requests are not canonicalized.
if .Method == "CONNECT" {
// If r.URL.Path is /tree and its handler is not registered,
// the /tree -> /tree/ redirect applies to CONNECT requests
// but the path canonicalization does not.
, , := .matchOrRedirect(, .Method, , .URL)
if != nil {
return RedirectHandler(.String(), StatusMovedPermanently), .Path, nil, nil
}
// Redo the match, this time with r.Host instead of r.URL.Host.
// Pass a nil URL to skip the trailing-slash redirect logic.
, , _ = .matchOrRedirect(.Host, .Method, , nil)
} else {
// All other requests have any port stripped and path cleaned
// before passing to mux.handler.
= stripHostPort(.Host)
= cleanPath()
// If the given path is /tree and its handler is not registered,
// redirect for /tree/.
var *url.URL
, , = .matchOrRedirect(, .Method, , .URL)
if != nil {
return RedirectHandler(.String(), StatusMovedPermanently), .Path, nil, nil
}
if != {
// Redirect to cleaned path.
:= ""
if != nil {
= .pattern.String()
}
:= &url.URL{Path: , RawQuery: .URL.RawQuery}
return RedirectHandler(.String(), StatusMovedPermanently), , nil, nil
}
}
if == nil {
// We didn't find a match with the request method. To distinguish between
// Not Found and Method Not Allowed, see if there is another pattern that
// matches except for the method.
:= .matchingMethods(, )
if len() > 0 {
return HandlerFunc(func( ResponseWriter, *Request) {
.Header().Set("Allow", strings.Join(, ", "))
Error(, StatusText(StatusMethodNotAllowed), StatusMethodNotAllowed)
}), "", nil, nil
}
return NotFoundHandler(), "", nil, nil
}
return .handler, .pattern.String(), .pattern,
}
// matchOrRedirect looks up a node in the tree that matches the host, method and path.
//
// If the url argument is non-nil, handler also deals with trailing-slash
// redirection: when a path doesn't match exactly, the match is tried again
// after appending "/" to the path. If that second match succeeds, the last
// return value is the URL to redirect to.
func ( *ServeMux) (, , string, *url.URL) ( *routingNode, []string, *url.URL) {
.mu.RLock()
defer .mu.RUnlock()
, := .tree.match(, , )
// If we have an exact match, or we were asked not to try trailing-slash redirection,
// or the URL already has a trailing slash, then we're done.
if !exactMatch(, ) && != nil && !strings.HasSuffix(, "/") {
// If there is an exact match with a trailing slash, then redirect.
+= "/"
, := .tree.match(, , )
if exactMatch(, ) {
return nil, nil, &url.URL{Path: cleanPath(.Path) + "/", RawQuery: .RawQuery}
}
}
return , , nil
}
// exactMatch reports whether the node's pattern exactly matches the path.
// As a special case, if the node is nil, exactMatch return false.
//
// Before wildcards were introduced, it was clear that an exact match meant
// that the pattern and path were the same string. The only other possibility
// was that a trailing-slash pattern, like "/", matched a path longer than
// it, like "/a".
//
// With wildcards, we define an inexact match as any one where a multi wildcard
// matches a non-empty string. All other matches are exact.
// For example, these are all exact matches:
//
// pattern path
// /a /a
// /{x} /a
// /a/{$} /a/
// /a/ /a/
//
// The last case has a multi wildcard (implicitly), but the match is exact because
// the wildcard matches the empty string.
//
// Examples of matches that are not exact:
//
// pattern path
// / /a
// /a/{x...} /a/b
func exactMatch( *routingNode, string) bool {
if == nil {
return false
}
// We can't directly implement the definition (empty match for multi
// wildcard) because we don't record a match for anonymous multis.
// If there is no multi, the match is exact.
if !.pattern.lastSegment().multi {
return true
}
// If the path doesn't end in a trailing slash, then the multi match
// is non-empty.
if len() > 0 && [len()-1] != '/' {
return false
}
// Only patterns ending in {$} or a multi wildcard can
// match a path with a trailing slash.
// For the match to be exact, the number of pattern
// segments should be the same as the number of slashes in the path.
// E.g. "/a/b/{$}" and "/a/b/{...}" exactly match "/a/b/", but "/a/" does not.
return len(.pattern.segments) == strings.Count(, "/")
}
// matchingMethods return a sorted list of all methods that would match with the given host and path.
func ( *ServeMux) (, string) []string {
// Hold the read lock for the entire method so that the two matches are done
// on the same set of registered patterns.
.mu.RLock()
defer .mu.RUnlock()
:= map[string]bool{}
.tree.matchingMethods(, , )
// matchOrRedirect will try appending a trailing slash if there is no match.
if !strings.HasSuffix(, "/") {
.tree.matchingMethods(, +"/", )
}
return slices.Sorted(maps.Keys())
}
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func ( *ServeMux) ( ResponseWriter, *Request) {
if .RequestURI == "*" {
if .ProtoAtLeast(1, 1) {
.Header().Set("Connection", "close")
}
.WriteHeader(StatusBadRequest)
return
}
var Handler
if use121 {
, _ = .mux121.findHandler()
} else {
, .Pattern, .pat, .matches = .findHandler()
}
.ServeHTTP(, )
}
// The four functions below all call ServeMux.register so that callerLocation
// always refers to user code.
// Handle registers the handler for the given pattern.
// If the given pattern conflicts, with one that is already registered, Handle
// panics.
func ( *ServeMux) ( string, Handler) {
if use121 {
.mux121.handle(, )
} else {
.register(, )
}
}
// HandleFunc registers the handler function for the given pattern.
// If the given pattern conflicts, with one that is already registered, HandleFunc
// panics.
func ( *ServeMux) ( string, func(ResponseWriter, *Request)) {
if use121 {
.mux121.handleFunc(, )
} else {
.register(, HandlerFunc())
}
}
// Handle registers the handler for the given pattern in [DefaultServeMux].
// The documentation for [ServeMux] explains how patterns are matched.
func ( string, Handler) {
if use121 {
DefaultServeMux.mux121.handle(, )
} else {
DefaultServeMux.register(, )
}
}
// HandleFunc registers the handler function for the given pattern in [DefaultServeMux].
// The documentation for [ServeMux] explains how patterns are matched.
func ( string, func(ResponseWriter, *Request)) {
if use121 {
DefaultServeMux.mux121.handleFunc(, )
} else {
DefaultServeMux.register(, HandlerFunc())
}
}
func ( *ServeMux) ( string, Handler) {
if := .registerErr(, ); != nil {
panic()
}
}
func ( *ServeMux) ( string, Handler) error {
if == "" {
return errors.New("http: invalid pattern")
}
if == nil {
return errors.New("http: nil handler")
}
if , := .(HandlerFunc); && == nil {
return errors.New("http: nil handler")
}
, := parsePattern()
if != nil {
return fmt.Errorf("parsing %q: %w", , )
}
// Get the caller's location, for better conflict error messages.
// Skip register and whatever calls it.
, , , := runtime.Caller(3)
if ! {
.loc = "unknown location"
} else {
.loc = fmt.Sprintf("%s:%d", , )
}
.mu.Lock()
defer .mu.Unlock()
// Check for conflict.
if := .index.possiblyConflictingPatterns(, func( *pattern) error {
if .conflictsWith() {
:= describeConflict(, )
return fmt.Errorf("pattern %q (registered at %s) conflicts with pattern %q (registered at %s):\n%s",
, .loc, , .loc, )
}
return nil
}); != nil {
return
}
.tree.addPattern(, )
.index.addPattern()
return nil
}
// Serve accepts incoming HTTP connections on the listener l,
// creating a new service goroutine for each. The service goroutines
// read requests and then call handler to reply to them.
//
// The handler is typically nil, in which case [DefaultServeMux] is used.
//
// HTTP/2 support is only enabled if the Listener returns [*tls.Conn]
// connections and they were configured with "h2" in the TLS
// Config.NextProtos.
//
// Serve always returns a non-nil error.
func ( net.Listener, Handler) error {
:= &Server{Handler: }
return .Serve()
}
// ServeTLS accepts incoming HTTPS connections on the listener l,
// creating a new service goroutine for each. The service goroutines
// read requests and then call handler to reply to them.
//
// The handler is typically nil, in which case [DefaultServeMux] is used.
//
// Additionally, files containing a certificate and matching private key
// for the server must be provided. If the certificate is signed by a
// certificate authority, the certFile should be the concatenation
// of the server's certificate, any intermediates, and the CA's certificate.
//
// ServeTLS always returns a non-nil error.
func ( net.Listener, Handler, , string) error {
:= &Server{Handler: }
return .ServeTLS(, , )
}
// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
// Addr optionally specifies the TCP address for the server to listen on,
// in the form "host:port". If empty, ":http" (port 80) is used.
// The service names are defined in RFC 6335 and assigned by IANA.
// See net.Dial for details of the address format.
Addr string
Handler Handler // handler to invoke, http.DefaultServeMux if nil
// DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler,
// otherwise responds with 200 OK and Content-Length: 0.
DisableGeneralOptionsHandler bool
// TLSConfig optionally provides a TLS configuration for use
// by ServeTLS and ListenAndServeTLS. Note that this value is
// cloned by ServeTLS and ListenAndServeTLS, so it's not
// possible to modify the configuration with methods like
// tls.Config.SetSessionTicketKeys. To use
// SetSessionTicketKeys, use Server.Serve with a TLS Listener
// instead.
TLSConfig *tls.Config
// ReadTimeout is the maximum duration for reading the entire
// request, including the body. A zero or negative value means
// there will be no timeout.
//
// Because ReadTimeout does not let Handlers make per-request
// decisions on each request body's acceptable deadline or
// upload rate, most users will prefer to use
// ReadHeaderTimeout. It is valid to use them both.
ReadTimeout time.Duration
// ReadHeaderTimeout is the amount of time allowed to read
// request headers. The connection's read deadline is reset
// after reading the headers and the Handler can decide what
// is considered too slow for the body. If zero, the value of
// ReadTimeout is used. If negative, or if zero and ReadTimeout
// is zero or negative, there is no timeout.
ReadHeaderTimeout time.Duration
// WriteTimeout is the maximum duration before timing out
// writes of the response. It is reset whenever a new
// request's header is read. Like ReadTimeout, it does not
// let Handlers make decisions on a per-request basis.
// A zero or negative value means there will be no timeout.
WriteTimeout time.Duration
// IdleTimeout is the maximum amount of time to wait for the
// next request when keep-alives are enabled. If zero, the value
// of ReadTimeout is used. If negative, or if zero and ReadTimeout
// is zero or negative, there is no timeout.
IdleTimeout time.Duration
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes is used.
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// 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 not nil, HTTP/2 support is not enabled
// automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
ConnState func(net.Conn, ConnState)
// ErrorLog specifies an optional logger for errors accepting
// connections, unexpected behavior from handlers, and
// underlying FileSystem errors.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// BaseContext optionally specifies a function that returns
// the base context for incoming requests on this server.
// The provided Listener is the specific Listener that's
// about to start accepting requests.
// If BaseContext is nil, the default is context.Background().
// If non-nil, it must return a non-nil context.
BaseContext func(net.Listener) context.Context
// ConnContext optionally specifies a function that modifies
// the context used for a new connection c. The provided ctx
// is derived from the base context and has a ServerContextKey
// value.
ConnContext func(ctx context.Context, c net.Conn) context.Context
// HTTP2 configures HTTP/2 connections.
//
// This field does not yet have any effect.
// See https://go.dev/issue/67813.
HTTP2 *HTTP2Config
// Protocols is the set of protocols accepted by the server.
//
// If Protocols includes UnencryptedHTTP2, the server will accept
// unencrypted HTTP/2 connections. The server can serve both
// HTTP/1 and unencrypted HTTP/2 on the same address and port.
//
// If Protocols is nil, the default is usually HTTP/1 and HTTP/2.
// If TLSNextProto is non-nil and does not contain an "h2" entry,
// the default is HTTP/1 only.
Protocols *Protocols
inShutdown atomic.Bool // true when server is in shutdown
disableKeepAlives atomic.Bool
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
onShutdown []func()
listenerGroup sync.WaitGroup
}
// Close immediately closes all active net.Listeners and any
// connections in state [StateNew], [StateActive], or [StateIdle]. For a
// graceful shutdown, use [Server.Shutdown].
//
// Close does not attempt to close (and does not even know about)
// any hijacked connections, such as WebSockets.
//
// Close returns any error returned from closing the [Server]'s
// underlying Listener(s).
func ( *Server) () error {
.inShutdown.Store(true)
.mu.Lock()
defer .mu.Unlock()
:= .closeListenersLocked()
// Unlock s.mu while waiting for listenerGroup.
// The group Add and Done calls are made with s.mu held,
// to avoid adding a new listener in the window between
// us setting inShutdown above and waiting here.
.mu.Unlock()
.listenerGroup.Wait()
.mu.Lock()
for := range .activeConn {
.rwc.Close()
delete(.activeConn, )
}
return
}
// shutdownPollIntervalMax is the max polling interval when checking
// quiescence during Server.Shutdown. Polling starts with a small
// interval and backs off to the max.
// Ideally we could find a solution that doesn't involve polling,
// but which also doesn't have a high runtime cost (and doesn't
// involve any contentious mutexes), but that is left as an
// exercise for the reader.
const shutdownPollIntervalMax = 500 * time.Millisecond
// Shutdown gracefully shuts down the server without interrupting any
// active connections. Shutdown works by first closing all open
// listeners, then closing all idle connections, and then waiting
// indefinitely for connections to return to idle and then shut down.
// If the provided context expires before the shutdown is complete,
// Shutdown returns the context's error, otherwise it returns any
// error returned from closing the [Server]'s underlying Listener(s).
//
// When Shutdown is called, [Serve], [ListenAndServe], and
// [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the
// program doesn't exit and waits instead for Shutdown to return.
//
// Shutdown does not attempt to close nor wait for hijacked
// connections such as WebSockets. The caller of Shutdown should
// separately notify such long-lived connections of shutdown and wait
// for them to close, if desired. See [Server.RegisterOnShutdown] for a way to
// register shutdown notification functions.
//
// Once Shutdown has been called on a server, it may not be reused;
// future calls to methods such as Serve will return ErrServerClosed.
func ( *Server) ( context.Context) error {
.inShutdown.Store(true)
.mu.Lock()
:= .closeListenersLocked()
for , := range .onShutdown {
go ()
}
.mu.Unlock()
.listenerGroup.Wait()
:= time.Millisecond
:= func() time.Duration {
// Add 10% jitter.
:= + time.Duration(rand.Intn(int(/10)))
// Double and clamp for next time.
*= 2
if > shutdownPollIntervalMax {
= shutdownPollIntervalMax
}
return
}
:= time.NewTimer(())
defer .Stop()
for {
if .closeIdleConns() {
return
}
select {
case <-.Done():
return .Err()
case <-.C:
.Reset(())
}
}
}
// RegisterOnShutdown registers a function to call on [Server.Shutdown].
// This can be used to gracefully shutdown connections that have
// undergone ALPN protocol upgrade or that have been hijacked.
// This function should start protocol-specific graceful shutdown,
// but should not wait for shutdown to complete.
func ( *Server) ( func()) {
.mu.Lock()
.onShutdown = append(.onShutdown, )
.mu.Unlock()
}
// closeIdleConns closes all idle connections and reports whether the
// server is quiescent.
func ( *Server) () bool {
.mu.Lock()
defer .mu.Unlock()
:= true
for := range .activeConn {
, := .getState()
// Issue 22682: treat StateNew connections as if
// they're idle if we haven't read the first request's
// header in over 5 seconds.
if == StateNew && < time.Now().Unix()-5 {
= StateIdle
}
if != StateIdle || == 0 {
// Assume unixSec == 0 means it's a very new
// connection, without state set yet.
= false
continue
}
.rwc.Close()
delete(.activeConn, )
}
return
}
func ( *Server) () error {
var error
for := range .listeners {
if := (*).Close(); != nil && == nil {
=
}
}
return
}
// A ConnState represents the state of a client connection to a server.
// It's used by the optional [Server.ConnState] hook.
type ConnState int
const (
// StateNew represents a new connection that is expected to
// send a request immediately. Connections begin at this
// state and then transition to either StateActive or
// StateClosed.
StateNew ConnState = iota
// StateActive represents a connection that has read 1 or more
// bytes of a request. The Server.ConnState hook for
// StateActive fires before the request has entered a handler
// 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
// cannot be used to do per-request work; ConnState only notes
// the overall state of the connection.
StateActive
// StateIdle represents a connection that has finished
// handling a request and is in the keep-alive state, waiting
// for a new request. Connections transition from StateIdle
// to either StateActive or StateClosed.
StateIdle
// StateHijacked represents a hijacked connection.
// This is a terminal state. It does not transition to StateClosed.
StateHijacked
// StateClosed represents a closed connection.
// This is a terminal state. Hijacked connections do not
// transition to StateClosed.
StateClosed
)
var stateName = map[ConnState]string{
StateNew: "new",
StateActive: "active",
StateIdle: "idle",
StateHijacked: "hijacked",
StateClosed: "closed",
}
func ( ConnState) () string {
return stateName[]
}
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
srv *Server
}
// ServeHTTP should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/erda-project/erda-infra
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname badServeHTTP net/http.serverHandler.ServeHTTP
func ( serverHandler) ( ResponseWriter, *Request) {
:= .srv.Handler
if == nil {
= DefaultServeMux
}
if !.srv.DisableGeneralOptionsHandler && .RequestURI == "*" && .Method == "OPTIONS" {
= globalOptionsHandler{}
}
.ServeHTTP(, )
}
func badServeHTTP(serverHandler, ResponseWriter, *Request)
// AllowQuerySemicolons returns a handler that serves requests by converting any
// unescaped semicolons in the URL query to ampersands, and invoking the handler h.
//
// This restores the pre-Go 1.17 behavior of splitting query parameters on both
// semicolons and ampersands. (See golang.org/issue/25192). Note that this
// behavior doesn't match that of many proxies, and the mismatch can lead to
// security issues.
//
// AllowQuerySemicolons should be invoked before [Request.ParseForm] is called.
func ( Handler) Handler {
return HandlerFunc(func( ResponseWriter, *Request) {
if strings.Contains(.URL.RawQuery, ";") {
:= new(Request)
* = *
.URL = new(url.URL)
*.URL = *.URL
.URL.RawQuery = strings.ReplaceAll(.URL.RawQuery, ";", "&")
.ServeHTTP(, )
} else {
.ServeHTTP(, )
}
})
}
// ListenAndServe listens on the TCP network address s.Addr and then
// calls [Serve] to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If s.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close],
// the returned error is [ErrServerClosed].
func ( *Server) () error {
if .shuttingDown() {
return ErrServerClosed
}
:= .Addr
if == "" {
= ":http"
}
, := net.Listen("tcp", )
if != nil {
return
}
return .Serve()
}
var testHookServerServe func(*Server, net.Listener) // used if non-nil
// shouldConfigureHTTP2ForServe reports whether Server.Serve should configure
// automatic HTTP/2. (which sets up the s.TLSNextProto map)
func ( *Server) () bool {
if .TLSConfig == nil {
// Compatibility with Go 1.6:
// If there's no TLSConfig, it's possible that the user just
// didn't set it on the http.Server, but did pass it to
// tls.NewListener and passed that listener to Serve.
// So we should configure HTTP/2 (to set up s.TLSNextProto)
// in case the listener returns an "h2" *tls.Conn.
return true
}
if .protocols().UnencryptedHTTP2() {
return true
}
// The user specified a TLSConfig on their http.Server.
// In this, case, only configure HTTP/2 if their tls.Config
// explicitly mentions "h2". Otherwise http2.ConfigureServer
// would modify the tls.Config to add it, but they probably already
// passed this tls.Config to tls.NewListener. And if they did,
// it's too late anyway to fix it. It would only be potentially racy.
// See Issue 15908.
return slices.Contains(.TLSConfig.NextProtos, http2NextProtoTLS)
}
// ErrServerClosed is returned by the [Server.Serve], [ServeTLS], [ListenAndServe],
// and [ListenAndServeTLS] methods after a call to [Server.Shutdown] or [Server.Close].
var ErrServerClosed = errors.New("http: Server closed")
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call s.Handler to reply to them.
//
// HTTP/2 support is only enabled if the Listener returns [*tls.Conn]
// connections and they were configured with "h2" in the TLS
// Config.NextProtos.
//
// Serve always returns a non-nil error and closes l.
// After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed].
func ( *Server) ( net.Listener) error {
if := testHookServerServe; != nil {
(, ) // call hook with unwrapped listener
}
:=
= &onceCloseListener{Listener: }
defer .Close()
if := .setupHTTP2_Serve(); != nil {
return
}
if !.trackListener(&, true) {
return ErrServerClosed
}
defer .trackListener(&, false)
:= context.Background()
if .BaseContext != nil {
= .BaseContext()
if == nil {
panic("BaseContext returned a nil context")
}
}
var time.Duration // how long to sleep on accept failure
:= context.WithValue(, ServerContextKey, )
for {
, := .Accept()
if != nil {
if .shuttingDown() {
return ErrServerClosed
}
if , := .(net.Error); && .Temporary() {
if == 0 {
= 5 * time.Millisecond
} else {
*= 2
}
if := 1 * time.Second; > {
=
}
.logf("http: Accept error: %v; retrying in %v", , )
time.Sleep()
continue
}
return
}
:=
if := .ConnContext; != nil {
= (, )
if == nil {
panic("ConnContext returned nil")
}
}
= 0
:= .newConn()
.setState(.rwc, StateNew, runHooks) // before Serve can return
go .serve()
}
}
// ServeTLS accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines perform TLS
// setup and then read requests, calling s.Handler to reply to them.
//
// Files containing a certificate and matching private key for the
// server must be provided if neither the [Server]'s
// TLSConfig.Certificates, TLSConfig.GetCertificate nor
// config.GetConfigForClient are populated.
// If the certificate is signed by a certificate authority, the
// certFile should be the concatenation of the server's certificate,
// any intermediates, and the CA's certificate.
//
// ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the
// returned error is [ErrServerClosed].
func ( *Server) ( net.Listener, , string) error {
// Setup HTTP/2 before s.Serve, to initialize s.TLSConfig
// before we clone it and create the TLS Listener.
if := .setupHTTP2_ServeTLS(); != nil {
return
}
:= cloneTLSConfig(.TLSConfig)
.NextProtos = adjustNextProtos(.NextProtos, .protocols())
:= len(.Certificates) > 0 || .GetCertificate != nil || .GetConfigForClient != nil
if ! || != "" || != "" {
var error
.Certificates = make([]tls.Certificate, 1)
.Certificates[0], = tls.LoadX509KeyPair(, )
if != nil {
return
}
}
:= tls.NewListener(, )
return .Serve()
}
func ( *Server) () Protocols {
if .Protocols != nil {
return *.Protocols // user-configured set
}
// The historic way of disabling HTTP/2 is to set TLSNextProto to
// a non-nil map with no "h2" entry.
, := .TLSNextProto["h2"]
:= .TLSNextProto != nil && !
// If GODEBUG=http2server=0, then HTTP/2 is disabled unless
// the user has manually added an "h2" entry to TLSNextProto
// (probably by using x/net/http2 directly).
if http2server.Value() == "0" && ! {
= true
}
var Protocols
.SetHTTP1(true) // default always includes HTTP/1
if ! {
.SetHTTP2(true)
}
return
}
// adjustNextProtos adds or removes "http/1.1" and "h2" entries from
// a tls.Config.NextProtos list, according to the set of protocols in protos.
func adjustNextProtos( []string, Protocols) []string {
var Protocols
= slices.DeleteFunc(, func( string) bool {
switch {
case "http/1.1":
if !.HTTP1() {
return true
}
.SetHTTP1(true)
case "h2":
if !.HTTP2() {
return true
}
.SetHTTP2(true)
}
return false
})
if .HTTP2() && !.HTTP2() {
= append(, "h2")
}
if .HTTP1() && !.HTTP1() {
= append(, "http/1.1")
}
return
}
// trackListener adds or removes a net.Listener to the set of tracked
// listeners.
//
// We store a pointer to interface in the map set, in case the
// net.Listener is not comparable. This is safe because we only call
// trackListener via Serve and can track+defer untrack the same
// pointer to local variable there. We never need to compare a
// Listener from another caller.
//
// It reports whether the server is still up (not Shutdown or Closed).
func ( *Server) ( *net.Listener, bool) bool {
.mu.Lock()
defer .mu.Unlock()
if .listeners == nil {
.listeners = make(map[*net.Listener]struct{})
}
if {
if .shuttingDown() {
return false
}
.listeners[] = struct{}{}
.listenerGroup.Add(1)
} else {
delete(.listeners, )
.listenerGroup.Done()
}
return true
}
func ( *Server) ( *conn, bool) {
.mu.Lock()
defer .mu.Unlock()
if .activeConn == nil {
.activeConn = make(map[*conn]struct{})
}
if {
.activeConn[] = struct{}{}
} else {
delete(.activeConn, )
}
}
func ( *Server) () time.Duration {
if .IdleTimeout != 0 {
return .IdleTimeout
}
return .ReadTimeout
}
func ( *Server) () time.Duration {
if .ReadHeaderTimeout != 0 {
return .ReadHeaderTimeout
}
return .ReadTimeout
}
func ( *Server) () bool {
return !.disableKeepAlives.Load() && !.shuttingDown()
}
func ( *Server) () bool {
return .inShutdown.Load()
}
// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
// By default, keep-alives are always enabled. Only very
// resource-constrained environments or servers in the process of
// shutting down should disable them.
func ( *Server) ( bool) {
if {
.disableKeepAlives.Store(false)
return
}
.disableKeepAlives.Store(true)
// Close idle HTTP/1 conns:
.closeIdleConns()
// TODO: Issue 26303: close HTTP/2 conns as soon as they become idle.
}
func ( *Server) ( string, ...any) {
if .ErrorLog != nil {
.ErrorLog.Printf(, ...)
} else {
log.Printf(, ...)
}
}
// logf prints to the ErrorLog of the *Server associated with request r
// via ServerContextKey. If there's no associated server, or if ErrorLog
// is nil, logging is done via the log package's standard logger.
func logf( *Request, string, ...any) {
, := .Context().Value(ServerContextKey).(*Server)
if != nil && .ErrorLog != nil {
.ErrorLog.Printf(, ...)
} else {
log.Printf(, ...)
}
}
// ListenAndServe listens on the TCP network address addr and then calls
// [Serve] with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case [DefaultServeMux] is used.
//
// ListenAndServe always returns a non-nil error.
func ( string, Handler) error {
:= &Server{Addr: , Handler: }
return .ListenAndServe()
}
// ListenAndServeTLS acts identically to [ListenAndServe], except that it
// expects HTTPS connections. Additionally, files containing a certificate and
// matching private key for the server must be provided. If the certificate
// is signed by a certificate authority, the certFile should be the concatenation
// of the server's certificate, any intermediates, and the CA's certificate.
func (, , string, Handler) error {
:= &Server{Addr: , Handler: }
return .ListenAndServeTLS(, )
}
// ListenAndServeTLS listens on the TCP network address s.Addr and
// then calls [ServeTLS] 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 neither the [Server]'s TLSConfig.Certificates
// nor TLSConfig.GetCertificate are populated. If the certificate is
// signed by a certificate authority, the certFile should be the
// concatenation of the server's certificate, any intermediates, and
// the CA's certificate.
//
// If s.Addr is blank, ":https" is used.
//
// ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or
// [Server.Close], the returned error is [ErrServerClosed].
func ( *Server) (, string) error {
if .shuttingDown() {
return ErrServerClosed
}
:= .Addr
if == "" {
= ":https"
}
, := net.Listen("tcp", )
if != nil {
return
}
defer .Close()
return .ServeTLS(, , )
}
// setupHTTP2_ServeTLS conditionally configures HTTP/2 on
// s and reports whether there was an error setting it up. If it is
// not configured for policy reasons, nil is returned.
func ( *Server) () error {
.nextProtoOnce.Do(.onceSetNextProtoDefaults)
return .nextProtoErr
}
// setupHTTP2_Serve is called from (*Server).Serve and conditionally
// configures HTTP/2 on s using a more conservative policy than
// setupHTTP2_ServeTLS because Serve is called after tls.Listen,
// and may be called concurrently. See shouldConfigureHTTP2ForServe.
//
// The tests named TestTransportAutomaticHTTP2* and
// TestConcurrentServerServe in server_test.go demonstrate some
// of the supported use cases and motivations.
func ( *Server) () error {
.nextProtoOnce.Do(.onceSetNextProtoDefaults_Serve)
return .nextProtoErr
}
func ( *Server) () {
if .shouldConfigureHTTP2ForServe() {
.onceSetNextProtoDefaults()
}
}
var http2server = godebug.New("http2server")
// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
// configured otherwise. (by setting s.TLSNextProto non-nil)
// It must only be called via s.nextProtoOnce (use s.setupHTTP2_*).
func ( *Server) () {
if omitBundledHTTP2 {
return
}
:= .protocols()
if !.HTTP2() && !.UnencryptedHTTP2() {
return
}
if http2server.Value() == "0" {
http2server.IncNonDefault()
return
}
if , := .TLSNextProto["h2"]; {
// TLSNextProto already contains an HTTP/2 implementation.
// The user probably called golang.org/x/net/http2.ConfigureServer
// to add it.
return
}
:= &http2Server{}
.nextProtoErr = http2ConfigureServer(, )
}
// 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
// call runs for longer than its time limit, the handler responds with
// a 503 Service Unavailable error and the given message in its body.
// (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 supports the [Pusher] interface but does not support
// the [Hijacker] or [Flusher] interfaces.
func ( Handler, time.Duration, string) Handler {
return &timeoutHandler{
handler: ,
body: ,
dt: ,
}
}
// ErrHandlerTimeout is returned on [ResponseWriter] Write calls
// in handlers which have timed out.
var ErrHandlerTimeout = errors.New("http: Handler timeout")
type timeoutHandler struct {
handler Handler
body string
dt time.Duration
// When set, no context will be created and this context will
// be used instead.
testContext context.Context
}
func ( *timeoutHandler) () string {
if .body != "" {
return .body
}
return "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>"
}
func ( *timeoutHandler) ( ResponseWriter, *Request) {
:= .testContext
if == nil {
var context.CancelFunc
, = context.WithTimeout(.Context(), .dt)
defer ()
}
= .WithContext()
:= make(chan struct{})
:= &timeoutWriter{
w: ,
h: make(Header),
req: ,
}
:= make(chan any, 1)
go func() {
defer func() {
if := recover(); != nil {
<-
}
}()
.handler.ServeHTTP(, )
close()
}()
select {
case := <-:
panic()
case <-:
.mu.Lock()
defer .mu.Unlock()
:= .Header()
maps.Copy(, .h)
if !.wroteHeader {
.code = StatusOK
}
.WriteHeader(.code)
.Write(.wbuf.Bytes())
case <-.Done():
.mu.Lock()
defer .mu.Unlock()
switch := .Err(); {
case context.DeadlineExceeded:
.WriteHeader(StatusServiceUnavailable)
io.WriteString(, .errorBody())
.err = ErrHandlerTimeout
default:
.WriteHeader(StatusServiceUnavailable)
.err =
}
}
}
type timeoutWriter struct {
w ResponseWriter
h Header
wbuf bytes.Buffer
req *Request
mu sync.Mutex
err error
wroteHeader bool
code int
}
var _ Pusher = (*timeoutWriter)(nil)
// Push implements the [Pusher] interface.
func ( *timeoutWriter) ( string, *PushOptions) error {
if , := .w.(Pusher); {
return .Push(, )
}
return ErrNotSupported
}
func ( *timeoutWriter) () Header { return .h }
func ( *timeoutWriter) ( []byte) (int, error) {
.mu.Lock()
defer .mu.Unlock()
if .err != nil {
return 0, .err
}
if !.wroteHeader {
.writeHeaderLocked(StatusOK)
}
return .wbuf.Write()
}
func ( *timeoutWriter) ( int) {
checkWriteHeaderCode()
switch {
case .err != nil:
return
case .wroteHeader:
if .req != nil {
:= relevantCaller()
logf(.req, "http: superfluous response.WriteHeader call from %s (%s:%d)", .Function, path.Base(.File), .Line)
}
default:
.wroteHeader = true
.code =
}
}
func ( *timeoutWriter) ( int) {
.mu.Lock()
defer .mu.Unlock()
.writeHeaderLocked()
}
// onceCloseListener wraps a net.Listener, protecting it from
// multiple Close calls.
type onceCloseListener struct {
net.Listener
once sync.Once
closeErr error
}
func ( *onceCloseListener) () error {
.once.Do(.close)
return .closeErr
}
func ( *onceCloseListener) () { .closeErr = .Listener.Close() }
// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}
func (globalOptionsHandler) ( ResponseWriter, *Request) {
.Header().Set("Content-Length", "0")
if .ContentLength != 0 {
// Read up to 4KB of OPTIONS body (as mentioned in the
// spec as being reserved for future use), but anything
// over that is considered a waste of server resources
// (or an attack) and we abort and close the connection,
// courtesy of MaxBytesReader's EOF behavior.
:= MaxBytesReader(, .Body, 4<<10)
io.Copy(io.Discard, )
}
}
// initALPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
// Requests come from ALPN protocol handlers.
type initALPNRequest struct {
ctx context.Context
c *tls.Conn
h serverHandler
}
// BaseContext is an exported but unadvertised [http.Handler] method
// recognized by x/net/http2 to pass down a context; the TLSNextProto
// API predates context support so we shoehorn through the only
// interface we have available.
func ( initALPNRequest) () context.Context { return .ctx }
func ( initALPNRequest) ( ResponseWriter, *Request) {
if .TLS == nil {
.TLS = &tls.ConnectionState{}
*.TLS = .c.ConnectionState()
}
if .Body == nil {
.Body = NoBody
}
if .RemoteAddr == "" {
.RemoteAddr = .c.RemoteAddr().String()
}
.h.ServeHTTP(, )
}
// loggingConn is used for debugging.
type loggingConn struct {
name string
net.Conn
}
var (
uniqNameMu sync.Mutex
uniqNameNext = make(map[string]int)
)
func newLoggingConn( string, net.Conn) net.Conn {
uniqNameMu.Lock()
defer uniqNameMu.Unlock()
uniqNameNext[]++
return &loggingConn{
name: fmt.Sprintf("%s-%d", , uniqNameNext[]),
Conn: ,
}
}
func ( *loggingConn) ( []byte) ( int, error) {
log.Printf("%s.Write(%d) = ....", .name, len())
, = .Conn.Write()
log.Printf("%s.Write(%d) = %d, %v", .name, len(), , )
return
}
func ( *loggingConn) ( []byte) ( int, error) {
log.Printf("%s.Read(%d) = ....", .name, len())
, = .Conn.Read()
log.Printf("%s.Read(%d) = %d, %v", .name, len(), , )
return
}
func ( *loggingConn) () ( error) {
log.Printf("%s.Close() = ...", .name)
= .Conn.Close()
log.Printf("%s.Close() = %v", .name, )
return
}
// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr.
// It only contains one field (and a pointer field at that), so it
// fits in an interface value without an extra allocation.
type checkConnErrorWriter struct {
c *conn
}
func ( checkConnErrorWriter) ( []byte) ( int, error) {
, = .c.rwc.Write()
if != nil && .c.werr == nil {
.c.werr =
.c.cancelCtx()
}
return
}
func numLeadingCRorLF( []byte) ( int) {
for , := range {
if == '\r' || == '\n' {
++
continue
}
break
}
return
}
// tlsRecordHeaderLooksLikeHTTP reports whether a TLS record header
// looks like it might've been a misdirected plaintext HTTP request.
func tlsRecordHeaderLooksLikeHTTP( [5]byte) bool {
switch string([:]) {
case "GET /", "HEAD ", "POST ", "PUT /", "OPTIO":
return true
}
return false
}
// MaxBytesHandler returns a [Handler] that runs h with its [ResponseWriter] and [Request.Body] wrapped by a MaxBytesReader.
func ( Handler, int64) Handler {
return HandlerFunc(func( ResponseWriter, *Request) {
:= *
.Body = MaxBytesReader(, .Body, )
.ServeHTTP(, &)
})
}
The pages are generated with Golds v0.7.3. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |