use super::*;
use pingora_core::protocols::http::error_resp;
use std::borrow::Cow;
#[derive(Debug)]
pub enum PurgeStatus {
NoCache,
Found,
NotFound,
Error(Box<Error>),
}
fn purge_response(purge_status: &PurgeStatus) -> Cow<'static, ResponseHeader> {
let resp = match purge_status {
PurgeStatus::NoCache => &*NOT_PURGEABLE,
PurgeStatus::Found => &*OK,
PurgeStatus::NotFound => &*NOT_FOUND,
PurgeStatus::Error(ref _e) => &*INTERNAL_ERROR,
};
Cow::Borrowed(resp)
}
fn gen_purge_response(code: u16) -> ResponseHeader {
let mut resp = ResponseHeader::build(code, Some(3)).unwrap();
resp.insert_header(header::SERVER, &SERVER_NAME[..])
.unwrap();
resp.insert_header(header::CONTENT_LENGTH, 0).unwrap();
resp.insert_header(header::CACHE_CONTROL, "private, no-store")
.unwrap();
resp
}
static OK: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(200));
static NOT_FOUND: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(404));
static NOT_PURGEABLE: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(405));
static INTERNAL_ERROR: Lazy<ResponseHeader> = Lazy::new(|| error_resp::gen_error_response(500));
impl<SV, C> HttpProxy<SV, C>
where
C: custom::Connector,
{
pub(crate) async fn proxy_purge(
&self,
session: &mut Session,
ctx: &mut SV::CTX,
) -> Option<(bool, Option<Box<Error>>)>
where
SV: ProxyHttp + Send + Sync,
SV::CTX: Send + Sync,
{
let purge_status = if session.cache.enabled() {
match session.cache.purge().await {
Ok(found) => {
if found {
PurgeStatus::Found
} else {
PurgeStatus::NotFound
}
}
Err(e) => {
session.cache.disable(NoCacheReason::StorageError);
warn!(
"Fail to purge cache: {e}, {}",
self.inner.request_summary(session, ctx)
);
PurgeStatus::Error(e)
}
}
} else {
PurgeStatus::NoCache
};
let mut purge_resp = purge_response(&purge_status);
if let Err(e) =
self.inner
.purge_response_filter(session, ctx, purge_status, &mut purge_resp)
{
error!(
"Failed purge response filter: {e}, {}",
self.inner.request_summary(session, ctx)
);
purge_resp = Cow::Borrowed(&*INTERNAL_ERROR)
}
let write_result = match purge_resp {
Cow::Borrowed(r) => session.as_mut().write_response_header_ref(r).await,
Cow::Owned(r) => session.as_mut().write_response_header(Box::new(r)).await,
};
let (reuse, err) = match write_result {
Ok(_) => (true, None),
Err(e) => {
let e = e.into_down();
error!(
"Failed to send purge response: {e}, {}",
self.inner.request_summary(session, ctx)
);
(false, Some(e))
}
};
Some((reuse, err))
}
}