package fasthttpimport ()var errNoCertOrKeyProvided = errors.New("cert or key has not provided")// Deprecated: ErrAlreadyServing is never returned from Serve. See issue #633.varErrAlreadyServing = errors.New("Server is already serving connections")// ServeConn serves HTTP requests from the given connection// using the given handler.//// ServeConn returns nil if all requests from the c are successfully served.// It returns non-nil error otherwise.//// Connection c must immediately propagate all the data passed to Write()// to the client. Otherwise requests' processing may hang.//// ServeConn closes c before returning.func ( net.Conn, RequestHandler) error { := serverPool.Get()if == nil { = &Server{} } := .(*Server) .Handler = := .ServeConn() .Handler = nilserverPool.Put()return}var serverPool sync.Pool// Serve serves incoming connections from the given listener// using the given handler.//// Serve blocks until the given listener returns permanent error.func ( net.Listener, RequestHandler) error { := &Server{Handler: , }return .Serve()}// ServeTLS serves HTTPS requests from the given net.Listener// using the given handler.//// certFile and keyFile are paths to TLS certificate and key files.func ( net.Listener, , string, RequestHandler) error { := &Server{Handler: , }return .ServeTLS(, , )}// ServeTLSEmbed serves HTTPS requests from the given net.Listener// using the given handler.//// certData and keyData must contain valid TLS certificate and key data.func ( net.Listener, , []byte, RequestHandler) error { := &Server{Handler: , }return .ServeTLSEmbed(, , )}// ListenAndServe serves HTTP requests from the given TCP addr// using the given handler.func ( string, RequestHandler) error { := &Server{Handler: , }return .ListenAndServe()}// ListenAndServeUNIX serves HTTP requests from the given UNIX addr// using the given handler.//// The function deletes existing file at addr before starting serving.//// The server sets the given file mode for the UNIX addr.func ( string, os.FileMode, RequestHandler) error { := &Server{Handler: , }return .ListenAndServeUNIX(, )}// ListenAndServeTLS serves HTTPS requests from the given TCP addr// using the given handler.//// certFile and keyFile are paths to TLS certificate and key files.func (, , string, RequestHandler) error { := &Server{Handler: , }return .ListenAndServeTLS(, , )}// ListenAndServeTLSEmbed serves HTTPS requests from the given TCP addr// using the given handler.//// certData and keyData must contain valid TLS certificate and key data.func ( string, , []byte, RequestHandler) error { := &Server{Handler: , }return .ListenAndServeTLSEmbed(, , )}// RequestHandler must process incoming requests.//// RequestHandler must call ctx.TimeoutError() before returning// if it keeps references to ctx and/or its members after the return.// Consider wrapping RequestHandler into TimeoutHandler if response time// must be limited.typeRequestHandlerfunc(ctx *RequestCtx)// ServeHandler must process tls.Config.NextProto negotiated requests.typeServeHandlerfunc(c net.Conn) error// Server implements HTTP server.//// Default Server settings should satisfy the majority of Server users.// Adjust Server settings only if you really understand the consequences.//// It is forbidden copying Server instances. Create new Server instances// instead.//// It is safe to call Server methods from concurrently running goroutines.typeServerstruct { noCopy noCopy// Handler for processing incoming requests. // // Take into account that no `panic` recovery is done by `fasthttp` (thus any `panic` will take down the entire server). // Instead the user should use `recover` to handle these situations. Handler RequestHandler// ErrorHandler for returning a response in case of an error while receiving or parsing the request. // // The following is a non-exhaustive list of errors that can be expected as argument: // * io.EOF // * io.ErrUnexpectedEOF // * ErrGetOnly // * ErrSmallBuffer // * ErrBodyTooLarge // * ErrBrokenChunks ErrorHandler func(ctx *RequestCtx, err error)// HeaderReceived is called after receiving the header // // non zero RequestConfig field values will overwrite the default configs HeaderReceived func(header *RequestHeader) RequestConfig// ContinueHandler is called after receiving the Expect 100 Continue Header // // https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.1 // Using ContinueHandler a server can make decisioning on whether or not // to read a potentially large request body based on the headers // // The default is to automatically read request bodies of Expect 100 Continue requests // like they are normal requests ContinueHandler func(header *RequestHeader) bool// Server name for sending in response headers. // // Default server name is used if left blank. Name string// The maximum number of concurrent connections the server may serve. // // DefaultConcurrency is used if not set. // // Concurrency only works if you either call Serve once, or only ServeConn multiple times. // It works with ListenAndServe as well. Concurrency int// Per-connection buffer size for requests' reading. // This also limits the maximum header size. // // Increase this buffer if your clients send multi-KB RequestURIs // and/or multi-KB headers (for example, BIG cookies). // // Default buffer size is used if not set. ReadBufferSize int// Per-connection buffer size for responses' writing. // // Default buffer size is used if not set. WriteBufferSize int// ReadTimeout is the amount of time allowed to read // the full request including body. The connection's read // deadline is reset when the connection opens, or for // keep-alive connections after the first byte has been read. // // By default request read timeout is unlimited. ReadTimeout time.Duration// WriteTimeout is the maximum duration before timing out // writes of the response. It is reset after the request handler // has returned. // // By default response write timeout is unlimited. WriteTimeout time.Duration// IdleTimeout is the maximum amount of time to wait for the // next request when keep-alive is enabled. If IdleTimeout // is zero, the value of ReadTimeout is used. IdleTimeout time.Duration// Maximum number of concurrent client connections allowed per IP. // // By default unlimited number of concurrent connections // may be established to the server from a single IP address. MaxConnsPerIP int// Maximum number of requests served per connection. // // The server closes connection after the last request. // 'Connection: close' header is added to the last response. // // By default unlimited number of requests may be served per connection. MaxRequestsPerConn int// MaxKeepaliveDuration is a no-op and only left here for backwards compatibility. // Deprecated: Use IdleTimeout instead. MaxKeepaliveDuration time.Duration// MaxIdleWorkerDuration is the maximum idle time of a single worker in the underlying // worker pool of the Server. Idle workers beyond this time will be cleared. MaxIdleWorkerDuration time.Duration// Period between tcp keep-alive messages. // // TCP keep-alive period is determined by operation system by default. TCPKeepalivePeriod time.Duration// Maximum request body size. // // The server rejects requests with bodies exceeding this limit. // // Request body size is limited by DefaultMaxRequestBodySize by default. MaxRequestBodySize int// Whether to disable keep-alive connections. // // The server will close all the incoming connections after sending // the first response to client if this option is set to true. // // By default keep-alive connections are enabled. DisableKeepalive bool// Whether to enable tcp keep-alive connections. // // Whether the operating system should send tcp keep-alive messages on the tcp connection. // // By default tcp keep-alive connections are disabled. TCPKeepalive bool// Aggressively reduces memory usage at the cost of higher CPU usage // if set to true. // // Try enabling this option only if the server consumes too much memory // serving mostly idle keep-alive connections. This may reduce memory // usage by more than 50%. // // Aggressive memory usage reduction is disabled by default. ReduceMemoryUsage bool// Rejects all non-GET requests if set to true. // // This option is useful as anti-DoS protection for servers // accepting only GET requests and HEAD requests. The request size is limited // by ReadBufferSize if GetOnly is set. // // Server accepts all the requests by default. GetOnly bool// Will not pre parse Multipart Form data if set to true. // // This option is useful for servers that desire to treat // multipart form data as a binary blob, or choose when to parse the data. // // Server pre parses multipart form data by default. DisablePreParseMultipartForm bool// Logs all errors, including the most frequent // 'connection reset by peer', 'broken pipe' and 'connection timeout' // errors. Such errors are common in production serving real-world // clients. // // By default the most frequent errors such as // 'connection reset by peer', 'broken pipe' and 'connection timeout' // are suppressed in order to limit output log traffic. LogAllErrors bool// Will not log potentially sensitive content in error logs // // This option is useful for servers that handle sensitive data // in the request/response. // // Server logs all full errors by default. SecureErrorLogMessage bool// Header names are passed as-is without normalization // if this option is set. // // Disabled header names' normalization may be useful only for proxying // incoming requests to other servers expecting case-sensitive // header names. See https://github.com/valyala/fasthttp/issues/57 // for details. // // By default request and response header names are normalized, i.e. // The first letter and the first letters following dashes // are uppercased, while all the other letters are lowercased. // Examples: // // * HOST -> Host // * content-type -> Content-Type // * cONTENT-lenGTH -> Content-Length DisableHeaderNamesNormalizing bool// SleepWhenConcurrencyLimitsExceeded is a duration to be slept of if // the concurrency limit in exceeded (default [when is 0]: don't sleep // and accept new connections immediately). SleepWhenConcurrencyLimitsExceeded time.Duration// NoDefaultServerHeader, when set to true, causes the default Server header // to be excluded from the Response. // // The default Server header value is the value of the Name field or an // internal default value in its absence. With this option set to true, // the only time a Server header will be sent is if a non-zero length // value is explicitly provided during a request. NoDefaultServerHeader bool// NoDefaultDate, when set to true, causes the default Date // header to be excluded from the Response. // // The default Date header value is the current date value. When // set to true, the Date will not be present. NoDefaultDate bool// NoDefaultContentType, when set to true, causes the default Content-Type // header to be excluded from the Response. // // The default Content-Type header value is the internal default value. When // set to true, the Content-Type will not be present. NoDefaultContentType bool// KeepHijackedConns is an opt-in disable of connection // close by fasthttp after connections' HijackHandler returns. // This allows to save goroutines, e.g. when fasthttp used to upgrade // http connections to WS and connection goes to another handler, // which will close it when needed. KeepHijackedConns bool// CloseOnShutdown when true adds a `Connection: close` header when the server is shutting down. CloseOnShutdown bool// StreamRequestBody enables request body streaming, // and calls the handler sooner when given body is // larger than the current limit. StreamRequestBody bool// 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)// Logger, which is used by RequestCtx.Logger(). // // By default standard logger from log package is used. Logger Logger// TLSConfig optionally provides a TLS configuration for use // by ServeTLS, ServeTLSEmbed, ListenAndServeTLS, ListenAndServeTLSEmbed, // AppendCert, AppendCertEmbed and NextProto. // // Note that this value is cloned by ServeTLS, ServeTLSEmbed, ListenAndServeTLS // and ListenAndServeTLSEmbed, 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// FormValueFunc, which is used by RequestCtx.FormValue and support for customizing // the behaviour of the RequestCtx.FormValue function. // // NetHttpFormValueFunc gives a FormValueFunc func implementation that is consistent with net/http. FormValueFunc FormValueFunc nextProtos map[string]ServeHandler concurrency uint32 concurrencyCh chanstruct{} perIPConnCounter perIPConnCounter ctxPool sync.Pool readerPool sync.Pool writerPool sync.Pool hijackConnPool sync.Pool// We need to know our listeners and idle connections so we can close them in Shutdown(). ln []net.Listener idleConns map[net.Conn]time.Time idleConnsMu sync.Mutex mu sync.Mutex open int32 stop int32 done chanstruct{}}// TimeoutHandler creates RequestHandler, which returns StatusRequestTimeout// error with the given msg to the client if h didn't return during// the given duration.//// The returned handler may return StatusTooManyRequests error with the given// msg to the client if there are more than Server.Concurrency concurrent// handlers h are running at the moment.func ( RequestHandler, time.Duration, string) RequestHandler {returnTimeoutWithCodeHandler(, , , StatusRequestTimeout)}// TimeoutWithCodeHandler creates RequestHandler, which returns an error with// the given msg and status code to the client if h didn't return during// the given duration.//// The returned handler may return StatusTooManyRequests error with the given// msg to the client if there are more than Server.Concurrency concurrent// handlers h are running at the moment.func ( RequestHandler, time.Duration, string, int) RequestHandler {if <= 0 {return }returnfunc( *RequestCtx) { := .s.concurrencyChselect {case<-struct{}{}:default: .Error(, StatusTooManyRequests)return } := .timeoutChif == nil { = make(chanstruct{}, 1) .timeoutCh = }gofunc() { () <- struct{}{} <- }() .timeoutTimer = initTimer(.timeoutTimer, )select {case<-:case<-.timeoutTimer.C: .TimeoutErrorWithCode(, ) }stopTimer(.timeoutTimer) }}// RequestConfig configure the per request deadline and body limitstypeRequestConfigstruct {// ReadTimeout is the maximum duration for reading the entire // request body. // a zero value means that default values will be honored ReadTimeout time.Duration// WriteTimeout is the maximum duration before timing out // writes of the response. // a zero value means that default values will be honored WriteTimeout time.Duration// Maximum request body size. // a zero value means that default values will be honored MaxRequestBodySize int}// CompressHandler returns RequestHandler that transparently compresses// response body generated by h if the request contains 'gzip' or 'deflate'// 'Accept-Encoding' header.func ( RequestHandler) RequestHandler {returnCompressHandlerLevel(, CompressDefaultCompression)}// CompressHandlerLevel returns RequestHandler that transparently compresses// response body generated by h if the request contains a 'gzip' or 'deflate'// 'Accept-Encoding' header.//// Level is the desired compression level://// - CompressNoCompression// - CompressBestSpeed// - CompressBestCompression// - CompressDefaultCompression// - CompressHuffmanOnlyfunc ( RequestHandler, int) RequestHandler {returnfunc( *RequestCtx) { ()if .Request.Header.HasAcceptEncodingBytes(strGzip) { .Response.gzipBody() //nolint:errcheck } elseif .Request.Header.HasAcceptEncodingBytes(strDeflate) { .Response.deflateBody() //nolint:errcheck } }}// CompressHandlerBrotliLevel returns RequestHandler that transparently compresses// response body generated by h if the request contains a 'br', 'gzip' or 'deflate'// 'Accept-Encoding' header.//// brotliLevel is the desired compression level for brotli.//// - CompressBrotliNoCompression// - CompressBrotliBestSpeed// - CompressBrotliBestCompression// - CompressBrotliDefaultCompression//// otherLevel is the desired compression level for gzip and deflate.//// - CompressNoCompression// - CompressBestSpeed// - CompressBestCompression// - CompressDefaultCompression// - CompressHuffmanOnlyfunc ( RequestHandler, , int) RequestHandler {returnfunc( *RequestCtx) { ()switch {case .Request.Header.HasAcceptEncodingBytes(strBr): .Response.brotliBody() //nolint:errcheckcase .Request.Header.HasAcceptEncodingBytes(strGzip): .Response.gzipBody() //nolint:errcheckcase .Request.Header.HasAcceptEncodingBytes(strDeflate): .Response.deflateBody() //nolint:errcheck } }}// RequestCtx contains incoming request and manages outgoing response.//// It is forbidden copying RequestCtx instances.//// RequestHandler should avoid holding references to incoming RequestCtx and/or// its members after the return.// If holding RequestCtx references after the return is unavoidable// (for instance, ctx is passed to a separate goroutine and ctx lifetime cannot// be controlled), then the RequestHandler MUST call ctx.TimeoutError()// before return.//// It is unsafe modifying/reading RequestCtx instance from concurrently// running goroutines. The only exception is TimeoutError*, which may be called// while other goroutines accessing RequestCtx.typeRequestCtxstruct { noCopy noCopy// Incoming request. // // Copying Request by value is forbidden. Use pointer to Request instead. Request Request// Outgoing response. // // Copying Response by value is forbidden. Use pointer to Response instead. Response Response userValues userData connID uint64 connRequestNum uint64 connTime time.Time remoteAddr net.Addr time time.Time logger ctxLogger s *Server c net.Conn fbr firstByteReader timeoutResponse *Response timeoutCh chanstruct{} timeoutTimer *time.Timer hijackHandler HijackHandler hijackNoResponse bool formValueFunc FormValueFunc}// HijackHandler must process the hijacked connection c.//// If KeepHijackedConns is disabled, which is by default,// the connection c is automatically closed after returning from HijackHandler.//// The connection c must not be used after returning from the handler, if KeepHijackedConns is disabled.//// When KeepHijackedConns enabled, fasthttp will not Close() the connection,// you must do it when you need it. You must not use c in any way after calling Close().typeHijackHandlerfunc(c net.Conn)// Hijack registers the given handler for connection hijacking.//// The handler is called after returning from RequestHandler// and sending http response. The current connection is passed// to the handler. The connection is automatically closed after// returning from the handler.//// The server skips calling the handler in the following cases://// - 'Connection: close' header exists in either request or response.// - Unexpected error during response writing to the connection.//// The server stops processing requests from hijacked connections.//// Server limits such as Concurrency, ReadTimeout, WriteTimeout, etc.// aren't applied to hijacked connections.//// The handler must not retain references to ctx members.//// Arbitrary 'Connection: Upgrade' protocols may be implemented// with HijackHandler. For instance,//// - WebSocket ( https://en.wikipedia.org/wiki/WebSocket )// - HTTP/2.0 ( https://en.wikipedia.org/wiki/HTTP/2 )func ( *RequestCtx) ( HijackHandler) { .hijackHandler = }// HijackSetNoResponse changes the behavior of hijacking a request.// If HijackSetNoResponse is called with false fasthttp will send a response// to the client before calling the HijackHandler (default). If HijackSetNoResponse// is called with true no response is send back before calling the// HijackHandler supplied in the Hijack function.func ( *RequestCtx) ( bool) { .hijackNoResponse = }// Hijacked returns true after Hijack is called.func ( *RequestCtx) () bool {return .hijackHandler != nil}// SetUserValue stores the given value (arbitrary object)// under the given key in ctx.//// The value stored in ctx may be obtained by UserValue*.//// This functionality may be useful for passing arbitrary values between// functions involved in request processing.//// All the values are removed from ctx after returning from the top// RequestHandler. Additionally, Close method is called on each value// implementing io.Closer before removing the value from ctx.func ( *RequestCtx) ( interface{}, interface{}) { .userValues.Set(, )}// SetUserValueBytes stores the given value (arbitrary object)// under the given key in ctx.//// The value stored in ctx may be obtained by UserValue*.//// This functionality may be useful for passing arbitrary values between// functions involved in request processing.//// All the values stored in ctx are deleted after returning from RequestHandler.func ( *RequestCtx) ( []byte, interface{}) { .userValues.SetBytes(, )}// UserValue returns the value stored via SetUserValue* under the given key.func ( *RequestCtx) ( interface{}) interface{} {return .userValues.Get()}// UserValueBytes returns the value stored via SetUserValue*// under the given key.func ( *RequestCtx) ( []byte) interface{} {return .userValues.GetBytes()}// VisitUserValues calls visitor for each existing userValue with a key that is a string or []byte.//// visitor must not retain references to key and value after returning.// Make key and/or value copies if you need storing them after returning.func ( *RequestCtx) ( func([]byte, interface{})) {for , := 0, len(.userValues); < ; ++ { := &.userValues[]if , := .key.(string); { (s2b(.key.(string)), .value) } }}// VisitUserValuesAll calls visitor for each existing userValue.//// visitor must not retain references to key and value after returning.// Make key and/or value copies if you need storing them after returning.func ( *RequestCtx) ( func(interface{}, interface{})) {for , := 0, len(.userValues); < ; ++ { := &.userValues[] (.key, .value) }}// ResetUserValues allows to reset user values from Request Contextfunc ( *RequestCtx) () { .userValues.Reset()}// RemoveUserValue removes the given key and the value under it in ctx.func ( *RequestCtx) ( interface{}) { .userValues.Remove()}// RemoveUserValueBytes removes the given key and the value under it in ctx.func ( *RequestCtx) ( []byte) { .userValues.RemoveBytes()}type connTLSer interface { Handshake() error ConnectionState() tls.ConnectionState}// IsTLS returns true if the underlying connection is tls.Conn.//// tls.Conn is an encrypted connection (aka SSL, HTTPS).func ( *RequestCtx) () bool {// cast to (connTLSer) instead of (*tls.Conn), since it catches // cases with overridden tls.Conn such as: // // type customConn struct { // *tls.Conn // // // other custom fields here // }// perIPConn wraps the net.Conn in the Conn fieldif , := .c.(*perIPConn); { , := .Conn.(connTLSer)return } , := .c.(connTLSer)return}// TLSConnectionState returns TLS connection state.//// The function returns nil if the underlying connection isn't tls.Conn.//// The returned state may be used for verifying TLS version, client certificates,// etc.func ( *RequestCtx) () *tls.ConnectionState { , := .c.(connTLSer)if ! {returnnil } := .ConnectionState()return &}// Conn returns a reference to the underlying net.Conn.//// WARNING: Only use this method if you know what you are doing!//// Reading from or writing to the returned connection will end badly!func ( *RequestCtx) () net.Conn {return .c}func ( *RequestCtx) () { .userValues.Reset() .Request.Reset() .Response.Reset() .fbr.reset() .connID = 0 .connRequestNum = 0 .connTime = zeroTime .remoteAddr = nil .time = zeroTime .c = nil// Don't reset ctx.s! // We have a pool per server so the next time this ctx is used it // will be assigned the same value again. // ctx might still be in use for context.Done() and context.Err() // which are safe to use as they only use ctx.s and no other value.if .timeoutResponse != nil { .timeoutResponse.Reset() }if .timeoutTimer != nil {stopTimer(.timeoutTimer) } .hijackHandler = nil .hijackNoResponse = false}type firstByteReader struct { c net.Conn ch byte byteRead bool}func ( *firstByteReader) () { .c = nil .ch = 0 .byteRead = false}func ( *firstByteReader) ( []byte) (int, error) {iflen() == 0 {return0, nil } := 0if !.byteRead { [0] = .ch = [1:] .byteRead = true = 1 } , := .c.Read()return + , }// Logger is used for logging formatted messages.typeLoggerinterface {// Printf must have the same semantics as log.Printf.Printf(format string, args ...interface{})}var ctxLoggerLock sync.Mutextype ctxLogger struct { ctx *RequestCtx logger Logger}func ( *ctxLogger) ( string, ...interface{}) { := fmt.Sprintf(, ...)ctxLoggerLock.Lock() .logger.Printf("%.3f %s - %s", time.Since(.ctx.ConnTime()).Seconds(), .ctx.String(), )ctxLoggerLock.Unlock()}var zeroTCPAddr = &net.TCPAddr{IP: net.IPv4zero,}// String returns unique string representation of the ctx.//// The returned value may be useful for logging.func ( *RequestCtx) () string {returnfmt.Sprintf("#%016X - %s<->%s - %s %s", .ID(), .LocalAddr(), .RemoteAddr(), .Request.Header.Method(), .URI().FullURI())}// ID returns unique ID of the request.func ( *RequestCtx) () uint64 {return (.connID << 32) | .connRequestNum}// ConnID returns unique connection ID.//// This ID may be used to match distinct requests to the same incoming// connection.func ( *RequestCtx) () uint64 {return .connID}// Time returns RequestHandler call time.func ( *RequestCtx) () time.Time {return .time}// ConnTime returns the time the server started serving the connection// the current request came from.func ( *RequestCtx) () time.Time {return .connTime}// ConnRequestNum returns request sequence number// for the current connection.//// Sequence starts with 1.func ( *RequestCtx) () uint64 {return .connRequestNum}// SetConnectionClose sets 'Connection: close' response header and closes// connection after the RequestHandler returns.func ( *RequestCtx) () { .Response.SetConnectionClose()}// SetStatusCode sets response status code.func ( *RequestCtx) ( int) { .Response.SetStatusCode()}// SetContentType sets response Content-Type.func ( *RequestCtx) ( string) { .Response.Header.SetContentType()}// SetContentTypeBytes sets response Content-Type.//// It is safe modifying contentType buffer after function return.func ( *RequestCtx) ( []byte) { .Response.Header.SetContentTypeBytes()}// RequestURI returns RequestURI.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .Request.Header.RequestURI()}// URI returns requested uri.//// This uri is valid until your request handler returns.func ( *RequestCtx) () *URI {return .Request.URI()}// Referer returns request referer.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .Request.Header.Referer()}// UserAgent returns User-Agent header value from the request.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .Request.Header.UserAgent()}// Path returns requested path.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .URI().Path()}// Host returns requested host.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .URI().Host()}// QueryArgs returns query arguments from RequestURI.//// It doesn't return POST'ed arguments - use PostArgs() for this.//// See also PostArgs, FormValue and FormFile.//// These args are valid until your request handler returns.func ( *RequestCtx) () *Args {return .URI().QueryArgs()}// PostArgs returns POST arguments.//// It doesn't return query arguments from RequestURI - use QueryArgs for this.//// See also QueryArgs, FormValue and FormFile.//// These args are valid until your request handler returns.func ( *RequestCtx) () *Args {return .Request.PostArgs()}// MultipartForm returns request's multipart form.//// Returns ErrNoMultipartForm if request's content-type// isn't 'multipart/form-data'.//// All uploaded temporary files are automatically deleted after// returning from RequestHandler. Either move or copy uploaded files// into new place if you want retaining them.//// Use SaveMultipartFile function for permanently saving uploaded file.//// The returned form is valid until your request handler returns.//// See also FormFile and FormValue.func ( *RequestCtx) () (*multipart.Form, error) {return .Request.MultipartForm()}// FormFile returns uploaded file associated with the given multipart form key.//// The file is automatically deleted after returning from RequestHandler,// so either move or copy uploaded file into new place if you want retaining it.//// Use SaveMultipartFile function for permanently saving uploaded file.//// The returned file header is valid until your request handler returns.func ( *RequestCtx) ( string) (*multipart.FileHeader, error) { , := .MultipartForm()if != nil {returnnil, }if .File == nil {returnnil, } := .File[]if == nil {returnnil, ErrMissingFile }return [0], nil}// ErrMissingFile may be returned from FormFile when the is no uploaded file// associated with the given multipart form key.varErrMissingFile = errors.New("there is no uploaded file associated with the given key")// SaveMultipartFile saves multipart file fh under the given filename path.func ( *multipart.FileHeader, string) ( error) {var (multipart.File *os.File ) , = .Open()if != nil {return }varboolif , = .(*os.File); {// Windows can't rename files that are opened.if = .Close(); != nil {return }// If renaming fails we try the normal copying method. // Renaming could fail if the files are on different devices.ifos.Rename(.Name(), ) == nil {returnnil }// Reopen f for the code below.if , = .Open(); != nil {return } }deferfunc() { := .Close()if == nil { = } }()if , = os.Create(); != nil {return }deferfunc() { := .Close()if == nil { = } }() _, = copyZeroAlloc(, )return}// FormValue returns form value associated with the given key.//// The value is searched in the following places://// - Query string.// - POST or PUT body.//// There are more fine-grained methods for obtaining form values://// - QueryArgs for obtaining values from query string.// - PostArgs for obtaining values from POST or PUT body.// - MultipartForm for obtaining values from multipart form.// - FormFile for obtaining uploaded files.//// The returned value is valid until your request handler returns.func ( *RequestCtx) ( string) []byte {if .formValueFunc != nil {return .formValueFunc(, ) }returndefaultFormValue(, )}typeFormValueFuncfunc(*RequestCtx, string) []bytevar ( defaultFormValue = func( *RequestCtx, string) []byte { := .QueryArgs().Peek()iflen() > 0 {return } = .PostArgs().Peek()iflen() > 0 {return } , := .MultipartForm()if == nil && .Value != nil { := .Value[]iflen() > 0 {return []byte([0]) } }returnnil }// NetHttpFormValueFunc gives consistent behavior with net/http. POST and PUT body parameters take precedence over URL query string values.NetHttpFormValueFunc = func( *RequestCtx, string) []byte { := .PostArgs().Peek()iflen() > 0 {return } , := .MultipartForm()if == nil && .Value != nil { := .Value[]iflen() > 0 {return []byte([0]) } } = .QueryArgs().Peek()iflen() > 0 {return }returnnil })// IsGet returns true if request method is GET.func ( *RequestCtx) () bool {return .Request.Header.IsGet()}// IsPost returns true if request method is POST.func ( *RequestCtx) () bool {return .Request.Header.IsPost()}// IsPut returns true if request method is PUT.func ( *RequestCtx) () bool {return .Request.Header.IsPut()}// IsDelete returns true if request method is DELETE.func ( *RequestCtx) () bool {return .Request.Header.IsDelete()}// IsConnect returns true if request method is CONNECT.func ( *RequestCtx) () bool {return .Request.Header.IsConnect()}// IsOptions returns true if request method is OPTIONS.func ( *RequestCtx) () bool {return .Request.Header.IsOptions()}// IsTrace returns true if request method is TRACE.func ( *RequestCtx) () bool {return .Request.Header.IsTrace()}// IsPatch returns true if request method is PATCH.func ( *RequestCtx) () bool {return .Request.Header.IsPatch()}// Method return request method.//// Returned value is valid until your request handler returns.func ( *RequestCtx) () []byte {return .Request.Header.Method()}// IsHead returns true if request method is HEAD.func ( *RequestCtx) () bool {return .Request.Header.IsHead()}// RemoteAddr returns client address for the given request.//// Always returns non-nil result.func ( *RequestCtx) () net.Addr {if .remoteAddr != nil {return .remoteAddr }if .c == nil {returnzeroTCPAddr } := .c.RemoteAddr()if == nil {returnzeroTCPAddr }return}// SetRemoteAddr sets remote address to the given value.//// Set nil value to restore default behaviour for using// connection remote address.func ( *RequestCtx) ( net.Addr) { .remoteAddr = }// LocalAddr returns server address for the given request.//// Always returns non-nil result.func ( *RequestCtx) () net.Addr {if .c == nil {returnzeroTCPAddr } := .c.LocalAddr()if == nil {returnzeroTCPAddr }return}// RemoteIP returns the client ip the request came from.//// Always returns non-nil result.func ( *RequestCtx) () net.IP {returnaddrToIP(.RemoteAddr())}// LocalIP returns the server ip the request came to.//// Always returns non-nil result.func ( *RequestCtx) () net.IP {returnaddrToIP(.LocalAddr())}func addrToIP( net.Addr) net.IP { , := .(*net.TCPAddr)if ! {returnnet.IPv4zero }return .IP}// Error sets response status code to the given value and sets response body// to the given message.//// Warning: this will reset the response headers and body already set!func ( *RequestCtx) ( string, int) { .Response.Reset() .SetStatusCode() .SetContentTypeBytes(defaultContentType) .SetBodyString()}// Success sets response Content-Type and body to the given values.func ( *RequestCtx) ( string, []byte) { .SetContentType() .SetBody()}// SuccessString sets response Content-Type and body to the given values.func ( *RequestCtx) (, string) { .SetContentType() .SetBodyString()}// Redirect sets 'Location: uri' response header and sets the given statusCode.//// statusCode must have one of the following values://// - StatusMovedPermanently (301)// - StatusFound (302)// - StatusSeeOther (303)// - StatusTemporaryRedirect (307)// - StatusPermanentRedirect (308)//// All other statusCode values are replaced by StatusFound (302).//// The redirect uri may be either absolute or relative to the current// request uri. Fasthttp will always send an absolute uri back to the client.// To send a relative uri you can use the following code://// strLocation = []byte("Location") // Put this with your top level var () declarations.// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri")// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently)func ( *RequestCtx) ( string, int) { := AcquireURI() .URI().CopyTo() .Update() .redirect(.FullURI(), )ReleaseURI()}// RedirectBytes sets 'Location: uri' response header and sets// the given statusCode.//// statusCode must have one of the following values://// - StatusMovedPermanently (301)// - StatusFound (302)// - StatusSeeOther (303)// - StatusTemporaryRedirect (307)// - StatusPermanentRedirect (308)//// All other statusCode values are replaced by StatusFound (302).//// The redirect uri may be either absolute or relative to the current// request uri. Fasthttp will always send an absolute uri back to the client.// To send a relative uri you can use the following code://// strLocation = []byte("Location") // Put this with your top level var () declarations.// ctx.Response.Header.SetCanonical(strLocation, "/relative?uri")// ctx.Response.SetStatusCode(fasthttp.StatusMovedPermanently)func ( *RequestCtx) ( []byte, int) { := b2s() .Redirect(, )}func ( *RequestCtx) ( []byte, int) { .Response.Header.setNonSpecial(strLocation, ) = getRedirectStatusCode() .Response.SetStatusCode()}func getRedirectStatusCode( int) int {if == StatusMovedPermanently || == StatusFound || == StatusSeeOther || == StatusTemporaryRedirect || == StatusPermanentRedirect {return }returnStatusFound}// SetBody sets response body to the given value.//// It is safe re-using body argument after the function returns.func ( *RequestCtx) ( []byte) { .Response.SetBody()}// SetBodyString sets response body to the given value.func ( *RequestCtx) ( string) { .Response.SetBodyString()}// ResetBody resets response body contents.func ( *RequestCtx) () { .Response.ResetBody()}// SendFile sends local file contents from the given path as response body.//// This is a shortcut to ServeFile(ctx, path).//// SendFile logs all the errors via ctx.Logger.//// See also ServeFile, FSHandler and FS.//// WARNING: do not pass any user supplied paths to this function!// WARNING: if path is based on user input users will be able to request// any file on your filesystem! Use fasthttp.FS with a sane Root instead.func ( *RequestCtx) ( string) {ServeFile(, )}// SendFileBytes sends local file contents from the given path as response body.//// This is a shortcut to ServeFileBytes(ctx, path).//// SendFileBytes logs all the errors via ctx.Logger.//// See also ServeFileBytes, FSHandler and FS.//// WARNING: do not pass any user supplied paths to this function!// WARNING: if path is based on user input users will be able to request// any file on your filesystem! Use fasthttp.FS with a sane Root instead.func ( *RequestCtx) ( []byte) {ServeFileBytes(, )}// IfModifiedSince returns true if lastModified exceeds 'If-Modified-Since'// value from the request header.//// The function returns true also 'If-Modified-Since' request header is missing.func ( *RequestCtx) ( time.Time) bool { := .Request.Header.peek(strIfModifiedSince)iflen() == 0 {returntrue } , := ParseHTTPDate()if != nil {returntrue } = .Truncate(time.Second)return .Before()}// NotModified resets response and sets '304 Not Modified' response status code.func ( *RequestCtx) () { .Response.Reset() .SetStatusCode(StatusNotModified)}// NotFound resets response and sets '404 Not Found' response status code.func ( *RequestCtx) () { .Response.Reset() .SetStatusCode(StatusNotFound) .SetBodyString("404 Page not found")}// Write writes p into response body.func ( *RequestCtx) ( []byte) (int, error) { .Response.AppendBody()returnlen(), nil}// WriteString appends s to response body.func ( *RequestCtx) ( string) (int, error) { .Response.AppendBodyString()returnlen(), nil}// PostBody returns POST request body.//// The returned bytes are valid until your request handler returns.func ( *RequestCtx) () []byte {return .Request.Body()}// SetBodyStream sets response body stream and, optionally body size.//// bodyStream.Close() is called after finishing reading all body data// if it implements io.Closer.//// If bodySize is >= 0, then bodySize bytes must be provided by bodyStream// before returning io.EOF.//// If bodySize < 0, then bodyStream is read until io.EOF.//// See also SetBodyStreamWriter.func ( *RequestCtx) ( io.Reader, int) { .Response.SetBodyStream(, )}// SetBodyStreamWriter registers the given stream writer for populating// response body.//// Access to RequestCtx and/or its members is forbidden from sw.//// This function may be used in the following cases://// - if response body is too big (more than 10MB).// - if response body is streamed from slow external sources.// - if response body must be streamed to the client in chunks.// (aka `http server push`).func ( *RequestCtx) ( StreamWriter) { .Response.SetBodyStreamWriter()}// IsBodyStream returns true if response body is set via SetBodyStream*.func ( *RequestCtx) () bool {return .Response.IsBodyStream()}// Logger returns logger, which may be used for logging arbitrary// request-specific messages inside RequestHandler.//// Each message logged via returned logger contains request-specific information// such as request id, request duration, local address, remote address,// request method and request url.//// It is safe re-using returned logger for logging multiple messages// for the current request.//// The returned logger is valid until your request handler returns.func ( *RequestCtx) () Logger {if .logger.ctx == nil { .logger.ctx = }if .logger.logger == nil { .logger.logger = .s.logger() }return &.logger}// TimeoutError sets response status code to StatusRequestTimeout and sets// body to the given msg.//// All response modifications after TimeoutError call are ignored.//// TimeoutError MUST be called before returning from RequestHandler if there are// references to ctx and/or its members in other goroutines remain.//// Usage of this function is discouraged. Prefer eliminating ctx references// from pending goroutines instead of using this function.func ( *RequestCtx) ( string) { .TimeoutErrorWithCode(, StatusRequestTimeout)}// TimeoutErrorWithCode sets response body to msg and response status// code to statusCode.//// All response modifications after TimeoutErrorWithCode call are ignored.//// TimeoutErrorWithCode MUST be called before returning from RequestHandler// if there are references to ctx and/or its members in other goroutines remain.//// Usage of this function is discouraged. Prefer eliminating ctx references// from pending goroutines instead of using this function.func ( *RequestCtx) ( string, int) {varResponse .SetStatusCode() .SetBodyString() .TimeoutErrorWithResponse(&)}// TimeoutErrorWithResponse marks the ctx as timed out and sends the given// response to the client.//// All ctx modifications after TimeoutErrorWithResponse call are ignored.//// TimeoutErrorWithResponse MUST be called before returning from RequestHandler// if there are references to ctx and/or its members in other goroutines remain.//// Usage of this function is discouraged. Prefer eliminating ctx references// from pending goroutines instead of using this function.func ( *RequestCtx) ( *Response) { := &Response{} .CopyTo() .timeoutResponse = }// NextProto adds nph to be processed when key is negotiated when TLS// connection is established.//// This function can only be called before the server is started.func ( *Server) ( string, ServeHandler) {if .nextProtos == nil { .nextProtos = make(map[string]ServeHandler) } .configTLS() .TLSConfig.NextProtos = append(.TLSConfig.NextProtos, ) .nextProtos[] = }func ( *Server) ( net.Conn) ( string, error) {if , := .(connTLSer); {if .ReadTimeout > 0 {if := .SetReadDeadline(time.Now().Add(.ReadTimeout)); != nil {panic(fmt.Sprintf("BUG: error in SetReadDeadline(%v): %v", .ReadTimeout, )) } }if .WriteTimeout > 0 {if := .SetWriteDeadline(time.Now().Add(.WriteTimeout)); != nil {panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%v): %v", .WriteTimeout, )) } } = .Handshake()if == nil { = .ConnectionState().NegotiatedProtocol } }return}// ListenAndServe serves HTTP requests from the given TCP4 addr.//// Pass custom listener to Serve if you need listening on non-TCP4 media// such as IPv6.//// Accepted connections are configured to enable TCP keep-alives.func ( *Server) ( string) error { , := net.Listen("tcp4", )if != nil {return }return .Serve()}// ListenAndServeUNIX serves HTTP requests from the given UNIX addr.//// The function deletes existing file at addr before starting serving.//// The server sets the given file mode for the UNIX addr.func ( *Server) ( string, os.FileMode) error {if := os.Remove(); != nil && !os.IsNotExist() {returnfmt.Errorf("unexpected error when trying to remove unix socket file %q: %w", , ) } , := net.Listen("unix", )if != nil {return }if = os.Chmod(, ); != nil {returnfmt.Errorf("cannot chmod %#o for %q: %w", , , ) }return .Serve()}// ListenAndServeTLS serves HTTPS requests from the given TCP4 addr.//// certFile and keyFile are paths to TLS certificate and key files.//// Pass custom listener to Serve if you need listening on non-TCP4 media// such as IPv6.//// If the certFile or keyFile has not been provided to the server structure,// the function will use the previously added TLS configuration.//// Accepted connections are configured to enable TCP keep-alives.func ( *Server) (, , string) error { , := net.Listen("tcp4", )if != nil {return }return .ServeTLS(, , )}// ListenAndServeTLSEmbed serves HTTPS requests from the given TCP4 addr.//// certData and keyData must contain valid TLS certificate and key data.//// Pass custom listener to Serve if you need listening on arbitrary media// such as IPv6.//// If the certFile or keyFile has not been provided the server structure,// the function will use previously added TLS configuration.//// Accepted connections are configured to enable TCP keep-alives.func ( *Server) ( string, , []byte) error { , := net.Listen("tcp4", )if != nil {return }return .ServeTLSEmbed(, , )}// ServeTLS serves HTTPS requests from the given listener.//// certFile and keyFile are paths to TLS certificate and key files.//// If the certFile or keyFile has not been provided the server structure,// the function will use previously added TLS configuration.func ( *Server) ( net.Listener, , string) error { .mu.Lock() .configTLS() := len(.TLSConfig.Certificates) > 0 || .TLSConfig.GetCertificate != nilif ! || != "" || != "" {if := .AppendCert(, ); != nil { .mu.Unlock()return } }// BuildNameToCertificate has been deprecated since 1.14. // But since we also support older versions we'll keep this here. .TLSConfig.BuildNameToCertificate() //nolint:staticcheck .mu.Unlock()return .Serve(tls.NewListener(, .TLSConfig.Clone()), )}// ServeTLSEmbed serves HTTPS requests from the given listener.//// certData and keyData must contain valid TLS certificate and key data.//// If the certFile or keyFile has not been provided the server structure,// the function will use previously added TLS configuration.func ( *Server) ( net.Listener, , []byte) error { .mu.Lock() .configTLS() := len(.TLSConfig.Certificates) > 0 || .TLSConfig.GetCertificate != nilif ! || len() != 0 || len() != 0 {if := .AppendCertEmbed(, ); != nil { .mu.Unlock()return } }// BuildNameToCertificate has been deprecated since 1.14. // But since we also support older versions we'll keep this here. .TLSConfig.BuildNameToCertificate() //nolint:staticcheck .mu.Unlock()return .Serve(tls.NewListener(, .TLSConfig.Clone()), )}// AppendCert appends certificate and keyfile to TLS Configuration.//// This function allows programmer to handle multiple domains// in one server structure. See examples/multidomainfunc ( *Server) (, string) error {iflen() == 0 && len() == 0 {returnerrNoCertOrKeyProvided } , := tls.LoadX509KeyPair(, )if != nil {returnfmt.Errorf("cannot load TLS key pair from certFile=%q and keyFile=%q: %w", , , ) } .configTLS() .TLSConfig.Certificates = append(.TLSConfig.Certificates, )returnnil}// AppendCertEmbed does the same as AppendCert but using in-memory data.func ( *Server) (, []byte) error {iflen() == 0 && len() == 0 {returnerrNoCertOrKeyProvided } , := tls.X509KeyPair(, )if != nil {returnfmt.Errorf("cannot load TLS key pair from the provided certData(%d) and keyData(%d): %w",len(), len(), ) } .configTLS() .TLSConfig.Certificates = append(.TLSConfig.Certificates, )returnnil}func ( *Server) () {if .TLSConfig == nil { .TLSConfig = &tls.Config{} }}// DefaultConcurrency is the maximum number of concurrent connections// the Server may serve by default (i.e. if Server.Concurrency isn't set).constDefaultConcurrency = 256 * 1024// Serve serves incoming connections from the given listener.//// Serve blocks until the given listener returns permanent error.func ( *Server) ( net.Listener) error {vartime.Timevartime.Timevarnet.Connvarerror := .getConcurrency() .mu.Lock() .ln = append(.ln, )if .done == nil { .done = make(chanstruct{}) }if .concurrencyCh == nil { .concurrencyCh = make(chanstruct{}, ) } .mu.Unlock() := &workerPool{WorkerFunc: .serveConn,MaxWorkersCount: ,LogAllErrors: .LogAllErrors,MaxIdleWorkerDuration: .MaxIdleWorkerDuration,Logger: .logger(),connState: .setState, } .Start()// Count our waiting to accept a connection as an open connection. // This way we can't get into any weird state where just after accepting // a connection Shutdown is called which reads open as 0 because it isn't // incremented yet.atomic.AddInt32(&.open, 1)deferatomic.AddInt32(&.open, -1)for {if , = acceptConn(, , &); != nil { .Stop()if == io.EOF {returnnil }return } .setState(, StateNew)atomic.AddInt32(&.open, 1)if !.Serve() {atomic.AddInt32(&.open, -1) .writeFastError(, StatusServiceUnavailable,"The connection cannot be served because Server.Concurrency limit exceeded") .Close() .setState(, StateClosed)iftime.Since() > time.Minute { .logger().Printf("The incoming connection cannot be served, because %d concurrent connections are served. "+"Try increasing Server.Concurrency", ) = time.Now() }// The current server reached concurrency limit, // so give other concurrently running servers a chance // accepting incoming connections on the same address. // // There is a hope other servers didn't reach their // concurrency limits yet :) // // See also: https://github.com/valyala/fasthttp/pull/485#discussion_r239994990if .SleepWhenConcurrencyLimitsExceeded > 0 {time.Sleep(.SleepWhenConcurrencyLimitsExceeded) } } = nil }}// Shutdown gracefully shuts down the server without interrupting any active connections.// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down.//// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.// Make sure the program doesn't exit and waits instead for Shutdown to return.//// Shutdown does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.func ( *Server) () error {return .ShutdownWithContext(context.Background())}// ShutdownWithContext gracefully shuts down the server without interrupting any active connections.// ShutdownWithContext works by first closing all open listeners and then waiting for all connections to return to idle or context timeout and then shut down.//// When ShutdownWithContext is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.// Make sure the program doesn't exit and waits instead for Shutdown to return.//// ShutdownWithContext does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.func ( *Server) ( context.Context) ( error) { .mu.Lock()defer .mu.Unlock()atomic.StoreInt32(&.stop, 1)deferatomic.StoreInt32(&.stop, 0)if .ln == nil {returnnil }for , := range .ln {if = .Close(); != nil {return } }if .done != nil {close(.done) }// Closing the listener will make Serve() call Stop on the worker pool. // Setting .stop to 1 will make serveConn() break out of its loop. // Now we just have to wait until all workers are done or timeout. := time.NewTicker(time.Millisecond * 100)defer .Stop():for { .closeIdleConns()if := atomic.LoadInt32(&.open); == 0 {break }// This is not an optimal solution but using a sync.WaitGroup // here causes data races as it's hard to prevent Add() to be called // while Wait() is waiting.select {case<-.Done(): = .Err()breakcase<-.C:continue } } .done = nil .ln = nilreturn}func acceptConn( *Server, net.Listener, *time.Time) (net.Conn, error) {for { , := .Accept()if != nil {if , := .(net.Error); && .Timeout() { .logger().Printf("Timeout error when accepting new connections: %v", )time.Sleep(time.Second)continue }if != io.EOF && !strings.Contains(.Error(), "use of closed network connection") { .logger().Printf("Permanent error when accepting new connections: %v", )returnnil, }returnnil, io.EOF }if , := .(*net.TCPConn); && .TCPKeepalive {if := .SetKeepAlive(.TCPKeepalive); != nil { _ = .Close()returnnil, }if .TCPKeepalivePeriod > 0 {if := .SetKeepAlivePeriod(.TCPKeepalivePeriod); != nil { _ = .Close()returnnil, } } }if .MaxConnsPerIP > 0 { := wrapPerIPConn(, )if == nil {iftime.Since(*) > time.Minute { .logger().Printf("The number of connections from %s exceeds MaxConnsPerIP=%d",getConnIP4(), .MaxConnsPerIP) * = time.Now() }continue } = }return , nil }}func wrapPerIPConn( *Server, net.Conn) net.Conn { := getUint32IP()if == 0 {return } := .perIPConnCounter.Register()if > .MaxConnsPerIP { .perIPConnCounter.Unregister() .writeFastError(, StatusTooManyRequests, "The number of connections from your ip exceeds MaxConnsPerIP") .Close()returnnil }returnacquirePerIPConn(, , &.perIPConnCounter)}var defaultLogger = Logger(log.New(os.Stderr, "", log.LstdFlags))func ( *Server) () Logger {if .Logger != nil {return .Logger }returndefaultLogger}var (// ErrPerIPConnLimit may be returned from ServeConn if the number of connections // per ip exceeds Server.MaxConnsPerIP.ErrPerIPConnLimit = errors.New("too many connections per ip")// ErrConcurrencyLimit may be returned from ServeConn if the number // of concurrently served connections exceeds Server.Concurrency.ErrConcurrencyLimit = errors.New("cannot serve the connection because Server.Concurrency concurrent connections are served"))// ServeConn serves HTTP requests from the given connection.//// ServeConn returns nil if all requests from the c are successfully served.// It returns non-nil error otherwise.//// Connection c must immediately propagate all the data passed to Write()// to the client. Otherwise requests' processing may hang.//// ServeConn closes c before returning.func ( *Server) ( net.Conn) error {if .MaxConnsPerIP > 0 { := wrapPerIPConn(, )if == nil {returnErrPerIPConnLimit } = } := atomic.AddUint32(&.concurrency, 1)if > uint32(.getConcurrency()) {atomic.AddUint32(&.concurrency, ^uint32(0)) .writeFastError(, StatusServiceUnavailable, "The connection cannot be served because Server.Concurrency limit exceeded") .Close()returnErrConcurrencyLimit }atomic.AddInt32(&.open, 1) := .serveConn()atomic.AddUint32(&.concurrency, ^uint32(0))if != errHijacked { := .Close() .setState(, StateClosed)if == nil { = } } else { = nil .setState(, StateHijacked) }return}var errHijacked = errors.New("connection has been hijacked")// GetCurrentConcurrency returns a number of currently served// connections.//// This function is intended be used by monitoring systemsfunc ( *Server) () uint32 {returnatomic.LoadUint32(&.concurrency)}// GetOpenConnectionsCount returns a number of opened connections.//// This function is intended be used by monitoring systemsfunc ( *Server) () int32 {ifatomic.LoadInt32(&.stop) == 0 {// Decrement by one to avoid reporting the extra open value that gets // counted while the server is listening.returnatomic.LoadInt32(&.open) - 1 }// This is not perfect, because s.stop could have changed to zero // before we load the value of s.open. However, in the common case // this avoids underreporting open connections by 1 during server shutdown.returnatomic.LoadInt32(&.open)}func ( *Server) () int { := .Concurrencyif <= 0 { = DefaultConcurrency }return}var globalConnID uint64func nextConnID() uint64 {returnatomic.AddUint64(&globalConnID, 1)}// DefaultMaxRequestBodySize is the maximum request body size the server// reads by default.//// See Server.MaxRequestBodySize for details.constDefaultMaxRequestBodySize = 4 * 1024 * 1024func ( *Server) () time.Duration {if .IdleTimeout != 0 {return .IdleTimeout }return .ReadTimeout}func ( *Server) () {atomic.AddInt32(&.open, -1)atomic.AddUint32(&.concurrency, ^uint32(0))}func ( *Server) ( net.Conn) ( error) {defer .serveConnCleanup()atomic.AddUint32(&.concurrency, 1)varstringif , = .getNextProto(); != nil {return }if , := .nextProtos[]; {// Remove read or write deadlines that might have previously been set. // The next handler is responsible for setting its own deadlines.if .ReadTimeout > 0 || .WriteTimeout > 0 {if := .SetDeadline(zeroTime); != nil {panic(fmt.Sprintf("BUG: error in SetDeadline(zeroTime): %v", )) } }return () } := .getServerName() := uint64(0) := nextConnID() := time.Now() := .MaxRequestBodySizeif <= 0 { = DefaultMaxRequestBodySize } := .WriteTimeout := time.Duration(0) := .acquireCtx() .connTime = := .IsTLS()var ( *bufio.Reader *bufio.Writer *ResponseHijackHandlerboolbool = true )for { ++// If this is a keep-alive connection set the idle timeout.if > 1 {if := .idleTimeout(); > 0 {if := .SetReadDeadline(time.Now().Add()); != nil {break } } }if !.ReduceMemoryUsage || != nil {if == nil { = acquireReader() }// If this is a keep-alive connection we want to try and read the first bytes // within the idle time.if > 1 {var []byte , = .Peek(1)iflen() == 0 {// If reading from a keep-alive connection returns nothing it means // the connection was closed (either timeout or from the other side).if != io.EOF { = ErrNothingRead{} } } } } else {// If this is a keep-alive connection acquireByteReader will try to peek // a couple of bytes already so the idle timeout will already be used. , = acquireByteReader(&) } .Request.isTLS = .Response.Header.noDefaultContentType = .NoDefaultContentType .Response.Header.noDefaultDate = .NoDefaultDate// Secure header error logs configuration .Request.Header.secureErrorLogMessage = .SecureErrorLogMessage .Response.Header.secureErrorLogMessage = .SecureErrorLogMessage .Request.secureErrorLogMessage = .SecureErrorLogMessage .Response.secureErrorLogMessage = .SecureErrorLogMessageif == nil { .setState(, StateActive)if .ReadTimeout > 0 {if := .SetReadDeadline(time.Now().Add(.ReadTimeout)); != nil {break } } elseif .IdleTimeout > 0 && > 1 {// If this was an idle connection and the server has an IdleTimeout but // no ReadTimeout then we should remove the ReadTimeout.if := .SetReadDeadline(zeroTime); != nil {break } }if .DisableHeaderNamesNormalizing { .Request.Header.DisableNormalizing() .Response.Header.DisableNormalizing() }// Reading Headers. // // If we have pipeline response in the outgoing buffer, // we only want to try and read the next headers once. // If we have to wait for the next request we flush the // outgoing buffer first so it doesn't have to wait.if != nil && .Buffered() > 0 { = .Request.Header.readLoop(, false)if == errNeedMore { = .Flush()if != nil {break } = .Request.Header.Read() } } else { = .Request.Header.Read() }if == nil {if := .HeaderReceived; != nil { := (&.Request.Header)if .ReadTimeout > 0 { := time.Now().Add(.ReadTimeout)if := .SetReadDeadline(); != nil {panic(fmt.Sprintf("BUG: error in SetReadDeadline(%v): %v", , )) } }switch {case .MaxRequestBodySize > 0: = .MaxRequestBodySizecase .MaxRequestBodySize > 0: = .MaxRequestBodySizedefault: = DefaultMaxRequestBodySize }if .WriteTimeout > 0 { = .WriteTimeout } else { = .WriteTimeout } }// read bodyif .StreamRequestBody { = .Request.readBodyStream(, , .GetOnly, !.DisablePreParseMultipartForm) } else { = .Request.readLimitBody(, , .GetOnly, !.DisablePreParseMultipartForm) } }if (.ReduceMemoryUsage && .Buffered() == 0) || != nil {releaseReader(, ) = nil } }if != nil {if == io.EOF { = nil } elseif , := .(ErrNothingRead); {if > 1 {// This is not the first request and we haven't read a single byte // of a new request yet. This means it's just a keep-alive connection // closing down either because the remote closed it or because // or a read timeout on our side. Either way just close the connection // and don't return any error response. = nil } else { = .error } }if != nil { = .writeErrorResponse(, , , ) }break }// 'Expect: 100-continue' request handling. // See https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 for details.if .Request.MayContinue() {// Allow the ability to deny reading the incoming request bodyif .ContinueHandler != nil {if = .ContinueHandler(&.Request.Header); ! {if != nil { .Reset(.c) } .SetStatusCode(StatusExpectationFailed) } }if {if == nil { = acquireWriter() }// Send 'HTTP/1.1 100 Continue' response. _, = .Write(strResponseContinue)if != nil {break } = .Flush()if != nil {break }if .ReduceMemoryUsage {releaseWriter(, ) = nil }// Read request body.if == nil { = acquireReader() }if .StreamRequestBody { = .Request.ContinueReadBodyStream(, , !.DisablePreParseMultipartForm) } else { = .Request.ContinueReadBody(, , !.DisablePreParseMultipartForm) }if (.ReduceMemoryUsage && .Buffered() == 0) || != nil {releaseReader(, ) = nil }if != nil { = .writeErrorResponse(, , , )break } } }// store req.ConnectionClose so even if it was changed inside of handler = .DisableKeepalive || .Request.Header.ConnectionClose()if != "" { .Response.Header.SetServer() } .connID = .connRequestNum = .time = time.Now()// If a client denies a request the handler should not be calledif { .Handler() } = .timeoutResponseif != nil {// Acquire a new ctx because the old one will still be in use by the timeout out handler. = .acquireCtx() .CopyTo(&.Response) }if .IsHead() { .Response.SkipBody = true } = .hijackHandler .hijackHandler = nil = .hijackNoResponse && != nil .hijackNoResponse = falseif > 0 {if := .SetWriteDeadline(time.Now().Add()); != nil {panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%v): %v", , )) } = } elseif > 0 {// We don't want a write timeout but we previously set one, remove it.if := .SetWriteDeadline(zeroTime); != nil {panic(fmt.Sprintf("BUG: error in SetWriteDeadline(zeroTime): %v", )) } = 0 } = || (.MaxRequestsPerConn > 0 && >= uint64(.MaxRequestsPerConn)) || .Response.Header.ConnectionClose() || (.CloseOnShutdown && atomic.LoadInt32(&.stop) == 1)if { .Response.Header.SetConnectionClose() } elseif !.Request.Header.IsHTTP11() {// Set 'Connection: keep-alive' response header for HTTP/1.0 request. // There is no need in setting this header for http/1.1, since in http/1.1 // connections are keep-alive by default. .Response.Header.setNonSpecial(strConnection, strKeepAlive) }if != "" && len(.Response.Header.Server()) == 0 { .Response.Header.SetServer() }if ! {if == nil { = acquireWriter() }if = writeResponse(, ); != nil {break }// Only flush the writer if we don't have another request in the pipeline. // This is a big of an ugly optimization for https://www.techempower.com/benchmarks/ // This benchmark will send 16 pipelined requests. It is faster to pack as many responses // in a TCP packet and send it back at once than waiting for a flush every request. // In real world circumstances this behaviour could be argued as being wrong.if == nil || .Buffered() == 0 || { = .Flush()if != nil {break } }if {break }if .ReduceMemoryUsage && == nil {releaseWriter(, ) = nil } }if != nil {vario.Reader = if != nil { = = nil }if != nil { = .Flush()if != nil {break }releaseWriter(, ) = nil } = .SetDeadline(zeroTime)if != nil {break }gohijackConnHandler(, , , , ) = errHijackedbreak }if .Request.bodyStream != nil {if , := .Request.bodyStream.(*requestStream); {releaseRequestStream() } .Request.bodyStream = nil } .setState(, StateIdle) .userValues.Reset() .Request.Reset() .Response.Reset()ifatomic.LoadInt32(&.stop) == 1 { = nilbreak } }if != nil {releaseReader(, ) }if != nil {releaseWriter(, ) }if == nil { .releaseCtx() }return}func ( *Server) ( net.Conn, ConnState) { .trackConn(, )if := .ConnState; != nil { (, ) }}func hijackConnHandler( *RequestCtx, io.Reader, net.Conn, *Server, HijackHandler) { := .acquireHijackConn(, ) ()if , := .(*bufio.Reader); {releaseReader(, ) }if !.KeepHijackedConns { .Close() .releaseHijackConn() } .releaseCtx()}func ( *Server) ( io.Reader, net.Conn) *hijackConn { := .hijackConnPool.Get()if == nil { := &hijackConn{Conn: ,r: ,s: , }return } := .(*hijackConn) .Conn = .r = return}func ( *Server) ( *hijackConn) { .Conn = nil .r = nil .hijackConnPool.Put()}type hijackConn struct {net.Conn r io.Reader s *Server}func ( *hijackConn) () net.Conn {return .Conn}func ( *hijackConn) ( []byte) (int, error) {return .r.Read()}func ( *hijackConn) () error {if !.s.KeepHijackedConns {// when we do not keep hijacked connections, // it is closed in hijackConnHandler.returnnil } := .Conn .s.releaseHijackConn()return .Close()}// LastTimeoutErrorResponse returns the last timeout response set// via TimeoutError* call.//// This function is intended for custom server implementations.func ( *RequestCtx) () *Response {return .timeoutResponse}func writeResponse( *RequestCtx, *bufio.Writer) error {if .timeoutResponse != nil {returnerrors.New("cannot write timed out response") } := .Response.Write()return}const ( defaultReadBufferSize = 4096 defaultWriteBufferSize = 4096)func acquireByteReader( **RequestCtx) (*bufio.Reader, error) { := * := .s := .c .releaseCtx()// Make GC happy, so it could garbage collect ctx while we wait for the // next request. = nil * = nilvar [1]byte , := .Read([:]) = .acquireCtx() * = if != nil {// Treat all errors as EOF on unsuccessful read // of the first request byte.returnnil, io.EOF }if != 1 {// developer sanity-checkpanic("BUG: Reader must return at least one byte") } .fbr.c = .fbr.ch = [0] .fbr.byteRead = false := acquireReader() .Reset(&.fbr)return , nil}func acquireReader( *RequestCtx) *bufio.Reader { := .s.readerPool.Get()if == nil { := .s.ReadBufferSizeif <= 0 { = defaultReadBufferSize }returnbufio.NewReaderSize(.c, ) } := .(*bufio.Reader) .Reset(.c)return}func releaseReader( *Server, *bufio.Reader) { .readerPool.Put()}func acquireWriter( *RequestCtx) *bufio.Writer { := .s.writerPool.Get()if == nil { := .s.WriteBufferSizeif <= 0 { = defaultWriteBufferSize }returnbufio.NewWriterSize(.c, ) } := .(*bufio.Writer) .Reset(.c)return}func releaseWriter( *Server, *bufio.Writer) { .writerPool.Put()}func ( *Server) ( net.Conn) ( *RequestCtx) { := .ctxPool.Get()if == nil { := !.ReduceMemoryUsage = new(RequestCtx) .Request.keepBodyBuffer = .Response.keepBodyBuffer = .s = } else { = .(*RequestCtx) }if .FormValueFunc != nil { .formValueFunc = .FormValueFunc } .c = return}// Init2 prepares ctx for passing to RequestHandler.//// conn is used only for determining local and remote addresses.//// This function is intended for custom Server implementations.// See https://github.com/valyala/httpteleport for details.func ( *RequestCtx) ( net.Conn, Logger, bool) { .c = .remoteAddr = nil .logger.logger = .connID = nextConnID() .s = fakeServer .connRequestNum = 0 .connTime = time.Now() := ! .Request.keepBodyBuffer = .Response.keepBodyBuffer = }// Init prepares ctx for passing to RequestHandler.//// remoteAddr and logger are optional. They are used by RequestCtx.Logger().//// This function is intended for custom Server implementations.func ( *RequestCtx) ( *Request, net.Addr, Logger) {if == nil { = zeroTCPAddr } := &fakeAddrer{laddr: zeroTCPAddr,raddr: , }if == nil { = defaultLogger } .Init2(, , true) .CopyTo(&.Request)}// Deadline returns the time when work done on behalf of this context// should be canceled. Deadline returns ok==false when no deadline is// set. Successive calls to Deadline return the same results.//// This method always returns 0, false and is only present to make// RequestCtx implement the context interface.func ( *RequestCtx) () ( time.Time, bool) {return}// Done returns a channel that's closed when work done on behalf of this// context should be canceled. Done may return nil if this context can// never be canceled. Successive calls to Done return the same value.//// Note: Because creating a new channel for every request is just too expensive, so// RequestCtx.s.done is only closed when the server is shutting downfunc ( *RequestCtx) () <-chanstruct{} {return .s.done}// Err returns a non-nil error value after Done is closed,// successive calls to Err return the same error.// If Done is not yet closed, Err returns nil.// If Done is closed, Err returns a non-nil error explaining why:// Canceled if the context was canceled (via server Shutdown)// or DeadlineExceeded if the context's deadline passed.//// Note: Because creating a new channel for every request is just too expensive, so// RequestCtx.s.done is only closed when the server is shutting downfunc ( *RequestCtx) () error {select {case<-.s.done:returncontext.Canceleddefault:returnnil }}// Value returns the value associated with this context for key, or nil// if no value is associated with key. Successive calls to Value with// the same key returns the same result.//// This method is present to make RequestCtx implement the context interface.// This method is the same as calling ctx.UserValue(key)func ( *RequestCtx) ( interface{}) interface{} {return .UserValue()}var fakeServer = &Server{// Initialize concurrencyCh for TimeoutHandlerconcurrencyCh: make(chanstruct{}, DefaultConcurrency),}type fakeAddrer struct {net.Conn laddr net.Addr raddr net.Addr}func ( *fakeAddrer) () net.Addr {return .raddr}func ( *fakeAddrer) () net.Addr {return .laddr}func ( *fakeAddrer) ( []byte) (int, error) {// developer sanity-checkpanic("BUG: unexpected Read call")}func ( *fakeAddrer) ( []byte) (int, error) {// developer sanity-checkpanic("BUG: unexpected Write call")}func ( *fakeAddrer) () error {// developer sanity-checkpanic("BUG: unexpected Close call")}func ( *Server) ( *RequestCtx) {if .timeoutResponse != nil {// developer sanity-checkpanic("BUG: cannot release timed out RequestCtx") } .reset() .ctxPool.Put()}func ( *Server) () string { := .Nameif == "" {if !.NoDefaultServerHeader { = defaultServerName } }return}func ( *Server) ( io.Writer, int, string) { .Write(formatStatusLine(nil, strHTTP11, , s2b(StatusMessage()))) //nolint:errcheck := .getServerName()if != "" { = fmt.Sprintf("Server: %s\r\n", ) } := ""if !.NoDefaultDate {serverDateOnce.Do(updateServerDate) = fmt.Sprintf("Date: %s\r\n", serverDate.Load()) }fmt.Fprintf(, "Connection: close\r\n"+ + +"Content-Type: text/plain\r\n"+"Content-Length: %d\r\n"+"\r\n"+"%s",len(), )}func defaultErrorHandler( *RequestCtx, error) {if , := .(*ErrSmallBuffer); { .Error("Too big request header", StatusRequestHeaderFieldsTooLarge) } elseif , := .(*net.OpError); && .Timeout() { .Error("Request timeout", StatusRequestTimeout) } else { .Error("Error when parsing request", StatusBadRequest) }}func ( *Server) ( *bufio.Writer, *RequestCtx, string, error) *bufio.Writer { := defaultErrorHandlerif .ErrorHandler != nil { = .ErrorHandler } (, )if != "" { .Response.Header.SetServer() } .SetConnectionClose()if == nil { = acquireWriter() }writeResponse(, ) //nolint:errcheck .Response.Reset() .Flush()return}func ( *Server) ( net.Conn, ConnState) { .idleConnsMu.Lock()switch {caseStateIdle:if .idleConns == nil { .idleConns = make(map[net.Conn]time.Time) } .idleConns[] = time.Now()caseStateNew:if .idleConns == nil { .idleConns = make(map[net.Conn]time.Time) }// Count the connection as Idle after 5 seconds. // Same as net/http.Server: https://github.com/golang/go/blob/85d7bab91d9a3ed1f76842e4328973ea75efef54/src/net/http/server.go#L2834-L2836 .idleConns[] = time.Now().Add(time.Second * 5)default:delete(.idleConns, ) } .idleConnsMu.Unlock()}func ( *Server) () { .idleConnsMu.Lock() := time.Now()for , := range .idleConns {if .Sub() >= 0 { _ = .Close()delete(.idleConns, ) } } .idleConnsMu.Unlock()}// A ConnState represents the state of a client connection to a server.// It's used by the optional Server.ConnState hook.typeConnStateintconst (// 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.StateNewConnState = 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 {returnstateName[]}
The pages are generated with Goldsv0.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.