#![cfg(feature = "streaming")]
use futures_util::StreamExt;
use http_cache::{CacheMode, HttpCacheOptions, StreamingManager};
use http_cache_reqwest::StreamingCache;
use reqwest::Client;
use reqwest_middleware::ClientBuilder;
use std::time::Instant;
use wiremock::{matchers::method, Mock, MockServer, ResponseTemplate};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mock_server = MockServer::start().await;
let large_content = "X".repeat(10000); Mock::given(method("GET"))
.respond_with(
ResponseTemplate::new(200)
.set_body_string(&large_content)
.append_header("cache-control", "max-age=300, public")
.append_header("content-type", "text/plain"),
)
.mount(&mock_server)
.await;
let streaming_manager = StreamingManager::with_temp_dir(1000)
.await
.expect("Failed to create streaming manager");
let client = ClientBuilder::new(Client::new())
.with(StreamingCache::with_options(
streaming_manager,
CacheMode::Default,
HttpCacheOptions {
cache_status_headers: true,
..Default::default()
},
))
.build();
let url = format!("{}/", mock_server.uri());
println!("Testing streaming HTTP caching with reqwest...");
let start = Instant::now();
let response = client.get(&url).send().await?;
let duration1 = start.elapsed();
println!("First request: {:?}", duration1);
println!("Status: {}", response.status().as_u16());
let mut first_cache_headers = Vec::new();
for (name, value) in response.headers() {
let name_str = name.as_str();
if name_str.starts_with("x-cache") {
first_cache_headers.push((name.clone(), value.clone()));
}
}
let mut stream = response.bytes_stream();
let mut body_size = 0;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
body_size += chunk.len();
}
println!("First response body size: {} bytes", body_size);
for (name, value) in first_cache_headers {
println!("Cache header {}: {}", name, value.to_str().unwrap_or(""));
}
println!();
let start = Instant::now();
let response = client.get(&url).send().await?;
let duration2 = start.elapsed();
println!("Second request: {:?}", duration2);
println!("Status: {}", response.status().as_u16());
let mut cache_headers = Vec::new();
for (name, value) in response.headers() {
let name_str = name.as_str();
if name_str.starts_with("x-cache") {
cache_headers.push((name.clone(), value.clone()));
}
}
let mut cached_stream = response.bytes_stream();
let mut cached_body_size = 0;
while let Some(chunk) = cached_stream.next().await {
let chunk = chunk?;
cached_body_size += chunk.len();
}
println!("Second response body size: {} bytes", cached_body_size);
for (name, value) in cache_headers {
println!("Cache header {}: {}", name, value.to_str().unwrap_or(""));
}
if cached_body_size != body_size {
println!("Warning: Content size mismatch");
}
Ok(())
}