1use parking_lot::Mutex;
2use std::collections::VecDeque;
3use std::sync::Arc;
4use tracing::debug;
5
6pub type HttpParseResult = Result<(String, String, Vec<(String, String)>), httparse::Error>;
8
9pub struct HttpParserCache {
11 parsers: Arc<Mutex<VecDeque<ReusableParser>>>,
12 max_cache_size: usize,
13}
14
15#[derive(Default)]
17pub struct ReusableParser {
18 }
21
22impl ReusableParser {
23 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn parse_response(
30 &mut self,
31 buffer: &[u8],
32 ) -> Result<(u16, Vec<(String, String)>), httparse::Error> {
33 let mut headers = [httparse::EMPTY_HEADER; 128];
35 let mut response = httparse::Response::new(&mut headers);
36
37 match response.parse(buffer)? {
38 httparse::Status::Complete(_) => {
39 let status_code = response.code.ok_or(httparse::Error::Status)?;
40
41 let mut parsed_headers = Vec::with_capacity(response.headers.len());
43 for header in response.headers.iter() {
44 parsed_headers.push((
45 header.name.to_string(),
46 String::from_utf8_lossy(header.value).to_string(),
47 ));
48 }
49
50 Ok((status_code, parsed_headers))
51 }
52 httparse::Status::Partial => Err(httparse::Error::TooManyHeaders),
53 }
54 }
55
56 pub fn parse_request(&mut self, buffer: &[u8]) -> HttpParseResult {
58 let mut headers = [httparse::EMPTY_HEADER; 128];
60 let mut request = httparse::Request::new(&mut headers);
61
62 match request.parse(buffer)? {
63 httparse::Status::Complete(_) => {
64 let method = request.method.ok_or(httparse::Error::Status)?;
65 let path = request.path.ok_or(httparse::Error::Status)?;
66
67 let mut parsed_headers = Vec::with_capacity(request.headers.len());
69 for header in request.headers.iter() {
70 parsed_headers.push((
71 header.name.to_string(),
72 String::from_utf8_lossy(header.value).to_string(),
73 ));
74 }
75
76 Ok((method.to_string(), path.to_string(), parsed_headers))
77 }
78 httparse::Status::Partial => Err(httparse::Error::TooManyHeaders),
79 }
80 }
81
82 pub fn reset(&mut self) {
84 }
86}
87
88impl HttpParserCache {
89 pub fn new(max_cache_size: usize) -> Self {
91 Self {
92 parsers: Arc::new(Mutex::new(VecDeque::with_capacity(max_cache_size))),
93 max_cache_size,
94 }
95 }
96
97 pub fn get(&self) -> CachedParser {
99 let mut parser = {
100 let mut parsers = self.parsers.lock();
101 parsers.pop_front().unwrap_or_else(|| {
102 debug!("Creating new HTTP parser");
103 ReusableParser::new()
104 })
105 };
106
107 parser.reset();
108
109 CachedParser {
110 parser: Some(parser),
111 cache: Arc::downgrade(&self.parsers),
112 max_cache_size: self.max_cache_size,
113 }
114 }
115
116 pub fn size(&self) -> usize {
118 self.parsers.lock().len()
119 }
120
121 pub fn warm_up(&self, count: usize) {
123 let mut parsers = self.parsers.lock();
124 let current_size = parsers.len();
125 let to_create =
126 (count.saturating_sub(current_size)).min(self.max_cache_size - current_size);
127
128 for _ in 0..to_create {
129 parsers.push_back(ReusableParser::new());
130 }
131
132 debug!("Parser cache warmed up with {} parsers", to_create);
133 }
134}
135
136impl Default for HttpParserCache {
137 fn default() -> Self {
138 Self::new(8) }
140}
141
142pub struct CachedParser {
144 parser: Option<ReusableParser>,
145 cache: std::sync::Weak<Mutex<VecDeque<ReusableParser>>>,
146 max_cache_size: usize,
147}
148
149impl CachedParser {
150 pub fn parse_response(
152 &mut self,
153 buffer: &[u8],
154 ) -> Result<(u16, Vec<(String, String)>), httparse::Error> {
155 self.parser
156 .as_mut()
157 .expect("Parser not available")
158 .parse_response(buffer)
159 }
160
161 pub fn parse_request(&mut self, buffer: &[u8]) -> HttpParseResult {
163 self.parser
164 .as_mut()
165 .expect("Parser not available")
166 .parse_request(buffer)
167 }
168}
169
170impl Drop for CachedParser {
171 fn drop(&mut self) {
172 if let (Some(parser), Some(cache)) = (self.parser.take(), self.cache.upgrade()) {
173 let mut parsers = cache.lock();
174 if parsers.len() < self.max_cache_size {
175 parsers.push_back(parser);
176 debug!("Parser returned to cache");
177 }
178 }
179 }
180}
181
182use std::collections::HashMap;
184use std::hash::{Hash, Hasher};
185use std::time::{Duration, Instant};
186
187#[derive(Clone, Debug)]
189pub struct CacheKey {
190 method: String,
191 path: String,
192 headers_hash: u64,
193}
194
195impl CacheKey {
196 pub fn new(method: &str, path: &str, headers: &[(String, String)]) -> Self {
197 let mut hasher = std::collections::hash_map::DefaultHasher::new();
198
199 let relevant_headers: Vec<_> = headers
201 .iter()
202 .filter(|(name, _)| {
203 let name_lower = name.to_lowercase();
204 !name_lower.starts_with("cache-")
205 && name_lower != "date"
206 && name_lower != "last-modified"
207 && name_lower != "etag"
208 })
209 .collect();
210
211 relevant_headers.hash(&mut hasher);
212
213 Self {
214 method: method.to_string(),
215 path: path.to_string(),
216 headers_hash: hasher.finish(),
217 }
218 }
219}
220
221impl Hash for CacheKey {
222 fn hash<H: Hasher>(&self, state: &mut H) {
223 self.method.hash(state);
224 self.path.hash(state);
225 self.headers_hash.hash(state);
226 }
227}
228
229impl PartialEq for CacheKey {
230 fn eq(&self, other: &Self) -> bool {
231 self.method == other.method
232 && self.path == other.path
233 && self.headers_hash == other.headers_hash
234 }
235}
236
237impl Eq for CacheKey {}
238
239#[derive(Clone)]
241pub struct CachedResponse {
242 pub status_code: u16,
243 pub headers: Vec<(String, String)>,
244 pub body: bytes::Bytes,
245 pub cached_at: Instant,
246 pub expires_at: Option<Instant>,
247}
248
249pub struct ResponseCache {
251 cache: Arc<Mutex<HashMap<CacheKey, CachedResponse>>>,
252 max_entries: usize,
253}
254
255impl ResponseCache {
256 pub fn new(max_entries: usize, _default_ttl: Duration) -> Self {
257 Self {
258 cache: Arc::new(Mutex::new(HashMap::with_capacity(max_entries))),
259 max_entries,
260 }
261 }
262
263 pub fn get(&self, key: &CacheKey) -> Option<CachedResponse> {
265 let mut cache = self.cache.lock();
266
267 if let Some(entry) = cache.get(key) {
268 if let Some(expires_at) = entry.expires_at {
270 if Instant::now() > expires_at {
271 cache.remove(key);
272 return None;
273 }
274 }
275
276 Some(entry.clone())
277 } else {
278 None
279 }
280 }
281
282 pub fn put(&self, key: CacheKey, response: CachedResponse) {
284 let mut cache = self.cache.lock();
285
286 if cache.len() >= self.max_entries {
288 let oldest_key = cache
290 .iter()
291 .min_by_key(|(_, v)| v.cached_at)
292 .map(|(k, _)| k.clone());
293
294 if let Some(key_to_remove) = oldest_key {
295 cache.remove(&key_to_remove);
296 }
297 }
298
299 cache.insert(key, response);
300 }
301
302 pub fn cleanup_expired(&self) {
304 let mut cache = self.cache.lock();
305 let now = Instant::now();
306
307 cache.retain(|_, entry| match entry.expires_at {
308 None => true,
309 Some(expires_at) => now <= expires_at,
310 });
311 }
312
313 pub fn stats(&self) -> CacheStats {
315 let cache = self.cache.lock();
316 CacheStats {
317 entries: cache.len(),
318 max_entries: self.max_entries,
319 }
320 }
321
322 pub fn clear(&self) {
324 let mut cache = self.cache.lock();
325 cache.clear();
326 }
327}
328
329#[derive(Debug, Clone)]
330pub struct CacheStats {
331 pub entries: usize,
332 pub max_entries: usize,
333}
334
335use std::sync::OnceLock;
337
338static GLOBAL_PARSER_CACHE: OnceLock<HttpParserCache> = OnceLock::new();
339static GLOBAL_RESPONSE_CACHE: OnceLock<ResponseCache> = OnceLock::new();
340
341pub fn global_parser_cache() -> &'static HttpParserCache {
343 GLOBAL_PARSER_CACHE.get_or_init(|| {
344 let cache = HttpParserCache::new(8);
345 cache.warm_up(4);
346 cache
347 })
348}
349
350pub fn global_response_cache() -> &'static ResponseCache {
352 GLOBAL_RESPONSE_CACHE.get_or_init(|| {
353 ResponseCache::new(100, Duration::from_secs(300)) })
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 #[test]
362 fn test_parser_cache() {
363 let cache = HttpParserCache::new(2);
364
365 {
366 let mut parser1 = cache.get();
367 let http_response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello";
368 let result = parser1.parse_response(http_response).unwrap();
369 assert_eq!(result.0, 200);
370 assert_eq!(result.1.len(), 1);
371 assert_eq!(result.1[0].0, "Content-Length");
372 }
373
374 assert_eq!(cache.size(), 1);
376
377 {
378 let mut parser2 = cache.get();
379 let http_request = b"GET /api HTTP/1.1\r\nHost: localhost\r\n\r\n";
380 let result = parser2.parse_request(http_request).unwrap();
381 assert_eq!(result.0, "GET");
382 assert_eq!(result.1, "/api");
383 assert_eq!(result.2.len(), 1);
384 }
385 }
386
387 #[test]
388 fn test_response_cache() {
389 let cache = ResponseCache::new(2, Duration::from_secs(1));
390
391 let key = CacheKey::new("GET", "/api", &[]);
392 let response = CachedResponse {
393 status_code: 200,
394 headers: vec![("Content-Type".to_string(), "application/json".to_string())],
395 body: bytes::Bytes::from("test"),
396 cached_at: Instant::now(),
397 expires_at: Some(Instant::now() + Duration::from_secs(1)),
398 };
399
400 cache.put(key.clone(), response.clone());
401
402 let cached = cache.get(&key).unwrap();
403 assert_eq!(cached.status_code, 200);
404 assert_eq!(cached.body, bytes::Bytes::from("test"));
405
406 std::thread::sleep(Duration::from_millis(1100));
408 assert!(cache.get(&key).is_none());
409 }
410
411 #[test]
412 fn test_cache_key_equality() {
413 let headers1 = vec![
414 ("Content-Type".to_string(), "application/json".to_string()),
415 ("Authorization".to_string(), "Bearer token".to_string()),
416 ];
417
418 let headers2 = vec![
419 ("Content-Type".to_string(), "application/json".to_string()),
420 ("Authorization".to_string(), "Bearer token".to_string()),
421 (
422 "Date".to_string(),
423 "Wed, 21 Oct 2015 07:28:00 GMT".to_string(),
424 ),
425 ];
426
427 let key1 = CacheKey::new("GET", "/api", &headers1);
428 let key2 = CacheKey::new("GET", "/api", &headers2);
429
430 assert_eq!(key1, key2);
432 }
433}