Documentation ¶
Overview ¶
Package rfc provides symbols for specifications, primarily IETF RFCs.
This includes strings, such as header names, as well as logic functions, such as cache control rules.
All symbols in this package should document the precise RFC and ideally the exact section where they are defined, to allow readers to easily verify correctness.
This is primarily intended for IETF HTTP RFCs, but may include other specifications as well (e.g. ANSI, W3C, WHATWG, etc). If a symbol documents simply "RFC" then it refers to an IETF RFC. If the symbol is an RFC from a different organization, it should document the organization or project, e.g. "Rust RFC 2436" or "ISO/IEC 23009."
Index ¶
- Constants
- Variables
- func AcceptsGzip(r *http.Request) bool
- func CanCache(reqMethod string, reqHeaders http.Header, respCode int, ...) bool
- func ETag(t time.Time) string
- func FormatHTTPDate(t time.Time) string
- func FreshFor(respHeaders http.Header, respCC CacheControlMap, reqTime, respTime time.Time) time.Duration
- func GetHTTPDate(headers http.Header, key string) (time.Time, bool)
- func GetHTTPDeltaSeconds(m map[string][]string, key string) (time.Duration, bool)
- func GetUnmodifiedTime(h http.Header) (time.Time, bool)
- func ParseETag(e string) (time.Time, error)
- func ParseETags(eTags []string) (time.Time, bool)
- func ParseHTTPDate(d string) (time.Time, bool)
- func SortMimeTypes(m []MimeType)
- type CacheControlMap
- type EmailAddress
- type MimeType
- func (m MimeType) Charset() string
- func (m MimeType) Facet() string
- func (m MimeType) Less(o MimeType) bool
- func (m MimeType) Quality() float64
- func (m MimeType) Satisfy(o MimeType) bool
- func (m MimeType) String() string
- func (m MimeType) SubType() string
- func (m MimeType) Syntax() string
- func (m MimeType) Type() string
- type Reuse
- type URL
Examples ¶
Constants ¶
const ( IfModifiedSince = "If-Modified-Since" // RFC7232§3.3 LastModified = "Last-Modified" // RFC7232§2.2 ETagHeader = "ETag" IfMatch = "If-Match" IfUnmodifiedSince = "If-Unmodified-Since" Date = "Date" ETagVersion = 1 )
const ( AcceptEncoding = "Accept-Encoding" // RFC7231§5.3.4 CacheControl = "Cache-Control" // RFC7234§5.2 ContentDisposition = "Content-Disposition" // RFC6266 ContentEncoding = "Content-Encoding" // RFC7231§3.1.2.2 ContentType = "Content-Type" // RFC7231§3.1.1.5 PermissionsPolicy = "Permissions-Policy" // W3C "Permissions Policy" Server = "Server" // RFC7231§7.4.2 UserAgent = "User-Agent" // RFC7231§5.5.3 Vary = "Vary" // RFC7231§7.1.4 Age = "Age" // RFC7234§5.1 Location = "Location" // RFC7231§7.1.2 Authorization = "Authorization" // RFC7235§4.2 )
These are the names of HTTP Headers, for convenience and so that typos are caught at compile-time.
const ( ApplicationJSON = "application/json" // RFC4627§6 ApplicationOctetStream = "application/octet-stream" // RFC2046§4.5.2 ContentTypeMultiPartMixed = "multipart/mixed" // RFC1341§7.2 ContentTypeTextPlain = "text/plain" // RFC2046§4.1 ContentTypeURIList = "text/uri-list" // RFC2483§5 Gzip = "gzip" // RFC7230§4.2.3 )
These are (some) valid values for content encoding and MIME types, for convenience and so that typos are caught at compile-time.
const LastModifiedFormat = "Mon, 02 Jan 2006 15:04:05 MST" // RFC1123
LastModifiedFormat is the format used by dates in the HTTP Last-Modified header.
Variables ¶
var CacheableRequestMethods = map[string]struct{}{ http.MethodGet: {}, http.MethodHead: {}, }
CacheableRequestMethods is the list of all request methods which elicit cache-able responses.
var CacheableResponseCodes = map[int]struct{}{ http.StatusOK: {}, http.StatusNonAuthoritativeInfo: {}, http.StatusNoContent: {}, http.StatusPartialContent: {}, http.StatusMultipleChoices: {}, http.StatusMovedPermanently: {}, http.StatusNotFound: {}, http.StatusMethodNotAllowed: {}, http.StatusGone: {}, http.StatusRequestURITooLong: {}, http.StatusNotImplemented: {}, }
CacheableResponseCodes provides fast lookup of whether a HTTP response code is cache-able by default.
var MIME_CSS = MimeType{ Name: "text/css", Parameters: map[string]string{"charset": "utf-8"}, }
MIME_CSS is a pre-defined MimeType for CSS data.
var MIME_HTML = MimeType{ Name: "text/html", Parameters: map[string]string{"charset": "utf-8"}, }
MIME_HTML is a pre-defined MimeType for HTML data.
var MIME_JS = MimeType{ Name: "text/javascript", Parameters: map[string]string{"charset": "utf-8"}, }
MIME_JS is a pre-defined MimeType for JavaScript data.
var MIME_JSON = MimeType{ Name: "application/json", Parameters: map[string]string{}, }
MIME_JSON is a pre-defined MimeType for JSON data.
var MIME_PLAINTEXT = MimeType{ Name: "text/plain", Parameters: map[string]string{"charset": "utf-8"}, }
MIME_PLAINTEXT is a pre-defined MimeType for plain text data.
var ValidHTTPCodes = map[int]struct{}{ http.StatusContinue: {}, http.StatusSwitchingProtocols: {}, http.StatusProcessing: {}, http.StatusEarlyHints: {}, http.StatusOK: {}, http.StatusCreated: {}, http.StatusAccepted: {}, http.StatusNonAuthoritativeInfo: {}, http.StatusNoContent: {}, http.StatusResetContent: {}, http.StatusPartialContent: {}, http.StatusMultiStatus: {}, http.StatusAlreadyReported: {}, http.StatusIMUsed: {}, http.StatusMultipleChoices: {}, http.StatusMovedPermanently: {}, http.StatusFound: {}, http.StatusSeeOther: {}, http.StatusNotModified: {}, http.StatusUseProxy: {}, 306: {}, http.StatusTemporaryRedirect: {}, http.StatusPermanentRedirect: {}, http.StatusBadRequest: {}, http.StatusUnauthorized: {}, http.StatusPaymentRequired: {}, http.StatusForbidden: {}, http.StatusNotFound: {}, http.StatusMethodNotAllowed: {}, http.StatusNotAcceptable: {}, http.StatusProxyAuthRequired: {}, http.StatusRequestTimeout: {}, http.StatusConflict: {}, http.StatusGone: {}, http.StatusLengthRequired: {}, http.StatusPreconditionFailed: {}, http.StatusRequestEntityTooLarge: {}, http.StatusRequestURITooLong: {}, http.StatusUnsupportedMediaType: {}, http.StatusRequestedRangeNotSatisfiable: {}, http.StatusExpectationFailed: {}, http.StatusTeapot: {}, http.StatusMisdirectedRequest: {}, http.StatusUnprocessableEntity: {}, http.StatusLocked: {}, http.StatusFailedDependency: {}, http.StatusTooEarly: {}, http.StatusUpgradeRequired: {}, http.StatusPreconditionRequired: {}, http.StatusTooManyRequests: {}, http.StatusRequestHeaderFieldsTooLarge: {}, http.StatusUnavailableForLegalReasons: {}, http.StatusInternalServerError: {}, http.StatusNotImplemented: {}, http.StatusBadGateway: {}, http.StatusServiceUnavailable: {}, http.StatusGatewayTimeout: {}, http.StatusHTTPVersionNotSupported: {}, http.StatusVariantAlsoNegotiates: {}, http.StatusInsufficientStorage: {}, http.StatusLoopDetected: {}, http.StatusNotExtended: {}, http.StatusNetworkAuthenticationRequired: {}, }
ValidHTTPCodes provides fast lookup of whether a HTTP response code is valid.
Functions ¶
func AcceptsGzip ¶
AcceptsGzip returns whether r accepts gzip encoding, per RFC7231§5.3.4.
func CanCache ¶
func CanCache(reqMethod string, reqHeaders http.Header, respCode int, respHeaders http.Header, strictRFC bool) bool
CanCache returns whether an object can be cached per RFC 7234, based on the request headers, response headers, and response code.
If strictRFC is false, this ignores request headers denying cacheability such as `no-cache`, in order to protect origins. TODO add options to ignore/violate request Cache-Control (to protect origins)
func ETag ¶
ETag takes the last time the object was modified, and returns an ETag string. Note the string is the complete header value, including quotes. ETags must be quoted strings.
func FormatHTTPDate ¶
FormatHTTPDate formats t as an RFC7231§7.1.1 HTTP-date.
func FreshFor ¶
func FreshFor(respHeaders http.Header, respCC CacheControlMap, reqTime, respTime time.Time) time.Duration
FreshFor gives a duration for which an HTTP response may still be cached - from the time of the request.
respHeaders is the collection of headers passed in the original response respCC is the parsed Cache-Control header that was present in the original response reqTime is the time at which the request was made respTime is the time at which the original response was received
func GetHTTPDate ¶
GetHTTPDate is a helper function which gets an HTTP date from the given map (which is typically a `http.Header` or `CacheControl`.
Returns false if the given key doesn't exist in the map, or if the value isn't a valid HTTP Date per RFC2616§3.3.
Example ¶
hdrs := http.Header{} hdrs.Set("Date", "Tue, 30 Jun 2020 19:07:15 GMT") t, ok := GetHTTPDate(hdrs, "Date") if !ok { fmt.Println("Failed to get date") return } fmt.Printf("%s\n", t)
Output: 2020-06-30 19:07:15 +0000 GMT
func GetHTTPDeltaSeconds ¶
GetHTTPDeltaSeconds is a helper function which gets an HTTP Delta Seconds from the given map (which is typically a `http.Header` or `CacheControl`). Returns false if the given key doesn't exist in the map, or if the value isn't a valid Delta Seconds per RFC2616§3.3.2.
func GetUnmodifiedTime ¶
GetUnmodifiedTime gets the latest time out of the Etags (if present), or the If-Unmodified-Since (if present)
func ParseETag ¶
ParseETag takes a complete ETag header string, including the quotes (if the client correctly set them), and returns the last modified time encoded in the ETag.
func ParseETags ¶
ParseETags the latest time of any valid ETag, and whether a valid ETag was found.
func ParseHTTPDate ¶
ParseHTTPDate parses the given RFC7231§7.1.1 HTTP-date.
Example ¶
t, ok := ParseHTTPDate("Tue, 30 Jun 2020 19:07:15 GMT") if !ok { fmt.Println("Failed to parse date") return } fmt.Printf("%s\n", t)
Output: 2020-06-30 19:07:15 +0000 GMT
func SortMimeTypes ¶
func SortMimeTypes(m []MimeType)
SortMimeTypes sorts the passed MimeTypes according to their "quality value". See MimeType.Less for more information on how MimeTypes are compared.
Example ¶
// Normally don't do this, but for the sake of brevity in an example I will mimes := []MimeType{ MimeType{ "text/html", map[string]string{}, }, MimeType{ "text/xml", map[string]string{"q": "0.9"}, }, MimeType{ "text/*", map[string]string{"q": "0.9"}, }, MimeType{ "*/*", map[string]string{}, }, } SortMimeTypes(mimes) for _, m := range mimes { fmt.Printf("%s, ", m) } fmt.Println()
Output: text/html, */*, text/xml; q=0.9, text/*; q=0.9,
Types ¶
type CacheControlMap ¶
CacheControlMap is the parameters found in an HTTP Cache-Control header, each mapped to its specified value.
func ParseCacheControl ¶
func ParseCacheControl(h http.Header) CacheControlMap
ParseCacheControl parses the Cache-Control header from the headers object, and returns the parsed map of cache control directives.
TODO verify Header/CacheControl are properly CanonicalCase/lowercase. Put cache-control text in constants?
Example ¶
hdrs := http.Header{} hdrs.Set(CacheControl, "no-store, no-cache, must-revalidate, post-check=0, pre-check=0") cchm := ParseCacheControl(hdrs) fmt.Println(cchm.Has("no-store")) fmt.Println(cchm.Has("no-cache")) fmt.Println(cchm.Has("must-revalidate")) fmt.Println(cchm["post-check"]) fmt.Println(cchm["pre-check"])
Output: true true true 0 0
func (CacheControlMap) Has ¶
func (ccm CacheControlMap) Has(param string) bool
Has returns whether or not the CacheControlMap contains the named parameter.
Example ¶
hdrs := http.Header{} hdrs.Set(CacheControl, "no-cache") ccm := ParseCacheControl(hdrs) if ccm.Has("no-cache") { fmt.Println("Has 'no-cache'") } if ccm.Has("no-store") { fmt.Println("Has 'no-store'") }
Output: Has 'no-cache'
func (CacheControlMap) String ¶
func (ccm CacheControlMap) String() string
String implements the Stringer interface by returning a textual representation of the CacheControlMap.
type EmailAddress ¶
EmailAddress is an alias of net/mail.Address that implements JSON encoding and decoding, as well as scanning from database driver values.
func (EmailAddress) MarshalJSON ¶
func (a EmailAddress) MarshalJSON() ([]byte, error)
MarshalJSON implements the encoding/json.Marshaler interface
func (*EmailAddress) Scan ¶
func (a *EmailAddress) Scan(src interface{}) error
Scan implements the database/sql.Scanner interface
func (*EmailAddress) UnmarshalJSON ¶
func (a *EmailAddress) UnmarshalJSON(data []byte) error
UnmarshalJSON implements the encoding/json.Unmarshaler interface
type MimeType ¶
type MimeType struct { // Name is the full name of the MIME Type, e.g. 'application/json'. // Usually for printing, it's better to call MimeType.String Name string // Parameters contains a map of provided parameter names to corresponding values. Note that for // MimeTypes constructed with NewMimeType, this will always be initialized, even when empty. Parameters map[string]string }
MimeType represents a "Media Type" as defined by RFC6838, along with some ease-of-use functionality.
Note that this structure is in no way guaranteed to represent a *real* MIME Type, only one that is *syntactically valid*. The hope is that it will make content negotiation easier for developers, and should not be considered a security measure by any standard.
func MimeTypesFromAccept ¶
MimeTypesFromAccept constructs a *sorted* list of MimeTypes from the provided text, which is assumed to be from an HTTP 'Accept' header. The list is sorted using to SortMimeTypes.
If a is an empty string, this will return an empty slice and no error.
Example ¶
const acceptLine = "text/html,text/xml;q=0.9,text/*;q=0.9,*/*" mimes, err := MimeTypesFromAccept(acceptLine) if err != nil { fmt.Println(err.Error()) return } for _, m := range mimes { fmt.Printf("%s, ", m) } fmt.Println()
Output: text/html, */*, text/xml; q=0.9, text/*; q=0.9,
func NewMimeType ¶
NewMimeType creates a new MimeType, initializing its Parameters map.
If v cannot be parsed as a valid MIME (by mime.ParseMediaType), returns an error.
Example ¶
m, err := NewMimeType("text/plain;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } fmt.Println("Name:", m.Name, "Parameters:", m.Parameters)
Output: Name: text/plain Parameters: map[charset:utf-8]
func (MimeType) Charset ¶
Charset retrieves the "charset" parameter of a MimeType.
Returns an empty string if no charset exists in the parameters, or if the parameters themselves are not initialized.
Example ¶
m, err := NewMimeType("text/plain;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } c := m.Charset() // it's okay to ignore this error, because I was a good boy and used NewMimeType fmt.Println(c)
Output: utf-8
func (MimeType) Facet ¶
Facet returns the MimeType's "facet" if one exists, otherwise an empty string.
Example ¶
m, err := NewMimeType("text/vnd.plain+crlf;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } fmt.Println(m.Facet())
Output: vnd
func (MimeType) Less ¶
Less checks whether or not this MimeType is "less than" some other MimeType, o.
This is done using a comparison of "quality value" of the two MimeTypes, as specified in RFC7231.
See Also: The MDN documentation on "quality value" comparisons: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values
Example ¶
one, err := NewMimeType("text/plain") if err != nil { fmt.Println(err.Error()) return } two, err := NewMimeType("text/*") if err != nil { fmt.Println(err.Error()) return } three, err := NewMimeType("text/plain;q=0.9") if err != nil { fmt.Println(err.Error()) return } fmt.Println(one.Less(two), two.Less(three), one.Less(three))
Output: false false false
func (MimeType) Quality ¶
Quality retrieves and parses the "quality" parameter of a MimeType.
As specified in RFC7231, the quality parameter's name is "q", not actually "quality". To obtain a literal "quality" parameter value, access MimeType.Parameters directly. MimeTypes with no "q" parameter implicitly have a "quality" of 1.0.
Example ¶
m, err := NewMimeType("text/plain;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } q := m.Quality() fmt.Print(q) m.Parameters["q"] = "0.9" q = m.Quality() fmt.Println("", q)
Output: 1 0.9
func (MimeType) Satisfy ¶
Satisfy checks whether or not the MimeType "satifies" some other MimeType, o.
Note that this does not check if the two are literally the *same*. Specifically, if the Type or SubType of the given MimeType o is the special '*' name, then this will instead check whether or not this MimeType can *satisfy* the other according to RFC7231. This means that this satisfaction check is NOT associative - that is a.Satisfy(b) does not imply b.Satisfy(a).
See Also: The MDN documentation on the Accept Header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
Example ¶
m, err := NewMimeType("text/plain") if err != nil { fmt.Println(err.Error()) return } o, err := NewMimeType("text/*") if err != nil { fmt.Println(err.Error()) return } fmt.Println(m.Satisfy(o), o.Satisfy(m))
Output: true false
func (MimeType) String ¶
String implements the Stringer interface using mime.FormatMediaType.
Example ¶
m, err := NewMimeType("text/plain;foo=bar;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } fmt.Println(m)
Output: text/plain; charset=utf-8; foo=bar
func (MimeType) SubType ¶
SubType returns only the "sub" type of a MimeType.
Example ¶
m, err := NewMimeType("text/vnd.plain+crlf;charset=utf-8") if err != nil { fmt.Println(err.Error()) return } fmt.Println(m.SubType())
Output: vnd.plain+crlf
type Reuse ¶
type Reuse int
Reuse is an "enumerated" type describing the necessary behavior of a cache with regard to its cached objects.
const ( // ReuseCan indicates that the cached response may be served. ReuseCan Reuse = iota // ReuseCannot indicates that the cached response must not be served. ReuseCannot // ReuseMustRevalidate indicates that the cached response must be // revalidated, and cannot be served stale if revalidation fails for some // reason. ReuseMustRevalidate // ReuseMustRevalidateCanStale indicates the response must be revalidated, // but if the parent cannot be reached, may be served stale, per // RFC7234§4.2.4. ReuseMustRevalidateCanStale )
type URL ¶
URL is an alias of net/url.URL that implements JSON encoding and decoding, as well as scanning from database driver values.
func (URL) MarshalJSON ¶
MarshalJSON implements the encoding/json.Marshaler interface
func (*URL) UnmarshalJSON ¶
UnmarshalJSON implements the encoding/json.Unmarshaler interface