Skip to content

Commit 9f79796

Browse files
feat: Don't raise an error for malformed request cookies
Request cookie parsing will be tolerant of malformed request cookies. Invalid cookies will be ignored, with a WARN-level log record to document the event.
1 parent 716ba3b commit 9f79796

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

libs/pavex/src/cookie/components.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use biscotti::{Processor, RequestCookies};
77
use http::HeaderValue;
88
use http::header::{COOKIE, SET_COOKIE};
99
use pavex_macros::{post_process, request_scoped};
10+
use tracing_log_error::log_error;
1011

1112
/// Parse cookies out of the incoming request.
1213
///
@@ -16,8 +17,11 @@ pub fn extract_request_cookies<'request>(
1617
request_head: &'request RequestHead,
1718
processor: &Processor,
1819
) -> Result<RequestCookies<'request>, ExtractRequestCookiesError> {
19-
let mut cookies = RequestCookies::new();
20-
for header in request_head.headers.get_all(COOKIE).into_iter() {
20+
fn extract_request_cookie<'request>(
21+
header: &'request HeaderValue,
22+
processor: &Processor,
23+
cookies: &mut RequestCookies<'request>,
24+
) -> Result<(), ExtractRequestCookiesError> {
2125
let header = header
2226
.to_str()
2327
.map_err(ExtractRequestCookiesError::InvalidHeaderValue)?;
@@ -31,7 +35,30 @@ pub fn extract_request_cookies<'request>(
3135
_ => ExtractRequestCookiesError::Unexpected(UnexpectedError::new(e)),
3236
}
3337
})?;
38+
Ok(())
3439
}
40+
41+
let mut cookies = RequestCookies::new();
42+
for header in request_head.headers.get_all(COOKIE).into_iter() {
43+
// Per RFC 6265 (HTTP State Management Mechanism), servers are free to ignore the Cookie
44+
// header entirely (Section 4.2.2), and the spec places no requirement to reject requests
45+
// containing malformed cookies. In practice, major frameworks (Tomcat, Django, Express, etc.)
46+
// use tolerant, best-effort parsing to avoid breaking legitimate requests just because one
47+
// cookie is corrupt, truncated, or non-compliant.
48+
//
49+
// We follow the same approach: skip only the invalid cookie(s) and keep the rest.
50+
// This prevents unnecessary 4xx/5xx responses, avoids breaking user sessions due to
51+
// transient client or proxy bugs, and mitigates the risk of denial-of-service from
52+
// intentionally malformed Cookie headers.
53+
if let Err(e) = extract_request_cookie(header, processor, &mut cookies) {
54+
log_error!(
55+
e,
56+
level: tracing::Level::WARN,
57+
"A request cookie is invalid, ignoring it"
58+
);
59+
}
60+
}
61+
3562
Ok(cookies)
3663
}
3764

0 commit comments

Comments
 (0)