httpcache

package module
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 5, 2025 License: Apache-2.0 Imports: 11 Imported by: 1

README

httpcache

Go Reference Go Report Card Test codecov

httpcache is a Go package that provides a standards-compliant http.RoundTripper for transparent HTTP response caching, following RFC 9111 (HTTP Caching).

!!! note This package is intended for use as a private (client-side) cache. It is not a shared or proxy cache. It is designed to be used with an HTTP client to cache responses from origin servers, improving performance and reducing load on those servers.

Features

  • Plug-and-Play: Drop-in replacement for http.RoundTripper with no additional configuration required.
  • RFC 9111 Compliance: Handles validation, expiration, and revalidation. View full compliance details.
  • Cache Control: Supports all required HTTP cache control directives, as well as extensions like stale-while-revalidate and stale-if-error.
  • Cache Backends: Built-in support for file system and memory caches, with the ability to implement custom backends.
  • Extensible: Options for logging, transport and timeouts.
  • Debuggable: Adds a cache status header to every response.
  • Zero Dependencies: No external dependencies, pure Go implementation.

Made with VHS

Demonstration of HTTP caching in action. See _examples/app for code.

Installation

To install the package, run:

go get github.com/bartventer/httpcache

Quick Start

To get started, create a new HTTP client with the httpcache transport, specifying a cache backend DSN. You'll need to register the desired cache backend before using it. Here's an example using the built-in file system cache:

package main

import (
    "log/slog"
    "net/http"
    "time"
    
	"github.com/bartventer/httpcache"
    // Register the file system cache backend
    _ "github.com/bartventer/httpcache/store/fscache" 
)

func main() {
    // Example DSN for the file system cache backend
    dsn := "fscache://?appname=myapp" 
    client := &http.Client{
        Transport: httpcache.NewTransport(
            dsn,
            httpcache.WithSWRTimeout(10*time.Second),
            httpcache.WithLogger(slog.Default()),
    	),
    }
    // ... Use the client as usual
}

!!! tip The DSN (Data Source Name) specifies the cache backend and its configuration. In this example, fscache://?appname=myapp uses the file system cache with an application name of myapp. You can customize the DSN based on the backend you choose.

Cache Backends

Backend DSN Example Description
fscache fscache://?appname=myapp Built-in file system cache, stores responses on disk
memcache memcache:// Built-in memory cache, stores responses in memory

Consult the documentation for each backend for specific configuration options and usage details.

Custom Cache Backends

To implement a custom cache backend, create a type that satisfies the store.Cache interface, then register it using the store.Register function. Refer to the built-in backends for examples of how to implement this interface.

Options

Option Description Default Value
WithTransport(http.RoundTripper) Set the underlying transport http.DefaultTransport
WithSWRTimeout(time.Duration) Set the stale-while-revalidate timeout 5 * time.Second
WithLogger(*slog.Logger) Set a logger for debug output slog.New(slog.DiscardHandler)

Cache Status Header

Every response includes a cache status header to indicate how the response was served. The header is named X-Httpcache-Status and can have the following values:

Status Description
HIT Served from cache
MISS Fetched from origin
STALE Served stale from cache
REVALIDATED Revalidated with origin
BYPASS Cache bypassed
Example
X-Httpcache-Status: HIT

Limitations

  • Range Requests & Partial Content: This cache does not support HTTP range requests or partial/incomplete responses (e.g., status code 206, Range/Content-Range headers). All requests with a Range header are bypassed, and 206 responses are not cached. For example:

    GET /example.txt HTTP/1.1
    Host: example.com
    Range: bytes=0-99
    

    The above request will bypass the cache and fetch the response directly from the origin server. See RFC 9111 §3.3-3.4 for details.

RFC 9111 Compliance Matrix

RFC 9111

Main Section Requirement Implemented Notes
1. Introduction N/A N/A Nothing to implement
2. Overview of Cache Operation N/A N/A Nothing to implement
3. Storing Responses in Caches Required ✔️ Details
4. Constructing Responses from Caches Required ✔️ Details
5. Field Definitions Required ✔️ Details
6. Relationship to Applications and Other Caches N/A N/A Nothing to implement
7. Security Considerations N/A N/A Nothing to implement
8. IANA Considerations N/A N/A Nothing to implement
9. References N/A N/A Nothing to implement

Legend for Requirements:

Requirement Description
Required Must be implemented for RFC compliance
Optional Implementation is discretionary
Obsolete Directive is no longer relevant as per RFC 9111
Deprecated Directive is deprecated as per RFC 9111, but can still be implemented
N/A Nothing to implement or not applicable to private caches
§3. Storing Responses in Caches (Details)
Section Requirement Implemented Notes
3.1. Storing Header and Trailer Fields Required ✔️
3.2. Updating Stored Header Fields Required ✔️
3.3. Storing Incomplete Responses Optional See Limitations
3.4. Combining Partial Content Optional ^^
3.5. Storing Responses to Authenticated Requests Required ✔️
§4. Constructing Responses from Caches (Details)
Section Requirement Implemented Notes
4.1. Calculating Cache Keys with the Vary Header Field Required ✔️
4.2. Freshness Required ✔️ Details
§4.2. Freshness (Subsections)
Section Requirement Implemented Notes
4.2.1. Calculating Freshness Lifetime Required ✔️
4.2.2. Calculating Heuristic Freshness Required ✔️
4.2.3. Calculating Age Required ✔️
4.2.4. Serving Stale Responses Required ✔️
Section Requirement Implemented Notes
4.3. Validation Required ✔️ Details
§4.3. Validation (Subsections)
Section Requirement Implemented Notes
4.3.1. Sending a Validation Request Required ✔️
4.3.2. Handling Received Validation Request N/A N/A Not applicable to private client-side caches
4.3.3. Handling a Validation Response Required ✔️
4.3.4. Freshening Stored Responses upon Validation Required ✔️
4.3.5. Freshening Responses with HEAD Required ✔️
Section Requirement Implemented Notes
4.4. Invalidating Stored Responses Required ✔️
§5. Field Definitions (Details)
Section Requirement Implemented Notes
5.1. Age Required ✔️
5.2. Cache-Control Required ✔️ Details
5.3. Expires Required ✔️
5.4. Pragma Deprecated Deprecated by RFC 9111; not implemented
5.5. Warning Obsolete Obsoleted by RFC 9111; not implemented
§5.2. Cache-Control Directives
Section Requirement Implemented Notes
5.2.1. Request Directives Optional ✔️ Details
§5.2.1. Request Directives (Details)
Directive Requirement Implemented Notes
5.2.1.1. max-age Optional ✔️
5.2.1.2. max-stale Optional ✔️
5.2.1.3. min-fresh Optional ✔️
5.2.1.4. no-cache Optional ✔️
5.2.1.5. no-store Optional ✔️
5.2.1.6. no-transform Optional ✔️ Compliant by default - implementation never transforms content
5.2.1.7. only-if-cached Optional ✔️
Section Requirement Implemented Notes
5.2.2. Response Directives Required ✔️ Details
§5.2.2. Response Directives (Details)
Directive Requirement Implemented Notes
5.2.2.1. max-age Required ✔️
5.2.2.2. must-revalidate Required ✔️
5.2.2.3. must-understand Required ✔️
5.2.2.4. no-cache Required ✔️ Both qualified and unqualified forms supported
5.2.2.5. no-store Required ✔️
5.2.2.6. no-transform Required ✔️ Compliant by default - implementation never transforms content
5.2.2.7. private N/A N/A Intended for shared caches; not applicable to private caches
5.2.2.8. proxy-revalidate N/A N/A Intended for shared caches; not applicable to private caches
5.2.2.9. public Optional ✔️
5.2.2.10. s-maxage N/A N/A Intended for shared caches; not applicable to private caches
Section Requirement Implemented Notes
5.2.3. Extension Directives Optional partially Details
§5.2.3. Extension Directives (Details)

The following registered extension directives are supported:

Directive Description
stale-while-revalidate Allows serving stale responses while revalidating in background (RFC 5861)
stale-if-error Allows serving stale responses if the origin returns an error (RFC 5861)

The following extension directives are not recognized and will be ignored:

Directive Description
immutable Indicates that the response will not change over time (RFC 8246)

License

This project is licensed under the Apache License 2.0. See the LICENSE file for details.

Documentation

Overview

Package httpcache provides an implementation of http.RoundTripper that adds transparent HTTP response caching according to RFC 9111 (HTTP Caching).

The main entry point is NewTransport, which returns an http.RoundTripper for use with http.Client. httpcache supports the required standard HTTP caching directives, as well as extension directives such as stale-while-revalidate and stale-if-error.

Example usage:

package main

import (
	"log/slog"
	"net/http"
	"time"

	"github.com/bartventer/httpcache"

	// Register a cache backend by importing the package
	_ "github.com/bartventer/httpcache/store/fscache"
)

func main() {
	dsn := "fscache://?appname=myapp" // // Example DSN for the file system cache backend
	client := &http.Client{
		Transport: httpcache.NewTransport(
			dsn,
			httpcache.WithSWRTimeout(10*time.Second),
			httpcache.WithLogger(slog.Default()),
		),
	}
}

Index

Constants

View Source
const CacheStatusHeader = internal.CacheStatusHeader
View Source
const DefaultSWRTimeout = 5 * time.Second // Default timeout for Stale-While-Revalidate

Variables

View Source
var ErrNilCache = errors.New("httpcache: cache cannot be nil")

ErrNilCache is returned when a nil cache is provided to [NewRoundTripper]. Although not recommended, it is possible to handle this error gracefully by recovering from the panic that occurs when a nil cache is passed.

Example usage:

defer func() {
	if r := recover(); r != nil {
		if err, ok := r.(error); ok && errors.Is(err, ErrNilCache) {
			// Handle the error gracefully, e.g., log it or return a default transport
			log.Println("Cache cannot be nil:", err)
			client := &http.Client{
				Transport: http.DefaultTransport, // Fallback to default transport
			}
			// Use the fallback client as needed
			_ = client
		} else {
			// Re-panic if it's not the expected error
			panic(r)
		}
	}
}()

Functions

func NewTransport

func NewTransport(dsn string, options ...Option) http.RoundTripper

NewTransport returns an http.RoundTripper that caches HTTP responses using the specified cache backend.

The backend is selected via a DSN (e.g., "memcache://", "fscache://"). Panics if the cache cannot be opened or is nil. A blank import is required to register the cache backend.

To configure the transport, you can use functional options such as WithTransport, WithSWRTimeout, and WithLogger.

Types

type Option

type Option interface {
	// contains filtered or unexported methods
}

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for debug output; default: slog.New(slog.DiscardHandler).

func WithSWRTimeout

func WithSWRTimeout(timeout time.Duration) Option

WithSWRTimeout sets the timeout for Stale-While-Revalidate requests; default: DefaultSWRTimeout.

func WithTransport

func WithTransport(transport http.RoundTripper) Option

WithTransport sets the underlying HTTP transport for making requests; default: http.DefaultTransport.

Directories

Path Synopsis
_examples
app command
testutil
Package testutil provides utility functions for testing in Go.
Package testutil provides utility functions for testing in Go.
Package store defines interfaces to be implemented by cache backends as used by the github.com/bartventer/httpcache package.
Package store defines interfaces to be implemented by cache backends as used by the github.com/bartventer/httpcache package.
acceptance
Package acceptancetest provides a suite of acceptance tests for Cache implementations.
Package acceptancetest provides a suite of acceptance tests for Cache implementations.
fscache
Package fscache implements a file system-based store.Cache.
Package fscache implements a file system-based store.Cache.
memcache
Package memcache provides an in-memory implementation of store.Cache.
Package memcache provides an in-memory implementation of store.Cache.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL