diff --git a/http-cache-reqwest/Cargo.toml b/http-cache-reqwest/Cargo.toml index 882de73..0a59db4 100644 --- a/http-cache-reqwest/Cargo.toml +++ b/http-cache-reqwest/Cargo.toml @@ -31,6 +31,7 @@ url = { version = "2.5.4", features = ["serde"] } # Optional dependencies for streaming feature futures-util = { version = "0.3.31", optional = true } +httpdate = "1.0.3" [dependencies.http-cache] path = "../http-cache" diff --git a/http-cache-reqwest/examples/reqwest_basic.rs b/http-cache-reqwest/examples/reqwest_basic.rs index 1bc25d3..bd20730 100644 --- a/http-cache-reqwest/examples/reqwest_basic.rs +++ b/http-cache-reqwest/examples/reqwest_basic.rs @@ -8,6 +8,7 @@ use reqwest::Client; use reqwest_middleware::ClientBuilder; use std::time::Instant; use wiremock::{matchers::method, Mock, MockServer, ResponseTemplate}; +use wiremock::matchers::header; #[tokio::main] async fn main() -> Result<(), Box> { diff --git a/http-cache-reqwest/src/lib.rs b/http-cache-reqwest/src/lib.rs index 681bfd2..b3bb3ae 100644 --- a/http-cache-reqwest/src/lib.rs +++ b/http-cache-reqwest/src/lib.rs @@ -403,7 +403,7 @@ impl Middleware for ReqwestMiddleware<'_> { } fn update_headers(&mut self, parts: &Parts) -> Result<()> { for header in parts.headers.iter() { - self.req.headers_mut().append(header.0.clone(), header.1.clone()); + self.req.headers_mut().insert(header.0.clone(), header.1.clone()); } Ok(()) } diff --git a/http-cache-reqwest/src/test.rs b/http-cache-reqwest/src/test.rs index abc23db..59fce5b 100644 --- a/http-cache-reqwest/src/test.rs +++ b/http-cache-reqwest/src/test.rs @@ -1,12 +1,14 @@ use crate::{BadRequest, Cache, HttpCacheError}; use std::sync::Arc; - +use std::time::{Duration, SystemTime}; use http_cache::*; use reqwest::Client; use reqwest_middleware::ClientBuilder; +use tokio::time::sleep; #[cfg(any(feature = "streaming", feature = "rate-limiting"))] use wiremock::matchers::path; use wiremock::{matchers::method, Mock, MockServer, ResponseTemplate}; +use wiremock::matchers::header; /// Helper function to create a temporary cache manager fn create_cache_manager() -> CACacheManager { @@ -704,6 +706,49 @@ async fn revalidation_200() -> Result<()> { Ok(()) } +#[tokio::test] +async fn duplicate_header() -> Result<()> { + let now = SystemTime::now(); + let expires = SystemTime::now() + Duration::from_secs(2); + + let mock_server = MockServer::start().await; + let mock = Mock::given(method(GET)).and(header("x-test", "test")) + .respond_with( + ResponseTemplate::new(200) + .insert_header("expires", httpdate::fmt_http_date(now)) + .set_body_bytes("ok"), + ) + .expect(2); + let mock_guard = mock_server.register_as_scoped(mock).await; + let url = format!("{}/", &mock_server.uri()); + let manager = create_cache_manager(); + + // Construct reqwest client with cache defaults + let client = ClientBuilder::new(Client::new()) + .with(Cache(HttpCache { + mode: CacheMode::Default, + manager: manager.clone(), + options: Default::default(), + })) + .build(); + + let resp1 = client.get(url.clone()).header("x-test", "test").send().await?; + + let wait_until = expires + Duration::from_secs(2); + while SystemTime::now() < wait_until { + sleep(Duration::from_millis(100)).await; + } + + let resp2 = client.get(url.clone()).header("x-test", "test").send().await?; + + drop(mock_guard); + + assert_eq!(resp1.text().await?, "ok"); + assert_eq!(resp2.text().await?, "ok"); + + Ok(()) +} + #[tokio::test] async fn revalidation_500() -> Result<()> { let mock_server = MockServer::start().await;