Support double-quoted in HttpHeaders::getValuesAsList
This commit introduces support for double-quoted HTTP header values in HttpHeaders::getValuesAsList, as described in RFC 9110 section 5.5. Closes gh-29785
This commit is contained in:
parent
fb0aa5abb3
commit
20c79e1481
|
|
@ -1537,8 +1537,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Return all values of a given header name,
|
||||
* even if this header is set multiple times.
|
||||
* Return all values of a given header name, even if this header is set
|
||||
* multiple times.
|
||||
* <p>This method supports double-quoted values, as described in
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-8">RFC
|
||||
* 9110, section 5.5</a>.
|
||||
* @param headerName the header name
|
||||
* @return all associated values
|
||||
* @since 4.3
|
||||
|
|
@ -1549,7 +1552,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
List<String> result = new ArrayList<>();
|
||||
for (String value : values) {
|
||||
if (value != null) {
|
||||
Collections.addAll(result, StringUtils.tokenizeToStringArray(value, ","));
|
||||
result.addAll(tokenizeQuoted(value));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
@ -1557,6 +1560,53 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<String> tokenizeQuoted(String str) {
|
||||
List<String> tokens = new ArrayList<>();
|
||||
boolean quoted = false;
|
||||
boolean trim = true;
|
||||
StringBuilder builder = new StringBuilder(str.length());
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
char ch = str.charAt(i);
|
||||
if (ch == '"') {
|
||||
if (builder.isEmpty()) {
|
||||
quoted = true;
|
||||
}
|
||||
else if (quoted) {
|
||||
quoted = false;
|
||||
trim = false;
|
||||
}
|
||||
else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
else if (ch == '\\' && quoted && i < str.length() - 1) {
|
||||
builder.append(str.charAt(++i));
|
||||
}
|
||||
else if (ch == ',' && !quoted) {
|
||||
addToken(builder, tokens, trim);
|
||||
builder.setLength(0);
|
||||
trim = false;
|
||||
}
|
||||
else if (quoted || (!builder.isEmpty() && trim) || !Character.isWhitespace(ch)) {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
if (!builder.isEmpty()) {
|
||||
addToken(builder, tokens, trim);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static void addToken(StringBuilder builder, List<String> tokens, boolean trim) {
|
||||
String token = builder.toString();
|
||||
if (trim) {
|
||||
token = token.trim();
|
||||
}
|
||||
if (!token.isEmpty()) {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the well-known {@code "Content-*"} HTTP headers.
|
||||
* <p>Such headers should be cleared from the response if the intended
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -713,4 +713,19 @@ public class HttpHeadersTests {
|
|||
assertThat(headers2).isEqualTo(headers1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getValuesAsList() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Foo", "Bar");
|
||||
headers.add("Foo", "Baz, Qux");
|
||||
headers.add("Quux", "\t\"Corge\", \"Grault\"");
|
||||
headers.add("Garply", " Waldo \"Fred\\!\", \"\tPlugh, Xyzzy! \"");
|
||||
headers.add("Example-Dates", "\"Sat, 04 May 1996\", \"Wed, 14 Sep 2005\"");
|
||||
|
||||
assertThat(headers.getValuesAsList("Foo")).containsExactly("Bar", "Baz", "Qux");
|
||||
assertThat(headers.getValuesAsList("Quux")).containsExactly("Corge", "Grault");
|
||||
assertThat(headers.getValuesAsList("Garply")).containsExactly("Waldo \"Fred\\!\"", "\tPlugh, Xyzzy! ");
|
||||
assertThat(headers.getValuesAsList("Example-Dates")).containsExactly("Sat, 04 May 1996", "Wed, 14 Sep 2005");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue