func (req *Request) Write(w *bufio.Writer) error {
	if len(req.Header.Host()) == 0 || req.parsedURI {
		uri := req.URI()
		host := uri.Host()
		if len(host) == 0 {
			return errRequestHostRequired
		}
		req.Header.SetHostBytes(host)
		req.Header.SetRequestURIBytes(uri.RequestURI())
	}

	if req.bodyStream != nil {
		return req.writeBodyStream(w)
	}

	body := req.bodyBytes()
	var err error
	if req.onlyMultipartForm() {
		body, err = marshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
		if err != nil {
			return fmt.Errorf("error when marshaling multipart form: %s", err)
		}
		req.Header.SetMultipartFormBoundary(req.multipartFormBoundary)
	}

	hasBody := !req.Header.ignoreBody()
	if hasBody {
		if len(body) == 0 {
			body = req.postArgs.QueryString()
		}
		req.Header.SetContentLength(len(body))
	}
	if err = req.Header.Write(w); err != nil {
		return err
	}
	if hasBody {
		_, err = w.Write(body)
	} else if len(body) > 0 {
		return fmt.Errorf("non-zero body for non-POST request. body=%q", body)
	}
	return err
}

func ( req * Request ) Write ( w * bufio . Writer ) error { if len ( req . Header . Host ( ) ) == 0 || req . parsedURI { uri := req . URI ( ) host := uri . Host ( ) if len ( host ) == 0 { return errRequestHostRequired } req . Header . SetHostBytes ( host ) req . Header . SetRequestURIBytes ( uri . RequestURI ( ) ) } if req . bodyStream != nil { return req . writeBodyStream ( w ) } body := req . bodyBytes ( ) var err error if req . onlyMultipartForm ( ) { body , err = marshalMultipartForm ( req . multipartForm , req . multipartFormBoundary ) if err != nil { return fmt . Errorf ( " " , err ) } req . Header . SetMultipartFormBoundary ( req . multipartFormBoundary ) } hasBody := ! req . Header . ignoreBody ( ) if hasBody { if len ( body ) == 0 { body = req . postArgs . QueryString ( ) } req . Header . SetContentLength ( len ( body ) ) } if err = req . Header . Write ( w ) ; err != nil { return err } if hasBody { _ , err = w . Write ( body ) } else if len ( body ) > 0 { return fmt . Errorf ( " " , body ) } return err }

// Write writes request to w.
//
// Write doesn't flush request to w for performance reasons.
//
// See also WriteTo.

Write writes request to w . Write doesn t flush request to w for performance reasons . See also WriteTo .


func (resp *Response) Write(w *bufio.Writer) error {
	sendBody := !resp.mustSkipBody()

	if resp.bodyStream != nil {
		return resp.writeBodyStream(w, sendBody)
	}

	body := resp.bodyBytes()
	bodyLen := len(body)
	if sendBody || bodyLen > 0 {
		resp.Header.SetContentLength(bodyLen)
	}
	if err := resp.Header.Write(w); err != nil {
		return err
	}
	if sendBody {
		if _, err := w.Write(body); err != nil {
			return err
		}
	}
	return nil
}

func ( resp * Response ) Write ( w * bufio . Writer ) error { sendBody := ! resp . mustSkipBody ( ) if resp . bodyStream != nil { return resp . writeBodyStream ( w , sendBody ) } body := resp . bodyBytes ( ) bodyLen := len ( body ) if sendBody || bodyLen > 0 { resp . Header . SetContentLength ( bodyLen ) } if err := resp . Header . Write ( w ) ; err != nil { return err } if sendBody { if _ , err := w . Write ( body ) ; err != nil { return err } } return nil }

// Write writes response to w.
//
// Write doesn't flush response to w for performance reasons.
//
// See also WriteTo.

Write writes response to w . Write doesn t flush response to w for performance reasons . See also WriteTo .


func (h *ResponseHeader) SetLastModified(t time.Time) {
	h.bufKV.value = AppendHTTPDate(h.bufKV.value[:0], t)
	h.SetCanonical(strLastModified, h.bufKV.value)
}

func ( h * ResponseHeader ) SetLastModified ( t time . Time ) { h . bufKV . value = AppendHTTPDate ( h . bufKV . value [ : 0 ] , t ) h . SetCanonical ( strLastModified , h . bufKV . value ) }

// SetLastModified sets 'Last-Modified' header to the given value.

SetLastModified sets Last - Modified header to the given value .


func (h *ResponseHeader) PeekCookie(key string) []byte {
	return peekArgStr(h.cookies, key)
}

func ( h * ResponseHeader ) PeekCookie ( key string ) [ ] byte { return peekArgStr ( h . cookies , key ) }

// PeekCookie is able to returns cookie by a given key from response.

PeekCookie is able to returns cookie by a given key from response .


func (h *ResponseHeader) ContentType() []byte {
	contentType := h.contentType
	if !h.noDefaultContentType && len(h.contentType) == 0 {
		contentType = defaultContentType
	}
	return contentType
}

func ( h * ResponseHeader ) ContentType ( ) [ ] byte { contentType := h . contentType if ! h . noDefaultContentType && len ( h . contentType ) == 0 { contentType = defaultContentType } return contentType }

// ContentType returns Content-Type header value.

ContentType returns Content - Type header value .


func (h *ResponseHeader) SetServer(server string) {
	h.server = append(h.server[:0], server...)
}

func ( h * ResponseHeader ) SetServer ( server string ) { h . server = append ( h . server [ : 0 ] , server ... ) }


func (h *ResponseHeader) SetServerBytes(server []byte) {
	h.server = append(h.server[:0], server...)
}

func ( h * ResponseHeader ) SetServerBytes ( server [ ] byte ) { h . server = append ( h . server [ : 0 ] , server ... ) }

// SetServerBytes sets Server header value.

SetServerBytes sets Server header value .


func (h *RequestHeader) Host() []byte {
	if len(h.host) > 0 {
		return h.host
	}
	if !h.rawHeadersParsed {
		// fast path without employing full headers parsing.
		host := peekRawHeader(h.rawHeaders, strHost)
		if len(host) > 0 {
			h.host = append(h.host[:0], host...)
			return h.host
		}
	}

	// slow path.
	h.parseRawHeaders()
	return h.host
}


func (h *RequestHeader) SetHost(host string) {
	h.parseRawHeaders()
	h.host = append(h.host[:0], host...)
}

func ( h * RequestHeader ) SetHost ( host string ) { h . parseRawHeaders ( ) h . host = append ( h . host [ : 0 ] , host ... ) }


func (h *RequestHeader) SetHostBytes(host []byte) {
	h.parseRawHeaders()
	h.host = append(h.host[:0], host...)
}

func ( h * RequestHeader ) SetHostBytes ( host [ ] byte ) { h . parseRawHeaders ( ) h . host = append ( h . host [ : 0 ] , host ... ) }


func (h *RequestHeader) SetUserAgent(userAgent string) {
	h.parseRawHeaders()
	h.userAgent = append(h.userAgent[:0], userAgent...)
}

func ( h * RequestHeader ) SetUserAgent ( userAgent string ) { h . parseRawHeaders ( ) h . userAgent = append ( h . userAgent [ : 0 ] , userAgent ... ) }

// SetUserAgent sets User-Agent header value.

SetUserAgent sets User - Agent header value .


func (h *RequestHeader) SetUserAgentBytes(userAgent []byte) {
	h.parseRawHeaders()
	h.userAgent = append(h.userAgent[:0], userAgent...)
}

func ( h * RequestHeader ) SetUserAgentBytes ( userAgent [ ] byte ) { h . parseRawHeaders ( ) h . userAgent = append ( h . userAgent [ : 0 ] , userAgent ... ) }

// SetUserAgentBytes sets User-Agent header value.

SetUserAgentBytes sets User - Agent header value .


func (h *RequestHeader) Method() []byte {
	if len(h.method) == 0 {
		return strGet
	}
	return h.method
}

func ( h * RequestHeader ) Method ( ) [ ] byte { if len ( h . method ) == 0 { return strGet } return h . method }


func (h *RequestHeader) SetMethod(method string) {
	h.method = append(h.method[:0], method...)
}

func ( h * RequestHeader ) SetMethod ( method string ) { h . method = append ( h . method [ : 0 ] , method ... ) }


func (h *RequestHeader) SetMethodBytes(method []byte) {
	h.method = append(h.method[:0], method...)
}

func ( h * RequestHeader ) SetMethodBytes ( method [ ] byte ) { h . method = append ( h . method [ : 0 ] , method ... ) }

// SetMethodBytes sets HTTP request method.

SetMethodBytes sets HTTP request method .


func (h *RequestHeader) RequestURI() []byte {
	requestURI := h.requestURI
	if len(requestURI) == 0 {
		requestURI = strSlash
	}
	return requestURI
}

func ( h * RequestHeader ) RequestURI ( ) [ ] byte { requestURI := h . requestURI if len ( requestURI ) == 0 { requestURI = strSlash } return requestURI }

// RequestURI returns RequestURI from the first HTTP request line.

RequestURI returns RequestURI from the first HTTP request line .


func (h *RequestHeader) SetRequestURI(requestURI string) {
	h.requestURI = append(h.requestURI[:0], requestURI...)
}

func ( h * RequestHeader ) SetRequestURI ( requestURI string ) { h . requestURI = append ( h . requestURI [ : 0 ] , requestURI ... ) }

// SetRequestURI sets RequestURI for the first HTTP request line.
// RequestURI must be properly encoded.
// Use URI.RequestURI for constructing proper RequestURI if unsure.

SetRequestURI sets RequestURI for the first HTTP request line . RequestURI must be properly encoded . Use URI . RequestURI for constructing proper RequestURI if unsure .


func (h *RequestHeader) SetRequestURIBytes(requestURI []byte) {
	h.requestURI = append(h.requestURI[:0], requestURI...)
}

func ( h * RequestHeader ) SetRequestURIBytes ( requestURI [ ] byte ) { h . requestURI = append ( h . requestURI [ : 0 ] , requestURI ... ) }

// SetRequestURIBytes sets RequestURI for the first HTTP request line.
// RequestURI must be properly encoded.
// Use URI.RequestURI for constructing proper RequestURI if unsure.

SetRequestURIBytes sets RequestURI for the first HTTP request line . RequestURI must be properly encoded . Use URI . RequestURI for constructing proper RequestURI if unsure .


func (h *RequestHeader) HasAcceptEncoding(acceptEncoding string) bool {
	h.bufKV.value = append(h.bufKV.value[:0], acceptEncoding...)
	return h.HasAcceptEncodingBytes(h.bufKV.value)
}

func ( h * RequestHeader ) HasAcceptEncoding ( acceptEncoding string ) bool { h . bufKV . value = append ( h . bufKV . value [ : 0 ] , acceptEncoding ... ) return h . HasAcceptEncodingBytes ( h . bufKV . value ) }

// HasAcceptEncoding returns true if the header contains
// the given Accept-Encoding value.

HasAcceptEncoding returns true if the header contains the given Accept - Encoding value .


func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool {
	ae := h.peek(strAcceptEncoding)
	n := bytes.Index(ae, acceptEncoding)
	if n < 0 {
		return false
	}
	b := ae[n+len(acceptEncoding):]
	if len(b) > 0 && b[0] != ',' {
		return false
	}
	if n == 0 {
		return true
	}
	return ae[n-1] == ' '
}

func
(
h
*
RequestHeader
)
HasAcceptEncodingBytes
(
acceptEncoding
[
]
byte
)
bool
{
ae
:=
h
.
peek
(
strAcceptEncoding
)
n
:=
bytes
.
Index
(
ae
,
acceptEncoding
)
if
n
<
0
{
return
false
}
b
:=
ae
[
n
+
len
(
acceptEncoding
)
:
]
if
len
(
b
)
>
0
&&
b
[
0
]
!=
','
{
return
false
}
if
n
==
0
{
return
true
}
return
ae
[
n
1
]
==
' '
}

// HasAcceptEncodingBytes returns true if the header contains
// the given Accept-Encoding value.

HasAcceptEncodingBytes returns true if the header contains the given Accept - Encoding value .


func (h *ResponseHeader) Len() int {
	n := 0
	h.VisitAll(func(k, v []byte) { n++ })
	return n
}

func ( h * ResponseHeader ) Len ( ) int { n := 0 h . VisitAll ( func ( k , v [ ] byte ) { n ++ } ) return n }

// Len returns the number of headers set,
// i.e. the number of times f is called in VisitAll.

Len returns the number of headers set i . e . the number of times f is called in VisitAll .


func (h *ResponseHeader) Reset() {
	h.disableNormalizing = false
	h.noDefaultContentType = false
	h.resetSkipNormalize()
}

func ( h * ResponseHeader ) Reset ( ) { h . disableNormalizing = false h . noDefaultContentType = false h . resetSkipNormalize ( ) }


func (h *ResponseHeader) SetCookie(cookie *Cookie) {
	h.cookies = setArgBytes(h.cookies, cookie.Key(), cookie.Cookie(), argsHasValue)
}

func ( h * ResponseHeader ) SetCookie ( cookie * Cookie ) { h . cookies = setArgBytes ( h . cookies , cookie . Key ( ) , cookie . Cookie ( ) , argsHasValue ) }

// SetCookie sets the given response cookie.
//
// It is save re-using the cookie after the function returns.

SetCookie sets the given response cookie . It is save re - using the cookie after the function returns .


func (h *ResponseHeader) DelClientCookie(key string) {
	h.DelCookie(key)

	c := AcquireCookie()
	c.SetKey(key)
	c.SetExpire(CookieExpireDelete)
	h.SetCookie(c)
	ReleaseCookie(c)
}

func ( h * ResponseHeader ) DelClientCookie ( key string ) { h . DelCookie ( key ) c := AcquireCookie ( ) c . SetKey ( key ) c . SetExpire ( CookieExpireDelete ) h . SetCookie ( c ) ReleaseCookie ( c ) }

// DelClientCookie instructs the client to remove the given cookie.
//
// Use DelCookie if you want just removing the cookie from response header.

DelClientCookie instructs the client to remove the given cookie . Use DelCookie if you want just removing the cookie from response header .


func (h *ResponseHeader) DelCookie(key string) {
	h.cookies = delAllArgs(h.cookies, key)
}

func ( h * ResponseHeader ) DelCookie ( key string ) { h . cookies = delAllArgs ( h . cookies , key ) }

// DelCookie removes cookie under the given key from response header.
//
// Note that DelCookie doesn't remove the cookie from the client.
// Use DelClientCookie instead.

DelCookie removes cookie under the given key from response header . Note that DelCookie doesn t remove the cookie from the client . Use DelClientCookie instead .


func (h *RequestHeader) DelCookie(key string) {
	h.parseRawHeaders()
	h.collectCookies()
	h.cookies = delAllArgs(h.cookies, key)
}

func ( h * RequestHeader ) DelCookie ( key string ) { h . parseRawHeaders ( ) h . collectCookies ( ) h . cookies = delAllArgs ( h . cookies , key ) }

// DelCookie removes cookie under the given key.

DelCookie removes cookie under the given key .


func (h *RequestHeader) DelAllCookies() {
	h.parseRawHeaders()
	h.collectCookies()
	h.cookies = h.cookies[:0]
}

func ( h * RequestHeader ) DelAllCookies ( ) { h . parseRawHeaders ( ) h . collectCookies ( ) h . cookies = h . cookies [ : 0 ] }

// DelAllCookies removes all the cookies from request headers.

DelAllCookies removes all the cookies from request headers .


func (h *ResponseHeader) Peek(key string) []byte {
	k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
	return h.peek(k)
}

func ( h * ResponseHeader ) Peek ( key string ) [ ] byte { k := getHeaderKeyBytes ( & h . bufKV , key , h . disableNormalizing ) return h . peek ( k ) }

// Peek returns header value for the given key.
//
// Returned value is valid until the next call to ResponseHeader.
// Do not store references to returned value. Make copies instead.

Peek returns header value for the given key . Returned value is valid until the next call to ResponseHeader . Do not store references to returned value . Make copies instead .


func (h *ResponseHeader) PeekBytes(key []byte) []byte {
	h.bufKV.key = append(h.bufKV.key[:0], key...)
	normalizeHeaderKey(h.bufKV.key, h.disableNormalizing)
	return h.peek(h.bufKV.key)
}

func ( h * ResponseHeader ) PeekBytes ( key [ ] byte ) [ ] byte { h . bufKV . key = append ( h . bufKV . key [ : 0 ] , key ... ) normalizeHeaderKey ( h . bufKV . key , h . disableNormalizing ) return h . peek ( h . bufKV . key ) }

// PeekBytes returns header value for the given key.
//
// Returned value is valid until the next call to ResponseHeader.
// Do not store references to returned value. Make copies instead.

PeekBytes returns header value for the given key . Returned value is valid until the next call to ResponseHeader . Do not store references to returned value . Make copies instead .


func (h *RequestHeader) Cookie(key string) []byte {
	h.parseRawHeaders()
	h.collectCookies()
	return peekArgStr(h.cookies, key)
}

func ( h * RequestHeader ) Cookie ( key string ) [ ] byte { h . parseRawHeaders ( ) h . collectCookies ( ) return peekArgStr ( h . cookies , key ) }

// Cookie returns cookie for the given key.

Cookie returns cookie for the given key .


func (h *RequestHeader) CookieBytes(key []byte) []byte {
	h.parseRawHeaders()
	h.collectCookies()
	return peekArgBytes(h.cookies, key)
}

func ( h * RequestHeader ) CookieBytes ( key [ ] byte ) [ ] byte { h . parseRawHeaders ( ) h . collectCookies ( ) return peekArgBytes ( h . cookies , key ) }

// CookieBytes returns cookie for the given key.

CookieBytes returns cookie for the given key .


func (h *ResponseHeader) Cookie(cookie *Cookie) bool {
	v := peekArgBytes(h.cookies, cookie.Key())
	if v == nil {
		return false
	}
	cookie.ParseBytes(v)
	return true
}

func ( h * ResponseHeader ) Cookie ( cookie * Cookie ) bool { v := peekArgBytes ( h . cookies , cookie . Key ( ) ) if v == nil { return false } cookie . ParseBytes ( v ) return true }

// Cookie fills cookie for the given cookie.Key.
//
// Returns false if cookie with the given cookie.Key is missing.

Cookie fills cookie for the given cookie . Key . Returns false if cookie with the given cookie . Key is missing .


func (h *RequestHeader) Read(r *bufio.Reader) error {
	n := 1
	for {
		err := h.tryRead(r, n)
		if err == nil {
			return nil
		}
		if err != errNeedMore {
			h.resetSkipNormalize()
			return err
		}
		n = r.Buffered() + 1
	}
}

func ( h * RequestHeader ) Read ( r * bufio . Reader ) error { n := 1 for { err := h . tryRead ( r , n ) if err == nil { return nil } if err != errNeedMore { h . resetSkipNormalize ( ) return err } n = r . Buffered ( ) + 1 } }

// Read reads request header from r.
//
// io.EOF is returned if r is closed before reading the first header byte.

Read reads request header from r . io . EOF is returned if r is closed before reading the first header byte .


func (h *ResponseHeader) Header() []byte {
	h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
	return h.bufKV.value
}

func ( h * ResponseHeader ) Header ( ) [ ] byte { h . bufKV . value = h . AppendBytes ( h . bufKV . value [ : 0 ] ) return h . bufKV . value }

// Header returns response header representation.
//
// The returned value is valid until the next call to ResponseHeader methods.

Header returns response header representation . The returned value is valid until the next call to ResponseHeader methods .


func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
	statusCode := h.StatusCode()
	if statusCode < 0 {
		statusCode = StatusOK
	}
	dst = append(dst, statusLine(statusCode)...)

	server := h.Server()
	if len(server) != 0 {
		dst = appendHeaderLine(dst, strServer, server)
	}
	dst = appendHeaderLine(dst, strDate, serverDate.Load().([]byte))

	// Append Content-Type only for non-zero responses
	// or if it is explicitly set.
	// See https://github.com/valyala/fasthttp/issues/28 .
	if h.ContentLength() != 0 || len(h.contentType) > 0 {
		dst = appendHeaderLine(dst, strContentType, h.ContentType())
	}

	if len(h.contentLengthBytes) > 0 {
		dst = appendHeaderLine(dst, strContentLength, h.contentLengthBytes)
	}

	for i, n := 0, len(h.h); i < n; i++ {
		kv := &h.h[i]
		if !bytes.Equal(kv.key, strDate) {
			dst = appendHeaderLine(dst, kv.key, kv.value)
		}
	}

	n := len(h.cookies)
	if n > 0 {
		for i := 0; i < n; i++ {
			kv := &h.cookies[i]
			dst = appendHeaderLine(dst, strSetCookie, kv.value)
		}
	}

	if h.ConnectionClose() {
		dst = appendHeaderLine(dst, strConnection, strClose)
	}

	return append(dst, strCRLF...)
}

// AppendBytes appends response header representation to dst and returns
// the extended dst.

AppendBytes appends response header representation to dst and returns the extended dst .


func (h *RequestHeader) Write(w *bufio.Writer) error {
	_, err := w.Write(h.Header())
	return err
}

func ( h * RequestHeader ) Write ( w * bufio . Writer ) error { _ , err := w . Write ( h . Header ( ) ) return err }


func (h *RequestHeader) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(h.Header())
	return int64(n), err
}

func ( h * RequestHeader ) WriteTo ( w io . Writer ) ( int64 , error ) { n , err := w . Write ( h . Header ( ) ) return int64 ( n ) , err }

// WriteTo writes request header to w.
//
// WriteTo implements io.WriterTo interface.

WriteTo writes request header to w . WriteTo implements io . WriterTo interface .


func (h *RequestHeader) Header() []byte {
	h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
	return h.bufKV.value
}

func ( h * RequestHeader ) Header ( ) [ ] byte { h . bufKV . value = h . AppendBytes ( h . bufKV . value [ : 0 ] ) return h . bufKV . value }

// Header returns request header representation.
//
// The returned representation is valid until the next call to RequestHeader methods.

Header returns request header representation . The returned representation is valid until the next call to RequestHeader methods .


func (h *RequestHeader) AppendBytes(dst []byte) []byte {
	// there is no need in h.parseRawHeaders() here - raw headers are specially handled below.
	dst = append(dst, h.Method()...)
	dst = append(dst, ' ')
	dst = append(dst, h.RequestURI()...)
	dst = append(dst, ' ')
	dst = append(dst, strHTTP11...)
	dst = append(dst, strCRLF...)

	if !h.rawHeadersParsed && len(h.rawHeaders) > 0 {
		return append(dst, h.rawHeaders...)
	}

	userAgent := h.UserAgent()
	if len(userAgent) > 0 {
		dst = appendHeaderLine(dst, strUserAgent, userAgent)
	}

	host := h.Host()
	if len(host) > 0 {
		dst = appendHeaderLine(dst, strHost, host)
	}

	contentType := h.ContentType()
	if !h.ignoreBody() {
		if len(contentType) == 0 {
			contentType = strPostArgsContentType
		}
		dst = appendHeaderLine(dst, strContentType, contentType)

		if len(h.contentLengthBytes) > 0 {
			dst = appendHeaderLine(dst, strContentLength, h.contentLengthBytes)
		}
	} else if len(contentType) > 0 {
		dst = appendHeaderLine(dst, strContentType, contentType)
	}

	for i, n := 0, len(h.h); i < n; i++ {
		kv := &h.h[i]
		dst = appendHeaderLine(dst, kv.key, kv.value)
	}

	// there is no need in h.collectCookies() here, since if cookies aren't collected yet,
	// they all are located in h.h.
	n := len(h.cookies)
	if n > 0 {
		dst = append(dst, strCookie...)
		dst = append(dst, strColonSpace...)
		dst = appendRequestCookieBytes(dst, h.cookies)
		dst = append(dst, strCRLF...)
	}

	if h.ConnectionClose() {
		dst = appendHeaderLine(dst, strConnection, strClose)
	}

	return append(dst, strCRLF...)
}

// AppendBytes appends request header representation to dst and returns
// the extended dst.

AppendBytes appends request header representation to dst and returns the extended dst .


func ServeFileUncompressed(ctx *RequestCtx, path string) {
	ctx.Request.Header.DelBytes(strAcceptEncoding)
	ServeFile(ctx, path)
}

func ServeFileUncompressed ( ctx * RequestCtx , path string ) { ctx . Request . Header . DelBytes ( strAcceptEncoding ) ServeFile ( ctx , path ) }

// ServeFileUncompressed returns HTTP response containing file contents
// from the given path.
//
// Directory contents is returned if path points to directory.
//
// ServeFile may be used for saving network traffic when serving files
// with good compression ratio.
//
// See also RequestCtx.SendFile.

ServeFileUncompressed returns HTTP response containing file contents from the given path . Directory contents is returned if path points to directory . ServeFile may be used for saving network traffic when serving files with good compression ratio . See also RequestCtx . SendFile .


func (fs *FS) NewRequestHandler() RequestHandler {
	fs.once.Do(fs.initRequestHandler)
	return fs.h
}

func ( fs * FS ) NewRequestHandler ( ) RequestHandler { fs . once . Do ( fs . initRequestHandler ) return fs . h }

// NewRequestHandler returns new request handler with the given FS settings.
//
// The returned handler caches requested file handles
// for FS.CacheDuration.
// Make sure your program has enough 'max open files' limit aka
// 'ulimit -n' if FS.Root folder contains many files.
//
// Do not create multiple request handlers from a single FS instance -
// just reuse a single request handler.

NewRequestHandler returns new request handler with the given FS settings . The returned handler caches requested file handles for FS . CacheDuration . Make sure your program has enough max open files limit aka ulimit - n if FS . Root folder contains many files . Do not create multiple request handlers from a single FS instance - just reuse a single request handler .


func FileLastModified(path string) (time.Time, error) {
	f, err := os.Open(path)
	if err != nil {
		return zeroTime, err
	}
	fileInfo, err := f.Stat()
	f.Close()
	if err != nil {
		return zeroTime, err
	}
	return fsModTime(fileInfo.ModTime()), nil
}

func FileLastModified ( path string ) ( time . Time , error ) { f , err := os . Open ( path ) if err != nil { return zeroTime , err } fileInfo , err := f . Stat ( ) f . Close ( ) if err != nil { return zeroTime , err } return fsModTime ( fileInfo . ModTime ( ) ) , nil }

// FileLastModified returns last modified time for the file.

FileLastModified returns last modified time for the file .


func (c *Cookie) CopyTo(src *Cookie) {
	c.Reset()
	c.key = append(c.key[:0], src.key...)
	c.value = append(c.value[:0], src.value...)
	c.expire = src.expire
	c.maxAge = src.maxAge
	c.domain = append(c.domain[:0], src.domain...)
	c.path = append(c.path[:0], src.path...)
	c.httpOnly = src.httpOnly
	c.secure = src.secure
	c.sameSite = src.sameSite
}

func ( c * Cookie ) CopyTo ( src * Cookie ) { c . Reset ( ) c . key = append ( c . key [ : 0 ] , src . key ... ) c . value = append ( c . value [ : 0 ] , src . value ... ) c . expire = src . expire c . maxAge = src . maxAge c . domain = append ( c . domain [ : 0 ] , src . domain ... ) c . path = append ( c . path [ : 0 ] , src . path ... ) c . httpOnly = src . httpOnly c . secure = src . secure c . sameSite = src . sameSite }


func (c *Cookie) SetPath(path string) {
	c.buf = append(c.buf[:0], path...)
	c.path = normalizePath(c.path, c.buf)
}

func ( c * Cookie ) SetPath ( path string ) { c . buf = append ( c . buf [ : 0 ] , path ... ) c . path = normalizePath ( c . path , c . buf ) }


func (c *Cookie) SetPathBytes(path []byte) {
	c.buf = append(c.buf[:0], path...)
	c.path = normalizePath(c.path, c.buf)
}

func ( c * Cookie ) SetPathBytes ( path [ ] byte ) { c . buf = append ( c . buf [ : 0 ] , path ... ) c . path = normalizePath ( c . path , c . buf ) }


func (c *Cookie) SetDomain(domain string) {
	c.domain = append(c.domain[:0], domain...)
}

func ( c * Cookie ) SetDomain ( domain string ) { c . domain = append ( c . domain [ : 0 ] , domain ... ) }


func (c *Cookie) SetDomainBytes(domain []byte) {
	c.domain = append(c.domain[:0], domain...)
}

func ( c * Cookie ) SetDomainBytes ( domain [ ] byte ) { c . domain = append ( c . domain [ : 0 ] , domain ... ) }


func (c *Cookie) Expire() time.Time {
	expire := c.expire
	if expire.IsZero() {
		expire = CookieExpireUnlimited
	}
	return expire
}

func ( c * Cookie ) Expire ( ) time . Time { expire := c . expire if expire . IsZero ( ) { expire = CookieExpireUnlimited } return expire }

// Expire returns cookie expiration time.
//
// CookieExpireUnlimited is returned if cookie doesn't expire

Expire returns cookie expiration time . CookieExpireUnlimited is returned if cookie doesn t expire


func (c *Cookie) SetValue(value string) {
	c.value = append(c.value[:0], value...)
}

func ( c * Cookie ) SetValue ( value string ) { c . value = append ( c . value [ : 0 ] , value ... ) }


func (c *Cookie) SetValueBytes(value []byte) {
	c.value = append(c.value[:0], value...)
}

func ( c * Cookie ) SetValueBytes ( value [ ] byte ) { c . value = append ( c . value [ : 0 ] , value ... ) }


func (c *Cookie) SetKey(key string) {
	c.key = append(c.key[:0], key...)
}

func ( c * Cookie ) SetKey ( key string ) { c . key = append ( c . key [ : 0 ] , key ... ) }


func (c *Cookie) SetKeyBytes(key []byte) {
	c.key = append(c.key[:0], key...)
}

func ( c * Cookie ) SetKeyBytes ( key [ ] byte ) { c . key = append ( c . key [ : 0 ] , key ... ) }


func (c *Cookie) Reset() {
	c.key = c.key[:0]
	c.value = c.value[:0]
	c.expire = zeroTime
	c.maxAge = 0
	c.domain = c.domain[:0]
	c.path = c.path[:0]
	c.httpOnly = false
	c.secure = false
	c.sameSite = CookieSameSiteDisabled
}

func ( c * Cookie ) Reset ( ) { c . key = c . key [ : 0 ] c . value = c . value [ : 0 ] c . expire = zeroTime c . maxAge = 0 c . domain = c . domain [ : 0 ] c . path = c . path [ : 0 ] c . httpOnly = false c . secure = false c . sameSite = CookieSameSiteDisabled }


func (c *Cookie) AppendBytes(dst []byte) []byte {
	if len(c.key) > 0 {
		dst = append(dst, c.key...)
		dst = append(dst, '=')
	}
	dst = append(dst, c.value...)

	if c.maxAge > 0 {
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieMaxAge...)
		dst = append(dst, '=')
		dst = AppendUint(dst, c.maxAge)
	} else if !c.expire.IsZero() {
		c.bufKV.value = AppendHTTPDate(c.bufKV.value[:0], c.expire)
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieExpires...)
		dst = append(dst, '=')
		dst = append(dst, c.bufKV.value...)
	}
	if len(c.domain) > 0 {
		dst = appendCookiePart(dst, strCookieDomain, c.domain)
	}
	if len(c.path) > 0 {
		dst = appendCookiePart(dst, strCookiePath, c.path)
	}
	if c.httpOnly {
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieHTTPOnly...)
	}
	if c.secure {
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieSecure...)
	}
	switch c.sameSite {
	case CookieSameSiteDefaultMode:
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieSameSite...)
	case CookieSameSiteLaxMode:
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieSameSite...)
		dst = append(dst, '=')
		dst = append(dst, strCookieSameSiteLax...)
	case CookieSameSiteStrictMode:
		dst = append(dst, ';', ' ')
		dst = append(dst, strCookieSameSite...)
		dst = append(dst, '=')
		dst = append(dst, strCookieSameSiteStrict...)
	}
	return dst
}

func
(
c
*
Cookie
)
AppendBytes
(
dst
[
]
byte
)
[
]
byte
{
if
len
(
c
.
key
)
>
0
{
dst
=
append
(
dst
,
c
.
key
...
)
dst
=
append
(
dst
,
'='
)
}
dst
=
append
(
dst
,
c
.
value
...
)
if
c
.
maxAge
>
0
{
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieMaxAge
...
)
dst
=
append
(
dst
,
'='
)
dst
=
AppendUint
(
dst
,
c
.
maxAge
)
}
else
if
!
c
.
expire
.
IsZero
(
)
{
c
.
bufKV
.
value
=
AppendHTTPDate
(
c
.
bufKV
.
value
[
:
0
]
,
c
.
expire
)
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieExpires
...
)
dst
=
append
(
dst
,
'='
)
dst
=
append
(
dst
,
c
.
bufKV
.
value
...
)
}
if
len
(
c
.
domain
)
>
0
{
dst
=
appendCookiePart
(
dst
,
strCookieDomain
,
c
.
domain
)
}
if
len
(
c
.
path
)
>
0
{
dst
=
appendCookiePart
(
dst
,
strCookiePath
,
c
.
path
)
}
if
c
.
httpOnly
{
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieHTTPOnly
...
)
}
if
c
.
secure
{
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieSecure
...
)
}
switch
c
.
sameSite
{
case
CookieSameSiteDefaultMode
:
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieSameSite
...
)
case
CookieSameSiteLaxMode
:
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieSameSite
...
)
dst
=
append
(
dst
,
'='
)
dst
=
append
(
dst
,
strCookieSameSiteLax
...
)
case
CookieSameSiteStrictMode
:
dst
=
append
(
dst
,
';'
,
' '
)
dst
=
append
(
dst
,
strCookieSameSite
...
)
dst
=
append
(
dst
,
'='
)
dst
=
append
(
dst
,
strCookieSameSiteStrict
...
)
}
return
dst
}

// AppendBytes appends cookie representation to dst and returns
// the extended dst.

AppendBytes appends cookie representation to dst and returns the extended dst .


func (c *Cookie) Cookie() []byte {
	c.buf = c.AppendBytes(c.buf[:0])
	return c.buf
}

func ( c * Cookie ) Cookie ( ) [ ] byte { c . buf = c . AppendBytes ( c . buf [ : 0 ] ) return c . buf }

// Cookie returns cookie representation.
//
// The returned value is valid until the next call to Cookie methods.

Cookie returns cookie representation . The returned value is valid until the next call to Cookie methods .


func (c *Cookie) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(c.Cookie())
	return int64(n), err
}

func ( c * Cookie ) WriteTo ( w io . Writer ) ( int64 , error ) { n , err := w . Write ( c . Cookie ( ) ) return int64 ( n ) , err }

// WriteTo writes cookie representation to w.
//
// WriteTo implements io.WriterTo interface.

WriteTo writes cookie representation to w . WriteTo implements io . WriterTo interface .


func (c *Cookie) Parse(src string) error {
	c.buf = append(c.buf[:0], src...)
	return c.ParseBytes(c.buf)
}

func ( c * Cookie ) Parse ( src string ) error { c . buf = append ( c . buf [ : 0 ] , src ... ) return c . ParseBytes ( c . buf ) }


func (c *Cookie) ParseBytes(src []byte) error {
	c.Reset()

	var s cookieScanner
	s.b = src

	kv := &c.bufKV
	if !s.next(kv) {
		return errNoCookies
	}

	c.key = append(c.key[:0], kv.key...)
	c.value = append(c.value[:0], kv.value...)

	for s.next(kv) {
		if len(kv.key) != 0 {
			// Case insensitive switch on first char
			switch kv.key[0] | 0x20 {
			case 'm':
				if caseInsensitiveCompare(strCookieMaxAge, kv.key) {
					maxAge, err := ParseUint(kv.value)
					if err != nil {
						return err
					}
					c.maxAge = maxAge
				}

			case 'e': // "expires"
				if caseInsensitiveCompare(strCookieExpires, kv.key) {
					v := b2s(kv.value)
					// Try the same two formats as net/http
					// See: https://github.com/golang/go/blob/00379be17e63a5b75b3237819392d2dc3b313a27/src/net/http/cookie.go#L133-L135
					exptime, err := time.ParseInLocation(time.RFC1123, v, time.UTC)
					if err != nil {
						exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", v)
						if err != nil {
							return err
						}
					}
					c.expire = exptime
				}

			case 'd': // "domain"
				if caseInsensitiveCompare(strCookieDomain, kv.key) {
					c.domain = append(c.domain[:0], kv.value...)
				}

			case 'p': // "path"
				if caseInsensitiveCompare(strCookiePath, kv.key) {
					c.path = append(c.path[:0], kv.value...)
				}

			case 's': // "samesite"
				if caseInsensitiveCompare(strCookieSameSite, kv.key) {
					// Case insensitive switch on first char
					switch kv.value[0] | 0x20 {
					case 'l': // "lax"
						if caseInsensitiveCompare(strCookieSameSiteLax, kv.value) {
							c.sameSite = CookieSameSiteLaxMode
						}
					case 's': // "strict"
						if caseInsensitiveCompare(strCookieSameSiteStrict, kv.value) {
							c.sameSite = CookieSameSiteStrictMode
						}
					}
				}
			}

		} else if len(kv.value) != 0 {
			// Case insensitive switch on first char
			switch kv.value[0] | 0x20 {
			case 'h': // "httponly"
				if caseInsensitiveCompare(strCookieHTTPOnly, kv.value) {
					c.httpOnly = true
				}

			case 's': // "secure"
				if caseInsensitiveCompare(strCookieSecure, kv.value) {
					c.secure = true
				} else if caseInsensitiveCompare(strCookieSameSite, kv.value) {
					c.sameSite = CookieSameSiteDefaultMode
				}
			}
		} // else empty or no match
	}
	return nil
}


func appendResponseCookieBytes(dst []byte, cookies []argsKV) []byte {
	for i, n := 0, len(cookies); i < n; i++ {
		kv := &cookies[i]
		dst = append(dst, kv.value...)
		if i+1 < n {
			dst = append(dst, ';', ' ')
		}
	}
	return dst
}

func
appendResponseCookieBytes
(
dst
[
]
byte
,
cookies
[
]
argsKV
)
[
]
byte
{
for
i
,
n
:=
0
,
len
(
cookies
)
;
i
<
n
;
i
++
{
kv
:=
&
cookies
[
i
]
dst
=
append
(
dst
,
kv
.
value
...
)
if
i
+
1
<
n
{
dst
=
append
(
dst
,
';'
,
' '
)
}
}
return
dst
}

// For Response we can not use the above function as response cookies
// already contain the key= in the value.

For Response we can not use the above function as response cookies already contain the key = in the value .


func AcquireTimer(timeout time.Duration) *time.Timer {
	v := timerPool.Get()
	if v == nil {
		return time.NewTimer(timeout)
	}
	t := v.(*time.Timer)
	initTimer(t, timeout)
	return t
}

func AcquireTimer ( timeout time . Duration ) * time . Timer { v := timerPool . Get ( ) if v == nil { return time . NewTimer ( timeout ) } t := v . ( * time . Timer ) initTimer ( t , timeout ) return t }

// AcquireTimer returns a time.Timer from the pool and updates it to
// send the current time on its channel after at least timeout.
//
// The returned Timer may be returned to the pool with ReleaseTimer
// when no longer needed. This allows reducing GC load.

AcquireTimer returns a time . Timer from the pool and updates it to send the current time on its channel after at least timeout . The returned Timer may be returned to the pool with ReleaseTimer when no longer needed . This allows reducing GC load .


func (ln *InmemoryListener) Accept() (net.Conn, error) {
	c, ok := <-ln.conns
	if !ok {
		return nil, fmt.Errorf("InmemoryListener is already closed: use of closed network connection")
	}
	close(c.accepted)
	return c.conn, nil
}

func ( ln * InmemoryListener ) Accept ( ) ( net . Conn , error ) { c , ok := <- ln . conns if ! ok { return nil , fmt . Errorf ( " " ) } close ( c . accepted ) return c . conn , nil }

// Accept implements net.Listener's Accept.
//
// It is safe calling Accept from concurrently running goroutines.
//
// Accept returns new connection per each Dial call.

Accept implements net . Listener s Accept . It is safe calling Accept from concurrently running goroutines . Accept returns new connection per each Dial call .


func (ln *InmemoryListener) Close() error {
	var err error

	ln.lock.Lock()
	if !ln.closed {
		close(ln.conns)
		ln.closed = true
	} else {
		err = fmt.Errorf("InmemoryListener is already closed")
	}
	ln.lock.Unlock()
	return err
}

func ( ln * InmemoryListener ) Close ( ) error { var err error ln . lock . Lock ( ) if ! ln . closed { close ( ln . conns ) ln . closed = true } else { err = fmt . Errorf ( " " ) } ln . lock . Unlock ( ) return err }

// Close implements net.Listener's Close.

Close implements net . Listener s Close .


func FileServer(r chi.Router, path string, root http.FileSystem) {
	if strings.ContainsAny(path, "{}*") {
		panic("FileServer does not permit URL parameters.")
	}

	fs := http.StripPrefix(path, http.FileServer(root))

	if path != "/" && path[len(path)-1] != '/' {
		r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
		path += "/"
	}
	path += "*"

	r.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fs.ServeHTTP(w, r)
	}))
}

func FileServer ( r chi . Router , path string , root http . FileSystem ) { if strings . ContainsAny ( path , " " ) { panic ( " " ) } fs := http . StripPrefix ( path , http . FileServer ( root ) ) if path != " " && path [ len ( path ) - 1 ] != '/' { r . Get ( path , http . RedirectHandler ( path + " " , 301 ) . ServeHTTP ) path += " " } path += " " r . Get ( path , http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { fs . ServeHTTP ( w , r ) } ) ) }

// FileServer conveniently sets up a http.FileServer handler to serve
// static files from a http.FileSystem.

FileServer conveniently sets up a http . FileServer handler to serve static files from a http . FileSystem .


func (x *Context) Reset() {
	x.Routes = nil
	x.RoutePath = ""
	x.RouteMethod = ""
	x.RoutePatterns = x.RoutePatterns[:0]
	x.URLParams.Keys = x.URLParams.Keys[:0]
	x.URLParams.Values = x.URLParams.Values[:0]

	x.routePattern = ""
	x.routeParams.Keys = x.routeParams.Keys[:0]
	x.routeParams.Values = x.routeParams.Values[:0]
	x.methodNotAllowed = false
}

func ( x * Context ) Reset ( ) { x . Routes = nil x . RoutePath = " " x . RouteMethod = " " x . RoutePatterns = x . RoutePatterns [ : 0 ] x . URLParams . Keys = x . URLParams . Keys [ : 0 ] x . URLParams . Values = x . URLParams . Values [ : 0 ] x . routePattern = " " x . routeParams . Keys = x . routeParams . Keys [ : 0 ] x . routeParams . Values = x . routeParams . Values [ : 0 ] x . methodNotAllowed = false }

// Reset a routing context to its initial state.

Reset a routing context to its initial state .


func (x *Context) URLParam(key string) string {
	for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
		if x.URLParams.Keys[k] == key {
			return x.URLParams.Values[k]
		}
	}
	return ""
}

func ( x * Context ) URLParam ( key string ) string { for k := len ( x . URLParams . Keys ) - 1 ; k >= 0 ; k -- { if x . URLParams . Keys [ k ] == key { return x . URLParams . Values [ k ] } } return " " }

// URLParam returns the corresponding URL parameter value from the request
// routing context.

URLParam returns the corresponding URL parameter value from the request routing context .


func URLParam(r *http.Request, key string) string {
	if rctx := RouteContext(r.Context()); rctx != nil {
		return rctx.URLParam(key)
	}
	return ""
}

func URLParam ( r * http . Request , key string ) string { if rctx := RouteContext ( r . Context ( ) ) ; rctx != nil { return rctx . URLParam ( key ) } return " " }

// URLParam returns the url parameter from a http.Request object.

URLParam returns the url parameter from a http . Request object .


func URLParamFromCtx(ctx context.Context, key string) string {
	if rctx := RouteContext(ctx); rctx != nil {
		return rctx.URLParam(key)
	}
	return ""
}

func URLParamFromCtx ( ctx context . Context , key string ) string { if rctx := RouteContext ( ctx ) ; rctx != nil { return rctx . URLParam ( key ) } return " " }

// URLParamFromCtx returns the url parameter from a http.Request Context.

URLParamFromCtx returns the url parameter from a http . Request Context .


func (s *RouteParams) Add(key, value string) {
	(*s).Keys = append((*s).Keys, key)
	(*s).Values = append((*s).Values, value)
}

func ( s * RouteParams ) Add ( key , value string ) { ( * s ) . Keys = append ( ( * s ) . Keys , key ) ( * s ) . Values = append ( ( * s ) . Values , value ) }

// Add will append a URL parameter to the end of the route param


func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler {
	fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		baseCtx := baseCtx

		// Copy over default net/http server context keys
		if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok {
			baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v)
		}
		if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok {
			baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v)
		}

		h.ServeHTTP(w, r.WithContext(baseCtx))
	})
	return fn
}

// ServerBaseContext wraps an http.Handler to set the request context to the
// `baseCtx`.

ServerBaseContext wraps an http . Handler to set the request context to the baseCtx .


func GetHead(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			rctx := chi.RouteContext(r.Context())
			routePath := rctx.RoutePath
			if routePath == "" {
				if r.URL.RawPath != "" {
					routePath = r.URL.RawPath
				} else {
					routePath = r.URL.Path
				}
			}

			// Temporary routing context to look-ahead before routing the request
			tctx := chi.NewRouteContext()

			// Attempt to find a HEAD handler for the routing path, if not found, traverse
			// the router as through its a GET route, but proceed with the request
			// with the HEAD method.
			if !rctx.Routes.Match(tctx, "HEAD", routePath) {
				rctx.RouteMethod = "GET"
				rctx.RoutePath = routePath
				next.ServeHTTP(w, r)
				return
			}
		}

		next.ServeHTTP(w, r)
	})
}

// GetHead automatically route undefined HEAD requests to GET handlers.

GetHead automatically route undefined HEAD requests to GET handlers .


func Ping(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("pong"))
}

func Ping ( w http . ResponseWriter , r * http . Request ) { w . Write ( [ ] byte ( " " ) ) }


func StripSlashes(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var path string
		rctx := chi.RouteContext(r.Context())
		if rctx.RoutePath != "" {
			path = rctx.RoutePath
		} else {
			path = r.URL.Path
		}
		if len(path) > 1 && path[len(path)-1] == '/' {
			rctx.RoutePath = path[:len(path)-1]
		}
		next.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func StripSlashes ( next http . Handler ) http . Handler { fn := func ( w http . ResponseWriter , r * http . Request ) { var path string rctx := chi . RouteContext ( r . Context ( ) ) if rctx . RoutePath != " " { path = rctx . RoutePath } else { path = r . URL . Path } if len ( path ) > 1 && path [ len ( path ) - 1 ] == '/' { rctx . RoutePath = path [ : len ( path ) - 1 ] } next . ServeHTTP ( w , r ) } return http . HandlerFunc ( fn ) }

// StripSlashes is a middleware that will match request paths with a trailing
// slash, strip it from the path and continue routing through the mux, if a route
// matches, then it will serve the handler.

StripSlashes is a middleware that will match request paths with a trailing slash strip it from the path and continue routing through the mux if a route matches then it will serve the handler .


func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler {
	cT := []string{}
	for _, t := range contentTypes {
		cT = append(cT, strings.ToLower(t))
	}

	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if r.ContentLength == 0 {
				// skip check for empty content body
				next.ServeHTTP(w, r)
				return
			}

			s := strings.ToLower(strings.TrimSpace(r.Header.Get("Content-Type")))
			if i := strings.Index(s, ";"); i > -1 {
				s = s[0:i]
			}

			for _, t := range cT {
				if t == s {
					next.ServeHTTP(w, r)
					return
				}
			}

			w.WriteHeader(http.StatusUnsupportedMediaType)
		}
		return http.HandlerFunc(fn)
	}
}

func
AllowContentType
(
contentTypes
...
string
)
func
(
next
http
.
Handler
)
http
.
Handler
{
cT
:=
[
]
string
{
}
for
_
,
t
:=
range
contentTypes
{
cT
=
append
(
cT
,
strings
.
ToLower
(
t
)
)
}
return
func
(
next
http
.
Handler
)
http
.
Handler
{
fn
:=
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
r
.
ContentLength
==
0
{
// skip check for empty content body
next
.
ServeHTTP
(
w
,
r
)
return
}
s
:=
strings
.
ToLower
(
strings
.
TrimSpace
(
r
.
Header
.
Get
(
"
"
)
)
)
if
i
:=
strings
.
Index
(
s
,
"
"
)
;
i
>
1
{
s
=
s
[
0
:
i
]
}
for
_
,
t
:=
range
cT
{
if
t
==
s
{
next
.
ServeHTTP
(
w
,
r
)
return
}
}
w
.
WriteHeader
(
http
.
StatusUnsupportedMediaType
)
}
return
http
.
HandlerFunc
(
fn
)
}
}

// AllowContentType enforces a whitelist of request Content-Types otherwise responds
// with a 415 Unsupported Media Type status.

AllowContentType enforces a whitelist of request Content - Types otherwise responds with a 415 Unsupported Media Type status .


func GetReqID(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
		return reqID
	}
	return ""
}

func GetReqID ( ctx context . Context ) string { if ctx == nil { return " " } if reqID , ok := ctx . Value ( RequestIDKey ) . ( string ) ; ok { return reqID } return " " }

// GetReqID returns a request ID from the given context if one is present.
// Returns the empty string if a request ID cannot be found.

GetReqID returns a request ID from the given context if one is present . Returns the empty string if a request ID cannot be found .


func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler {
	return &ChainHandler{mws, h, chain(mws, h)}
}

func ( mws Middlewares ) HandlerFunc ( h http . HandlerFunc ) http . Handler { return & ChainHandler { mws , h , chain ( mws , h ) } }

// HandlerFunc builds and returns a http.Handler from the chain of middlewares,
// with `h http.Handler` as the final handler.

HandlerFunc builds and returns a http . Handler from the chain of middlewares with h http . Handler as the final handler .


func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
	// Return ahead of time if there aren't any middlewares for the chain
	if len(middlewares) == 0 {
		return endpoint
	}

	// Wrap the end handler with the middleware chain
	h := middlewares[len(middlewares)-1](endpoint)
	for i := len(middlewares) - 2; i >= 0; i-- {
		h = middlewares[i](h)
	}

	return h
}

// chain builds a http.Handler composed of an inline middleware stack and endpoint
// handler in the order they are passed.

chain builds a http . Handler composed of an inline middleware stack and endpoint handler in the order they are passed .


func NewMux() *Mux {
	mux := &Mux{tree: &node{}, pool: &sync.Pool{}}
	mux.pool.New = func() interface{} {
		return NewRouteContext()
	}
	return mux
}

func NewMux ( ) * Mux { mux := & Mux { tree : & node { } , pool : & sync . Pool { } } mux . pool . New = func ( ) interface { } { return NewRouteContext ( ) } return mux }

// NewMux returns a newly initialized Mux object that implements the Router
// interface.

NewMux returns a newly initialized Mux object that implements the Router interface .


func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Ensure the mux has some routes defined on the mux
	if mx.handler == nil {
		mx.NotFoundHandler().ServeHTTP(w, r)
		return
	}

	// Check if a routing context already exists from a parent router.
	rctx, _ := r.Context().Value(RouteCtxKey).(*Context)
	if rctx != nil {
		mx.handler.ServeHTTP(w, r)
		return
	}

	// Fetch a RouteContext object from the sync pool, and call the computed
	// mx.handler that is comprised of mx.middlewares + mx.routeHTTP.
	// Once the request is finished, reset the routing context and put it back
	// into the pool for reuse from another request.
	rctx = mx.pool.Get().(*Context)
	rctx.Reset()
	rctx.Routes = mx
	r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx))
	mx.handler.ServeHTTP(w, r)
	mx.pool.Put(rctx)
}

// ServeHTTP is the single method of the http.Handler interface that makes
// Mux interoperable with the standard library. It uses a sync.Pool to get and
// reuse routing contexts for each request.

ServeHTTP is the single method of the http . Handler interface that makes Mux interoperable with the standard library . It uses a sync . Pool to get and reuse routing contexts for each request .


func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) {
	if mx.handler != nil {
		panic("chi: all middlewares must be defined before routes on a mux")
	}
	mx.middlewares = append(mx.middlewares, middlewares...)
}

func ( mx * Mux ) Use ( middlewares ... func ( http . Handler ) http . Handler ) { if mx . handler != nil { panic ( " " ) } mx . middlewares = append ( mx . middlewares , middlewares ... ) }

// Use appends a middleware handler to the Mux middleware stack.
//
// The middleware stack for any Mux will execute before searching for a matching
// route to a specific handler, which provides opportunity to respond early,
// change the course of the request execution, or set request-scoped values for
// the next http.Handler.

Use appends a middleware handler to the Mux middleware stack . The middleware stack for any Mux will execute before searching for a matching route to a specific handler which provides opportunity to respond early change the course of the request execution or set request - scoped values for the next http . Handler .


func (mx *Mux) Handle(pattern string, handler http.Handler) {
	mx.handle(mALL, pattern, handler)
}

func ( mx * Mux ) Handle ( pattern string , handler http . Handler ) { mx . handle ( mALL , pattern , handler ) }

// Handle adds the route `pattern` that matches any http method to
// execute the `handler` http.Handler.

Handle adds the route pattern that matches any http method to execute the handler http . Handler .


func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mALL, pattern, handlerFn)
}

func ( mx * Mux ) HandleFunc ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mALL , pattern , handlerFn ) }

// HandleFunc adds the route `pattern` that matches any http method to
// execute the `handlerFn` http.HandlerFunc.

HandleFunc adds the route pattern that matches any http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Method(method, pattern string, handler http.Handler) {
	m, ok := methodMap[strings.ToUpper(method)]
	if !ok {
		panic(fmt.Sprintf("chi: '%s' http method is not supported.", method))
	}
	mx.handle(m, pattern, handler)
}

func ( mx * Mux ) Method ( method , pattern string , handler http . Handler ) { m , ok := methodMap [ strings . ToUpper ( method ) ] if ! ok { panic ( fmt . Sprintf ( " " , method ) ) } mx . handle ( m , pattern , handler ) }

// Method adds the route `pattern` that matches `method` http method to
// execute the `handler` http.Handler.

Method adds the route pattern that matches method http method to execute the handler http . Handler .


func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) {
	mx.Method(method, pattern, handlerFn)
}

func ( mx * Mux ) MethodFunc ( method , pattern string , handlerFn http . HandlerFunc ) { mx . Method ( method , pattern , handlerFn ) }

// MethodFunc adds the route `pattern` that matches `method` http method to
// execute the `handlerFn` http.HandlerFunc.

MethodFunc adds the route pattern that matches method http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mCONNECT, pattern, handlerFn)
}

func ( mx * Mux ) Connect ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mCONNECT , pattern , handlerFn ) }

// Connect adds the route `pattern` that matches a CONNECT http method to
// execute the `handlerFn` http.HandlerFunc.

Connect adds the route pattern that matches a CONNECT http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mDELETE, pattern, handlerFn)
}

func ( mx * Mux ) Delete ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mDELETE , pattern , handlerFn ) }

// Delete adds the route `pattern` that matches a DELETE http method to
// execute the `handlerFn` http.HandlerFunc.

Delete adds the route pattern that matches a DELETE http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mGET, pattern, handlerFn)
}

func ( mx * Mux ) Get ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mGET , pattern , handlerFn ) }

// Get adds the route `pattern` that matches a GET http method to
// execute the `handlerFn` http.HandlerFunc.

Get adds the route pattern that matches a GET http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mHEAD, pattern, handlerFn)
}

func ( mx * Mux ) Head ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mHEAD , pattern , handlerFn ) }

// Head adds the route `pattern` that matches a HEAD http method to
// execute the `handlerFn` http.HandlerFunc.

Head adds the route pattern that matches a HEAD http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mOPTIONS, pattern, handlerFn)
}

func ( mx * Mux ) Options ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mOPTIONS , pattern , handlerFn ) }

// Options adds the route `pattern` that matches a OPTIONS http method to
// execute the `handlerFn` http.HandlerFunc.

Options adds the route pattern that matches a OPTIONS http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mPATCH, pattern, handlerFn)
}

func ( mx * Mux ) Patch ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mPATCH , pattern , handlerFn ) }

// Patch adds the route `pattern` that matches a PATCH http method to
// execute the `handlerFn` http.HandlerFunc.

Patch adds the route pattern that matches a PATCH http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mPOST, pattern, handlerFn)
}

func ( mx * Mux ) Post ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mPOST , pattern , handlerFn ) }

// Post adds the route `pattern` that matches a POST http method to
// execute the `handlerFn` http.HandlerFunc.

Post adds the route pattern that matches a POST http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mPUT, pattern, handlerFn)
}

func ( mx * Mux ) Put ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mPUT , pattern , handlerFn ) }

// Put adds the route `pattern` that matches a PUT http method to
// execute the `handlerFn` http.HandlerFunc.

Put adds the route pattern that matches a PUT http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) {
	mx.handle(mTRACE, pattern, handlerFn)
}

func ( mx * Mux ) Trace ( pattern string , handlerFn http . HandlerFunc ) { mx . handle ( mTRACE , pattern , handlerFn ) }

// Trace adds the route `pattern` that matches a TRACE http method to
// execute the `handlerFn` http.HandlerFunc.

Trace adds the route pattern that matches a TRACE http method to execute the handlerFn http . HandlerFunc .


func (mx *Mux) NotFound(handlerFn http.HandlerFunc) {
	// Build NotFound handler chain
	m := mx
	hFn := handlerFn
	if mx.inline && mx.parent != nil {
		m = mx.parent
		hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
	}

	// Update the notFoundHandler from this point forward
	m.notFoundHandler = hFn
	m.updateSubRoutes(func(subMux *Mux) {
		if subMux.notFoundHandler == nil {
			subMux.NotFound(hFn)
		}
	})
}

// NotFound sets a custom http.HandlerFunc for routing paths that could
// not be found. The default 404 handler is `http.NotFound`.

NotFound sets a custom http . HandlerFunc for routing paths that could not be found . The default 404 handler is http . NotFound .


func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) {
	// Build MethodNotAllowed handler chain
	m := mx
	hFn := handlerFn
	if mx.inline && mx.parent != nil {
		m = mx.parent
		hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
	}

	// Update the methodNotAllowedHandler from this point forward
	m.methodNotAllowedHandler = hFn
	m.updateSubRoutes(func(subMux *Mux) {
		if subMux.methodNotAllowedHandler == nil {
			subMux.MethodNotAllowed(hFn)
		}
	})
}

// MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the
// method is unresolved. The default handler returns a 405 with an empty body.

MethodNotAllowed sets a custom http . HandlerFunc for routing paths where the method is unresolved . The default handler returns a 405 with an empty body .


func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router {
	// Similarly as in handle(), we must build the mux handler once further
	// middleware registration isn't allowed for this stack, like now.
	if !mx.inline && mx.handler == nil {
		mx.buildRouteHandler()
	}

	// Copy middlewares from parent inline muxs
	var mws Middlewares
	if mx.inline {
		mws = make(Middlewares, len(mx.middlewares))
		copy(mws, mx.middlewares)
	}
	mws = append(mws, middlewares...)

	im := &Mux{pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws}

	return im
}

// With adds inline middlewares for an endpoint handler.

With adds inline middlewares for an endpoint handler .


func (mx *Mux) NotFoundHandler() http.HandlerFunc {
	if mx.notFoundHandler != nil {
		return mx.notFoundHandler
	}
	return http.NotFound
}

func ( mx * Mux ) NotFoundHandler ( ) http . HandlerFunc { if mx . notFoundHandler != nil { return mx . notFoundHandler } return http . NotFound }

// NotFoundHandler returns the default Mux 404 responder whenever a route
// cannot be found.

NotFoundHandler returns the default Mux 404 responder whenever a route cannot be found .


func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc {
	if mx.methodNotAllowedHandler != nil {
		return mx.methodNotAllowedHandler
	}
	return methodNotAllowedHandler
}

func ( mx * Mux ) MethodNotAllowedHandler ( ) http . HandlerFunc { if mx . methodNotAllowedHandler != nil { return mx . methodNotAllowedHandler } return methodNotAllowedHandler }

// MethodNotAllowedHandler returns the default Mux 405 responder whenever
// a method cannot be resolved for a route.

MethodNotAllowedHandler returns the default Mux 405 responder whenever a method cannot be resolved for a route .


func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node {
	if len(pattern) == 0 || pattern[0] != '/' {
		panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern))
	}

	// Build the final routing handler for this Mux.
	if !mx.inline && mx.handler == nil {
		mx.buildRouteHandler()
	}

	// Build endpoint handler with inline middlewares for the route
	var h http.Handler
	if mx.inline {
		mx.handler = http.HandlerFunc(mx.routeHTTP)
		h = Chain(mx.middlewares...).Handler(handler)
	} else {
		h = handler
	}

	// Add the endpoint to the tree and return the node
	return mx.tree.InsertRoute(method, pattern, h)
}

// handle registers a http.Handler in the routing tree for a particular http method
// and routing pattern.

handle registers a http . Handler in the routing tree for a particular http method and routing pattern .


func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
	// Grab the route context object
	rctx := r.Context().Value(RouteCtxKey).(*Context)

	// The request routing path
	routePath := rctx.RoutePath
	if routePath == "" {
		if r.URL.RawPath != "" {
			routePath = r.URL.RawPath
		} else {
			routePath = r.URL.Path
		}
	}

	// Check if method is supported by chi
	if rctx.RouteMethod == "" {
		rctx.RouteMethod = r.Method
	}
	method, ok := methodMap[rctx.RouteMethod]
	if !ok {
		mx.MethodNotAllowedHandler().ServeHTTP(w, r)
		return
	}

	// Find the route
	if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
		h.ServeHTTP(w, r)
		return
	}
	if rctx.methodNotAllowed {
		mx.MethodNotAllowedHandler().ServeHTTP(w, r)
	} else {
		mx.NotFoundHandler().ServeHTTP(w, r)
	}
}

func
(
mx
*
Mux
)
routeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
// Grab the route context object
rctx
:=
r
.
Context
(
)
.
Value
(
RouteCtxKey
)
.
(
*
Context
)
// The request routing path
routePath
:=
rctx
.
RoutePath
if
routePath
==
"
"
{
if
r
.
URL
.
RawPath
!=
"
"
{
routePath
=
r
.
URL
.
RawPath
}
else
{
routePath
=
r
.
URL
.
Path
}
}
// Check if method is supported by chi
if
rctx
.
RouteMethod
==
"
"
{
rctx
.
RouteMethod
=
r
.
Method
}
method
,
ok
:=
methodMap
[
rctx
.
RouteMethod
]
if
!
ok
{
mx
.
MethodNotAllowedHandler
(
)
.
ServeHTTP
(
w
,
r
)
return
}
// Find the route
if
_
,
_
,
h
:=
mx
.
tree
.
FindRoute
(
rctx
,
method
,
routePath
)
;
h
!=
{
h
.
ServeHTTP
(
w
,
r
)
return
}
if
rctx
.
methodNotAllowed
{
mx
.
MethodNotAllowedHandler
(
)
.
ServeHTTP
(
w
,
r
)
}
else
{
mx
.
NotFoundHandler
(
)
.
ServeHTTP
(
w
,
r
)
}
}

// routeHTTP routes a http.Request through the Mux routing tree to serve
// the matching handler for a particular http method.

routeHTTP routes a http . Request through the Mux routing tree to serve the matching handler for a particular http method .


func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) {
	for _, r := range mx.tree.routes() {
		subMux, ok := r.SubRoutes.(*Mux)
		if !ok {
			continue
		}
		fn(subMux)
	}
}

func ( mx * Mux ) updateSubRoutes ( fn func ( subMux * Mux ) ) { for _ , r := range mx . tree . routes ( ) { subMux , ok := r . SubRoutes . ( * Mux ) if ! ok { continue } fn ( subMux ) } }

// Recursively update data on child routers.

Recursively update data on child routers .


func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(405)
	w.Write(nil)
}

func methodNotAllowedHandler ( w http . ResponseWriter , r * http . Request ) { w . WriteHeader ( 405 ) w . Write ( nil ) }

// methodNotAllowedHandler is a helper function to respond with a 405,
// method not allowed.

methodNotAllowedHandler is a helper function to respond with a 405 method not allowed .


func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			entry := f.NewLogEntry(r)
			ww := NewWrapResponseWriter(w, r.ProtoMajor)

			t1 := time.Now()
			defer func() {
				entry.Write(ww.Status(), ww.BytesWritten(), time.Since(t1))
			}()

			next.ServeHTTP(ww, WithLogEntry(r, entry))
		}
		return http.HandlerFunc(fn)
	}
}

func RequestLogger ( f LogFormatter ) func ( next http . Handler ) http . Handler { return func ( next http . Handler ) http . Handler { fn := func ( w http . ResponseWriter , r * http . Request ) { entry := f . NewLogEntry ( r ) ww := NewWrapResponseWriter ( w , r . ProtoMajor ) t1 := time . Now ( ) defer func ( ) { entry . Write ( ww . Status ( ) , ww . BytesWritten ( ) , time . Since ( t1 ) ) } ( ) next . ServeHTTP ( ww , WithLogEntry ( r , entry ) ) } return http . HandlerFunc ( fn ) } }

// RequestLogger returns a logger handler using a custom LogFormatter.

RequestLogger returns a logger handler using a custom LogFormatter .


func GetLogEntry(r *http.Request) LogEntry {
	entry, _ := r.Context().Value(LogEntryCtxKey).(LogEntry)
	return entry
}

func GetLogEntry ( r * http . Request ) LogEntry { entry , _ := r . Context ( ) . Value ( LogEntryCtxKey ) . ( LogEntry ) return entry }

// GetLogEntry returns the in-context LogEntry for a request.

GetLogEntry returns the in - context LogEntry for a request .


func WithLogEntry(r *http.Request, entry LogEntry) *http.Request {
	r = r.WithContext(context.WithValue(r.Context(), LogEntryCtxKey, entry))
	return r
}

func WithLogEntry ( r * http . Request , entry LogEntry ) * http . Request { r = r . WithContext ( context . WithValue ( r . Context ( ) , LogEntryCtxKey , entry ) ) return r }

// WithLogEntry sets the in-context LogEntry for a request.

WithLogEntry sets the in - context LogEntry for a request .


func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
	useColor := !l.NoColor
	entry := &defaultLogEntry{
		DefaultLogFormatter: l,
		request:             r,
		buf:                 &bytes.Buffer{},
		useColor:            useColor,
	}

	reqID := GetReqID(r.Context())
	if reqID != "" {
		cW(entry.buf, useColor, nYellow, "[%s] ", reqID)
	}
	cW(entry.buf, useColor, nCyan, "\"")
	cW(entry.buf, useColor, bMagenta, "%s ", r.Method)

	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}
	cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto)

	entry.buf.WriteString("from ")
	entry.buf.WriteString(r.RemoteAddr)
	entry.buf.WriteString(" - ")

	return entry
}

func ( l * DefaultLogFormatter ) NewLogEntry ( r * http . Request ) LogEntry { useColor := ! l . NoColor entry := & defaultLogEntry { DefaultLogFormatter : l , request : r , buf : & bytes . Buffer { } , useColor : useColor , } reqID := GetReqID ( r . Context ( ) ) if reqID != " " { cW ( entry . buf , useColor , nYellow , " " , reqID ) } cW ( entry . buf , useColor , nCyan , " \" " ) cW ( entry . buf , useColor , bMagenta , " " , r . Method ) scheme := " " if r . TLS != nil { scheme = " " } cW ( entry . buf , useColor , nCyan , " \" " , scheme , r . Host , r . RequestURI , r . Proto ) entry . buf . WriteString ( " " ) entry . buf . WriteString ( r . RemoteAddr ) entry . buf . WriteString ( " " ) return entry }

// NewLogEntry creates a new LogEntry for the request.

NewLogEntry creates a new LogEntry for the request .


func ContentCharset(charsets ...string) func(next http.Handler) http.Handler {
	for i, c := range charsets {
		charsets[i] = strings.ToLower(c)
	}

	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if !contentEncoding(r.Header.Get("Content-Type"), charsets...) {
				w.WriteHeader(http.StatusUnsupportedMediaType)
				return
			}

			next.ServeHTTP(w, r)
		})
	}
}

func ContentCharset ( charsets ... string ) func ( next http . Handler ) http . Handler { for i , c := range charsets { charsets [ i ] = strings . ToLower ( c ) } return func ( next http . Handler ) http . Handler { return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { if ! contentEncoding ( r . Header . Get ( " " ) , charsets ... ) { w . WriteHeader ( http . StatusUnsupportedMediaType ) return } next . ServeHTTP ( w , r ) } ) } }

// ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match.
// An empty charset will allow requests with no Content-Type header or no specified charset.

ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match . An empty charset will allow requests with no Content - Type header or no specified charset .


func contentEncoding(ce string, charsets ...string) bool {
	_, ce = split(strings.ToLower(ce), ";")
	_, ce = split(ce, "charset=")
	ce, _ = split(ce, ";")
	for _, c := range charsets {
		if ce == c {
			return true
		}
	}

	return false
}

func contentEncoding ( ce string , charsets ... string ) bool { _ , ce = split ( strings . ToLower ( ce ) , " " ) _ , ce = split ( ce , " " ) ce , _ = split ( ce , " " ) for _ , c := range charsets { if ce == c { return true } } return false }

// Check the content encoding against a list of acceptable values.

Check the content encoding against a list of acceptable values .


func split(str, sep string) (string, string) {
	var a, b string
	var parts = strings.SplitN(str, sep, 2)
	a = strings.TrimSpace(parts[0])
	if len(parts) == 2 {
		b = strings.TrimSpace(parts[1])
	}

	return a, b
}

func split ( str , sep string ) ( string , string ) { var a , b string var parts = strings . SplitN ( str , sep , 2 ) a = strings . TrimSpace ( parts [ 0 ] ) if len ( parts ) == 2 { b = strings . TrimSpace ( parts [ 1 ] ) } return a , b }

// Split a string in two parts, cleaning any whitespace.

Split a string in two parts cleaning any whitespace .


func (n *node) addChild(child *node, prefix string) *node {
	search := prefix

	// handler leaf node added to the tree is the child.
	// this may be overridden later down the flow
	hn := child

	// Parse next segment
	segTyp, _, segRexpat, segTail, segStartIdx, segEndIdx := patNextSegment(search)

	// Add child depending on next up segment
	switch segTyp {

	case ntStatic:
		// Search prefix is all static (that is, has no params in path)
		// noop

	default:
		// Search prefix contains a param, regexp or wildcard

		if segTyp == ntRegexp {
			rex, err := regexp.Compile(segRexpat)
			if err != nil {
				panic(fmt.Sprintf("chi: invalid regexp pattern '%s' in route param", segRexpat))
			}
			child.prefix = segRexpat
			child.rex = rex
		}

		if segStartIdx == 0 {
			// Route starts with a param
			child.typ = segTyp

			if segTyp == ntCatchAll {
				segStartIdx = -1
			} else {
				segStartIdx = segEndIdx
			}
			if segStartIdx < 0 {
				segStartIdx = len(search)
			}
			child.tail = segTail // for params, we set the tail

			if segStartIdx != len(search) {
				// add static edge for the remaining part, split the end.
				// its not possible to have adjacent param nodes, so its certainly
				// going to be a static node next.

				search = search[segStartIdx:] // advance search position

				nn := &node{
					typ:    ntStatic,
					label:  search[0],
					prefix: search,
				}
				hn = child.addChild(nn, search)
			}

		} else if segStartIdx > 0 {
			// Route has some param

			// starts with a static segment
			child.typ = ntStatic
			child.prefix = search[:segStartIdx]
			child.rex = nil

			// add the param edge node
			search = search[segStartIdx:]

			nn := &node{
				typ:   segTyp,
				label: search[0],
				tail:  segTail,
			}
			hn = child.addChild(nn, search)

		}
	}

	n.children[child.typ] = append(n.children[child.typ], child)
	n.children[child.typ].Sort()
	return hn
}

// addChild appends the new `child` node to the tree using the `pattern` as the trie key.
// For a URL router like chi's, we split the static, param, regexp and wildcard segments
// into different nodes. In addition, addChild will recursively call itself until every
// pattern segment is added to the url pattern tree as individual nodes, depending on type.

addChild appends the new child node to the tree using the pattern as the trie key . For a URL router like chi s we split the static param regexp and wildcard segments into different nodes . In addition addChild will recursively call itself until every pattern segment is added to the url pattern tree as individual nodes depending on type .


func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
	nn := n
	search := path

	for t, nds := range nn.children {
		ntyp := nodeTyp(t)
		if len(nds) == 0 {
			continue
		}

		var xn *node
		xsearch := search

		var label byte
		if search != "" {
			label = search[0]
		}

		switch ntyp {
		case ntStatic:
			xn = nds.findEdge(label)
			if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) {
				continue
			}
			xsearch = xsearch[len(xn.prefix):]

		case ntParam, ntRegexp:
			// short-circuit and return no matching route for empty param values
			if xsearch == "" {
				continue
			}

			// serially loop through each node grouped by the tail delimiter
			for idx := 0; idx < len(nds); idx++ {
				xn = nds[idx]

				// label for param nodes is the delimiter byte
				p := strings.IndexByte(xsearch, xn.tail)

				if p < 0 {
					if xn.tail == '/' {
						p = len(xsearch)
					} else {
						continue
					}
				}

				if ntyp == ntRegexp && xn.rex != nil {
					if xn.rex.Match([]byte(xsearch[:p])) == false {
						continue
					}
				} else if strings.IndexByte(xsearch[:p], '/') != -1 {
					// avoid a match across path segments
					continue
				}

				rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p])
				xsearch = xsearch[p:]
				break
			}

		default:
			// catch-all nodes
			rctx.routeParams.Values = append(rctx.routeParams.Values, search)
			xn = nds[0]
			xsearch = ""
		}

		if xn == nil {
			continue
		}

		// did we find it yet?
		if len(xsearch) == 0 {
			if xn.isLeaf() {
				h, _ := xn.endpoints[method]
				if h != nil && h.handler != nil {
					rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
					return xn
				}

				// flag that the routing context found a route, but not a corresponding
				// supported method
				rctx.methodNotAllowed = true
			}
		}

		// recursively find the next node..
		fin := xn.findRoute(rctx, method, xsearch)
		if fin != nil {
			return fin
		}

		// Did not find final handler, let's remove the param here if it was set
		if xn.typ > ntStatic {
			if len(rctx.routeParams.Values) > 0 {
				rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1]
			}
		}

	}

	return nil
}

// Recursive edge traversal by checking all nodeTyp groups along the way.
// It's like searching through a multi-dimensional radix trie.

Recursive edge traversal by checking all nodeTyp groups along the way . It s like searching through a multi - dimensional radix trie .


func ArticleCtx(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var article *Article
		var err error

		if articleID := chi.URLParam(r, "articleID"); articleID != "" {
			article, err = dbGetArticle(articleID)
		} else if articleSlug := chi.URLParam(r, "articleSlug"); articleSlug != "" {
			article, err = dbGetArticleBySlug(articleSlug)
		} else {
			render.Render(w, r, ErrNotFound)
			return
		}
		if err != nil {
			render.Render(w, r, ErrNotFound)
			return
		}

		ctx := context.WithValue(r.Context(), "article", article)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func ArticleCtx ( next http . Handler ) http . Handler { return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { var article * Article var err error if articleID := chi . URLParam ( r , " " ) ; articleID != " " { article , err = dbGetArticle ( articleID ) } else if articleSlug := chi . URLParam ( r , " " ) ; articleSlug != " " { article , err = dbGetArticleBySlug ( articleSlug ) } else { render . Render ( w , r , ErrNotFound ) return } if err != nil { render . Render ( w , r , ErrNotFound ) return } ctx := context . WithValue ( r . Context ( ) , " " , article ) next . ServeHTTP ( w , r . WithContext ( ctx ) ) } ) }

// ArticleCtx middleware is used to load an Article object from
// the URL parameters passed through as the request. In case
// the Article could not be found, we stop here and return a 404.

ArticleCtx middleware is used to load an Article object from the URL parameters passed through as the request . In case the Article could not be found we stop here and return a 404 .


func SearchArticles(w http.ResponseWriter, r *http.Request) {
	render.RenderList(w, r, NewArticleListResponse(articles))
}

func SearchArticles ( w http . ResponseWriter , r * http . Request ) { render . RenderList ( w , r , NewArticleListResponse ( articles ) ) }

// SearchArticles searches the Articles data for a matching article.
// It's just a stub, but you get the idea.

SearchArticles searches the Articles data for a matching article . It s just a stub but you get the idea .


func CreateArticle(w http.ResponseWriter, r *http.Request) {
	data := &ArticleRequest{}
	if err := render.Bind(r, data); err != nil {
		render.Render(w, r, ErrInvalidRequest(err))
		return
	}

	article := data.Article
	dbNewArticle(article)

	render.Status(r, http.StatusCreated)
	render.Render(w, r, NewArticleResponse(article))
}

func CreateArticle ( w http . ResponseWriter , r * http . Request ) { data := & ArticleRequest { } if err := render . Bind ( r , data ) ; err != nil { render . Render ( w , r , ErrInvalidRequest ( err ) ) return } article := data . Article dbNewArticle ( article ) render . Status ( r , http . StatusCreated ) render . Render ( w , r , NewArticleResponse ( article ) ) }

// CreateArticle persists the posted Article and returns it
// back to the client as an acknowledgement.

CreateArticle persists the posted Article and returns it back to the client as an acknowledgement .


func GetArticle(w http.ResponseWriter, r *http.Request) {
	// Assume if we've reach this far, we can access the article
	// context because this handler is a child of the ArticleCtx
	// middleware. The worst case, the recoverer middleware will save us.
	article := r.Context().Value("article").(*Article)

	if err := render.Render(w, r, NewArticleResponse(article)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}

// GetArticle returns the specific Article. You'll notice it just
// fetches the Article right off the context, as its understood that
// if we made it this far, the Article must be on the context. In case
// its not due to a bug, then it will panic, and our Recoverer will save us.

GetArticle returns the specific Article . You ll notice it just fetches the Article right off the context as its understood that if we made it this far the Article must be on the context . In case its not due to a bug then it will panic and our Recoverer will save us .


func UpdateArticle(w http.ResponseWriter, r *http.Request) {
	article := r.Context().Value("article").(*Article)

	data := &ArticleRequest{Article: article}
	if err := render.Bind(r, data); err != nil {
		render.Render(w, r, ErrInvalidRequest(err))
		return
	}
	article = data.Article
	dbUpdateArticle(article.ID, article)

	render.Render(w, r, NewArticleResponse(article))
}

func UpdateArticle ( w http . ResponseWriter , r * http . Request ) { article := r . Context ( ) . Value ( " " ) . ( * Article ) data := & ArticleRequest { Article : article } if err := render . Bind ( r , data ) ; err != nil { render . Render ( w , r , ErrInvalidRequest ( err ) ) return } article = data . Article dbUpdateArticle ( article . ID , article ) render . Render ( w , r , NewArticleResponse ( article ) ) }

// UpdateArticle updates an existing Article in our persistent store.

UpdateArticle updates an existing Article in our persistent store .


func DeleteArticle(w http.ResponseWriter, r *http.Request) {
	var err error

	// Assume if we've reach this far, we can access the article
	// context because this handler is a child of the ArticleCtx
	// middleware. The worst case, the recoverer middleware will save us.
	article := r.Context().Value("article").(*Article)

	article, err = dbRemoveArticle(article.ID)
	if err != nil {
		render.Render(w, r, ErrInvalidRequest(err))
		return
	}

	render.Render(w, r, NewArticleResponse(article))
}

// DeleteArticle removes an existing Article from our persistent store.

DeleteArticle removes an existing Article from our persistent store .


func adminRouter() chi.Router {
	r := chi.NewRouter()
	r.Use(AdminOnly)
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: index"))
	})
	r.Get("/accounts", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: list accounts.."))
	})
	r.Get("/users/{userId}", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintf("admin: view user id %v", chi.URLParam(r, "userId"))))
	})
	return r
}

func adminRouter ( ) chi . Router { r := chi . NewRouter ( ) r . Use ( AdminOnly ) r . Get ( " " , func ( w http . ResponseWriter , r * http . Request ) { w . Write ( [ ] byte ( " " ) ) } ) r . Get ( " " , func ( w http . ResponseWriter , r * http . Request ) { w . Write ( [ ] byte ( " " ) ) } ) r . Get ( " " , func ( w http . ResponseWriter , r * http . Request ) { w . Write ( [ ] byte ( fmt . Sprintf ( " " , chi . URLParam ( r , " " ) ) ) ) } ) return r }

// A completely separate router for administrator routes


func AdminOnly(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		isAdmin, ok := r.Context().Value("acl.admin").(bool)
		if !ok || !isAdmin {
			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func AdminOnly ( next http . Handler ) http . Handler { return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { isAdmin , ok := r . Context ( ) . Value ( " " ) . ( bool ) if ! ok || ! isAdmin { http . Error ( w , http . StatusText ( http . StatusForbidden ) , http . StatusForbidden ) return } next . ServeHTTP ( w , r ) } ) }

// AdminOnly middleware restricts access to just administrators.

AdminOnly middleware restricts access to just administrators .


func paginate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// just a stub.. some ideas are to look at URL query params for something like
		// the page number, or the limit, and send a query cursor down the chain
		next.ServeHTTP(w, r)
	})
}

// paginate is a stub, but very possible to implement middleware logic
// to handle the request params for handling a paginated request.

paginate is a stub but very possible to implement middleware logic to handle the request params for handling a paginated request .


func init() {
	render.Respond = func(w http.ResponseWriter, r *http.Request, v interface{}) {
		if err, ok := v.(error); ok {

			// We set a default error status response code if one hasn't been set.
			if _, ok := r.Context().Value(render.StatusCtxKey).(int); !ok {
				w.WriteHeader(400)
			}

			// We log the error
			fmt.Printf("Logging err: %s\n", err.Error())

			// We change the response to not reveal the actual error message,
			// instead we can transform the message something more friendly or mapped
			// to some code / language, etc.
			render.DefaultResponder(w, r, render.M{"status": "error"})
			return
		}

		render.DefaultResponder(w, r, v)
	}
}

// This is entirely optional, but I wanted to demonstrate how you could easily
// add your own logic to the render.Respond method.

This is entirely optional but I wanted to demonstrate how you could easily add your own logic to the render . Respond method .


func NewCompressor(level int, types ...string) *Compressor {
	// If types are provided, set those as the allowed types. If none are
	// provided, use the default list.
	allowedTypes := make(map[string]bool)
	if len(types) > 0 {
		for _, t := range types {
			allowedTypes[t] = true
		}
	} else {
		for _, t := range defaultCompressibleContentTypes {
			allowedTypes[t] = true
		}
	}

	c := &Compressor{
		level:          level,
		encoders:       make(map[string]EncoderFunc),
		pooledEncoders: make(map[string]*sync.Pool),
		allowedTypes:   allowedTypes,
	}
	// Set the default encoders.  The precedence order uses the reverse
	// ordering that the encoders were added. This means adding new encoders
	// will move them to the front of the order.
	//
	// TODO:
	// lzma: Opera.
	// sdch: Chrome, Android. Gzip output + dictionary header.
	// br:   Brotli, see https://github.com/go-chi/chi/pull/326

	// HTTP 1.1 "deflate" (RFC 2616) stands for DEFLATE data (RFC 1951)
	// wrapped with zlib (RFC 1950). The zlib wrapper uses Adler-32
	// checksum compared to CRC-32 used in "gzip" and thus is faster.
	//
	// But.. some old browsers (MSIE, Safari 5.1) incorrectly expect
	// raw DEFLATE data only, without the mentioned zlib wrapper.
	// Because of this major confusion, most modern browsers try it
	// both ways, first looking for zlib headers.
	// Quote by Mark Adler: http://stackoverflow.com/a/9186091/385548
	//
	// The list of browsers having problems is quite big, see:
	// http://zoompf.com/blog/2012/02/lose-the-wait-http-compression
	// https://web.archive.org/web/20120321182910/http://www.vervestudios.co/projects/compression-tests/results
	//
	// That's why we prefer gzip over deflate. It's just more reliable
	// and not significantly slower than gzip.
	c.SetEncoder("deflate", encoderDeflate)

	// TODO: Exception for old MSIE browsers that can't handle non-HTML?
	// https://zoompf.com/blog/2012/02/lose-the-wait-http-compression
	c.SetEncoder("gzip", encoderGzip)

	// NOTE: Not implemented, intentionally:
	// case "compress": // LZW. Deprecated.
	// case "bzip2":    // Too slow on-the-fly.
	// case "zopfli":   // Too slow on-the-fly.
	// case "xz":       // Too slow on-the-fly.
	return c
}

// case "xz":       // Too slow on-the-fly.

// NewCompressor creates a new Compressor that will handle encoding responses.
//
// The level should be one of the ones defined in the flate package.
// The types are the content types that are allowed to be compressed.

NewCompressor creates a new Compressor that will handle encoding responses . The level should be one of the ones defined in the flate package . The types are the content types that are allowed to be compressed .


func (c *Compressor) Handler() func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			encoder, encoding, cleanup := c.selectEncoder(r.Header, w)

			cw := &compressResponseWriter{
				ResponseWriter: w,
				w:              w,
				contentTypes:   c.allowedTypes,
				encoding:       encoding,
			}
			if encoder != nil {
				cw.w = encoder
			}
			// Re-add the encoder to the pool if applicable.
			defer cleanup()
			defer cw.Close()

			next.ServeHTTP(cw, r)
		}

		return http.HandlerFunc(fn)
	}

}

// Handler returns a new middleware that will compress the response based on the
// current Compressor.

Handler returns a new middleware that will compress the response based on the current Compressor .


func (c *Compressor) selectEncoder(h http.Header, w io.Writer) (io.Writer, string, func()) {
	header := h.Get("Accept-Encoding")

	// Parse the names of all accepted algorithms from the header.
	accepted := strings.Split(strings.ToLower(header), ",")

	// Find supported encoder by accepted list by precedence
	for _, name := range c.encodingPrecedence {
		if matchAcceptEncoding(accepted, name) {
			if pool, ok := c.pooledEncoders[name]; ok {
				encoder := pool.Get().(ioResetterWriter)
				cleanup := func() {
					pool.Put(encoder)
				}
				encoder.Reset(w)
				return encoder, name, cleanup

			}
			if fn, ok := c.encoders[name]; ok {
				return fn(w, c.level), name, func() {}
			}
		}

	}

	// No encoder found to match the accepted encoding
	return nil, "", func() {}
}

// selectEncoder returns the encoder, the name of the encoder, and a closer function.

selectEncoder returns the encoder the name of the encoder and a closer function .


func DefaultCompress(next http.Handler) http.Handler {
	return Compress(flate.DefaultCompression)(next)
}

func DefaultCompress ( next http . Handler ) http . Handler { return Compress ( flate . DefaultCompression ) ( next ) }

// DefaultCompress is a middleware that compresses response
// body of predefined content types to a data format based
// on Accept-Encoding request header. It uses a default
// compression level.
// DEPRECATED

DefaultCompress is a middleware that compresses response body of predefined content types to a data format based on Accept - Encoding request header . It uses a default compression level . DEPRECATED


func Throttle(limit int) func(http.Handler) http.Handler {
	return ThrottleBacklog(limit, 0, defaultBacklogTimeout)
}

func Throttle ( limit int ) func ( http . Handler ) http . Handler { return ThrottleBacklog ( limit , 0 , defaultBacklogTimeout ) }

// Throttle is a middleware that limits number of currently processed requests
// at a time.

Throttle is a middleware that limits number of currently processed requests at a time .


func ThrottleBacklog(limit int, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler {
	if limit < 1 {
		panic("chi/middleware: Throttle expects limit > 0")
	}

	if backlogLimit < 0 {
		panic("chi/middleware: Throttle expects backlogLimit to be positive")
	}

	t := throttler{
		tokens:         make(chan token, limit),
		backlogTokens:  make(chan token, limit+backlogLimit),
		backlogTimeout: backlogTimeout,
	}

	// Filling tokens.
	for i := 0; i < limit+backlogLimit; i++ {
		if i < limit {
			t.tokens <- token{}
		}
		t.backlogTokens <- token{}
	}

	fn := func(h http.Handler) http.Handler {
		t.h = h
		return &t
	}

	return fn
}

func
ThrottleBacklog
(
limit
int
,
backlogLimit
int
,
backlogTimeout
time
.
Duration
)
func
(
http
.
Handler
)
http
.
Handler
{
if
limit
<
1
{
panic
(
"
"
)
}
if
backlogLimit
<
0
{
panic
(
"
"
)
}
t
:=
throttler
{
tokens
:
make
(
chan
token
,
limit
)
,
backlogTokens
:
make
(
chan
token
,
limit
+
backlogLimit
)
,
backlogTimeout
:
backlogTimeout
,
}
// Filling tokens.
for
i
:=
0
;
i
<
limit
+
backlogLimit
;
i
++
{
if
i
<
limit
{
t
.
tokens
<-
token
{
}
}
t
.
backlogTokens
<-
token
{
}
}
fn
:=
func
(
h
http
.
Handler
)
http
.
Handler
{
t
.
h
=
h
return
&
t
}
return
fn
}

// ThrottleBacklog is a middleware that limits number of currently processed
// requests at a time and provides a backlog for holding a finite number of
// pending requests.

ThrottleBacklog is a middleware that limits number of currently processed requests at a time and provides a backlog for holding a finite number of pending requests .


func (t *throttler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	select {
	case <-ctx.Done():
		http.Error(w, errContextCanceled, http.StatusServiceUnavailable)
		return
	case btok := <-t.backlogTokens:
		timer := time.NewTimer(t.backlogTimeout)

		defer func() {
			t.backlogTokens <- btok
		}()

		select {
		case <-timer.C:
			http.Error(w, errTimedOut, http.StatusServiceUnavailable)
			return
		case <-ctx.Done():
			http.Error(w, errContextCanceled, http.StatusServiceUnavailable)
			return
		case tok := <-t.tokens:
			defer func() {
				t.tokens <- tok
			}()
			t.h.ServeHTTP(w, r)
		}
		return
	default:
		http.Error(w, errCapacityExceeded, http.StatusServiceUnavailable)
		return
	}
}

func ( t * throttler ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) { ctx := r . Context ( ) select { case <- ctx . Done ( ) : http . Error ( w , errContextCanceled , http . StatusServiceUnavailable ) return case btok := <- t . backlogTokens : timer := time . NewTimer ( t . backlogTimeout ) defer func ( ) { t . backlogTokens <- btok } ( ) select { case <- timer . C : http . Error ( w , errTimedOut , http . StatusServiceUnavailable ) return case <- ctx . Done ( ) : http . Error ( w , errContextCanceled , http . StatusServiceUnavailable ) return case tok := <- t . tokens : defer func ( ) { t . tokens <- tok } ( ) t . h . ServeHTTP ( w , r ) } return default : http . Error ( w , errCapacityExceeded , http . StatusServiceUnavailable ) return } }

// ServeHTTP is the primary throttler request handler


func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter {
	_, fl := w.(http.Flusher)

	bw := basicWriter{ResponseWriter: w}

	if protoMajor == 2 {
		_, ps := w.(http.Pusher)
		if fl && ps {
			return &http2FancyWriter{bw}
		}
	} else {
		_, hj := w.(http.Hijacker)
		_, rf := w.(io.ReaderFrom)
		if fl && hj && rf {
			return &httpFancyWriter{bw}
		}
	}
	if fl {
		return &flushWriter{bw}
	}

	return &bw
}

func NewWrapResponseWriter ( w http . ResponseWriter , protoMajor int ) WrapResponseWriter { _ , fl := w . ( http . Flusher ) bw := basicWriter { ResponseWriter : w } if protoMajor == 2 { _ , ps := w . ( http . Pusher ) if fl && ps { return & http2FancyWriter { bw } } } else { _ , hj := w . ( http . Hijacker ) _ , rf := w . ( io . ReaderFrom ) if fl && hj && rf { return & httpFancyWriter { bw } } } if fl { return & flushWriter { bw } } return & bw }

// NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to
// hook into various parts of the response process.

NewWrapResponseWriter wraps an http . ResponseWriter returning a proxy that allows you to hook into various parts of the response process .


func (rs todosResource) Routes() chi.Router {
	r := chi.NewRouter()
	// r.Use() // some middleware..

	r.Get("/", rs.List)    // GET /todos - read a list of todos
	r.Post("/", rs.Create) // POST /todos - create a new todo and persist it
	r.Put("/", rs.Delete)

	r.Route("/{id}", func(r chi.Router) {
		// r.Use(rs.TodoCtx) // lets have a todos map, and lets actually load/manipulate
		r.Get("/", rs.Get)       // GET /todos/{id} - read a single todo by :id
		r.Put("/", rs.Update)    // PUT /todos/{id} - update a single todo by :id
		r.Delete("/", rs.Delete) // DELETE /todos/{id} - delete a single todo by :id
		r.Get("/sync", rs.Sync)
	})

	return r
}

// Routes creates a REST router for the todos resource


func NewAWSProvider(awsConfig AWSConfig) (*AWSProvider, error) {
	config := aws.NewConfig().WithMaxRetries(awsConfig.APIRetries)

	config.WithHTTPClient(
		instrumented_http.NewClient(config.HTTPClient, &instrumented_http.Callbacks{
			PathProcessor: func(path string) string {
				parts := strings.Split(path, "/")
				return parts[len(parts)-1]
			},
		}),
	)

	session, err := session.NewSessionWithOptions(session.Options{
		Config:            *config,
		SharedConfigState: session.SharedConfigEnable,
	})
	if err != nil {
		return nil, err
	}

	if awsConfig.AssumeRole != "" {
		log.Infof("Assuming role: %s", awsConfig.AssumeRole)
		session.Config.WithCredentials(stscreds.NewCredentials(session, awsConfig.AssumeRole))
	}

	provider := &AWSProvider{
		client:               route53.New(session),
		domainFilter:         awsConfig.DomainFilter,
		zoneIDFilter:         awsConfig.ZoneIDFilter,
		zoneTypeFilter:       awsConfig.ZoneTypeFilter,
		zoneTagFilter:        awsConfig.ZoneTagFilter,
		batchChangeSize:      awsConfig.BatchChangeSize,
		batchChangeInterval:  awsConfig.BatchChangeInterval,
		evaluateTargetHealth: awsConfig.EvaluateTargetHealth,
		dryRun:               awsConfig.DryRun,
	}

	return provider, nil
}

func NewAWSProvider ( awsConfig AWSConfig ) ( * AWSProvider , error ) { config := aws . NewConfig ( ) . WithMaxRetries ( awsConfig . APIRetries ) config . WithHTTPClient ( instrumented_http . NewClient ( config . HTTPClient , & instrumented_http . Callbacks { PathProcessor : func ( path string ) string { parts := strings . Split ( path , " " ) return parts [ len ( parts ) - 1 ] } , } ) , ) session , err := session . NewSessionWithOptions ( session . Options { Config : * config , SharedConfigState : session . SharedConfigEnable , } ) if err != nil { return nil , err } if awsConfig . AssumeRole != " " { log . Infof ( " " , awsConfig . AssumeRole ) session . Config . WithCredentials ( stscreds . NewCredentials ( session , awsConfig . AssumeRole ) ) } provider := & AWSProvider { client : route53 . New ( session ) , domainFilter : awsConfig . DomainFilter , zoneIDFilter : awsConfig . ZoneIDFilter , zoneTypeFilter : awsConfig . ZoneTypeFilter , zoneTagFilter : awsConfig . ZoneTagFilter , batchChangeSize : awsConfig . BatchChangeSize , batchChangeInterval : awsConfig . BatchChangeInterval , evaluateTargetHealth : awsConfig . EvaluateTargetHealth , dryRun : awsConfig . DryRun , } return provider , nil }

// NewAWSProvider initializes a new AWS Route53 based Provider.

NewAWSProvider initializes a new AWS Route53 based Provider .


func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint, recordsCache []*endpoint.Endpoint, zones map[string]*route53.HostedZone) []*route53.Change {
	changes := make([]*route53.Change, 0, len(endpoints))

	for _, endpoint := range endpoints {
		changes = append(changes, p.newChange(action, endpoint, recordsCache, zones))
	}

	return changes
}

func ( p * AWSProvider ) newChanges ( action string , endpoints [ ] * endpoint . Endpoint , recordsCache [ ] * endpoint . Endpoint , zones map [ string ] * route53 . HostedZone ) [ ] * route53 . Change { changes := make ( [ ] * route53 . Change , 0 , len ( endpoints ) ) for _ , endpoint := range endpoints { changes = append ( changes , p . newChange ( action , endpoint , recordsCache , zones ) ) } return changes }

// newChanges returns a collection of Changes based on the given records and action.

newChanges returns a collection of Changes based on the given records and action .


func suitableZones(hostname string, zones map[string]*route53.HostedZone) []*route53.HostedZone {
	var matchingZones []*route53.HostedZone
	var publicZone *route53.HostedZone

	for _, z := range zones {
		if aws.StringValue(z.Name) == hostname || strings.HasSuffix(hostname, "."+aws.StringValue(z.Name)) {
			if z.Config == nil || !aws.BoolValue(z.Config.PrivateZone) {
				// Only select the best matching public zone
				if publicZone == nil || len(aws.StringValue(z.Name)) > len(aws.StringValue(publicZone.Name)) {
					publicZone = z
				}
			} else {
				// Include all private zones
				matchingZones = append(matchingZones, z)
			}
		}
	}

	if publicZone != nil {
		matchingZones = append(matchingZones, publicZone)
	}

	return matchingZones
}

// suitableZones returns all suitable private zones and the most suitable public zone
//   for a given hostname and a set of zones.

suitableZones returns all suitable private zones and the most suitable public zone for a given hostname and a set of zones .


func isAWSLoadBalancer(ep *endpoint.Endpoint) bool {
	if ep.RecordType == endpoint.RecordTypeCNAME {
		return canonicalHostedZone(ep.Targets[0]) != ""
	}

	return false
}

func isAWSLoadBalancer ( ep * endpoint . Endpoint ) bool { if ep . RecordType == endpoint . RecordTypeCNAME { return canonicalHostedZone ( ep . Targets [ 0 ] ) != " " } return false }

// isAWSLoadBalancer determines if a given hostname belongs to an AWS load balancer.

isAWSLoadBalancer determines if a given hostname belongs to an AWS load balancer .