pingora_proxy/
proxy_purge.rs1use super::*;
16use pingora_core::protocols::http::error_resp;
17use std::borrow::Cow;
18
19#[derive(Debug)]
20pub enum PurgeStatus {
21 NoCache,
23 Found,
25 NotFound,
27 Error(Box<Error>),
30}
31
32fn purge_response(purge_status: &PurgeStatus) -> Cow<'static, ResponseHeader> {
35 let resp = match purge_status {
36 PurgeStatus::NoCache => &*NOT_PURGEABLE,
37 PurgeStatus::Found => &*OK,
38 PurgeStatus::NotFound => &*NOT_FOUND,
39 PurgeStatus::Error(ref _e) => &*INTERNAL_ERROR,
40 };
41 Cow::Borrowed(resp)
42}
43
44fn gen_purge_response(code: u16) -> ResponseHeader {
45 let mut resp = ResponseHeader::build(code, Some(3)).unwrap();
46 resp.insert_header(header::SERVER, &SERVER_NAME[..])
47 .unwrap();
48 resp.insert_header(header::CONTENT_LENGTH, 0).unwrap();
49 resp.insert_header(header::CACHE_CONTROL, "private, no-store")
50 .unwrap();
51 resp
53}
54
55static OK: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(200));
56static NOT_FOUND: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(404));
57static NOT_PURGEABLE: Lazy<ResponseHeader> = Lazy::new(|| gen_purge_response(405));
59static INTERNAL_ERROR: Lazy<ResponseHeader> = Lazy::new(|| error_resp::gen_error_response(500));
61
62impl<SV> HttpProxy<SV> {
63 pub(crate) async fn proxy_purge(
64 &self,
65 session: &mut Session,
66 ctx: &mut SV::CTX,
67 ) -> Option<(bool, Option<Box<Error>>)>
68 where
69 SV: ProxyHttp + Send + Sync,
70 SV::CTX: Send + Sync,
71 {
72 let purge_status = if session.cache.enabled() {
73 match session.cache.purge().await {
74 Ok(found) => {
75 if found {
76 PurgeStatus::Found
77 } else {
78 PurgeStatus::NotFound
79 }
80 }
81 Err(e) => {
82 session.cache.disable(NoCacheReason::StorageError);
83 warn!(
84 "Fail to purge cache: {e}, {}",
85 self.inner.request_summary(session, ctx)
86 );
87 PurgeStatus::Error(e)
88 }
89 }
90 } else {
91 PurgeStatus::NoCache
93 };
94
95 let mut purge_resp = purge_response(&purge_status);
96 if let Err(e) =
97 self.inner
98 .purge_response_filter(session, ctx, purge_status, &mut purge_resp)
99 {
100 error!(
101 "Failed purge response filter: {e}, {}",
102 self.inner.request_summary(session, ctx)
103 );
104 purge_resp = Cow::Borrowed(&*INTERNAL_ERROR)
105 }
106
107 let write_result = match purge_resp {
108 Cow::Borrowed(r) => session.as_mut().write_response_header_ref(r).await,
109 Cow::Owned(r) => session.as_mut().write_response_header(Box::new(r)).await,
110 };
111 let (reuse, err) = match write_result {
112 Ok(_) => (true, None),
113 Err(e) => {
115 let e = e.into_down();
116 error!(
117 "Failed to send purge response: {e}, {}",
118 self.inner.request_summary(session, ctx)
119 );
120 (false, Some(e))
121 }
122 };
123 Some((reuse, err))
124 }
125}