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, C> HttpProxy<SV, C>
63where
64 C: custom::Connector,
65{
66 pub(crate) async fn proxy_purge(
67 &self,
68 session: &mut Session,
69 ctx: &mut SV::CTX,
70 ) -> Option<(bool, Option<Box<Error>>)>
71 where
72 SV: ProxyHttp + Send + Sync,
73 SV::CTX: Send + Sync,
74 {
75 let purge_status = if session.cache.enabled() {
76 match session.cache.purge().await {
77 Ok(found) => {
78 if found {
79 PurgeStatus::Found
80 } else {
81 PurgeStatus::NotFound
82 }
83 }
84 Err(e) => {
85 session.cache.disable(NoCacheReason::StorageError);
86 warn!(
87 "Fail to purge cache: {e}, {}",
88 self.inner.request_summary(session, ctx)
89 );
90 PurgeStatus::Error(e)
91 }
92 }
93 } else {
94 PurgeStatus::NoCache
96 };
97
98 let mut purge_resp = purge_response(&purge_status);
99 if let Err(e) =
100 self.inner
101 .purge_response_filter(session, ctx, purge_status, &mut purge_resp)
102 {
103 error!(
104 "Failed purge response filter: {e}, {}",
105 self.inner.request_summary(session, ctx)
106 );
107 purge_resp = Cow::Borrowed(&*INTERNAL_ERROR)
108 }
109
110 let write_result = match purge_resp {
111 Cow::Borrowed(r) => session.as_mut().write_response_header_ref(r).await,
112 Cow::Owned(r) => session.as_mut().write_response_header(Box::new(r)).await,
113 };
114 let (reuse, err) = match write_result {
115 Ok(_) => (true, None),
116 Err(e) => {
118 let e = e.into_down();
119 error!(
120 "Failed to send purge response: {e}, {}",
121 self.inner.request_summary(session, ctx)
122 );
123 (false, Some(e))
124 }
125 };
126 Some((reuse, err))
127 }
128}