Skip to content

Commit d986298

Browse files
authored
Merge pull request #517 from pact-foundation/fix/pact-js-issue-1058
fix: only split known multi-value HTTP headers on commas
2 parents f64a23c + e671442 commit d986298

3 files changed

Lines changed: 26 additions & 6 deletions

File tree

rust/pact_matching/src/headers.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,14 @@ pub(crate) fn match_header_value(
101101
} else if PARAMETERISED_HEADERS.contains(&key.to_lowercase().as_str()) {
102102
match_parameter_header(expected, actual, key, "header", index, single_value)
103103
} else {
104-
MatchingRule::Equality.match_value(expected, actual, false, false)
104+
// Normalize whitespace around commas for comparison, since RFC 7230 allows optional whitespace
105+
// after commas in header values. This ensures "a,b" matches "a, b".
106+
let normalize_comma_whitespace = |s: &str| -> String {
107+
s.split(',').map(|v| v.trim()).collect::<Vec<_>>().join(",")
108+
};
109+
let normalized_expected = normalize_comma_whitespace(expected);
110+
let normalized_actual = normalize_comma_whitespace(actual);
111+
MatchingRule::Equality.match_value(normalized_expected.as_str(), normalized_actual.as_str(), false, false)
105112
.map_err(|err| {
106113
if single_value {
107114
vec![format!("{}", err)]

rust/pact_models/src/headers.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ pub static MULTI_VALUE_HEADERS: [&str; 12] = [
2626
];
2727

2828
/// Tries to parse the header value into multiple values, taking into account headers that should
29-
/// not be split.
29+
/// not be split. Only known multi-value headers (per RFC 7230/9110) are split on commas.
3030
pub fn parse_header(name: &str, value: &str) -> Vec<String> {
31-
if SINGLE_VALUE_HEADERS.contains(&name.to_lowercase().as_str()) {
32-
vec![ value.trim().to_string() ]
33-
} else {
31+
if MULTI_VALUE_HEADERS.contains(&name.to_lowercase().as_str()) {
3432
value.split(',').map(|v| v.trim().to_string()).collect()
33+
} else {
34+
vec![ value.trim().to_string() ]
3535
}
3636
}
3737

@@ -70,4 +70,17 @@ mod tests {
7070
let parsed = parse_header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/6.6.3 Chrome/112.0.5615.213 Safari/537.36");
7171
expect!(parsed).to(be_equal_to(vec!["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/6.6.3 Chrome/112.0.5615.213 Safari/537.36"]));
7272
}
73+
74+
/// Verifies that custom headers containing JSON (with commas) are not split into multiple values.
75+
/// See: https://github.com/pact-foundation/pact-reference/commit/6a985b9d0e512973a18943d3eaacae564a773c74
76+
/// This test covers the original bug from Pact JS.
77+
#[test]
78+
fn parse_custom_header_should_not_split_unknown_headers() {
79+
// JSON header value containing commas
80+
let header_name = "x-custom-json";
81+
let header_value = "{\"foo\":\"bar,baz\",\"arr\":[1,2,3]}";
82+
let parsed = parse_header(header_name, header_value);
83+
// Should not split into multiple values
84+
expect!(parsed).to(be_equal_to(vec![header_value.to_string()]));
85+
}
7386
}

rust/pact_models/src/json_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ mod tests {
596596
let result = headers_from_json(&headers);
597597
expect!(result.unwrap()).to(be_equal_to(hashmap! {
598598
"A".to_string() => vec!["B".to_string()],
599-
"B".to_string() => vec!["A".to_string(), "B".to_string(), "C".to_string()],
599+
"B".to_string() => vec!["A, B, C".to_string()],
600600
"C".to_string() => vec!["B".to_string()],
601601
"Date".to_string() => vec!["Sun, 12 Mar 2023 01:21:35 GMT".to_string()]
602602
}));

0 commit comments

Comments
 (0)