Documentation
¶
Overview ¶
Package fresh implements HTTP response freshness testing, a port of the npm "fresh" package. It determines whether a cached response is still fresh relative to a request's conditional headers, and is the same primitive that Express uses to answer 304 Not Modified requests.
Use this package when a server holds a representation of a resource together with its validators (an ETag and/or a Last-Modified time) and needs to decide whether the client's cached copy is still current. When Fresh reports true, the caller can skip sending the body and respond with 304 Not Modified; when it reports false, the resource is considered stale and the full response should be sent. This mirrors the conditional-request handling described in RFC 7232.
Freshness is evaluated from two request headers, If-None-Match and If-Modified-Since, checked against the response's ETag and Last-Modified headers. An unconditional request (neither If-None-Match nor If-Modified-Since present) is always treated as stale, because there is nothing to validate against. A Cache-Control: no-cache directive on the request forces revalidation and is likewise reported as stale, regardless of the validators.
When both conditional headers are present, both must pass for the response to be fresh. If-None-Match succeeds when the response ETag is listed in the header, using a weak comparison in which a leading "W/" prefix is ignored; a bare "*" matches any ETag. A missing response ETag fails the check unless the request sent "*". If-Modified-Since succeeds when the response's Last-Modified time is not strictly after the requested time; a missing Last-Modified, or a date in either header that cannot be parsed in any of the standard HTTP date formats, fails the check.
The behavior tracks the npm "fresh" module closely, including the "*" handling, weak ETag comparison, no-cache short-circuit, and the rule that a request with no conditional headers is stale. The signature is adapted to Go: rather than accepting two plain header maps by convention, Fresh takes two http.Header values, and nil headers are tolerated and treated as empty. Date parsing accepts the RFC 1123, RFC 1123 with numeric zone, RFC 850, and ANSI C asctime formats in addition to the preferred http.TimeFormat.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Fresh ¶
Fresh reports whether a response is fresh given the request headers and the response headers.
It returns true when the response's validators satisfy the request's conditional headers (If-None-Match / If-Modified-Since). If neither conditional header is present, or the request contains a Cache-Control no-cache directive, the response is considered stale (false).
Example ¶
ExampleFresh demonstrates a fresh response validated by ETag. The request carries an If-None-Match header, and the response advertises a matching ETag, so the client's cached copy is still current. When Fresh reports true, a server would typically answer 304 Not Modified and omit the body. The comparison ignores a leading "W/" weak-validator prefix. Here the tags are identical, so the response is fresh.
package main
import (
"fmt"
"net/http"
"github.com/malcolmston/express/fresh"
)
func main() {
reqHeaders := http.Header{}
reqHeaders.Set("If-None-Match", `"abc123"`)
resHeaders := http.Header{}
resHeaders.Set("ETag", `"abc123"`)
fmt.Println(fresh.Fresh(reqHeaders, resHeaders))
}
Output: true
Example (ModifiedSince) ¶
ExampleFresh_modifiedSince demonstrates freshness by modification date. The request's If-Modified-Since is later than the response's Last-Modified time, so the resource has not changed since the client last fetched it. Fresh reports true, allowing a 304 Not Modified response. Dates are parsed in the standard HTTP formats. If the Last-Modified time were strictly after the If-Modified-Since time, the response would instead be stale.
package main
import (
"fmt"
"net/http"
"github.com/malcolmston/express/fresh"
)
func main() {
reqHeaders := http.Header{}
reqHeaders.Set("If-Modified-Since", "Sat, 01 Jan 2000 00:00:00 GMT")
resHeaders := http.Header{}
resHeaders.Set("Last-Modified", "Fri, 31 Dec 1999 00:00:00 GMT")
fmt.Println(fresh.Fresh(reqHeaders, resHeaders))
}
Output: true
Example (NoCache) ¶
ExampleFresh_noCache shows how a Cache-Control: no-cache directive forces revalidation. Even though the request's If-None-Match matches the response ETag, the no-cache directive instructs caches to treat the response as stale. Fresh therefore returns false, short-circuiting the validator checks. This lets a client demand a fresh response regardless of its stored validators. It mirrors the no-cache handling of the original library.
package main
import (
"fmt"
"net/http"
"github.com/malcolmston/express/fresh"
)
func main() {
reqHeaders := http.Header{}
reqHeaders.Set("If-None-Match", `"abc123"`)
reqHeaders.Set("Cache-Control", "no-cache")
resHeaders := http.Header{}
resHeaders.Set("ETag", `"abc123"`)
fmt.Println(fresh.Fresh(reqHeaders, resHeaders))
}
Output: false
Example (NoConditionalHeaders) ¶
ExampleFresh_noConditionalHeaders illustrates an unconditional request. When neither If-None-Match nor If-Modified-Since is present, there is nothing to validate the cached copy against. In that situation Fresh always reports false, treating the response as stale so the full body is sent. This is the default outcome for a plain GET without cache validators. It matches the behavior of the npm "fresh" module.
package main
import (
"fmt"
"net/http"
"github.com/malcolmston/express/fresh"
)
func main() {
fmt.Println(fresh.Fresh(http.Header{}, http.Header{}))
}
Output: false
Example (Stale) ¶
ExampleFresh_stale shows a stale result caused by a mismatched ETag. The request's If-None-Match validator does not equal the response's current ETag, meaning the cached representation is out of date. Fresh returns false, and a server would send the full, updated response body. Any single non-matching validator is enough to make the response stale. This is the counterpart to the matching-ETag case.
package main
import (
"fmt"
"net/http"
"github.com/malcolmston/express/fresh"
)
func main() {
reqHeaders := http.Header{}
reqHeaders.Set("If-None-Match", `"old"`)
resHeaders := http.Header{}
resHeaders.Set("ETag", `"new"`)
fmt.Println(fresh.Fresh(reqHeaders, resHeaders))
}
Output: false
Types ¶
This section is empty.