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:
Arjen Poutsma
2023-01-20 12:22:09 +01:00
parent fb0aa5abb3
commit 20c79e1481
2 changed files with 69 additions and 4 deletions

View File

@@ -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