Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds cache mode fixes, overridden_cache_mode method, and impl Default for CacheMode #67

Merged
merged 12 commits into from
Jan 15, 2024
Merged
2 changes: 1 addition & 1 deletion .github/workflows/oranda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
oranda build

- name: Deploy to Github Pages
uses: JamesIves/github-pages-deploy-action@v4.4.3
uses: JamesIves/github-pages-deploy-action@v4.5.0
if: ${{ github.ref == 'refs/heads/main' }}
with:
branch: gh-pages
Expand Down
7 changes: 7 additions & 0 deletions http-cache-darkbird/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

# Changelog

## [0.1.5] - 2024-01-15

### Changed

- Updated the minimum versions of the following dependencies:
- http-cache [0.18.0]

## [0.1.4] - 2023-11-01

### Changed
Expand Down
4 changes: 2 additions & 2 deletions http-cache-darkbird/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache-darkbird"
version = "0.1.4"
version = "0.1.5"
description = "http-cache manager implementation for darkbird"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand All @@ -24,7 +24,7 @@ thiserror = "1.0.44"

[dependencies.http-cache]
path = "../http-cache"
version = "0.17.0"
version = "0.18.0"
default-features = false

[dev-dependencies]
Expand Down
7 changes: 7 additions & 0 deletions http-cache-mokadeser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

# Changelog

## [0.1.3] - 2024-01-15

### Changed

- Updated the minimum versions of the following dependencies:
- http-cache [0.18.0]

## [0.1.2] - 2023-11-01

### Changed
Expand Down
4 changes: 2 additions & 2 deletions http-cache-mokadeser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache-mokadeser"
version = "0.1.2"
version = "0.1.3"
description = "http-cache manager implementation for moka stored deserialized"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand All @@ -22,7 +22,7 @@ moka = { version = "0.12.0", features = ["future"]}

[dependencies.http-cache]
path = "../http-cache"
version = "0.17.0"
version = "0.18.0"
default-features = false
features = ["bincode"]

Expand Down
7 changes: 7 additions & 0 deletions http-cache-quickcache/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

# Changelog

## [0.6.3] - 2024-01-15

### Changed

- Updated the minimum versions of the following dependencies:
- http-cache [0.18.0]

## [0.6.2] - 2023-11-01

### Changed
Expand Down
4 changes: 2 additions & 2 deletions http-cache-quickcache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache-quickcache"
version = "0.6.2"
version = "0.6.3"
description = "http-cache manager implementation for quick-cache"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand All @@ -25,7 +25,7 @@ quick_cache = "0.4.0"

[dependencies.http-cache]
path = "../http-cache"
version = "0.17.0"
version = "0.18.0"
default-features = false
features = ["bincode"]

Expand Down
11 changes: 11 additions & 0 deletions http-cache-reqwest/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## [0.13.0] - 2024-01-15

### Added

- Implemented `overridden_cache_mode` method from `Middleware` trait. This method allows for overriding any cache mode set in the configuration, including `cache_mode_fn`.

### Changed

- Updated the minimum versions of the following dependencies:
- http-cache [0.18.0]

## [0.12.0] - 2023-11-01

### Added
Expand Down
4 changes: 2 additions & 2 deletions http-cache-reqwest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache-reqwest"
version = "0.12.0"
version = "0.13.0"
description = "http-cache middleware implementation for reqwest"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand All @@ -27,7 +27,7 @@ url = { version = "2.4.0", features = ["serde"] }

[dependencies.http-cache]
path = "../http-cache"
version = "0.17.0"
version = "0.18.0"
default-features = false

[dev-dependencies]
Expand Down
17 changes: 16 additions & 1 deletion http-cache-reqwest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@
//! Ok(())
//! }
//! ```
//!
//! ## Overriding the cache mode
//!
//! The cache mode can be overridden on a per-request basis by making use of the
//! `reqwest-middleware` extensions system.
//!
//! ```no_run
//! client.get("https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching")
//! .with_extension(CacheMode::OnlyIfCached)
//! .send()
//! .await?;
//! ```
mod error;

use anyhow::anyhow;
Expand Down Expand Up @@ -93,6 +105,9 @@ fn clone_req(request: &Request) -> std::result::Result<Request, Error> {

#[async_trait::async_trait]
impl Middleware for ReqwestMiddleware<'_> {
fn overridden_cache_mode(&self) -> Option<CacheMode> {
self.extensions.get().cloned()
}
fn is_method_get_head(&self) -> bool {
self.req.method() == Method::GET || self.req.method() == Method::HEAD
}
Expand Down Expand Up @@ -174,7 +189,7 @@ fn convert_response(response: HttpResponse) -> anyhow::Result<Response> {
let mut ret_res = http::Response::builder()
.status(response.status)
.url(response.url)
.version(response.version.try_into()?)
.version(response.version.into())
.body(response.body)?;
for header in response.headers {
ret_res.headers_mut().insert(
Expand Down
42 changes: 41 additions & 1 deletion http-cache-reqwest/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ async fn custom_cache_mode_fn() -> Result<()> {
// Construct reqwest client with cache defaults and custom cache mode
let client = ClientBuilder::new(Client::new())
.with(Cache(HttpCache {
mode: CacheMode::Default,
mode: CacheMode::NoStore,
manager: manager.clone(),
options: HttpCacheOptions {
cache_key: None,
Expand Down Expand Up @@ -217,6 +217,46 @@ async fn custom_cache_mode_fn() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn override_cache_mode() -> Result<()> {
let mock_server = MockServer::start().await;
let m = build_mock(CACHEABLE_PUBLIC, TEST_BODY, 200, 2);
let _mock_guard = mock_server.register_as_scoped(m).await;
let url = format!("{}/test.css", &mock_server.uri());
let manager = MokaManager::default();

// Construct reqwest client with cache defaults and custom cache mode
let client = ClientBuilder::new(Client::new())
.with(Cache(HttpCache {
mode: CacheMode::Default,
manager: manager.clone(),
options: HttpCacheOptions {
cache_key: None,
cache_options: None,
cache_mode_fn: None,
cache_bust: None,
},
}))
.build();

// Remote request and should cache
client.get(url.clone()).send().await?;

// Try to load cached object
let data = manager.get(&format!("{}:{}", GET, &Url::parse(&url)?)).await?;
assert!(data.is_some());

let url = format!("{}/", &mock_server.uri());
// To verify our endpoint receives the request rather than a cache hit
client.get(url.clone()).with_extension(CacheMode::NoStore).send().await?;

// Check no cache object was created
let data = manager.get(&format!("{}:{}", GET, &Url::parse(&url)?)).await?;
assert!(data.is_none());

Ok(())
}

#[tokio::test]
async fn cache_bust() -> Result<()> {
let mock_server = MockServer::start().await;
Expand Down
7 changes: 7 additions & 0 deletions http-cache-surf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [0.12.1] - 2024-01-15

### Changed

- Updated the minimum versions of the following dependencies:
- http-cache [0.18.0]

## [0.12.0] - 2023-11-01

### Added
Expand Down
4 changes: 2 additions & 2 deletions http-cache-surf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache-surf"
version = "0.12.0"
version = "0.12.1"
description = "http-cache middleware implementation for surf"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand All @@ -27,7 +27,7 @@ thiserror = "1.0.44"

[dependencies.http-cache]
path = "../http-cache"
version = "0.17.0"
version = "0.18.0"
default-features = false
features = ["with-http-types"]

Expand Down
2 changes: 1 addition & 1 deletion http-cache-surf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl<T: CacheManager> surf::middleware::Middleware for Cache<T> {
converted.insert_header(header.0.as_str(), val);
}
converted.set_status(res.status.try_into()?);
converted.set_version(Some(res.version.try_into()?));
converted.set_version(Some(res.version.into()));
converted.set_body(res.body);
Ok(surf::Response::from(converted))
} else {
Expand Down
8 changes: 8 additions & 0 deletions http-cache/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.18.0] - 2024-01-15

### Added

- `overridden_cache_mode` method to `Middleware` trait. This method allows for overriding any cache mode set in the configuration, including `cache_mode_fn`.

- Derive `Default` for the `CacheMode` enum with the mode `Default` selected to be used.

## [0.17.0] - 2023-11-01

### Added
Expand Down
2 changes: 1 addition & 1 deletion http-cache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-cache"
version = "0.17.0"
version = "0.18.0"
description = "An HTTP caching middleware"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache"
Expand Down
36 changes: 25 additions & 11 deletions http-cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ pub trait CacheManager: Send + Sync + 'static {
/// Describes the functionality required for interfacing with HTTP client middleware
#[async_trait::async_trait]
pub trait Middleware: Send {
/// Allows the cache mode to be overridden.
///
/// This overrides any cache mode set in the configuration, including cache_mode_fn.
fn overridden_cache_mode(&self) -> Option<CacheMode> {
None
}
/// Determines if the request method is either GET or HEAD
fn is_method_get_head(&self) -> bool;
/// Returns a new cache policy with default options
Expand All @@ -261,7 +267,7 @@ pub trait Middleware: Send {

/// Similar to [make-fetch-happen cache options](https://github.com/npm/make-fetch-happen#--optscache).
/// Passed in when the [`HttpCache`] struct is being built.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum CacheMode {
/// Will inspect the HTTP cache on the way to the network.
/// If there is a fresh response it will be used.
Expand All @@ -270,6 +276,7 @@ pub enum CacheMode {
/// It then updates the HTTP cache with the response.
/// If the revalidation request fails (for example, on a 500 or if you're offline),
/// the stale response will be returned.
#[default]
Default,
/// Behaves as if there is no HTTP cache at all.
NoStore,
Expand Down Expand Up @@ -432,11 +439,7 @@ impl<T: CacheManager> HttpCache<T> {
&self,
middleware: &impl Middleware,
) -> Result<bool> {
let mode = if let Some(cache_mode_fn) = &self.options.cache_mode_fn {
cache_mode_fn(&middleware.parts()?)
} else {
self.mode
};
let mode = self.cache_mode(middleware)?;

Ok(mode == CacheMode::IgnoreRules
|| middleware.is_method_get_head()
Expand Down Expand Up @@ -516,7 +519,7 @@ impl<T: CacheManager> HttpCache<T> {
}
}

match self.mode {
match self.cache_mode(&middleware)? {
CacheMode::Default => {
self.conditional_fetch(middleware, res, policy).await
}
Expand Down Expand Up @@ -544,7 +547,7 @@ impl<T: CacheManager> HttpCache<T> {
_ => self.remote_fetch(&mut middleware).await,
}
} else {
match self.mode {
match self.cache_mode(&middleware)? {
CacheMode::OnlyIfCached => {
// ENOTCACHED
let mut res = HttpResponse {
Expand All @@ -563,6 +566,16 @@ impl<T: CacheManager> HttpCache<T> {
}
}

fn cache_mode(&self, middleware: &impl Middleware) -> Result<CacheMode> {
Ok(if let Some(mode) = middleware.overridden_cache_mode() {
mode
} else if let Some(cache_mode_fn) = &self.options.cache_mode_fn {
cache_mode_fn(&middleware.parts()?)
} else {
self.mode
})
}

async fn remote_fetch(
&self,
middleware: &mut impl Middleware,
Expand All @@ -575,12 +588,13 @@ impl<T: CacheManager> HttpCache<T> {
None => middleware.policy(&res)?,
};
let is_get_head = middleware.is_method_get_head();
let mode = self.cache_mode(middleware)?;
let mut is_cacheable = is_get_head
&& self.mode != CacheMode::NoStore
&& self.mode != CacheMode::Reload
&& mode != CacheMode::NoStore
&& mode != CacheMode::Reload
&& res.status == 200
&& policy.is_storable();
if self.mode == CacheMode::IgnoreRules && res.status == 200 {
if mode == CacheMode::IgnoreRules && res.status == 200 {
is_cacheable = true;
}
if is_cacheable {
Expand Down