Expand description
§tower-etag-cache
A tower middleware for implementing ETag-based HTTP caching.
§Quickstart
The const-lru-provider
feature provides a const-lru-backed CacheProvider
implementation that’s ready to be used.
use axum::{error_handling::HandleErrorLayer, http::StatusCode, BoxError, Router};
use tower_etag_cache::{const_lru_provider::ConstLruProvider, EtagCacheLayer};
use tower_http::services::{ServeDir, ServeFile};
#[tokio::main]
pub async fn main() {
let app = Router::new()
.fallback_service(ServeDir::new("app").fallback(ServeFile::new("app/404.html")))
.layer(
ServiceBuilder::new()
.layer(HandleErrorLayer::new(handle_etag_cache_layer_err))
.layer(EtagCacheLayer::with_default_predicate(
ConstLruProvider::<_, _, 255, u8>::init(5),
)),
);
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handle_etag_cache_layer_err<T: Into<BoxError>>(err: T) -> (StatusCode, String) {
(StatusCode::INTERNAL_SERVER_ERROR, err.into().to_string())
}
The ConstLruProvider
calculates ETag as the base64-encoded blake3 hash of response bodies.
It keys entries by SimpleEtagCacheKey
, a struct comprising the request URI + sorted Vec
collections of header values for the Accept
, Accept-Language
, and Accept-Encoding
request headers. This causes it to vary ETags based on these headers.
Since the current implementation loads the entire response body into memory to calculate the ETag, ConstLruProvider
is not suitable for extremely large responses such as large files.
§How This Works
The EtagCache
tower service and EtagCacheLayer
tower layer is created with an inner tower service + any type that implements the CacheProvider
trait.
- comprises 2 tower services
- 1 that runs on incoming http requests to lookup ETags to check if a request’s
If-None-Match
matches an ETag in the cache - 1 that runs on outgoing http responses to calculate and save the ETag of the response
- 1 that runs on incoming http requests to lookup ETags to check if a request’s
- has an associated cache key type that is used to key cache entries
- has an associated transform response body type that it transforms outgoing http response bodies into after the ETag calculation and saving procedure
pub trait CacheProvider<ReqBody, ResBody>:
Service<http::Request<ReqBody>, Response = CacheGetResponse<ReqBody, Self::Key>> // runs on request
+ Service<(Self::Key, http::Response<ResBody>), Response = http::Response<Self::TResBody>> // runs on response
{
type Key;
type TResBody;
}
When a http request comes in,
- If the service’s passthrough_predicate indicates that the request should be passed through, the unmodified request is passed directly to the inner service and the response is directly returned to the client.
- Else the
CacheProvider
’s first ETag lookup service runs on the request. - If the service returns a cache hit, an empty HTTP 304 response is returned to the client with the relevant headers.
- Else the inner service runs on the unmodified request.
- If the service’s passthrough_predicate indicates that the response should be passed through, the unmodified response is returned to the client.
- Else the
CacheProvider
’s second ETag calculating and saving service runs on the http response returned by the inner service. - The service transforms the response body and modifies the response headers to include the saved ETag and other relevant headers and returns it to the client.
§PassthroughPredicate
The PassthroughPredicate
trait controls when requests and responses should ignore the caching layer.
The provided DefaultPredicate
is available for use with EtagCacheLayer::with_default_predicate
and has the following behaviour:
requests:
- only
GET
andHEAD
methods are ran through the caching layer
responses:
- only
HTTP 2XX
responses, excluding204 No Content
, are cached - only responses that dont already have the
ETag
header are cached - only responses that eiter have a missing, invalid, or non-zero
Content-Length
header are cached
Modules§
- http_
body_ impl - Implementation of
http_body::Body
forEtagCacheResBody
forResBody
andTResBody
types that yieldbytes::Bytes
data.
Structs§
- Cache
GetResponse - Struct returned by a
CacheProvider
’s first cache-lookupService
- Default
Predicate - A
PassthroughPredicate
with sensible defaults for controlling ETag cache behaviour - Etag
Cache - The eponymous tower
Service
- Etag
Cache Layer - The eponymous tower
Layer
- Etag
Cache Service Future Future
struct returned byEtagCache::call
Enums§
- Cache
GetResponse Result - Result of the cache-lookup
Service
- Etag
Cache ResBody http::Response
body type ofEtagCache
- Etag
Cache Service Error - Error type of the
EtagCache
Service
Traits§
- Cache
Provider - Typical type args for use in axum 0.6:
- Passthrough
Predicate - Controls when requests and responses should ignore the caching layer