Documentation
¶
Overview ¶
Package httph provides HTTP helpers and middleware compatible with net/http.
Index ¶
- func ErrorHandler(h func(http.ResponseWriter, *http.Request) error) http.HandlerFunc
- func FormHandler[Req any](h func(http.ResponseWriter, *http.Request, Req)) http.HandlerFunc
- func JSONHandler[Req any, Res any](h func(http.ResponseWriter, *http.Request, Req) (Res, error)) http.HandlerFunc
- func NoClickjacking(next http.Handler) http.Handler
- func NonceFromContext(ctx context.Context) string
- func VersionedAssets(next http.Handler) http.Handler
- type ContentSecurityPolicyOptions
- type GoGetOptions
- type HTTPError
- type Middleware
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ErrorHandler ¶ added in v0.3.6
func ErrorHandler(h func(http.ResponseWriter, *http.Request) error) http.HandlerFunc
ErrorHandler takes a function that is like a regular http.HandlerFunc from the standard library, except it also returns an error. If the error implements the statusCodeGiver interface, it returns that status code. Otherwise, it defaults to HTTP 500.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
_ "embed"
"maragu.dev/httph"
)
func main() {
h := httph.ErrorHandler(func(w http.ResponseWriter, r *http.Request) error {
return httph.HTTPError{Code: http.StatusTeapot}
})
// Error case
w := httptest.NewRecorder()
h.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/", nil))
body, _ := io.ReadAll(w.Result().Body)
fmt.Println(string(body))
}
Output: I'm a teapot
func FormHandler ¶
func FormHandler[Req any](h func(http.ResponseWriter, *http.Request, Req)) http.HandlerFunc
FormHandler takes a function that is like a regular http.Handler, except it also receives a struct with values parsed from http.Request.ParseForm. Any parsing errors will result in http.StatusBadRequest. Uses reflection under the hood. If the request struct satisfies the validator interface, also use it to validate the struct.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
_ "embed"
"maragu.dev/httph"
)
func main() {
type Req struct {
Name string
Age int
}
h := httph.FormHandler(func(w http.ResponseWriter, r *http.Request, req Req) {
_, _ = fmt.Fprintf(w, "Hello %v, you are %v years old", req.Name, req.Age)
})
w := httptest.NewRecorder()
vs := url.Values{
"name": {"World"},
"age": {"20"},
}
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(vs.Encode()))
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
h.ServeHTTP(w, r)
body, _ := io.ReadAll(w.Result().Body)
fmt.Println(string(body))
}
Output: Hello World, you are 20 years old
func JSONHandler ¶ added in v0.3.2
func JSONHandler[Req any, Res any](h func(http.ResponseWriter, *http.Request, Req) (Res, error)) http.HandlerFunc
JSONHandler takes a function that is like a regular http.Handler, except it also receives a struct with values parsed from the request body as JSON. The function also returns a struct that will be encoded as JSON in the response. If either the response struct or error satisfy the statusCodeGiver interface, the given HTTP status code is returned.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
_ "embed"
"maragu.dev/httph"
)
func main() {
type Req struct {
Name string
}
type Res struct {
Message string
}
h := httph.JSONHandler(func(w http.ResponseWriter, r *http.Request, req Req) (Res, error) {
return Res{Message: "Hello " + req.Name}, nil
})
w := httptest.NewRecorder()
h.ServeHTTP(w, httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{"Name":"World"}`)))
body, _ := io.ReadAll(w.Result().Body)
fmt.Println(string(body))
}
Output: {"Message":"Hello World"}
func NoClickjacking ¶
NoClickjacking is Middleware which sets headers to disallow frame embedding and XSS protection for older browsers. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
func NonceFromContext ¶ added in v0.4.0
NonceFromContext returns the CSP nonce generated by the ContentSecurityPolicy Middleware for this request, or "" if none was generated.
Types ¶
type ContentSecurityPolicyOptions ¶
type ContentSecurityPolicyOptions struct {
ChildSrc string
ConnectSrc string
DefaultSrc string
FontSrc string
FrameSrc string
ImgSrc string
ManifestSrc string
MediaSrc string
ObjectSrc string
ScriptSrc string
ScriptSrcElem string
ScriptSrcAttr string
StyleSrc string
StyleSrcElem string
StyleSrcAttr string
WorkerSrc string
BaseURI string
Sandbox string
FormAction string
FrameAncestors string
ReportTo string
// ScriptNonce generates a per-request nonce and appends 'nonce-<value>' to script-src,
// or sets script-src to just the nonce if the directive is otherwise empty.
// A non-empty ScriptSrcElem gets the nonce as well, while an empty one is left empty.
// The nonce is available to handlers through [NonceFromContext].
// Note that a nonce makes browsers ignore 'unsafe-inline' in the same directive, and that it doesn't
// authorize inline event handler attributes, which ScriptSrcAttr governs.
ScriptNonce bool
// StyleNonce is like [ContentSecurityPolicyOptions.ScriptNonce], but for style-src and StyleSrcElem,
// and doesn't authorize inline style attributes, which StyleSrcAttr governs.
StyleNonce bool
}
ContentSecurityPolicyOptions for the ContentSecurityPolicy Middleware. The field names match policy directives, and only values should be supplied, so no directive names and delimiters. Only non-experimental, non-deprecated directives are included. Fields with a Nonce suffix are not directives, but switch on nonce generation for the matching directive. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
type GoGetOptions ¶
type GoGetOptions struct {
Domain string // Domain to serve URLs for, for example: "maragu.dev"
Modules []string // Lit of module names, for example: "httph", "foo"
URLPrefix string // URL prefix to serve the module from, for example: "https://github.com/maragudk"
}
type HTTPError ¶ added in v0.3.5
HTTPError is an [error] that can be used to return an HTTP status code with an error message.
func (HTTPError) StatusCode ¶ added in v0.3.5
type Middleware ¶
Middleware is a function that takes an http.Handler and returns an http.Handler. This is a common middleware pattern in net/http.
func ContentSecurityPolicy ¶
func ContentSecurityPolicy(optsFunc func(opts *ContentSecurityPolicyOptions)) Middleware
ContentSecurityPolicy is Middleware to set CSP headers. By default this is a strict policy, disallowing everything but images, styles, scripts, and fonts from 'self'. With ContentSecurityPolicyOptions.ScriptNonce or ContentSecurityPolicyOptions.StyleNonce, one per-request nonce is added to the enabled directives and passed to the next handler through NonceFromContext. Send responses carrying a nonce with Cache-Control: no-store, because a cache may refresh a stored response's headers from a 304 and pair an old body with a new nonce. See https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP See https://infosec.mozilla.org/guidelines/web_security#content-security-policy
func GoGet ¶
func GoGet(opts GoGetOptions) Middleware
GoGet is Middleware to support redirecting go get requests to module VCS URLs, popularly known as vanity URLs. See https://www.maragu.dev/blog/til-http-middleware-for-custom-go-module-paths