Documentation ¶
Overview ¶
Package middleware provides helpful functions that implement some common functionalities in http servers. A middleware is a function that takes in a http.Handler as one of its arguments and returns a http.Handler
The middlewares All, Get, Post, Head, Put & Delete wrap other internal middleware. The effect of this is that the aforementioned middleware, in addition to their specialised functionality, will:
- Add logID for traceability.
- Add the "real" client IP address to the request context.
- Add client TLS fingerprint to the request context.
- Recover from panics in the wrappedHandler.
- Log http requests and responses.
- Rate limit requests by IP address.
- Shed load based on http response latencies.
- Handle automatic procurement/renewal of ACME tls certificates.
- Redirect http requests to https.
- Add some important HTTP security headers and assign them sensible default values.
- Implement Cross-Origin Resource Sharing support(CORS).
- Provide protection against Cross Site Request Forgeries(CSRF).
- Attempt to provide protection against form re-submission when a user reloads an already submitted web form.
- Implement http sessions.
Example (GetCspNonce) ¶
package main import ( "context" "fmt" "net/http" "os" "github.com/komuw/ong/config" "github.com/komuw/ong/log" "github.com/komuw/ong/middleware" ) func loginHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cspNonce := middleware.GetCspNonce(r.Context()) _ = cspNonce _, _ = fmt.Fprint(w, "welcome to your favorite website.") } } func main() { l := log.New(context.Background(), os.Stdout, 100) handler := middleware.Get( loginHandler(), config.WithOpts("example.com", 443, "super-h@rd-Pas1word", middleware.DirectIpStrategy, l), ) _ = handler // use handler }
Output:
Example (GetCsrfToken) ¶
package main import ( "context" "fmt" "net/http" "os" "github.com/komuw/ong/config" "github.com/komuw/ong/log" "github.com/komuw/ong/middleware" ) func welcomeHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { csrfToken := middleware.GetCsrfToken(r.Context()) _ = csrfToken _, _ = fmt.Fprint(w, "welcome.") } } func main() { l := log.New(context.Background(), os.Stdout, 100) handler := middleware.Get( welcomeHandler(), config.WithOpts("example.com", 443, "super-h@rd-Pas1word", middleware.DirectIpStrategy, l), ) _ = handler // use handler }
Output:
Index ¶
- Constants
- func All(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- func BasicAuth(wrappedHandler http.Handler, user, passwd, hint string) http.HandlerFunc
- func ClientFingerPrint(r *http.Request) string
- func ClientIP(r *http.Request) string
- func Delete(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- func Get(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- func GetCspNonce(c context.Context) string
- func GetCsrfToken(c context.Context) string
- func Head(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- func Post(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- func Put(wrappedHandler http.Handler, o config.Opts) http.HandlerFunc
- type ClientIPstrategy
Examples ¶
Constants ¶
const ( // DirectIpStrategy derives the client IP from [http.Request.RemoteAddr]. // It should be used if the server accepts direct connections, rather than through a proxy. // // See the warning in [ClientIP] DirectIpStrategy = clientip.DirectIpStrategy // LeftIpStrategy derives the client IP from the leftmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header. // // See the warning in [ClientIP] LeftIpStrategy = clientip.LeftIpStrategy // RightIpStrategy derives the client IP from the rightmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header. // // See the warning in [ClientIP] RightIpStrategy = clientip.RightIpStrategy // ProxyStrategy derives the client IP from the [PROXY protocol v1]. // This should be used when your application is behind a TCP proxy that uses the v1 PROXY protocol. // // See the warning in [ClientIP] // // [PROXY protocol v1]: https://www.haproxy.org/download/2.8/doc/proxy-protocol.txt ProxyStrategy = clientip.ProxyStrategy )
const ( // CsrfTokenFormName is the name of the html form name attribute for csrf token. CsrfTokenFormName = "csrftoken" // named after what django uses. // CsrfHeader is the name of the http header that Ong uses to store csrf token. CsrfHeader = "X-Csrf-Token" // named after what fiber uses. )
Variables ¶
This section is empty.
Functions ¶
func All ¶
All is a middleware that allows all http methods.
See the package documentation for the additional functionality provided by this middleware.
Example ¶
package main import ( "context" "io" "net/http" "os" "github.com/komuw/ong/config" "github.com/komuw/ong/log" "github.com/komuw/ong/middleware" ) func main() { l := log.New(context.Background(), os.Stdout, 100) opts := config.WithOpts("example.com", 443, "super-h@rd-Pas1word", middleware.DirectIpStrategy, l) myHandler := http.HandlerFunc( func(w http.ResponseWriter, _ *http.Request) { _, _ = io.WriteString(w, "Hello from a HandleFunc \n") }, ) handler := middleware.All(myHandler, opts) mux := http.NewServeMux() mux.Handle("/", handler) }
Output:
func BasicAuth ¶
func BasicAuth(wrappedHandler http.Handler, user, passwd, hint string) http.HandlerFunc
BasicAuth is a middleware that protects wrappedHandler using basic authentication.
func ClientFingerPrint ¶ added in v0.0.44
ClientFingerPrint returns the TLS fingerprint of the client. It is provided on a best-effort basis. If a fingerprint is not found, it returns a string that has the substring "NotFound" in it. There are different formats/algorithms of fingerprinting, this library(by design) does not subscribe to a particular format or algorithm.
func ClientIP ¶ added in v0.0.26
ClientIP returns the "real" client IP address. This will be based on the ClientIPstrategy that you chose.
Warning: This should be used with caution. Clients CAN easily spoof IP addresses. Fetching the "real" client is done in a best-effort basis and can be grossly inaccurate & precarious. You should especially heed this warning if you intend to use the IP addresses for security related activities. Proceed at your own risk.
func Delete ¶
Delete is a middleware that only allows http DELETE requests and http OPTIONS requests.
See the package documentation for the additional functionality provided by this middleware.
func Get ¶
Get is a middleware that only allows http GET requests and http OPTIONS requests.
See the package documentation for the additional functionality provided by this middleware.
Example ¶
package main import ( "context" "fmt" "net/http" "os" "github.com/komuw/ong/config" "github.com/komuw/ong/log" "github.com/komuw/ong/middleware" ) func loginHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cspNonce := middleware.GetCspNonce(r.Context()) _ = cspNonce _, _ = fmt.Fprint(w, "welcome to your favorite website.") } } func main() { l := log.New(context.Background(), os.Stdout, 100) opts := config.WithOpts("example.com", 443, "super-h@rd-Pas1word", middleware.DirectIpStrategy, l) handler := middleware.Get(loginHandler(), opts) _ = handler // use handler }
Output:
func GetCspNonce ¶
GetCspNonce returns the Content-Security-Policy nonce that was set for the http request in question.
func GetCsrfToken ¶
GetCsrfToken returns the csrf token that was set for the http request in question.
func Head ¶
Head is a middleware that only allows http HEAD requests and http OPTIONS requests.
See the package documentation for the additional functionality provided by this middleware.
Types ¶
type ClientIPstrategy ¶ added in v0.0.26
type ClientIPstrategy = clientip.ClientIPstrategy
ClientIPstrategy is a middleware option that describes the strategy to use when fetching the client's IP address.
func SingleIpStrategy ¶ added in v0.0.26
func SingleIpStrategy(headerName string) ClientIPstrategy
SingleIpStrategy derives the client IP from http header headerName.
headerName MUST NOT be either `X-Forwarded-For` or `Forwarded`. It can be something like `CF-Connecting-IP`, `Fastly-Client-IP`, `Fly-Client-IP`, etc; depending on your usecase.
See the warning in ClientIP