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

Use http-1.0.0 for http-cache-tower #70

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ members = [
"http-cache-surf",
"http-cache-quickcache",
"http-cache-darkbird",
"http-cache-mokadeser"
]
"http-cache-mokadeser",
"http-cache-tower"
]
4 changes: 2 additions & 2 deletions http-cache-darkbird/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust-version = "1.67.1"
[dependencies]
async-trait = "0.1.72"
darkbird = "6.1.8"
http-cache-semantics = "1.0.1"
http-cache-semantics = "2.0.1"
serde = { version = "1.0.178", features = ["derive"] }
thiserror = "1.0.44"

Expand All @@ -28,7 +28,7 @@ version = "0.18.0"
default-features = false

[dev-dependencies]
http = "0.2.9"
http = "1.0.0"
reqwest = { version = "0.11.18", default-features = false }
reqwest-middleware = "0.2.2"
tokio = { version = "1.29.1", features = [ "macros", "rt", "rt-multi-thread" ] }
Expand Down
4 changes: 2 additions & 2 deletions http-cache-mokadeser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ rust-version = "1.67.1"

[dependencies]
async-trait = "0.1.72"
http-cache-semantics = "1.0.1"
http-cache-semantics = "2.0.1"
moka = { version = "0.12.0", features = ["future"]}

[dependencies.http-cache]
Expand All @@ -27,7 +27,7 @@ default-features = false
features = ["bincode"]

[dev-dependencies]
http = "0.2.9"
http = "1.0.0"
reqwest = { version = "0.11.18", default-features = false }
reqwest-middleware = "0.2.2"
tokio = { version = "1.29.1", features = [ "macros", "rt", "rt-multi-thread" ] }
Expand Down
4 changes: 2 additions & 2 deletions http-cache-quickcache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust-version = "1.67.1"
[dependencies]
async-trait = "0.1.72"
bincode = "1.3.3"
http-cache-semantics = "1.0.1"
http-cache-semantics = "2.0.1"
serde = { version = "1.0.178", features = ["derive"] }
url = { version = "2.4.0", features = ["serde"] }
quick_cache = "0.4.0"
Expand All @@ -30,7 +30,7 @@ default-features = false
features = ["bincode"]

[dev-dependencies]
http = "0.2.9"
http = "1.0.0"
reqwest = { version = "0.11.18", default-features = false }
reqwest-middleware = "0.2.2"
tokio = { version = "1.29.1", features = [ "macros", "rt", "rt-multi-thread" ] }
Expand Down
2 changes: 1 addition & 1 deletion http-cache-reqwest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ edition = "2021"
anyhow = "1.0.72"
async-trait = "0.1.72"
http = "0.2.9"
http-cache-semantics = "1.0.1"
http-cache-semantics = "2.0.1"
reqwest = { version = "0.11.18", default-features = false }
reqwest-middleware = "0.2.2"
serde = { version = "1.0.178", features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions http-cache-surf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ edition = "2021"
[dependencies]
anyhow = "1.0.72"
async-trait = "0.1.72"
http = "0.2.9"
http-cache-semantics = "1.0.1"
http = "1.0.0"
http-cache-semantics = "2.0.1"
http-types = "2.12.0"
serde = { version = "1.0.178", features = ["derive"] }
surf = { version = "2.3.2", default-features = false }
Expand Down
43 changes: 43 additions & 0 deletions http-cache-tower/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "http-cache-tower"
version = "0.1.0"
description = "http-cache middleware implementation for tower"
authors = ["Christian Haynes <06chaynes@gmail.com>", "Kat Marchán <kzm@zkat.tech>"]
repository = "https://github.com/06chaynes/http-cache.git"
license = "MIT OR Apache-2.0"
readme = "README.md"
keywords = ["cache", "http", "middleware", "tower"]
categories = [
"caching",
"web-programming::http-client"
]
edition = "2021"

[dependencies]
futures-core = "0.3.23"
futures-util = { version = "0.3.23", default-features = false, features = [] }
http = "1.0.0"
http-body = "1.0.0"
pin-project-lite = "0.2.9"
tower-layer = "0.3.1"
tower-service = "0.3.2"
http-cache-semantics = "2.0.1"
serde = { version = "1.0.144", features = ["derive"] }
url = { version = "2.2.2", features = ["serde"] }
tower = { version = "0.4.13", features = ["util"] }

[dependencies.http-cache]
path = "../http-cache"
version = "0.18.0"

[dev-dependencies]
tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] }

[features]
default = ["manager-cacache"]
manager-cacache = ["http-cache/manager-cacache"]
manager-moka = ["http-cache/manager-moka"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
175 changes: 175 additions & 0 deletions http-cache-tower/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use futures_core::ready;
use futures_util::future::Either;

use std::{
convert::TryFrom,
convert::TryInto,
future::Future,
mem,
pin::Pin,
str,
str::FromStr,
task::{Context, Poll},
};

use http::{
header::{HeaderName, CACHE_CONTROL},
request, HeaderMap, HeaderValue, Method, Request, Response, StatusCode,
Uri, Version,
};
use http_body::Body;
use http_cache::{BoxError, CacheManager, Result};
use pin_project_lite::pin_project;
use tower::util::Oneshot;
use tower_layer::Layer;
use tower_service::Service;

pub use http_cache::{CacheMode, CacheOptions, HttpCache, HttpResponse};

#[cfg(feature = "manager-cacache")]
#[cfg_attr(docsrs, doc(cfg(feature = "manager-cacache")))]
pub use http_cache::CACacheManager;

#[cfg(feature = "manager-moka")]
#[cfg_attr(docsrs, doc(cfg(feature = "manager-moka")))]
pub use http_cache::{MokaCache, MokaCacheBuilder, MokaManager};

/// Wrapper for [`HttpCache`]
#[derive(Debug)]
pub struct Cache<S, T: CacheManager> {
inner: S,
cache: HttpCache<T>,
}

impl<S, T> Cache<S, T>
where
T: Clone + CacheManager,
{
/// Create a new [`Cache`].
pub fn new(inner: S, cache: HttpCache<T>) -> Self {
Self { inner, cache }
}

/// Returns a new [`Layer`] that wraps services with a `Cache` middleware.
pub fn layer(&self) -> CacheLayer<T> {
CacheLayer::new(self.cache.clone())
}
}

/// [`Layer`] with a [`Service`] to cache responses.
#[derive(Clone, Debug)]
pub struct CacheLayer<T: CacheManager> {
cache: HttpCache<T>,
}

impl<T> CacheLayer<T>
where
T: CacheManager,
{
/// Create a new [`CacheLayer`].
pub fn new(cache: HttpCache<T>) -> Self {
Self { cache }
}
}

impl<S, T> Layer<S> for CacheLayer<T>
where
S: Clone,
T: Clone + CacheManager,
{
type Service = Cache<S, T>;

fn layer(&self, inner: S) -> Self::Service {
Cache { inner, cache: self.cache.clone() }
}
}

impl<ReqBody, ResBody, S, T> Service<Request<ReqBody>> for Cache<S, T>
where
S: Clone + Service<Request<ReqBody>, Response = Response<ResBody>>,
ReqBody: Body + Clone,
T: Clone + CacheManager,
{
type Response = Response<ResBody>;
type Error = S::Error;
type Future = ResponseFuture<S, ReqBody, T>;

fn poll_ready(
&mut self,
cx: &mut Context<'_>,
) -> Poll<std::result::Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}

fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
let service = self.inner.clone();
let mut service = mem::replace(&mut self.inner, service);
ResponseFuture {
req: req.clone(),
future: Either::Left(service.call(req)),
service,
cache: self.cache.clone(),
state: ResponseFutureState::Init,
}
}
}

pin_project! {
/// Response future for [`Cache`].
#[derive(Debug)]
pub struct ResponseFuture<S, B, T>
where
S: Service<Request<B>>,
T: CacheManager,
{
#[pin]
future: Either<S::Future, Oneshot<S, Request<B>>>,
service: S,
req: Request<B>,
cache: HttpCache<T>,
state: ResponseFutureState<F>,
}
}

impl<S, ReqBody, ResBody, T> Future for ResponseFuture<S, ReqBody, T>
where
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
ReqBody: Body + Clone,
T: CacheManager + Clone,
{
type Output = std::result::Result<Response<ResBody>, S::Error>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
let mut curr_state = this.state;
match this.state.as_mut().project() {
ResponseFutureProj::Init => {
let request_parts = this.req.clone().into_parts().0;
let fut = this.cache.before_request(&request_parts);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@06chaynes, I took this line from the commented-out code in your branch, but there's no before_request method on cache. Assuming it's because the previous branch was out of date, what should be called here instead?

If you have an async version of the code, I can probably translate it to the hand-rolled future

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SebRollen yeah in that branch I was experimenting with a different implementation that I decided (at least for now) not to go with, though I did bring over a handful of changes.

Here is the implementation for Reqwest that has the logic as it currently is https://github.com/06chaynes/http-cache/blob/develop/http-cache-reqwest/src/lib.rs#L212

First the Middleware trait implementation is constructed, then the request is checked to determine if it's cacheable. If it isnt cacheable we just run the run_no_cache method of the HttpCache struct, handle the response normally, update the two cache headers, and pass it through. If it is cacheable we run the run method of the HttpCache struct and pass through the result.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed a commit to update the core and other crates http and http-cache-semantics versions

curr_state.set(ResponseFutureState::BeforeRequest { fut });
cx.waker().wake_by_ref();
Poll::Pending
}
ResponseFutureProj::BeforeRequest { fut } => {
let res = ready!(fut.poll(cx));
// TODO: What do we do with res here?
curr_state.set(ResponseFutureState::Inner);
cx.waker().wake_by_ref();
Poll::Pending
}
ResponseFutureProj::Inner => this.future.as_mut().poll(cx),
}
}
}

pin_project! {
#[project = ResponseFutureProj]
enum ResponseFutureState<F> {
Init,
BeforeRequest {
#[pin]
fut: F
},
Inner,
}
}
5 changes: 2 additions & 3 deletions http-cache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ rust-version = "1.67.1"
async-trait = "0.1.72"
bincode = { version = "1.3.3", optional = true }
cacache = { version = "12.0.0", default-features = false, features = ["mmap"], optional = true }
http = "0.2.9"
http-cache-semantics = "1.0.1"
http = "1.0.0"
http-cache-semantics = "2.0.1"
http-types = { version = "2.12.0", default-features = false, optional = true }
httpdate = "1.0.2"
moka = { version = "0.12.0", features = ["future"], optional = true }
Expand All @@ -30,7 +30,6 @@ url = { version = "2.4.0", features = ["serde"] }
[dev-dependencies]
async-attributes = "1.1.2"
async-std = { version = "1.12.0" }
http-cache-semantics = "1.0.1"
tokio = { version = "1.29.1", features = [ "macros", "rt", "rt-multi-thread" ] }

[features]
Expand Down
Loading