Package rfc9110
Overview
Package rfc9110 builds HTTP error statuses that carry the header fields RFC 9110 (HTTP Semantics) requires of them.
A Status can only be built by its constructors, and a status whose definition requires a header field takes that field's value as an argument. A 401 can't be built without a Challenge for its WWW-Authenticate field, nor a 405 without its Allow field:
rfc9110.Unauthorized(challenge)
rfc9110.MethodNotAllowed(rfc9110.MethodGet, rfc9110.MethodHead)Optional fields are added with With methods, such as Status.WithRetryAfter. Values with a grammar, such as a Token, are checked by a Parse function, so a status built from them is always well-formed.
For content negotiation, ParseMediaType parses a Content-Type and ParseAccept parses an Accept field, whose Accept.Negotiate picks the representation the client prefers.
The package covers the 4xx and 5xx status codes of Section 15.5 and 15.6, tokens and quoted strings (Section 5.6), media types (Section 8.3.1), the authentication challenge framework (Section 11), Retry-After (Section 10.2.3) and Accept (Section 12.5.1). It doesn't cover successful or redirection responses, or the other negotiation fields.
The RFC text is in rfc9110.txt in this directory, and the doc comments cite its sections.
Index
- Variables
func ParseRetryAftertype Accepttype AuthParamtype Challengetype MediaTypetype Methodtype Protocoltype RetryAftertype Statusfunc BadGatewayfunc BadRequestfunc Conflictfunc ContentTooLargefunc ExpectationFailedfunc Forbiddenfunc GatewayTimeoutfunc Gonefunc HTTPVersionNotSupportedfunc InternalServerErrorfunc LengthRequiredfunc MethodNotAllowedfunc MisdirectedRequestfunc NewStatusfunc NotAcceptablefunc NotFoundfunc NotImplementedfunc PreconditionFailedfunc ProxyAuthenticationRequiredfunc RangeNotSatisfiablefunc RequestTimeoutfunc ServiceUnavailablefunc URITooLongfunc Unauthorizedfunc UnprocessableContentfunc UnsupportedMediaTypefunc UpgradeRequiredfunc (Status) Codefunc (Status) Headerfunc (Status) WithAuthenticatefunc (Status) WithCacheControlfunc (Status) WithRetryAfterfunc (Status) WriteHeader
type Token
Variables
var (
// ErrInvalidToken is returned for a string that isn't a token
// (Section 5.6.2).
ErrInvalidToken = errors.New("invalid token")
// ErrInvalidQuotedString is returned for a string that can't be sent
// as a quoted-string, because it contains a control character
// (Section 5.6.4).
ErrInvalidQuotedString = errors.New("invalid quoted-string")
// ErrInvalidProtocol is returned for a string that isn't an Upgrade
// protocol (Section 7.8).
ErrInvalidProtocol = errors.New("invalid protocol")
)var ErrDuplicateAuthParam = errors.New("duplicate auth-param")ErrDuplicateAuthParam is returned for a challenge that has two parameters with the same name. Section 11.2 says each name "MUST only occur once per challenge".
var ErrInvalidAccept = errors.New("invalid Accept")ErrInvalidAccept is returned for an Accept field value that doesn't match the grammar of Section 12.5.1.
var ErrInvalidMediaType = errors.New("invalid media type")ErrInvalidMediaType is returned for a string that isn't a media type or a media range.
var ErrInvalidRetryAfter = errors.New("invalid Retry-After")ErrInvalidRetryAfter is returned by ParseRetryAfter for a value that is neither delay-seconds nor an HTTP-date.
var ErrInvalidStatus = errors.New("invalid status")ErrInvalidStatus is returned by NewStatus for a code it can't build.
Functions
ParseRetryAfter source
func ParseRetryAfter(s string, now time.Time) (time.Time, error)ParseRetryAfter returns the time that a Retry-After value of s, received at now, asks the client to wait until. It accepts delay-seconds and all three HTTP-date formats (Section 5.6.7), and returns ErrInvalidRetryAfter for anything else.
Types
Accept source
type Accept struct {
// contains filtered or unexported fields
}Accept is a parsed Accept request header field: the media ranges a client accepts, each with a weight. The zero Accept is an absent field, which accepts every media type (Section 12.4.1).
See RFC 9110, Section 12.5.1.
ParseAccept source
func ParseAccept(lines ...string) (Accept, error)ParseAccept parses the field lines of an Accept header field, as returned by http.Header.Values. A field with no media ranges is treated as absent. Any parameter named "q" is the weight, wherever it appears, as Section 12.5.1 asks recipients to do. It returns ErrInvalidAccept if a line doesn't match the grammar.
(Accept) Negotiate source
func (a Accept) Negotiate(offers ...MediaType) (MediaType, bool)Negotiate returns the offer the client prefers, or false if it accepts none of them. Offers with equal weights are preferred in the order given, so list the server's preferred representation first.
See RFC 9110, Section 12.1.
(Accept) Quality source
func (a Accept) Quality(m MediaType) intQuality returns the weight a client gives m, in thousandths: 1000 is most preferred and 0 is not acceptable. It's the weight of the most specific range that matches m. A range matches if its type and subtype are equal to m's or "*", and m has each of its parameters (other than "q") with an equal value, compared case-insensitively.
See RFC 9110, Section 12.5.1 and Table 5.
AuthParam source
type AuthParam struct {
// contains filtered or unexported fields
}AuthParam is an authentication parameter, a name and value such as realm="api". It's always sent with its value as a quoted-string.
See RFC 9110, Section 11.2.
NewAuthParam source
func NewAuthParam(name Token, value string) (AuthParam, error)NewAuthParam returns a parameter with the given name and value. It returns ErrInvalidToken if name isn't a token, and ErrInvalidQuotedString if value contains a control character.
(AuthParam) Name source
func (p AuthParam) Name() TokenName returns the parameter's name.
(AuthParam) String source
func (p AuthParam) String() stringString returns the parameter as sent: name="value".
(AuthParam) Value source
func (p AuthParam) Value() stringValue returns the parameter's unquoted value.
Challenge source
type Challenge struct {
// contains filtered or unexported fields
}Challenge is an authentication challenge, sent in a WWW-Authenticate or Proxy-Authenticate header field: a scheme and its parameters.
Packages for specific schemes, such as rfc6750 for Bearer and rfc7617 for Basic, build challenges with the parameters their scheme requires. Use NewChallenge for other schemes. The zero Challenge isn't valid.
See RFC 9110, Section 11.3.
NewChallenge source
func NewChallenge(scheme Token, params ...AuthParam) (Challenge, error)NewChallenge returns a challenge for the scheme with the given parameters. It returns ErrInvalidToken if scheme isn't a token or a parameter is the zero AuthParam, and ErrDuplicateAuthParam if two parameters share a name, compared case-insensitively.
(Challenge) Params source
func (c Challenge) Params() []AuthParamParams returns a copy of the challenge's parameters.
(Challenge) Scheme source
func (c Challenge) Scheme() TokenScheme returns the challenge's authentication scheme.
(Challenge) String source
func (c Challenge) String() stringString returns the challenge as sent, such as: Bearer realm="api".
MediaType source
type MediaType struct {
// contains filtered or unexported fields
}MediaType is a media type, such as "application/json" or "text/plain;charset=utf-8". Its type, subtype and parameter names are lowercase, because they're case-insensitive. Use ParseMediaType to build one.
See RFC 9110, Section 8.3.1.
MustMediaType source
func MustMediaType(s string) MediaTypeMustMediaType is like ParseMediaType but panics if s isn't a media type. It's for media types fixed at compile time.
ParseMediaType source
func ParseMediaType(s string) (MediaType, error)ParseMediaType parses a media type, as sent in Content-Type. It returns ErrInvalidMediaType if s doesn't match the grammar of Section 8.3.1, or repeats a parameter. Wildcards aren't media types, so "*/*" is rejected.
(MediaType) Essence source
func (m MediaType) Essence() stringEssence returns the type and subtype without parameters, such as "application/json".
(MediaType) IsJSON source
func (m MediaType) IsJSON() boolIsJSON reports whether m is application/json or has the structured syntax suffix +json (RFC 6839, Section 3.1), such as application/problem+json.
(MediaType) Param source
func (m MediaType) Param(name string) (string, bool)Param returns the value of the named parameter, which is matched case-insensitively.
(MediaType) String source
func (m MediaType) String() stringString returns the media type in its preferred form: lowercase, no whitespace, and parameter values quoted only when they aren't tokens.
(MediaType) Subtype source
func (m MediaType) Subtype() stringSubtype returns the subtype, such as "json" or "problem+json".
(MediaType) Type source
func (m MediaType) Type() stringType returns the top-level type, such as "application".
Method source
type Method stringMethod is a request method, such as MethodGet. Use ParseMethod for other methods.
See RFC 9110, Section 9.
const (
MethodGet Method = "GET"
MethodHead Method = "HEAD"
MethodPost Method = "POST"
MethodPut Method = "PUT"
MethodDelete Method = "DELETE"
MethodConnect Method = "CONNECT"
MethodOptions Method = "OPTIONS"
MethodTrace Method = "TRACE"
MethodPatch Method = "PATCH"
)The methods defined in Section 9.3, and PATCH from RFC 5789.
ParseMethod source
func ParseMethod(s string) (Method, error)ParseMethod returns s as a Method, or ErrInvalidToken if it isn't a token. Methods are case-sensitive.
Protocol source
type Protocol stringProtocol is a protocol named in an Upgrade header field: a name with an optional version, such as "websocket" or "HTTP/3.0". Use ParseProtocol to check a string's syntax.
See RFC 9110, Section 7.8.
ParseProtocol source
func ParseProtocol(s string) (Protocol, error)ParseProtocol returns s as a Protocol, or ErrInvalidProtocol if it isn't a token, optionally followed by "/" and a version token.
RetryAfter source
type RetryAfter struct {
// contains filtered or unexported fields
}RetryAfter is the value of a Retry-After header field: how long a client ought to wait before it tries again. The zero RetryAfter is a delay of zero seconds.
See RFC 9110, Section 10.2.3.
RetryAfterDate source
func RetryAfterDate(t time.Time) RetryAfterRetryAfterDate returns t as an HTTP-date, in UTC with whole seconds.
RetryAfterDelay source
func RetryAfterDelay(d time.Duration) RetryAfterRetryAfterDelay returns a delay of d, rounded up to whole seconds. A negative d is treated as zero.
(RetryAfter) String source
func (r RetryAfter) String() stringString returns the field value: delay-seconds or an HTTP-date.
Status source
type Status struct {
// contains filtered or unexported fields
}Status is a 4xx or 5xx status code together with the header fields that go with it. Build one with its constructor, such as NotFound or Unauthorized, or with NewStatus. The zero Status isn't valid.
Status is immutable: its With methods return a modified copy.
See RFC 9110, Section 15.
BadGateway source
func BadGateway() StatusBadGateway returns 502 Bad Gateway (Section 15.6.3).
BadRequest source
func BadRequest() StatusBadRequest returns 400 Bad Request (Section 15.5.1).
Conflict source
func Conflict() StatusConflict returns 409 Conflict (Section 15.5.10).
ContentTooLarge source
func ContentTooLarge() StatusContentTooLarge returns 413 Content Too Large (Section 15.5.14).
ExpectationFailed source
func ExpectationFailed() StatusExpectationFailed returns 417 Expectation Failed (Section 15.5.18).
Forbidden source
func Forbidden() StatusForbidden returns 403 Forbidden (Section 15.5.4).
GatewayTimeout source
func GatewayTimeout() StatusGatewayTimeout returns 504 Gateway Timeout (Section 15.6.5).
Gone source
func Gone() StatusGone returns 410 Gone (Section 15.5.11). A 410 is heuristically cacheable.
HTTPVersionNotSupported source
func HTTPVersionNotSupported() StatusHTTPVersionNotSupported returns 505 HTTP Version Not Supported (Section 15.6.6).
InternalServerError source
func InternalServerError() StatusInternalServerError returns 500 Internal Server Error (Section 15.6.1).
LengthRequired source
func LengthRequired() StatusLengthRequired returns 411 Length Required (Section 15.5.12).
MethodNotAllowed source
func MethodNotAllowed(allow ...Method) StatusMethodNotAllowed returns 405 Method Not Allowed, with an Allow field
listing the methods the resource supports. Section 10.2.1 says a 405
"MUST generate an Allow header field", and that it may be empty if the
resource allows no methods. ExampleMethodNotAllowed shows a 405 with the Allow field RFC 9110, Section
15.5.6, requires. Output:Example
package main
import (
"fmt"
"funnyhaha.technology/rfc/rfc9110"
)
func main() {
s := rfc9110.MethodNotAllowed(rfc9110.MethodGet, rfc9110.MethodHead)
fmt.Println(s.Code(), s.Header().Get("Allow"))
}
405 GET, HEAD
MisdirectedRequest source
func MisdirectedRequest() StatusMisdirectedRequest returns 421 Misdirected Request (Section 15.5.20).
NewStatus source
func NewStatus(code int) (Status, error)NewStatus returns the status for any 4xx or 5xx code that doesn't need a header field, such as 402 or a code defined by another RFC. It returns ErrInvalidStatus for a code outside 400 to 599, and for 401, 405, 407, 416 and 426, which must be built with their own constructors.
NotAcceptable source
func NotAcceptable() StatusNotAcceptable returns 406 Not Acceptable (Section 15.5.7).
NotFound source
func NotFound() StatusNotFound returns 404 Not Found (Section 15.5.5). A 404 is heuristically cacheable, so consider adding rfc9111.NoStore.
NotImplemented source
func NotImplemented() StatusNotImplemented returns 501 Not Implemented (Section 15.6.2). A 501 is heuristically cacheable.
PreconditionFailed source
func PreconditionFailed() StatusPreconditionFailed returns 412 Precondition Failed (Section 15.5.13).
ProxyAuthenticationRequired source
func ProxyAuthenticationRequired(c Challenge, more ...Challenge) StatusProxyAuthenticationRequired returns 407 Proxy Authentication Required, with a Proxy-Authenticate field holding the challenges (Section 15.5.8).
RangeNotSatisfiable source
func RangeNotSatisfiable(completeLength uint64) StatusRangeNotSatisfiable returns 416 Range Not Satisfiable, with a Content-Range field giving the representation's current length, as Section 15.5.17 says a server generating a 416 "SHOULD" send.
RequestTimeout source
func RequestTimeout() StatusRequestTimeout returns 408 Request Timeout (Section 15.5.9).
ServiceUnavailable source
func ServiceUnavailable() StatusServiceUnavailable returns 503 Service Unavailable (Section 15.6.4). Add Status.WithRetryAfter if you know when the service will be back.
URITooLong source
func URITooLong() StatusURITooLong returns 414 URI Too Long (Section 15.5.15). A 414 is heuristically cacheable.
Unauthorized source
func Unauthorized(c Challenge, more ...Challenge) StatusUnauthorized returns 401 Unauthorized, with a WWW-Authenticate field
holding the challenges. Section 15.5.2 says a 401 "MUST send a
WWW-Authenticate header field". ExampleUnauthorized shows a 401 written with the WWW-Authenticate challenge
RFC 9110, Section 15.5.2, requires. Output:Example
package main
import (
"fmt"
"net/http/httptest"
"funnyhaha.technology/rfc/rfc9110"
)
func main() {
realm, err := rfc9110.NewAuthParam("realm", "api")
if err != nil {
panic(err)
}
challenge, err := rfc9110.NewChallenge("Bearer", realm)
if err != nil {
panic(err)
}
rec := httptest.NewRecorder()
rfc9110.Unauthorized(challenge).WriteHeader(rec)
fmt.Println(rec.Code)
fmt.Println(rec.Header().Get("WWW-Authenticate"))
}
401
Bearer realm="api"
UnprocessableContent source
func UnprocessableContent() StatusUnprocessableContent returns 422 Unprocessable Content (Section 15.5.21).
UnsupportedMediaType source
func UnsupportedMediaType() StatusUnsupportedMediaType returns 415 Unsupported Media Type (Section 15.5.16).
UpgradeRequired source
func UpgradeRequired(p Protocol, more ...Protocol) StatusUpgradeRequired returns 426 Upgrade Required, with an Upgrade field listing the protocols in order of preference. Section 15.5.22 says a 426 "MUST send an Upgrade header field", and Section 7.8 that the sender "MUST also send an "Upgrade" connection option in the Connection header field", so that's set too.
(Status) Code source
func (s Status) Code() intCode returns the status code.
(Status) Header source
func (s Status) Header() http.HeaderHeader returns a copy of the status's header fields.
(Status) WithAuthenticate source
func (s Status) WithAuthenticate(c Challenge, more ...Challenge) StatusWithAuthenticate returns a copy of s with a WWW-Authenticate field holding the challenges, replacing any already set. Section 11.6.1 allows it on any response "to indicate that supplying credentials (or different credentials) might affect the response", such as a 403.
(Status) WithCacheControl source
func (s Status) WithCacheControl(dirs ...rfc9111.Directive) StatusWithCacheControl returns a copy of s with a Cache-Control field holding the directives, replacing any already set.
(Status) WithRetryAfter source
func (s Status) WithRetryAfter(r RetryAfter) StatusWithRetryAfter returns a copy of s with a Retry-After field
(Section 10.2.3). ExampleStatus_WithRetryAfter shows a 503 telling the client to retry in two
minutes. Output:Example
package main
import (
"fmt"
"time"
"funnyhaha.technology/rfc/rfc9110"
)
func main() {
s := rfc9110.ServiceUnavailable().WithRetryAfter(rfc9110.RetryAfterDelay(2 * time.Minute))
fmt.Println(s.Code(), s.Header().Get("Retry-After"))
}
503 120
(Status) WriteHeader source
func (s Status) WriteHeader(w http.ResponseWriter)WriteHeader copies the status's header fields to w and writes the status code. Set any other header fields first.
Token source
type Token stringToken is a short textual identifier with no whitespace or delimiters, such as an authentication scheme or a parameter name. Use ParseToken to check a string's syntax.
See RFC 9110, Section 5.6.2.
ParseToken source
func ParseToken(s string) (Token, error)ParseToken returns s as a Token, or ErrInvalidToken if it isn't one.