Merge branch '6.1.x'
This commit is contained in:
@@ -30,13 +30,16 @@ import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -62,7 +65,23 @@ import org.springframework.util.StringUtils;
|
||||
* <li>{@link #set(String, String)} sets the header value to a single string value</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note that {@code HttpHeaders} generally treats header names in a case-insensitive manner.
|
||||
* <p>Note that {@code HttpHeaders} instances created by the default constructor
|
||||
* treat header names in a case-insensitive manner. Instances created with the
|
||||
* {@link #HttpHeaders(MultiValueMap)} constructor like those instantiated
|
||||
* internally by the framework to adapt to existing HTTP headers data structures
|
||||
* do guarantee per-header get/set/add operations to be case-insensitive as
|
||||
* mandated by the HTTP specification. However, it is not necessarily the case
|
||||
* for operations that deal with the collection as a whole (like {@code size()},
|
||||
* {@code values()}, {@code keySet()} and {@code entrySet()}). Prefer using
|
||||
* {@link #headerSet()} for these cases.
|
||||
*
|
||||
* <p>Some backing implementations can store header names in a case-sensitive
|
||||
* manner, which will lead to duplicates during the entrySet() iteration where
|
||||
* multiple occurrences of a header name can surface depending on letter casing
|
||||
* but each such entry has the full {@code List} of values. — This can be
|
||||
* problematic for example when copying headers into a new instance by iterating
|
||||
* over the old instance's {@code entrySet()} and using
|
||||
* {@link #addAll(String, List)} rather than {@link #put(String, List)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
@@ -70,6 +89,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Josh Long
|
||||
* @author Sam Brannen
|
||||
* @author Simon Baslé
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpHeaders implements MultiValueMap<String, String>, Serializable {
|
||||
@@ -417,8 +437,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty instance of the {@code HttpHeaders} object.
|
||||
* <p>This is the common constructor, using a case-insensitive map structure.
|
||||
* Construct a new, empty instance of the {@code HttpHeaders} object
|
||||
* using an underlying case-insensitive map.
|
||||
*/
|
||||
public HttpHeaders() {
|
||||
this(CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ROOT)));
|
||||
@@ -1778,11 +1798,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
|
||||
// Map implementation
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.headers.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.headers.isEmpty();
|
||||
@@ -1824,29 +1839,81 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
this.headers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> putIfAbsent(String key, List<String> value) {
|
||||
return this.headers.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
// Map/MultiValueMap methods that can have duplicate header names: size/keySet/values/entrySet/forEach
|
||||
|
||||
/**
|
||||
* Return the number of headers in the collection. This can be inflated,
|
||||
* see {@link HttpHeaders class level javadoc}.
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return this.headers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Set} view of header names. This can include multiple
|
||||
* casing variants of a given header name, see
|
||||
* {@link HttpHeaders class level javadoc}.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return this.headers.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Collection} view of all the header values, reconstructed
|
||||
* from iterating over the {@link #keySet()}. This can include duplicates if
|
||||
* multiple casing variants of a given header name are tracked, see
|
||||
* {@link HttpHeaders class level javadoc}.
|
||||
*/
|
||||
@Override
|
||||
public Collection<List<String>> values() {
|
||||
return this.headers.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Set} views of header entries, reconstructed from
|
||||
* iterating over the {@link #keySet()}. This can include duplicate entries
|
||||
* if multiple casing variants of a given header name are tracked, see
|
||||
* {@link HttpHeaders class level javadoc}.
|
||||
* @see #headerSet()
|
||||
*/
|
||||
@Override
|
||||
public Set<Entry<String, List<String>>> entrySet() {
|
||||
return this.headers.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an action over each header, as when iterated via
|
||||
* {@link #entrySet()}. This can include duplicate entries
|
||||
* if multiple casing variants of a given header name are tracked, see
|
||||
* {@link HttpHeaders class level javadoc}.
|
||||
* @param action the action to be performed for each entry
|
||||
*/
|
||||
@Override
|
||||
public void forEach(BiConsumer<? super String, ? super List<String>> action) {
|
||||
this.headers.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> putIfAbsent(String key, List<String> value) {
|
||||
return this.headers.putIfAbsent(key, value);
|
||||
/**
|
||||
* Return a view of the headers as an entry {@code Set} of key-list pairs.
|
||||
* Both {@link Iterator#remove()} and {@link java.util.Map.Entry#setValue}
|
||||
* are supported and mutate the headers.
|
||||
* <p>This collection is guaranteed to contain one entry per header name
|
||||
* even if the backing structure stores multiple casing variants of names,
|
||||
* at the cost of first copying the names into a case-insensitive set for
|
||||
* filtering the iteration.
|
||||
* @return a {@code Set} view that iterates over all headers in a
|
||||
* case-insensitive manner
|
||||
* @since 6.1.15
|
||||
*/
|
||||
public Set<Entry<String, List<String>>> headerSet() {
|
||||
return new CaseInsensitiveEntrySet(this.headers);
|
||||
}
|
||||
|
||||
|
||||
@@ -1909,19 +1976,30 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* Helps to format HTTP header values, as HTTP header values themselves can
|
||||
* contain comma-separated values, can become confusing with regular
|
||||
* {@link Map} formatting that also uses commas between entries.
|
||||
* <p>Additionally, this method displays the native list of header names
|
||||
* with the mention {@code with native header names} if the underlying
|
||||
* implementation stores multiple casing variants of header names (see
|
||||
* {@link HttpHeaders class level javadoc}).
|
||||
* @param headers the headers to format
|
||||
* @return the headers to a String
|
||||
* @since 5.1.4
|
||||
*/
|
||||
public static String formatHeaders(MultiValueMap<String, String> headers) {
|
||||
return headers.entrySet().stream()
|
||||
.map(entry -> {
|
||||
List<String> values = entry.getValue();
|
||||
return entry.getKey() + ":" + (values.size() == 1 ?
|
||||
Set<String> headerNames = toCaseInsensitiveSet(headers.keySet());
|
||||
String suffix = "]";
|
||||
if (headerNames.size() != headers.size()) {
|
||||
suffix = "] with native header names " + headers.keySet();
|
||||
}
|
||||
|
||||
return headerNames.stream()
|
||||
.map(headerName -> {
|
||||
List<String> values = headers.get(headerName);
|
||||
Assert.notNull(values, "Expected at least one value for header " + headerName);
|
||||
return headerName + ":" + (values.size() == 1 ?
|
||||
"\"" + values.get(0) + "\"" :
|
||||
values.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")));
|
||||
})
|
||||
.collect(Collectors.joining(", ", "[", "]"));
|
||||
.collect(Collectors.joining(", ", "[", suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1974,4 +2052,103 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
return DATE_FORMATTER.format(time);
|
||||
}
|
||||
|
||||
|
||||
private static Set<String> toCaseInsensitiveSet(Set<String> originalSet) {
|
||||
final Set<String> deduplicatedSet = Collections.newSetFromMap(
|
||||
new LinkedCaseInsensitiveMap<>(originalSet.size(), Locale.ROOT));
|
||||
// add/addAll (put/putAll in LinkedCaseInsensitiveMap) retain the casing of the last occurrence.
|
||||
// Here we prefer the first.
|
||||
for (String header : originalSet) {
|
||||
//noinspection RedundantCollectionOperation
|
||||
if (!deduplicatedSet.contains(header)) {
|
||||
deduplicatedSet.add(header);
|
||||
}
|
||||
}
|
||||
return deduplicatedSet;
|
||||
}
|
||||
|
||||
|
||||
private static final class CaseInsensitiveEntrySet extends AbstractSet<Entry<String, List<String>>> {
|
||||
|
||||
private final MultiValueMap<String, String> headers;
|
||||
private final Set<String> deduplicatedNames;
|
||||
|
||||
public CaseInsensitiveEntrySet(MultiValueMap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
this.deduplicatedNames = toCaseInsensitiveSet(headers.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, List<String>>> iterator() {
|
||||
return new CaseInsensitiveIterator(this.deduplicatedNames.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.deduplicatedNames.size();
|
||||
}
|
||||
|
||||
private final class CaseInsensitiveIterator implements Iterator<Map.Entry<String, List<String>>> {
|
||||
|
||||
private final Iterator<String> namesIterator;
|
||||
|
||||
@Nullable
|
||||
private String currentName;
|
||||
|
||||
private CaseInsensitiveIterator(Iterator<String> namesIterator) {
|
||||
this.namesIterator = namesIterator;
|
||||
this.currentName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.namesIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<String, List<String>> next() {
|
||||
this.currentName = this.namesIterator.next();
|
||||
return new CaseInsensitiveEntry(this.currentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (this.currentName == null) {
|
||||
throw new IllegalStateException("No current Header in iterator");
|
||||
}
|
||||
if (!CaseInsensitiveEntrySet.this.headers.containsKey(this.currentName)) {
|
||||
throw new IllegalStateException("Header not present: " + this.currentName);
|
||||
}
|
||||
CaseInsensitiveEntrySet.this.headers.remove(this.currentName);
|
||||
}
|
||||
}
|
||||
|
||||
private final class CaseInsensitiveEntry implements Map.Entry<String, List<String>> {
|
||||
|
||||
private final String key;
|
||||
|
||||
CaseInsensitiveEntry(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getValue() {
|
||||
return Objects.requireNonNull(CaseInsensitiveEntrySet.this.headers.get(this.key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> setValue(List<String> value) {
|
||||
List<String> previousValues = Objects.requireNonNull(
|
||||
CaseInsensitiveEntrySet.this.headers.get(this.key));
|
||||
CaseInsensitiveEntrySet.this.headers.put(this.key, value);
|
||||
return previousValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -38,6 +40,7 @@ import org.springframework.util.MultiValueMap;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Sam Brannen
|
||||
* @author Simon Baslé
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
||||
@@ -90,12 +93,11 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
||||
@Override
|
||||
public int size() {
|
||||
Enumeration<String> names = this.headers.names();
|
||||
int size = 0;
|
||||
Set<String> deduplicated = new LinkedHashSet<>();
|
||||
while (names.hasMoreElements()) {
|
||||
size++;
|
||||
names.nextElement();
|
||||
deduplicated.add(names.nextElement().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
return size;
|
||||
return deduplicated.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,7 +187,7 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return headers.size();
|
||||
return TomcatHeadersAdapter.this.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -289,11 +291,17 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
||||
if (this.currentName == null) {
|
||||
throw new IllegalStateException("No current Header in iterator");
|
||||
}
|
||||
int index = headers.findHeader(this.currentName, 0);
|
||||
if (index == -1) {
|
||||
//implement a mix of removeHeader(String) and removeHeader(int)
|
||||
boolean found = false;
|
||||
for (int i = 0; i < headers.size(); i++) {
|
||||
if (headers.getName(i).equalsIgnoreCase(this.currentName)) {
|
||||
headers.removeHeader(i--);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new IllegalStateException("Header not present: " + this.currentName);
|
||||
}
|
||||
headers.removeHeader(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -32,7 +33,7 @@ import org.apache.hc.core5.http.HttpMessage;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -40,11 +41,13 @@ import org.springframework.util.MultiValueMap;
|
||||
* HttpClient headers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Simon Baslé
|
||||
* @since 6.1
|
||||
*/
|
||||
public final class HttpComponentsHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
private final HttpMessage message;
|
||||
private final Set<String> headerNames;
|
||||
|
||||
|
||||
/**
|
||||
@@ -54,6 +57,11 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
public HttpComponentsHeadersAdapter(HttpMessage message) {
|
||||
Assert.notNull(message, "Message must not be null");
|
||||
this.message = message;
|
||||
this.headerNames = Collections.newSetFromMap(new LinkedCaseInsensitiveMap<>(
|
||||
message.getHeaders().length, Locale.ROOT));
|
||||
for (Header header : message.getHeaders()) {
|
||||
this.headerNames.add(header.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +74,7 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
|
||||
@Override
|
||||
public void add(String key, @Nullable String value) {
|
||||
this.headerNames.add(key);
|
||||
this.message.addHeader(key, value);
|
||||
}
|
||||
|
||||
@@ -81,6 +90,7 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
|
||||
@Override
|
||||
public void set(String key, @Nullable String value) {
|
||||
this.headerNames.add(key);
|
||||
this.message.setHeader(key, value);
|
||||
}
|
||||
|
||||
@@ -91,14 +101,14 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
|
||||
@Override
|
||||
public Map<String, String> toSingleValueMap() {
|
||||
Map<String, String> map = CollectionUtils.newLinkedHashMap(size());
|
||||
Map<String, String> map = new LinkedCaseInsensitiveMap<>(this.message.getHeaders().length, Locale.ROOT);
|
||||
this.message.headerIterator().forEachRemaining(h -> map.putIfAbsent(h.getName(), h.getValue()));
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.message.getHeaders().length;
|
||||
return this.headerNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,6 +154,7 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
public List<String> remove(Object key) {
|
||||
if (key instanceof String headerName) {
|
||||
List<String> oldValues = get(key);
|
||||
this.headerNames.remove(headerName);
|
||||
this.message.removeHeaders(headerName);
|
||||
return oldValues;
|
||||
}
|
||||
@@ -157,23 +168,20 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.headerNames.clear();
|
||||
this.message.setHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
Set<String> keys = CollectionUtils.newLinkedHashSet(size());
|
||||
for (Header header : this.message.getHeaders()) {
|
||||
keys.add(header.getName());
|
||||
}
|
||||
return keys;
|
||||
return new HeaderNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<List<String>> values() {
|
||||
Collection<List<String>> values = new ArrayList<>(size());
|
||||
for (Header header : this.message.getHeaders()) {
|
||||
values.add(get(header.getName()));
|
||||
Collection<List<String>> values = new ArrayList<>(this.message.getHeaders().length);
|
||||
for (String headerName : keySet()) {
|
||||
values.add(get(headerName));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
@@ -199,10 +207,22 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
return HttpHeaders.formatHeaders(this);
|
||||
}
|
||||
|
||||
private class HeaderNames extends AbstractSet<String> {
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return new HeaderNamesIterator(headerNames.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return headerNames.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private final Iterator<Header> iterator = message.headerIterator();
|
||||
private final Iterator<String> iterator = keySet().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
@@ -211,7 +231,7 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
|
||||
@Override
|
||||
public Entry<String, List<String>> next() {
|
||||
return new HeaderEntry(this.iterator.next().getName());
|
||||
return new HeaderEntry(this.iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,4 +263,40 @@ public final class HttpComponentsHeadersAdapter implements MultiValueMap<String,
|
||||
}
|
||||
}
|
||||
|
||||
private final class HeaderNamesIterator implements Iterator<String> {
|
||||
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
@Nullable
|
||||
private String currentName;
|
||||
|
||||
private HeaderNamesIterator(Iterator<String> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
this.currentName = this.iterator.next();
|
||||
return this.currentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (this.currentName == null) {
|
||||
throw new IllegalStateException("No current Header in iterator");
|
||||
}
|
||||
if (!message.containsHeader(this.currentName)) {
|
||||
throw new IllegalStateException("Header not present: " + this.currentName);
|
||||
}
|
||||
headerNames.remove(this.currentName);
|
||||
message.removeHeaders(this.currentName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -31,7 +32,7 @@ import org.eclipse.jetty.http.HttpFields;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,7 @@ import org.springframework.util.MultiValueMap;
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Simon Baslé
|
||||
* @since 6.1
|
||||
*/
|
||||
public final class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||
@@ -103,7 +105,8 @@ public final class JettyHeadersAdapter implements MultiValueMap<String, String>
|
||||
|
||||
@Override
|
||||
public Map<String, String> toSingleValueMap() {
|
||||
Map<String, String> singleValueMap = CollectionUtils.newLinkedHashMap(this.headers.size());
|
||||
Map<String, String> singleValueMap = new LinkedCaseInsensitiveMap<>(
|
||||
this.headers.size(), Locale.ROOT);
|
||||
Iterator<HttpField> iterator = this.headers.iterator();
|
||||
iterator.forEachRemaining(field -> {
|
||||
if (!singleValueMap.containsKey(field.getName())) {
|
||||
@@ -232,7 +235,7 @@ public final class JettyHeadersAdapter implements MultiValueMap<String, String>
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return headers.size();
|
||||
return headers.getFieldNamesCollection().size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -27,7 +28,7 @@ import io.netty.handler.codec.http.HttpHeaders;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,7 @@ import org.springframework.util.MultiValueMap;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @author Simon Baslé
|
||||
* @since 6.1
|
||||
*/
|
||||
public final class Netty4HeadersAdapter implements MultiValueMap<String, String> {
|
||||
@@ -89,7 +91,8 @@ public final class Netty4HeadersAdapter implements MultiValueMap<String, String>
|
||||
|
||||
@Override
|
||||
public Map<String, String> toSingleValueMap() {
|
||||
Map<String, String> singleValueMap = CollectionUtils.newLinkedHashMap(this.headers.size());
|
||||
Map<String, String> singleValueMap = new LinkedCaseInsensitiveMap<>(
|
||||
this.headers.size(), Locale.ROOT);
|
||||
this.headers.entries()
|
||||
.forEach(entry -> {
|
||||
if (!singleValueMap.containsKey(entry.getKey())) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.StreamSupport;
|
||||
@@ -30,13 +31,14 @@ import io.netty5.handler.codec.http.headers.HttpHeaders;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@code MultiValueMap} implementation for wrapping Netty HTTP headers.
|
||||
*
|
||||
* @author Violeta Georgieva
|
||||
* @author Simon Baslé
|
||||
* @since 6.1
|
||||
*/
|
||||
public final class Netty5HeadersAdapter implements MultiValueMap<String, String> {
|
||||
@@ -92,7 +94,8 @@ public final class Netty5HeadersAdapter implements MultiValueMap<String, String>
|
||||
|
||||
@Override
|
||||
public Map<String, String> toSingleValueMap() {
|
||||
Map<String, String> singleValueMap = CollectionUtils.newLinkedHashMap(this.headers.size());
|
||||
Map<String, String> singleValueMap = new LinkedCaseInsensitiveMap<>(
|
||||
this.headers.size(), Locale.ROOT);
|
||||
this.headers.forEach(entry -> singleValueMap.putIfAbsent(
|
||||
entry.getKey().toString(), entry.getValue().toString()));
|
||||
return singleValueMap;
|
||||
|
||||
Reference in New Issue
Block a user