Documentation
¶
Overview ¶
Example (ClientIP) ¶
Example_clientIP shows how to choose a ClientIPFrom* middleware. There is no safe default — pick exactly ONE based on your network setup:
middleware.ClientIPFromRemoteAddr — this server is directly on the public internet, with no reverse proxy in front.
middleware.ClientIPFromHeader — your reverse proxy sets a dedicated single-IP header (X-Real-IP, CF-Connecting-IP, X-Client-IP) and overwrites any client-supplied value for every request.
middleware.ClientIPFromXFF — you sit behind one or more reverse proxies whose IP ranges you can enumerate (your VPC CIDR, Cloudflare's published IP list, etc.).
middleware.ClientIPFromXFFTrustedProxies — you sit behind a known, fixed number of reverse proxies whose IPs are dynamic (autoscaling pools, ephemeral containers).
Read the resulting IP with middleware.GetClientIP (string) or middleware.GetClientIPAddr (net/netip.Addr). These middlewares never mutate net/http.Request.RemoteAddr.
The legacy middleware.RealIP middleware is deprecated; it is vulnerable to IP spoofing (GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf).
Background: https://github.com/go-chi/chi/pull/967 https://adam-p.ca/blog/2022/03/x-forwarded-for/
r := chi.NewRouter()
// Pick ONE; the others are shown commented for reference.
// (1) Behind a reverse proxy that sets a single-IP header for every
// request and overwrites any client-supplied value (Cloudflare, Nginx
// with ngx_http_realip_module, Apache with mod_remoteip, ...).
r.Use(middleware.ClientIPFromHeader("CF-Connecting-IP"))
// (2) Behind reverse proxies whose IP ranges you can enumerate as CIDRs.
// The middleware walks X-Forwarded-For right-to-left, skipping trusted
// entries; fail-closed on garbage.
//
// r.Use(middleware.ClientIPFromXFF(
// "13.32.0.0/15", // CloudFront IPv4.
// "2600:9000::/28", // CloudFront IPv6.
// ))
// (3) Behind a known number of trusted reverse proxies whose IPs are
// dynamic.
//
// r.Use(middleware.ClientIPFromXFFTrustedProxies(2))
// (4) Directly on the public internet, no reverse proxy in front.
//
// r.Use(middleware.ClientIPFromRemoteAddr)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, middleware.GetClientIP(r.Context()))
})
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("CF-Connecting-IP", "198.51.100.42")
req.Header.Set("X-Forwarded-For", "1.2.3.4") // attacker-supplied; ignored.
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
fmt.Print(w.Body.String())
Output: 198.51.100.42
Index ¶
- Constants
- Variables
- func AllowContentEncoding(contentEncoding ...string) func(next http.Handler) http.Handler
- func AllowContentType(contentTypes ...string) func(http.Handler) http.Handler
- func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler
- func CleanPath(next http.Handler) http.Handler
- func ClientIPFromHeader(trustedHeader string) func(http.Handler) http.Handler
- func ClientIPFromRemoteAddr(h http.Handler) http.Handler
- func ClientIPFromXFF(trustedIPPrefixes ...string) func(http.Handler) http.Handler
- func ClientIPFromXFFTrustedProxies(numTrustedProxies int) func(http.Handler) http.Handler
- func Compress(level int, types ...string) func(next http.Handler) http.Handler
- func ContentCharset(charsets ...string) func(next http.Handler) http.Handler
- func GetClientIP(ctx context.Context) string
- func GetClientIPAddr(ctx context.Context) netip.Addr
- func GetHead(next http.Handler) http.Handler
- func GetReqID(ctx context.Context) string
- func Heartbeat(endpoint string) func(http.Handler) http.Handler
- func Logger(next http.Handler) http.Handler
- func Maybe(mw func(http.Handler) http.Handler, maybeFn func(r *http.Request) bool) func(http.Handler) http.Handler
- func New(h http.Handler) func(next http.Handler) http.Handler
- func NextRequestID() uint64
- func NoCache(h http.Handler) http.Handler
- func PageRoute(path string, handler http.Handler) func(http.Handler) http.Handler
- func PathRewrite(old, new string) func(http.Handler) http.Handler
- func PrintPrettyStack(rvr interface{})
- func Profiler() http.Handler
- func RealIP(h http.Handler) http.Handlerdeprecated
- func Recoverer(next http.Handler) http.Handler
- func RedirectSlashes(next http.Handler) http.Handler
- func RequestID(next http.Handler) http.Handler
- func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler
- func RequestSize(bytes int64) func(http.Handler) http.Handler
- func SetHeader(key, value string) func(http.Handler) http.Handler
- func StripPrefix(prefix string) func(http.Handler) http.Handler
- func StripSlashes(next http.Handler) http.Handler
- func Sunset(sunsetAt time.Time, links ...string) func(http.Handler) http.Handler
- func SupressNotFound(router *chi.Mux) func(next http.Handler) http.Handler
- func Throttle(limit int) func(http.Handler) http.Handler
- func ThrottleBacklog(limit, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler
- func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler
- func Timeout(timeout time.Duration) func(next http.Handler) http.Handler
- func URLFormat(next http.Handler) http.Handler
- func WithLogEntry(r *http.Request, entry LogEntry) *http.Request
- func WithValue(key, val interface{}) func(next http.Handler) http.Handler
- type Compressor
- type DefaultLogFormatter
- type EncoderFunc
- type HeaderRoute
- type HeaderRouter
- func (hr HeaderRouter) Handler(next http.Handler) http.Handler
- func (hr HeaderRouter) Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
- func (hr HeaderRouter) RouteAny(header string, match []string, ...) HeaderRouter
- func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter
- type LogEntry
- type LogFormatter
- type LoggerInterface
- type Pattern
- type ThrottleOpts
- type WrapResponseWriter
Examples ¶
Constants ¶
const RequestIDKey ctxKeyRequestID = 0
RequestIDKey is the key that holds the unique request ID in a request context.
Variables ¶
var ( // LogEntryCtxKey is the context.Context key to store the request log entry. LogEntryCtxKey = &contextKey{"LogEntry"} // DefaultLogger is called by the Logger middleware handler to log each request. // Its made a package-level variable so that it can be reconfigured for custom // logging configurations. DefaultLogger func(next http.Handler) http.Handler )
var IsTTY bool
var RequestIDHeader = "X-Request-Id"
RequestIDHeader is the name of the HTTP Header which contains the request id. Exported so that it can be changed by developers
var ( // URLFormatCtxKey is the context.Context key to store the URL format data // for a request. URLFormatCtxKey = &contextKey{"URLFormat"} )
Functions ¶
func AllowContentEncoding ¶
AllowContentEncoding enforces a whitelist of request Content-Encoding otherwise responds with a 415 Unsupported Media Type status.
func AllowContentType ¶
AllowContentType enforces a whitelist of request Content-Types otherwise responds with a 415 Unsupported Media Type status.
func BasicAuth ¶
BasicAuth implements a simple middleware handler for adding basic http auth to a route.
func CleanPath ¶
CleanPath middleware will clean out double slash mistakes from a user's request path. For example, if a user requests /users//1 or //users////1 will both be treated as: /users/1
func ClientIPFromHeader ¶ added in v5.3.0
ClientIPFromHeader stores the client IP from a single-IP header set by your reverse proxy. Read it with GetClientIP.
Only safe with headers your proxy unconditionally OVERWRITES on every request, e.g.:
- X-Real-IP — Nginx with ngx_http_realip_module
- X-Client-IP — Apache with mod_remoteip
- CF-Connecting-IP — Cloudflare
True-Client-IP, X-Azure-ClientIP, and Fastly-Client-IP look similar but pass through from the client by default in those products; don't use them unless your edge strips the inbound value.
If the header reaches us with multiple values (misconfigured proxy that appends, or a downstream proxy not stripping a client-supplied value), the LAST value wins — that's the one set by the hop closest to us, and therefore the most trusted. Fail-closed if the last value doesn't parse: no client IP is set rather than falling back to earlier (less-trusted) values.
v4-mapped IPv6 (::ffff:a.b.c.d) folds to plain v4 and IPv6 zones are stripped before storage.
func ClientIPFromRemoteAddr ¶ added in v5.3.0
ClientIPFromRemoteAddr stores the client IP read from the TCP RemoteAddr of the incoming request — the IP address of whoever opened the connection to this server. Read it with GetClientIP.
Use this when this server is directly connected to the public internet with NO reverse proxy in front of it. Behind a reverse proxy, RemoteAddr is the proxy's IP, not the client's — use ClientIPFromHeader or ClientIPFromXFF instead.
IPv4 clients on a dual-stack listener surface as ::ffff:a.b.c.d; they fold to plain v4 before storage so one logical client maps to one key. IPv6 zones are preserved (link-local connections may legitimately have one).
func ClientIPFromXFF ¶ added in v5.3.0
ClientIPFromXFF stores the client IP read from the X-Forwarded-For header, walking the chain right-to-left and skipping any IP that falls within one of the given trusted CIDR prefixes. The first IP that is not trusted is the client. Read it with GetClientIP.
An unparseable entry mid-chain aborts the walk and leaves no client IP set (fail-closed) — we can't safely trust anything left of garbage.
Use this when you sit behind one or more reverse proxies whose IP ranges you can enumerate as CIDRs:
r.Use(middleware.ClientIPFromXFF(
"13.32.0.0/15", // CloudFront IPv4
"52.46.0.0/18", // CloudFront IPv4
"2600:9000::/28", // CloudFront IPv6
))
Calling with no arguments returns the rightmost XFF entry, or no IP if that entry doesn't parse (fail-closed) — safe only if you have exactly one trusted hop directly in front of this server (e.g., nginx on localhost).
v4-mapped IPv6 (::ffff:a.b.c.d) folds to plain v4 and IPv6 zones are stripped before the prefix check and storage; otherwise an attacker could use either notation to alias a trusted IP past the check.
If you know the number of trusted proxies but not their IPs, use ClientIPFromXFFTrustedProxies instead.
Panics at startup if any prefix is invalid.
func ClientIPFromXFFTrustedProxies ¶ added in v5.3.0
ClientIPFromXFFTrustedProxies stores the client IP read from the X-Forwarded-For header, given the exact number of trusted reverse proxies between this server and the public internet. It returns the IP at position len(xff) - numTrustedProxies in the merged X-Forwarded-For list — the IP added by the outermost of your trusted proxies, the only IP in the chain that none of your proxies have allowed an attacker to forge. Read it with GetClientIP.
Use this when:
- You know exactly how many proxies you sit behind, AND
- Their IP addresses are dynamic (autoscaling proxy pools, ephemeral containers, dynamic CDN edges) so listing CIDRs with ClientIPFromXFF is impractical.
WARNING: This variant is brittle to network architecture changes. If you add or remove a proxy level, numTrustedProxies silently becomes wrong and you may start trusting an attacker-supplied IP. Prefer ClientIPFromXFF with explicit trusted CIDRs whenever you can.
If the XFF chain has fewer than numTrustedProxies entries (header missing or architecture changed), no client IP is set and GetClientIP returns "".
Like ClientIPFromXFF, v4-mapped IPv6 folds to plain v4 and IPv6 zones are stripped before storage.
Panics at startup if numTrustedProxies < 1.
func Compress ¶
Compress is a middleware that compresses response body of a given content types to a data format based on Accept-Encoding request header. It uses a given compression level.
NOTE: make sure to set the Content-Type header on your response otherwise this middleware will not compress the response body. For ex, in your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody)) or set it manually.
Passing a compression level of 5 is sensible value
func ContentCharset ¶
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 GetClientIP ¶ added in v5.3.0
GetClientIP returns the client IP as a string, as set by one of the ClientIPFrom* middlewares. Returns "" if no valid IP was set. Convenient for logging, rate-limit keys, etc.
func GetClientIPAddr ¶ added in v5.3.0
GetClientIPAddr returns the client IP as a netip.Addr, as set by one of the ClientIPFrom* middlewares. The returned Addr is the zero value if not set; use netip.Addr.IsValid to check. Useful when you need typed work — prefix containment, Is4/Is6, etc. — without re-parsing the string.
func GetReqID ¶
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 Heartbeat ¶
Heartbeat endpoint middleware useful to setting up a path like `/ping` that load balancers or uptime testing external services can make a request before hitting any routes. It's also convenient to place this above ACL middlewares as well.
func Logger ¶
Logger is a middleware that logs the start and end of each request, along with some useful data about what was requested, what the response status was, and how long it took to return. When standard output is a TTY, Logger will print in color, otherwise it will print in black and white. Logger prints a request ID if one is provided.
Alternatively, look at https://github.com/goware/httplog for a more in-depth http logger with structured logging support.
IMPORTANT NOTE: Logger should go before any other middleware that may change the response, such as middleware.Recoverer. Example:
r := chi.NewRouter()
r.Use(middleware.Logger) // <--<< Logger should come before Recoverer
r.Use(middleware.Recoverer)
r.Get("/", handler)
func Maybe ¶ added in v5.0.6
func Maybe(mw func(http.Handler) http.Handler, maybeFn func(r *http.Request) bool) func(http.Handler) http.Handler
Maybe middleware will allow you to change the flow of the middleware stack execution depending on return value of maybeFn(request). This is useful for example if you'd like to skip a middleware handler if a request does not satisfy the maybeFn logic.
func NextRequestID ¶
func NextRequestID() uint64
NextRequestID generates the next request ID in the sequence.
func NoCache ¶
NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent a router (or subrouter) from being cached by an upstream proxy and/or client.
As per http://wiki.nginx.org/HttpProxyModule - NoCache sets:
Expires: Thu, 01 Jan 1970 00:00:00 UTC Cache-Control: no-cache, private, max-age=0 X-Accel-Expires: 0 Pragma: no-cache (for HTTP/1.0 proxies/clients)
func PageRoute ¶ added in v5.0.4
PageRoute is a simple middleware which allows you to route a static GET request at the middleware stack level.
func PathRewrite ¶ added in v5.0.4
PathRewrite is a simple middleware which allows you to rewrite the request URL path.
func PrintPrettyStack ¶
func PrintPrettyStack(rvr interface{})
func Profiler ¶
Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
func MyService() http.Handler {
r := chi.NewRouter()
// ..middlewares
r.Mount("/debug", middleware.Profiler())
// ..routes
return r
}
func RealIP
deprecated
RealIP is a middleware that sets a http.Request's RemoteAddr to the results of parsing either the True-Client-IP, X-Real-IP or the X-Forwarded-For headers (in that order).
Deprecated: RealIP is vulnerable to IP spoofing — it mutates r.RemoteAddr to the leftmost X-Forwarded-For value, or to True-Client-IP / X-Real-IP whether or not your infrastructure actually sets them. See GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf.
Use ClientIPFromHeader, ClientIPFromXFF, ClientIPFromXFFTrustedProxies or ClientIPFromRemoteAddr and read the IP with GetClientIP instead. These never mutate r.RemoteAddr.
func Recoverer ¶
Recoverer is a middleware that recovers from panics, logs the panic (and a backtrace), and returns a HTTP 500 (Internal Server Error) status if possible. Recoverer prints a request ID if one is provided.
Alternatively, look at https://github.com/go-chi/httplog middleware pkgs.
func RedirectSlashes ¶
RedirectSlashes is a middleware that will match request paths with a trailing slash and redirect to the same path, less the trailing slash.
NOTE: RedirectSlashes middleware is *incompatible* with http.FileServer, see https://github.com/go-chi/chi/issues/343
func RequestID ¶
RequestID is a middleware that injects a request ID into the context of each request. A request ID is a string of the form "host.example.com/random-0001", where "random" is a base62 random string that uniquely identifies this go process, and where the last number is an atomically incremented request counter.
func RequestLogger ¶
func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler
RequestLogger returns a logger handler using a custom LogFormatter.
func RequestSize ¶ added in v5.0.9
RequestSize is a middleware that will limit request sizes to a specified number of bytes. It uses MaxBytesReader to do so.
func StripPrefix ¶ added in v5.2.0
StripPrefix is a middleware that will strip the provided prefix from the request path before handing the request over to the next handler.
func StripSlashes ¶
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 Sunset ¶ added in v5.0.11
Sunset set Deprecation/Sunset header to response This can be used to enable Sunset in a route or a route group For more: https://www.rfc-editor.org/rfc/rfc8594.html
func SupressNotFound ¶ added in v5.0.11
SupressNotFound will quickly respond with a 404 if the route is not found and will not continue to the next middleware handler.
This is handy to put at the top of your middleware stack to avoid unnecessary processing of requests that are not going to match any routes anyway. For example its super annoying to see a bunch of 404's in your logs from bots.
func Throttle ¶
Throttle is a middleware that limits number of currently processed requests at a time across all users. Note: Throttle is not a rate-limiter per user, instead it just puts a ceiling on the number of current in-flight requests being processed from the point from where the Throttle middleware is mounted.
func ThrottleBacklog ¶
func ThrottleBacklog(limit, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler
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 ThrottleWithOpts ¶
func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler
ThrottleWithOpts is a middleware that limits number of currently processed requests using passed ThrottleOpts.
func Timeout ¶
Timeout is a middleware that cancels ctx after a given timeout and return a 504 Gateway Timeout error to the client.
It's required that you select the ctx.Done() channel to check for the signal if the context has reached its deadline and return, otherwise the timeout signal will be just ignored.
ie. a route/handler may look like:
r.Get("/long", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
processTime := time.Duration(rand.Intn(4)+1) * time.Second
select {
case <-ctx.Done():
return
case <-time.After(processTime):
// The above channel simulates some hard work.
}
w.Write([]byte("done"))
})
func URLFormat ¶
URLFormat is a middleware that parses the url extension from a request path and stores it on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will trim the suffix from the routing path and continue routing.
Routers should not include a url parameter for the suffix when using this middleware.
Sample usage for url paths `/articles/1`, `/articles/1.json` and `/articles/1.xml`:
func routes() http.Handler {
r := chi.NewRouter()
r.Use(middleware.URLFormat)
r.Get("/articles/{id}", ListArticles)
return r
}
func ListArticles(w http.ResponseWriter, r *http.Request) {
urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string)
switch urlFormat {
case "json":
render.JSON(w, r, articles)
case "xml:"
render.XML(w, r, articles)
default:
render.JSON(w, r, articles)
}
}
func WithLogEntry ¶
WithLogEntry sets the in-context LogEntry for a request.
Types ¶
type Compressor ¶
type Compressor struct {
// contains filtered or unexported fields
}
Compressor represents a set of encoding configurations.
func NewCompressor ¶
func NewCompressor(level int, types ...string) *Compressor
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 (*Compressor) Handler ¶
func (c *Compressor) Handler(next http.Handler) http.Handler
Handler returns a new middleware that will compress the response based on the current Compressor.
func (*Compressor) SetEncoder ¶
func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc)
SetEncoder can be used to set the implementation of a compression algorithm.
The encoding should be a standardised identifier. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
For example, add the Brotli algorithm:
import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc"
compressor := middleware.NewCompressor(5, "text/html")
compressor.SetEncoder("br", func(w io.Writer, level int) io.Writer {
params := brotli_enc.NewBrotliParams()
params.SetQuality(level)
return brotli_enc.NewBrotliWriter(params, w)
})
type DefaultLogFormatter ¶
type DefaultLogFormatter struct {
Logger LoggerInterface
NoColor bool
}
DefaultLogFormatter is a simple logger that implements a LogFormatter.
func (*DefaultLogFormatter) NewLogEntry ¶
func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry
NewLogEntry creates a new LogEntry for the request.
type EncoderFunc ¶
An EncoderFunc is a function that wraps the provided io.Writer with a streaming compression algorithm and returns it.
In case of failure, the function should return nil.
type HeaderRoute ¶
type HeaderRoute struct {
Middleware func(next http.Handler) http.Handler
MatchOne Pattern
MatchAny []Pattern
}
func (HeaderRoute) IsMatch ¶
func (r HeaderRoute) IsMatch(value string) bool
type HeaderRouter ¶
type HeaderRouter map[string][]HeaderRoute
func RouteHeaders ¶
func RouteHeaders() HeaderRouter
RouteHeaders is a neat little header-based router that allows you to direct the flow of a request through a middleware stack based on a request header.
For example, lets say you'd like to setup multiple routers depending on the request Host header, you could then do something as so:
r := chi.NewRouter()
rSubdomain := chi.NewRouter()
r.Use(middleware.RouteHeaders().
Route("Host", "example.com", middleware.New(r)).
Route("Host", "*.example.com", middleware.New(rSubdomain)).
Handler)
r.Get("/", h)
rSubdomain.Get("/", h2)
Another example, imagine you want to setup multiple CORS handlers, where for your origin servers you allow authorized requests, but for third-party public requests, authorization is disabled.
r := chi.NewRouter()
r.Use(middleware.RouteHeaders().
Route("Origin", "https://app.skyweaver.net", cors.Handler(cors.Options{
AllowedOrigins: []string{"https://api.skyweaver.net"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"},
AllowCredentials: true, // <----------<<< allow credentials
})).
Route("Origin", "*", cors.Handler(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Content-Type"},
AllowCredentials: false, // <----------<<< do not allow credentials
})).
Handler)
func (HeaderRouter) Route ¶
func (hr HeaderRouter) Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
func (HeaderRouter) RouteAny ¶
func (hr HeaderRouter) RouteAny(header string, match []string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
func (HeaderRouter) RouteDefault ¶
func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter
type LogEntry ¶
type LogEntry interface {
Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{})
Panic(v interface{}, stack []byte)
}
LogEntry records the final log when a request completes. See defaultLogEntry for an example implementation.
func GetLogEntry ¶
GetLogEntry returns the in-context LogEntry for a request.
type LogFormatter ¶
LogFormatter initiates the beginning of a new LogEntry per request. See DefaultLogFormatter for an example implementation.
type LoggerInterface ¶
type LoggerInterface interface {
Print(v ...interface{})
}
LoggerInterface accepts printing to stdlib logger or compatible logger.
type ThrottleOpts ¶
type ThrottleOpts struct {
RetryAfterFn func(ctxDone bool) time.Duration
Limit int
BacklogLimit int
BacklogTimeout time.Duration
StatusCode int
}
ThrottleOpts represents a set of throttling options.
type WrapResponseWriter ¶
type WrapResponseWriter interface {
http.ResponseWriter
// Status returns the HTTP status of the request, or 0 if one has not
// yet been sent.
Status() int
// BytesWritten returns the total number of bytes sent to the client.
BytesWritten() int
// Tee causes the response body to be written to the given io.Writer in
// addition to proxying the writes through. Only one io.Writer can be
// tee'd to at once: setting a second one will overwrite the first.
// Writes will be sent to the proxy before being written to this
// io.Writer. It is illegal for the tee'd writer to be modified
// concurrently with writes.
Tee(io.Writer)
// Unwrap returns the original proxied target.
Unwrap() http.ResponseWriter
// Discard causes all writes to the original ResponseWriter be discarded,
// instead writing only to the tee'd writer if it's set.
// The caller is responsible for calling WriteHeader and Write on the
// original ResponseWriter once the processing is done.
Discard()
}
WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook into various parts of the response process.
func NewWrapResponseWriter ¶
func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter
NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to hook into various parts of the response process.
Source Files
¶
- basic_auth.go
- clean_path.go
- client_ip.go
- compress.go
- content_charset.go
- content_encoding.go
- content_type.go
- get_head.go
- heartbeat.go
- logger.go
- maybe.go
- middleware.go
- nocache.go
- page_route.go
- path_rewrite.go
- profiler.go
- realip.go
- recoverer.go
- request_id.go
- request_size.go
- route_headers.go
- strip.go
- sunset.go
- supress_notfound.go
- terminal.go
- throttle.go
- timeout.go
- url_format.go
- value.go
- wrap_writer.go