From 6a923d69e653f9dd966e7cbaca301e72cbd366c2 Mon Sep 17 00:00:00 2001 From: Alex Bakon Date: Fri, 15 Aug 2025 14:48:35 -0400 Subject: [PATCH 1/2] Cache-control parsing doesn't handle quotes --- src/common/cache_control.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/common/cache_control.rs b/src/common/cache_control.rs index 37bfa323..b235fda4 100644 --- a/src/common/cache_control.rs +++ b/src/common/cache_control.rs @@ -485,6 +485,20 @@ mod tests { ); } + #[test] + fn test_parse_quoted_comma() { + assert_eq!( + test_decode::(&["foo=\"a, private, immutable, b\", no-cache"]).unwrap(), + CacheControl::new() + .with_no_cache() + // These are wrong: these appear inside a quoted string and so + // should be treated as parameter for the "a" directive. + .with_private() + .with_immutable(), + "unknown extensions are ignored but shouldn't fail parsing", + ) + } + #[test] fn test_parse_extension() { assert_eq!( From bd43f7a83374d291b0f7040e2c8cc77424cd8be8 Mon Sep 17 00:00:00 2001 From: Alex Bakon Date: Mon, 18 Aug 2025 09:34:44 -0400 Subject: [PATCH 2/2] Group quoted blocks in csv::from_comma_delimited --- src/common/cache_control.rs | 7 +------ src/util/csv.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/common/cache_control.rs b/src/common/cache_control.rs index b235fda4..53fbb3ce 100644 --- a/src/common/cache_control.rs +++ b/src/common/cache_control.rs @@ -489,12 +489,7 @@ mod tests { fn test_parse_quoted_comma() { assert_eq!( test_decode::(&["foo=\"a, private, immutable, b\", no-cache"]).unwrap(), - CacheControl::new() - .with_no_cache() - // These are wrong: these appear inside a quoted string and so - // should be treated as parameter for the "a" directive. - .with_private() - .with_immutable(), + CacheControl::new().with_no_cache(), "unknown extensions are ignored but shouldn't fail parsing", ) } diff --git a/src/util/csv.rs b/src/util/csv.rs index ff91732e..a3d05ba4 100644 --- a/src/util/csv.rs +++ b/src/util/csv.rs @@ -14,8 +14,26 @@ where values .flat_map(|value| { value.to_str().into_iter().flat_map(|string| { + let mut in_quotes = false; string - .split(',') + .split(move |c| { + #[allow(clippy::collapsible_else_if)] + if in_quotes { + if c == '"' { + in_quotes = false; + } + false // dont split + } else { + if c == ',' { + true // split + } else { + if c == '"' { + in_quotes = true; + } + false // dont split + } + } + }) .filter_map(|x| match x.trim() { "" => None, y => Some(y),