mirror of
https://github.com/cloudflare/pingora.git
synced 2024-09-20 02:31:35 +02:00
Vary examples
This commit is contained in:
parent
7b838b8118
commit
2631da74b0
4 changed files with 308 additions and 30 deletions
2
.bleep
2
.bleep
|
@ -1 +1 @@
|
||||||
fa95ba9cdfb9a347913e0cffbb84ca003833ccaa
|
9d19d79b4015f2730c6213b9c20d9787e7ed896a
|
|
@ -18,7 +18,7 @@ use utils::server_utils::init;
|
||||||
use utils::websocket::WS_ECHO;
|
use utils::websocket::WS_ECHO;
|
||||||
|
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use reqwest::header::HeaderValue;
|
use reqwest::header::{HeaderName, HeaderValue};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio_tungstenite::tungstenite::{client::IntoClientRequest, Message};
|
use tokio_tungstenite::tungstenite::{client::IntoClientRequest, Message};
|
||||||
|
@ -135,6 +135,7 @@ async fn test_ws_server_ends_conn() {
|
||||||
|
|
||||||
mod test_cache {
|
mod test_cache {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::str::FromStr;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -1578,28 +1579,60 @@ mod test_cache {
|
||||||
assert_eq!(res.text().await.unwrap(), "hello world!");
|
assert_eq!(res.text().await.unwrap(), "hello world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_vary_req(url: &str, vary: &str) -> reqwest::Response {
|
async fn send_vary_req_with_headers_with_dups(
|
||||||
reqwest::Client::new()
|
url: &str,
|
||||||
|
vary_field: &str,
|
||||||
|
headers: Vec<(&str, &str)>,
|
||||||
|
dup_headers: Vec<(&str, &str)>,
|
||||||
|
) -> reqwest::Response {
|
||||||
|
let req_headers = headers
|
||||||
|
.iter()
|
||||||
|
.map(|(name, value)| {
|
||||||
|
(
|
||||||
|
HeaderName::from_str(name).unwrap(),
|
||||||
|
HeaderValue::from_str(value).unwrap(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut req_builder = reqwest::Client::new()
|
||||||
.get(url)
|
.get(url)
|
||||||
.header("x-vary-me", vary)
|
.headers(req_headers)
|
||||||
.send()
|
.header("set-vary", vary_field);
|
||||||
.await
|
|
||||||
.unwrap()
|
// Apply any duplicate headers
|
||||||
|
for (key, value) in dup_headers {
|
||||||
|
req_builder = req_builder.header(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
req_builder.send().await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_vary_req_with_headers(
|
||||||
|
url: &str,
|
||||||
|
vary_field: &str,
|
||||||
|
headers: Vec<(&str, &str)>,
|
||||||
|
) -> reqwest::Response {
|
||||||
|
send_vary_req_with_headers_with_dups(url, vary_field, headers, vec![]).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_vary_req(url: &str, vary_field: &str, value: &str) -> reqwest::Response {
|
||||||
|
send_vary_req_with_headers(url, vary_field, vec![(vary_field, value)]).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_vary_caching() {
|
async fn test_vary_caching() {
|
||||||
init();
|
init();
|
||||||
let url = "http://127.0.0.1:6148/unique/test_vary_caching/now";
|
let url = "http://127.0.0.1:6148/unique/test_vary_caching/vary";
|
||||||
|
let vary_field = "Accept";
|
||||||
|
|
||||||
let res = send_vary_req(url, "a").await;
|
let res = send_vary_req(url, vary_field, "image/png").await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
let cache_a_miss_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
let cache_a_miss_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
assert_eq!(headers["x-cache-status"], "miss");
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
assert_eq!(res.text().await.unwrap(), "hello world");
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
let res = send_vary_req(url, "a").await;
|
let res = send_vary_req(url, vary_field, "image/png").await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
let cache_hit_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
let cache_hit_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
@ -1608,14 +1641,14 @@ mod test_cache {
|
||||||
|
|
||||||
assert_eq!(cache_a_miss_epoch, cache_hit_epoch);
|
assert_eq!(cache_a_miss_epoch, cache_hit_epoch);
|
||||||
|
|
||||||
let res = send_vary_req(url, "b").await;
|
let res = send_vary_req(url, vary_field, "image/jpeg").await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
let cache_b_miss_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
let cache_b_miss_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
assert_eq!(headers["x-cache-status"], "miss");
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
assert_eq!(res.text().await.unwrap(), "hello world");
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
let res = send_vary_req(url, "b").await;
|
let res = send_vary_req(url, vary_field, "image/jpeg").await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
let cache_hit_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
let cache_hit_epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
@ -1626,19 +1659,235 @@ mod test_cache {
|
||||||
assert!(cache_a_miss_epoch != cache_b_miss_epoch);
|
assert!(cache_a_miss_epoch != cache_b_miss_epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_vary_caching_ignored_vary_header() {
|
||||||
|
init();
|
||||||
|
let url = "http://127.0.0.1:6148/unique/test_vary_caching_ignored_vary_header/vary";
|
||||||
|
let vary_field = "Some-Ignored-Vary-Header";
|
||||||
|
|
||||||
|
// Asset into cache (png)
|
||||||
|
let res = send_vary_req(url, vary_field, "image/png").await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
let epoch = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// HIT on png
|
||||||
|
let res = send_vary_req(url, vary_field, "image/png").await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(
|
||||||
|
epoch,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Vary header ignored -> get png, not jpeg
|
||||||
|
let res = send_vary_req(url, vary_field, "image/jpeg").await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(
|
||||||
|
epoch,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_vary_some_ignored() {
|
||||||
|
init();
|
||||||
|
let url = "http://127.0.0.1:6148/unique/test_vary_some_ignored/vary";
|
||||||
|
let vary_header = "Accept, SomeIgnoredVaryHeader";
|
||||||
|
|
||||||
|
// Make a request where we vary on some headers, and provide values for those.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "image/webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
let epoch1 = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Identical request should yield a HIT.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "image/webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(
|
||||||
|
epoch1,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Hit when changing a header we don't vary on.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "definitely-not-webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(
|
||||||
|
epoch1,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Get a secondary variant by changing Accept.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "definitely-not-webp"),
|
||||||
|
("Accept", "image/jpeg"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
let epoch2 = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
assert_ne!(epoch1, epoch2);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Cache hit on secondary variant.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "definitely-not-webp"),
|
||||||
|
("Accept", "image/jpeg"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(
|
||||||
|
epoch2,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cache hit on primary variant.
|
||||||
|
let res = send_vary_req_with_headers(
|
||||||
|
url,
|
||||||
|
vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "definitely-not-webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(
|
||||||
|
epoch1,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_vary_dup_header_some_ignored() {
|
||||||
|
init();
|
||||||
|
let url = "http://127.0.0.1:6148/unique/test_vary_dup_header_some_ignored/vary";
|
||||||
|
let first_vary_header = "SomeIgnoredVaryHeader";
|
||||||
|
let dup_vary_header = "Accept";
|
||||||
|
|
||||||
|
// Make a request where we vary on some headers, and provide values for those.
|
||||||
|
let res = send_vary_req_with_headers_with_dups(
|
||||||
|
url,
|
||||||
|
first_vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "image/webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
vec![("set-vary", dup_vary_header)],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
let epoch1 = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Identical request should yield a HIT.
|
||||||
|
let res = send_vary_req_with_headers_with_dups(
|
||||||
|
url,
|
||||||
|
first_vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "image/webp"),
|
||||||
|
("Accept", "image/webp"),
|
||||||
|
],
|
||||||
|
vec![("set-vary", dup_vary_header)],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
assert_eq!(
|
||||||
|
epoch1,
|
||||||
|
headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
|
||||||
|
// Get a secondary variant by changing Accept.
|
||||||
|
let res = send_vary_req_with_headers_with_dups(
|
||||||
|
url,
|
||||||
|
first_vary_header,
|
||||||
|
vec![
|
||||||
|
("SomeIgnoredVaryHeader", "image/webp"),
|
||||||
|
("Accept", "image/jpeg"),
|
||||||
|
],
|
||||||
|
vec![("set-vary", dup_vary_header)],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let headers = res.headers();
|
||||||
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
let epoch2 = headers["x-epoch"].to_str().unwrap().parse::<f64>().unwrap();
|
||||||
|
assert_ne!(epoch1, epoch2);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "hello world");
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_vary_purge() {
|
async fn test_vary_purge() {
|
||||||
init();
|
init();
|
||||||
let url = "http://127.0.0.1:6148/unique/test_vary_purge/now";
|
let url = "http://127.0.0.1:6148/unique/test_vary_purge/vary";
|
||||||
|
let vary_field = "Accept";
|
||||||
|
let opt1 = "image/png";
|
||||||
|
let opt2 = "image/jpeg";
|
||||||
|
|
||||||
send_vary_req(url, "a").await;
|
send_vary_req(url, vary_field, opt1).await;
|
||||||
let res = send_vary_req(url, "a").await;
|
let res = send_vary_req(url, vary_field, opt1).await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
assert_eq!(headers["x-cache-status"], "hit");
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
|
||||||
send_vary_req(url, "b").await;
|
send_vary_req(url, vary_field, opt2).await;
|
||||||
let res = send_vary_req(url, "b").await;
|
let res = send_vary_req(url, vary_field, opt2).await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
assert_eq!(headers["x-cache-status"], "hit");
|
assert_eq!(headers["x-cache-status"], "hit");
|
||||||
|
@ -1657,12 +1906,12 @@ mod test_cache {
|
||||||
|
|
||||||
//both should be miss
|
//both should be miss
|
||||||
|
|
||||||
let res = send_vary_req(url, "a").await;
|
let res = send_vary_req(url, vary_field, opt1).await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
assert_eq!(headers["x-cache-status"], "miss");
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
|
||||||
let res = send_vary_req(url, "b").await;
|
let res = send_vary_req(url, vary_field, opt2).await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
let headers = res.headers();
|
let headers = res.headers();
|
||||||
assert_eq!(headers["x-cache-status"], "miss");
|
assert_eq!(headers["x-cache-status"], "miss");
|
||||||
|
|
|
@ -218,7 +218,7 @@ http {
|
||||||
return 200 "hello world";
|
return 200 "hello world";
|
||||||
}
|
}
|
||||||
|
|
||||||
location /revalidate_vary {
|
location /vary {
|
||||||
header_filter_by_lua_block {
|
header_filter_by_lua_block {
|
||||||
ngx.header["Last-Modified"] = "Tue, 03 May 2022 01:04:39 GMT"
|
ngx.header["Last-Modified"] = "Tue, 03 May 2022 01:04:39 GMT"
|
||||||
ngx.header["Etag"] = '"abcd"'
|
ngx.header["Etag"] = '"abcd"'
|
||||||
|
@ -226,10 +226,7 @@ http {
|
||||||
if h["set-vary"] then
|
if h["set-vary"] then
|
||||||
ngx.header["Vary"] = h["set-vary"]
|
ngx.header["Vary"] = h["set-vary"]
|
||||||
end
|
end
|
||||||
if h["set-no-vary"] then
|
ngx.header["x-epoch"] = ngx.now()
|
||||||
-- expects proxy to force return no variance with this
|
|
||||||
ngx.header["Vary"] = "x-no-vary"
|
|
||||||
end
|
|
||||||
if not h["x-no-revalidate"] and (h["if-modified-since"] or h["if-none-match"]) then
|
if not h["x-no-revalidate"] and (h["if-modified-since"] or h["if-none-match"]) then
|
||||||
-- just assume they match
|
-- just assume they match
|
||||||
return ngx.exit(304)
|
return ngx.exit(304)
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
use super::cert;
|
use super::cert;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use http::header::VARY;
|
||||||
|
use http::HeaderValue;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pingora_cache::cache_control::CacheControl;
|
use pingora_cache::cache_control::CacheControl;
|
||||||
use pingora_cache::key::HashBinary;
|
use pingora_cache::key::HashBinary;
|
||||||
|
@ -31,6 +33,7 @@ use pingora_core::utils::CertKey;
|
||||||
use pingora_error::{Error, ErrorSource, Result};
|
use pingora_error::{Error, ErrorSource, Result};
|
||||||
use pingora_http::{RequestHeader, ResponseHeader};
|
use pingora_http::{RequestHeader, ResponseHeader};
|
||||||
use pingora_proxy::{ProxyHttp, Session};
|
use pingora_proxy::{ProxyHttp, Session};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
@ -269,6 +272,9 @@ static CACHE_PREDICTOR: Lazy<Predictor<32>> = Lazy::new(|| Predictor::new(5, Non
|
||||||
static EVICTION_MANAGER: Lazy<Manager> = Lazy::new(|| Manager::new(8192)); // 8192 bytes
|
static EVICTION_MANAGER: Lazy<Manager> = Lazy::new(|| Manager::new(8192)); // 8192 bytes
|
||||||
static CACHE_LOCK: Lazy<CacheLock> =
|
static CACHE_LOCK: Lazy<CacheLock> =
|
||||||
Lazy::new(|| CacheLock::new(std::time::Duration::from_secs(2)));
|
Lazy::new(|| CacheLock::new(std::time::Duration::from_secs(2)));
|
||||||
|
// Example of how one might restrict which fields can be varied on.
|
||||||
|
static CACHE_VARY_ALLOWED_HEADERS: Lazy<Option<HashSet<&str>>> =
|
||||||
|
Lazy::new(|| Some(vec!["accept", "accept-encoding"].into_iter().collect()));
|
||||||
|
|
||||||
// #[allow(clippy::upper_case_acronyms)]
|
// #[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct CacheCTX {
|
pub struct CacheCTX {
|
||||||
|
@ -342,15 +348,41 @@ impl ProxyHttp for ExampleProxyCache {
|
||||||
|
|
||||||
fn cache_vary_filter(
|
fn cache_vary_filter(
|
||||||
&self,
|
&self,
|
||||||
_meta: &CacheMeta,
|
meta: &CacheMeta,
|
||||||
_ctx: &mut Self::CTX,
|
_ctx: &mut Self::CTX,
|
||||||
req: &RequestHeader,
|
req: &RequestHeader,
|
||||||
) -> Option<HashBinary> {
|
) -> Option<HashBinary> {
|
||||||
// Here the response is always vary on request header "x-vary-me" if it exists
|
|
||||||
// in the real world, this callback should check Vary response header to decide
|
|
||||||
let vary_me = req.headers.get("x-vary-me")?;
|
|
||||||
let mut key = VarianceBuilder::new();
|
let mut key = VarianceBuilder::new();
|
||||||
key.add_value("headers.x-vary-me", vary_me);
|
|
||||||
|
// Vary per header from origin. Target headers are de-duplicated by key logic.
|
||||||
|
let vary_headers_lowercased: Vec<String> = meta
|
||||||
|
.headers()
|
||||||
|
.get_all(VARY)
|
||||||
|
.iter()
|
||||||
|
// Filter out any unparseable vary headers.
|
||||||
|
.flat_map(|vary_header| vary_header.to_str().ok())
|
||||||
|
.flat_map(|vary_header| vary_header.split(','))
|
||||||
|
.map(|s| s.trim().to_lowercase())
|
||||||
|
.filter(|header_name| {
|
||||||
|
// Filter only for allowed headers, if restricted.
|
||||||
|
CACHE_VARY_ALLOWED_HEADERS
|
||||||
|
.as_ref()
|
||||||
|
.map(|al| al.contains(header_name.as_str()))
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
vary_headers_lowercased.iter().for_each(|header_name| {
|
||||||
|
// Add this header and value to be considered in the variance key.
|
||||||
|
key.add_value(
|
||||||
|
header_name,
|
||||||
|
req.headers
|
||||||
|
.get(header_name)
|
||||||
|
.map(|v| v.as_bytes())
|
||||||
|
.unwrap_or(&[]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
key.finalize()
|
key.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue