Browse Source

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
pull/29868/head
Arjen Poutsma 2 years ago
parent
commit
20c79e1481
  1. 56
      spring-web/src/main/java/org/springframework/http/HttpHeaders.java
  2. 17
      spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java

56
spring-web/src/main/java/org/springframework/http/HttpHeaders.java

@ -1537,8 +1537,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable @@ -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 @@ -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 @@ -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

17
spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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…
Cancel
Save