Package rfc9111

import "funnyhaha.technology/rfc/rfc9111"
View the source code

Overview

Package rfc9111 builds Cache-Control response directives, as defined by RFC 9111 (HTTP Caching).

It matters for error responses because some error status codes are heuristically cacheable: a cache may store and reuse a 404, 405, 410, 414 or 501 response that has no explicit freshness information (RFC 9110, Section 15.1, and RFC 9111, Section 4.2.2). Send NoStore with an error that mustn't be reused:

rfc9110.NotFound().WithCacheControl(rfc9111.NoStore())

A client that caches what it fetches reads a response's directives with ParseCacheControl:

cc := rfc9111.ParseCacheControl(resp.Header.Values("Cache-Control")...)
if maxAge, ok := cc.MaxAge(); ok && !cc.NoStore() && !cc.NoCache() {
	// Reuse the response for up to maxAge.
}

The package covers the response directives of Section 5.2.2, without the optional field-name lists of no-cache and private, and parses the ones a private cache needs to decide on reuse. It doesn't cover request directives.

The RFC text is in rfc9111.txt in this directory, and the doc comments cite its sections.

Index

Functions

Format source

func Format(dirs ...Directive) string

Format returns the directives as a Cache-Control field value, such as "no-store, max-age=0". It leaves out zero Directives.

Example

ExampleFormat shows a Cache-Control value that stops caches reusing a 404, which is heuristically cacheable.

package main

import (
	"fmt"
	"net/http"

	"funnyhaha.technology/rfc/rfc9111"
)

func main() {
	fmt.Println(rfc9111.Format(rfc9111.NoStore(), rfc9111.MaxAge(0)))
	fmt.Println(rfc9111.HeuristicallyCacheable(http.StatusNotFound))
}

Output:

no-store, max-age=0
true

HeuristicallyCacheable source

func HeuristicallyCacheable(code int) bool

HeuristicallyCacheable reports whether a response with the status code may be stored and reused by a cache when it has no explicit freshness information. These are the codes RFC 9110, Section 15.1, lists: 200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414 and 501.

See RFC 9111, Section 4.2.2.

Types

CacheControl source

type CacheControl struct {
	// contains filtered or unexported fields
}

CacheControl is the response directives read from a Cache-Control field by ParseCacheControl: the ones that decide whether, and for how long, a private cache may reuse a response.

See RFC 9111, Section 5.2.2.

ParseCacheControl source

func ParseCacheControl(lines ...string) CacheControl

ParseCacheControl reads the response directives max-age, no-store, no-cache and private from the Cache-Control field lines, and ignores the rest, as Section 5.2.3 requires of unrecognised directives. Directive names are compared case-insensitively, and an argument may be a token or a quoted-string (Section 5.2).

When max-age appears more than once, the first is used (Section 4.2.1). An invalid max-age makes the response stale, a max-age of 0, which Section 4.2.1 allows. A no-cache or private with a list of field names is treated as if it had none, which is the stricter reading.

(CacheControl) MaxAge source

func (cc CacheControl) MaxAge() (time.Duration, bool)

MaxAge returns the max-age directive's duration, and whether it was present (Section 5.2.2.1).

(CacheControl) NoCache source

func (cc CacheControl) NoCache() bool

NoCache reports whether no-cache was present: a cache mustn't reuse the response without revalidating it (Section 5.2.2.4).

(CacheControl) NoStore source

func (cc CacheControl) NoStore() bool

NoStore reports whether no-store was present: a cache mustn't store the response (Section 5.2.2.5).

(CacheControl) Private source

func (cc CacheControl) Private() bool

Private reports whether private was present: a shared cache mustn't store the response, though a private cache may (Section 5.2.2.7).

Directive source

type Directive struct {
	// contains filtered or unexported fields
}

Directive is a Cache-Control response directive. Build one with its constructor, such as NoStore or MaxAge. The zero Directive is empty, and Format leaves it out.

See RFC 9111, Section 5.2.2.

MaxAge source

func MaxAge(d time.Duration) Directive

MaxAge returns max-age: the response is stale once its age exceeds d (Section 5.2.2.1). d is rounded down to whole seconds, a negative d is treated as zero, and d is capped at 2^31 seconds (Section 1.2.2).

MustRevalidate source

func MustRevalidate() Directive

MustRevalidate returns must-revalidate: a cache mustn't reuse the response once it's stale without revalidating it (Section 5.2.2.2).

MustUnderstand source

func MustUnderstand() Directive

MustUnderstand returns must-understand: a cache may store the response only if it understands the requirements of its status code (Section 5.2.2.3).

NoCache source

func NoCache() Directive

NoCache returns no-cache: a cache mustn't reuse the response without revalidating it (Section 5.2.2.4).

NoStore source

func NoStore() Directive

NoStore returns no-store: a cache mustn't store the response (Section 5.2.2.5).

NoTransform source

func NoTransform() Directive

NoTransform returns no-transform: an intermediary mustn't transform the content (Section 5.2.2.6).

Private source

func Private() Directive

Private returns private: a shared cache mustn't store the response (Section 5.2.2.7).

ProxyRevalidate source

func ProxyRevalidate() Directive

ProxyRevalidate returns proxy-revalidate: must-revalidate, for shared caches only (Section 5.2.2.8).

Public source

func Public() Directive

Public returns public: a cache may store the response, even if it would otherwise be prohibited (Section 5.2.2.9).

SMaxAge source

func SMaxAge(d time.Duration) Directive

SMaxAge returns s-maxage: max-age, for shared caches only (Section 5.2.2.10). d is treated as in MaxAge.

(Directive) String source

func (d Directive) String() string

String returns the directive as sent, such as "max-age=60".