HttpHeaders are no longer a MultiValueMap
This change removes the `MultiValueMap` nature of `HttpHeaders`, since it inherits APIs that do not align well with underlying server implementations. Notably, methods that allows to iterate over the whole collection of headers are susceptible to artificially introduced duplicates when multiple casings are used for a given header, depending on the underlying implementation. This change includes a dedicated key set implementation to support iterator-based removal, and either keeps map method implementations that are relevant or introduces header-focused methods that have a similar responsibility (like `hasHeaderValues(String, List)` and `containsHeaderValue(String, String)`). In order to nudge users away from using an HttpHeaders as a Map, the `asSingleValueMap` view is deprecated. In order to offer an escape hatch to users that do make use of the `MultiValueMap` API, a similar `asMultiValueMap` view is introduced but is immediately marked as deprecated. This change also adds map-like but header-focused assertions to `HttpHeadersAssert`, since it cannot extend `AbstractMapAssert` anymore. Closes gh-33913
This commit is contained in:
@@ -73,7 +73,7 @@ public class HttpEntity<T> {
|
||||
* Create a new, empty {@code HttpEntity}.
|
||||
*/
|
||||
protected HttpEntity() {
|
||||
this(null, null);
|
||||
this(null, (HttpHeaders) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,13 +81,35 @@ public class HttpEntity<T> {
|
||||
* @param body the entity body
|
||||
*/
|
||||
public HttpEntity(T body) {
|
||||
this(body, null);
|
||||
this(body, (HttpHeaders) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code HttpEntity} with the given headers and no body.
|
||||
* @param headers the entity headers
|
||||
* @since 7.0
|
||||
*/
|
||||
public HttpEntity(HttpHeaders headers) {
|
||||
this(null, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code HttpEntity} with the given body and headers.
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @since 7.0
|
||||
*/
|
||||
public HttpEntity(@Nullable T body, @Nullable HttpHeaders headers) {
|
||||
this.body = body;
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers != null ? headers : new HttpHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code HttpEntity} with the given headers and no body.
|
||||
* @param headers the entity headers
|
||||
* @deprecated Use {@link #HttpEntity(HttpHeaders)}
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpEntity(MultiValueMap<String, String> headers) {
|
||||
this(null, headers);
|
||||
}
|
||||
@@ -96,10 +118,12 @@ public class HttpEntity<T> {
|
||||
* Create a new {@code HttpEntity} with the given body and headers.
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @deprecated Use {@link #HttpEntity(Object, HttpHeaders)}
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {
|
||||
this.body = body;
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers != null ? headers : new HttpHeaders());
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers != null ? new HttpHeaders(headers) : new HttpHeaders());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
@@ -52,6 +53,7 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -71,23 +73,18 @@ import org.springframework.util.StringUtils;
|
||||
* {@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)}.
|
||||
* mandated by the HTTP specification. However, it is not necessarily how
|
||||
* entries are actually stored, and this can lead to the reported {@code size()}
|
||||
* being inflated. Prefer using {@link #headerSet()} or {@link #headerNames()}
|
||||
* to ensure a case-insensitive view.
|
||||
*
|
||||
* <p>This class is meant to reference "well-known" headers supported by Spring
|
||||
* Framework. If your application or library relies on other headers defined in RFCs,
|
||||
* please use methods that accept the header name as a parameter.
|
||||
*
|
||||
* <p>Since 7.0, this class no longer implements the {@code MultiValueMap}
|
||||
* contract.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
* @author Brian Clozel
|
||||
@@ -97,7 +94,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Simon Baslé
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpHeaders implements MultiValueMap<String, String>, Serializable {
|
||||
public class HttpHeaders implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8578554704772377436L;
|
||||
|
||||
@@ -472,6 +469,28 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@code HttpHeaders} instance by removing any read-only
|
||||
* wrapper that may have been previously applied around the given
|
||||
* {@code HttpHeaders} via {@link #readOnlyHttpHeaders(HttpHeaders)}.
|
||||
* <p>Once the writable instance is mutated, the read-only instance is
|
||||
* likely to be out of sync and should be discarded.
|
||||
* @param httpHeaders the headers to expose
|
||||
* @since 7.0
|
||||
*/
|
||||
public HttpHeaders(HttpHeaders httpHeaders) {
|
||||
Assert.notNull(httpHeaders, "HttpHeaders must not be null");
|
||||
if (httpHeaders == EMPTY) {
|
||||
this.headers = CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ENGLISH));
|
||||
}
|
||||
else {
|
||||
while (httpHeaders.headers instanceof HttpHeaders wrapped) {
|
||||
httpHeaders = wrapped;
|
||||
}
|
||||
this.headers = httpHeaders.headers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of header values for the given header name, if any.
|
||||
@@ -479,9 +498,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* @return the list of header values, or an empty list
|
||||
* @since 5.2
|
||||
*/
|
||||
public List<String> getOrEmpty(Object headerName) {
|
||||
public List<String> getOrEmpty(String headerName) {
|
||||
return getOrDefault(headerName, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of header values for the given header name, or the given
|
||||
* default list of values if the header is not present.
|
||||
* @param headerName the header name
|
||||
* @param defaultValue the fallback list if header is not present
|
||||
* @return the list of header values, or a default list of values
|
||||
*/
|
||||
public List<String> getOrDefault(String headerName, List<String> defaultValue) {
|
||||
List<String> values = get(headerName);
|
||||
return (values != null ? values : Collections.emptyList());
|
||||
return (values != null ? values : defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1723,14 +1753,13 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
|
||||
// MultiValueMap implementation
|
||||
// MultiValueMap-like methods
|
||||
|
||||
/**
|
||||
* Return the first header value for the given header name, if any.
|
||||
* @param headerName the header name
|
||||
* @return the first header value, or {@code null} if none
|
||||
*/
|
||||
@Override
|
||||
public @Nullable String getFirst(String headerName) {
|
||||
return this.headers.getFirst(headerName);
|
||||
}
|
||||
@@ -1743,19 +1772,33 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* @see #put(String, List)
|
||||
* @see #set(String, String)
|
||||
*/
|
||||
@Override
|
||||
public void add(String headerName, @Nullable String headerValue) {
|
||||
this.headers.add(headerName, headerValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(String key, List<? extends String> values) {
|
||||
this.headers.addAll(key, values);
|
||||
/**
|
||||
* Add all the given values under the given name.
|
||||
* <p>As values are represented as a {@code List}, duplicate values can be
|
||||
* introduced. See {@link #put(String, List)} to replace the list of values
|
||||
* instead.
|
||||
* @param headerName the header name
|
||||
* @param headerValues the values to add
|
||||
* @see #put(String, List)
|
||||
*/
|
||||
public void addAll(String headerName, List<? extends String> headerValues) {
|
||||
this.headers.addAll(headerName, headerValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(MultiValueMap<String, String> values) {
|
||||
this.headers.addAll(values);
|
||||
/**
|
||||
* Add all the values of the given {@code HttpHeaders} to the current header.
|
||||
* <p>As values are represented as a {@code List}, duplicate values can be
|
||||
* introduced. See {@link #putAll(HttpHeaders)} to replace the list of
|
||||
* values of each individual header name instead.
|
||||
* @param headers the headers to add
|
||||
* @see #putAll(HttpHeaders)
|
||||
*/
|
||||
public void addAll(HttpHeaders headers) {
|
||||
this.headers.addAll(headers.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1766,132 +1809,202 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* @see #put(String, List)
|
||||
* @see #add(String, String)
|
||||
*/
|
||||
@Override
|
||||
public void set(String headerName, @Nullable String headerValue) {
|
||||
this.headers.set(headerName, headerValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Set all single header value from the given Map under each of their
|
||||
* corresponding name.
|
||||
* @param values the name-single-value pairs
|
||||
* @see #putAll(Map)
|
||||
*/
|
||||
public void setAll(Map<String, String> values) {
|
||||
this.headers.setAll(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Return this HttpHeaders as a {@code Map} with the first values for each
|
||||
* header name.
|
||||
* <p>The difference between this method and {@link #asSingleValueMap()} is
|
||||
* that this method returns a copy of the headers, whereas the latter
|
||||
* returns a view. This copy also ensures that collection-iterating methods
|
||||
* like {@code entrySet()} are case-insensitive.
|
||||
* @return a single value representation of these headers
|
||||
*/
|
||||
public Map<String, String> toSingleValueMap() {
|
||||
return this.headers.toSingleValueMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Return this HttpHeaders as a {@code Map} with the first values for each
|
||||
* header name.
|
||||
* <p>The difference between this method and {@link #toSingleValueMap()} is
|
||||
* that this method returns a view of the headers, whereas the latter
|
||||
* returns a copy. This method is also susceptible to include multiple
|
||||
* casing variants of a given header name, see {@link #asMultiValueMap()}
|
||||
* javadoc.
|
||||
* @return a single value representation of these headers
|
||||
* @deprecated Use {@link #toSingleValueMap()} which performs a copy but
|
||||
* ensures that collection-iterating methods like {@code entrySet()} are
|
||||
* case-insensitive
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, String> asSingleValueMap() {
|
||||
return this.headers.asSingleValueMap();
|
||||
}
|
||||
|
||||
// Map implementation
|
||||
/**
|
||||
* Return this HttpHeaders as a {@code MultiValueMap} with the full list
|
||||
* of values for each header name.
|
||||
* <p>Note that some backing server headers implementations can store header
|
||||
* names in a case-sensitive manner, which will lead to duplicates during
|
||||
* iteration in methods like {@code entrySet()}, where multiple occurrences
|
||||
* of a header name can surface depending on letter casing but each such
|
||||
* entry has the full {@code List} of values.
|
||||
* @return a MultiValueMap representation of these headers
|
||||
* @deprecated This method is provided for backward compatibility with APIs
|
||||
* that would only accept maps. Generally avoid using HttpHeaders as a Map
|
||||
* or MultiValueMap.
|
||||
*/
|
||||
@Deprecated
|
||||
public MultiValueMap<String, String> asMultiValueMap() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
// Map-like implementation
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this HttpHeaders contains no header entry.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.headers.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this.headers.containsKey(key);
|
||||
/**
|
||||
* Returns {@code true} if this HttpHeaders contains an entry for the
|
||||
* given header name.
|
||||
* @param headerName the header name
|
||||
* @since 7.0
|
||||
*/
|
||||
public boolean containsHeader(String headerName) {
|
||||
return this.headers.containsKey(headerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.headers.containsValue(value);
|
||||
/**
|
||||
* Returns {@code true} if this HttpHeaders contains exactly the given list
|
||||
* of values for the given header name.
|
||||
* @param headerName the header name
|
||||
* @param values the expected list of values
|
||||
* @since 7.0
|
||||
*/
|
||||
public boolean hasHeaderValues(String headerName, List<String> values) {
|
||||
return ObjectUtils.nullSafeEquals(this.headers.get(headerName), values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> get(Object key) {
|
||||
return this.headers.get(key);
|
||||
/**
|
||||
* Returns {@code true} if this HttpHeaders contains the given header and
|
||||
* its list of values contains the given value.
|
||||
* @param headerName the header name
|
||||
* @param value the value expected to be in the list of values
|
||||
* @since 7.0
|
||||
*/
|
||||
public boolean containsHeaderValue(String headerName, String value) {
|
||||
final List<String> values = this.headers.get(headerName);
|
||||
if (values == null) {
|
||||
return false;
|
||||
}
|
||||
return values.contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> put(String key, List<String> value) {
|
||||
return this.headers.put(key, value);
|
||||
/**
|
||||
* Get the list of values associated with the given header name.
|
||||
* @param headerName the header name
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> get(String headerName) {
|
||||
return this.headers.get(headerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> remove(Object key) {
|
||||
/**
|
||||
* Set the list of values associated with the given header name. Returns the
|
||||
* previous list of values, or {@code null} if the header was not present.
|
||||
* @param headerName the header name
|
||||
* @param headerValues the new values
|
||||
* @return the old values for the given header name
|
||||
*/
|
||||
public @Nullable List<String> put(String headerName, List<String> headerValues) {
|
||||
return this.headers.put(headerName, headerValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set header values for the given header name if that header name isn't
|
||||
* already present in this HttpHeaders and return {@code null}. If the
|
||||
* header is already present, returns the associated value list instead.
|
||||
* @param headerName the header name
|
||||
* @param headerValues the header values to set if header is not present
|
||||
* @return the previous value or {@code null}
|
||||
*/
|
||||
public @Nullable List<String> putIfAbsent(String headerName, List<String> headerValues) {
|
||||
return this.headers.putIfAbsent(headerName, headerValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all the entries from the given HttpHeaders into this HttpHeaders.
|
||||
* @param headers the given headers
|
||||
* @see #put(String, List)
|
||||
*/
|
||||
public void putAll(HttpHeaders headers) {
|
||||
this.headers.putAll(headers.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all the entries from the given {@code MultiValueMap} into this
|
||||
* HttpHeaders.
|
||||
* @param headers the given headers
|
||||
* @see #put(String, List)
|
||||
*/
|
||||
public void putAll(Map<? extends String, ? extends List<String>> headers) {
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a header from this HttpHeaders instance, and return the associated
|
||||
* value list or {@code null} if that header wasn't present.
|
||||
* @param key the name of the header to remove
|
||||
* @return the value list associated with the removed header name
|
||||
*/
|
||||
public @Nullable List<String> remove(String key) {
|
||||
return this.headers.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
this.headers.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Remove all headers from this HttpHeaders instance.
|
||||
*/
|
||||
public void clear() {
|
||||
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}.
|
||||
* {@link #headerSet()}.
|
||||
* @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);
|
||||
this.headerSet().forEach(e -> action.accept(e.getKey(), e.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* Both {@link Iterator#remove()} and {@link 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,
|
||||
@@ -1905,6 +2018,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
return new CaseInsensitiveEntrySet(this.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of header names. Both {@link Set#remove(Object)} and
|
||||
* {@link Set#clear()} operations are supported and mutate the headers.
|
||||
* <p>This collection is guaranteed to contain only one casing variant
|
||||
* of each header name even if the backing structure stores multiple casing
|
||||
* variants of names. The first encountered variant is the one that is
|
||||
* retained.
|
||||
* @return a {@code Set} of all the headers names
|
||||
* @since 7.0
|
||||
*/
|
||||
public Set<String> headerNames() {
|
||||
return new CaseInsensitiveHeaderNameSet(this.headers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
@@ -1959,7 +2086,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* @since 5.1.4
|
||||
*/
|
||||
public static String formatHeaders(MultiValueMap<String, String> headers) {
|
||||
Set<String> headerNames = toCaseInsensitiveSet(headers.keySet());
|
||||
Set<String> headerNames = new CaseInsensitiveHeaderNameSet(headers);
|
||||
String suffix = "]";
|
||||
if (headerNames.size() != headers.size()) {
|
||||
suffix = "] with native header names " + headers.keySet();
|
||||
@@ -2027,34 +2154,28 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
|
||||
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 CaseInsensitiveHeaderNameSet extends AbstractSet<String> {
|
||||
|
||||
|
||||
private static final class CaseInsensitiveEntrySet extends AbstractSet<Entry<String, List<String>>> {
|
||||
private static final Object VALUE = new Object();
|
||||
|
||||
private final MultiValueMap<String, String> headers;
|
||||
private final Set<String> deduplicatedNames;
|
||||
private final Map<String, Object> deduplicatedNames;
|
||||
|
||||
public CaseInsensitiveEntrySet(MultiValueMap<String, String> headers) {
|
||||
public CaseInsensitiveHeaderNameSet(MultiValueMap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
this.deduplicatedNames = toCaseInsensitiveSet(headers.keySet());
|
||||
this.deduplicatedNames = new LinkedCaseInsensitiveMap<>(headers.size(), Locale.ROOT);
|
||||
// add/addAll (put/putAll in LinkedCaseInsensitiveMap) retain the casing of the last occurrence.
|
||||
// Here we prefer the first.
|
||||
for (String header : headers.keySet()) {
|
||||
if (!this.deduplicatedNames.containsKey(header)) {
|
||||
this.deduplicatedNames.put(header, VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, List<String>>> iterator() {
|
||||
return new CaseInsensitiveIterator(this.deduplicatedNames.iterator());
|
||||
public Iterator<String> iterator() {
|
||||
return new HeaderNamesIterator(this.headers, this.deduplicatedNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2062,15 +2183,87 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
return this.deduplicatedNames.size();
|
||||
}
|
||||
|
||||
private final class CaseInsensitiveIterator implements Iterator<Map.Entry<String, List<String>>> {
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.headers.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return this.headers.remove(o) != null && this.deduplicatedNames.remove(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.headers.clear();
|
||||
this.deduplicatedNames.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static class HeaderNamesIterator implements Iterator<String> {
|
||||
|
||||
|
||||
private @Nullable String currentName;
|
||||
|
||||
private final MultiValueMap<String, String> headers;
|
||||
private final Iterator<String> namesIterator;
|
||||
|
||||
public HeaderNamesIterator (MultiValueMap<String, String> headers, Map<String, Object> caseInsensitiveNames) {
|
||||
this.headers = headers;
|
||||
this.namesIterator = caseInsensitiveNames.keySet().iterator();
|
||||
this.currentName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.namesIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
this.currentName = this.namesIterator.next();
|
||||
return this.currentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (this.currentName == null) {
|
||||
throw new IllegalStateException("No current Header in iterator");
|
||||
}
|
||||
if (!this.headers.containsKey(this.currentName)) {
|
||||
throw new IllegalStateException("Header not present: " + this.currentName);
|
||||
}
|
||||
this.headers.remove(this.currentName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class CaseInsensitiveEntrySet extends AbstractSet<Entry<String, List<String>>> {
|
||||
|
||||
private final MultiValueMap<String, String> headers;
|
||||
private final CaseInsensitiveHeaderNameSet nameSet;
|
||||
|
||||
public CaseInsensitiveEntrySet(MultiValueMap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
this.nameSet = new CaseInsensitiveHeaderNameSet(headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<String, List<String>>> iterator() {
|
||||
return new CaseInsensitiveIterator(this.nameSet.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.nameSet.size();
|
||||
}
|
||||
|
||||
private final class CaseInsensitiveIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private final Iterator<String> namesIterator;
|
||||
|
||||
private @Nullable String currentName;
|
||||
|
||||
private CaseInsensitiveIterator(Iterator<String> namesIterator) {
|
||||
public CaseInsensitiveIterator(Iterator<String> namesIterator) {
|
||||
this.namesIterator = namesIterator;
|
||||
this.currentName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2079,24 +2272,17 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<String, List<String>> next() {
|
||||
this.currentName = this.namesIterator.next();
|
||||
return new CaseInsensitiveEntry(this.currentName);
|
||||
public Entry<String, List<String>> next() {
|
||||
return new CaseInsensitiveEntrySet.CaseInsensitiveEntry(this.namesIterator.next());
|
||||
}
|
||||
|
||||
@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);
|
||||
this.namesIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private final class CaseInsensitiveEntry implements Map.Entry<String, List<String>> {
|
||||
private final class CaseInsensitiveEntry implements Entry<String, List<String>> {
|
||||
|
||||
private final String key;
|
||||
|
||||
@@ -2121,6 +2307,22 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
CaseInsensitiveEntrySet.this.headers.put(this.key, value);
|
||||
return previousValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Map.Entry<?,?> that)) {
|
||||
return false;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(getKey(), that.getKey()) && ObjectUtils.nullSafeEquals(getValue(), that.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHash(getKey(), getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,17 +17,18 @@
|
||||
package org.springframework.http;
|
||||
|
||||
import java.util.AbstractMap.SimpleImmutableEntry;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -84,8 +85,8 @@ class ReadOnlyHttpHeaders extends HttpHeaders {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> get(Object key) {
|
||||
List<String> values = this.headers.get(key);
|
||||
public @Nullable List<String> get(String headerName) {
|
||||
List<String> values = this.headers.get(headerName);
|
||||
return (values != null ? Collections.unmodifiableList(values) : null);
|
||||
}
|
||||
|
||||
@@ -95,12 +96,12 @@ class ReadOnlyHttpHeaders extends HttpHeaders {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(String key, List<? extends String> values) {
|
||||
public void addAll(String key, List<? extends String> headerValues) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(MultiValueMap<String, String> values) {
|
||||
public void addAll(HttpHeaders values) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -120,27 +121,45 @@ class ReadOnlyHttpHeaders extends HttpHeaders {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Map<String, String> asSingleValueMap() {
|
||||
return Collections.unmodifiableMap(this.headers.asSingleValueMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return Collections.unmodifiableSet(this.headers.keySet());
|
||||
@Deprecated
|
||||
public MultiValueMap<String, String> asMultiValueMap() {
|
||||
return CollectionUtils.unmodifiableMultiValueMap(this.headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> headerNames() {
|
||||
return Collections.unmodifiableSet(super.headerNames());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> put(String key, List<String> value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> remove(Object key) {
|
||||
public @Nullable List<String> putIfAbsent(String headerName, List<String> headerValues) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
public void putAll(@Nullable HttpHeaders values) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> headers) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> remove(String key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -150,13 +169,8 @@ class ReadOnlyHttpHeaders extends HttpHeaders {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<List<String>> values() {
|
||||
return Collections.unmodifiableCollection(this.headers.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, List<String>>> entrySet() {
|
||||
return this.headers.entrySet().stream().map(SimpleImmutableEntry::new)
|
||||
public Set<Entry<String, List<String>>> headerSet() {
|
||||
return super.headerSet().stream().map(SimpleImmutableEntry::new)
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toCollection(LinkedHashSet::new), // Retain original ordering of entries
|
||||
Collections::unmodifiableSet));
|
||||
|
||||
@@ -79,7 +79,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param url the URL
|
||||
*/
|
||||
public RequestEntity(HttpMethod method, URI url) {
|
||||
this(null, null, method, url, null);
|
||||
this(null, (HttpHeaders) null, method, url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +89,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param url the URL
|
||||
*/
|
||||
public RequestEntity(@Nullable T body, HttpMethod method, URI url) {
|
||||
this(body, null, method, url, null);
|
||||
this(body, (HttpHeaders) null, method, url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +101,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @since 4.3
|
||||
*/
|
||||
public RequestEntity(@Nullable T body, HttpMethod method, URI url, Type type) {
|
||||
this(body, null, method, url, type);
|
||||
this(body, (HttpHeaders) null, method, url, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +109,52 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param headers the headers
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @since 7.0
|
||||
*/
|
||||
public RequestEntity(HttpHeaders headers, HttpMethod method, URI url) {
|
||||
this(null, headers, method, url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with method, URL, headers and body.
|
||||
* @param body the body
|
||||
* @param headers the headers
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @since 7.0
|
||||
*/
|
||||
public RequestEntity(@Nullable T body, @Nullable HttpHeaders headers,
|
||||
@Nullable HttpMethod method, URI url) {
|
||||
|
||||
this(body, headers, method, url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with method, URL, headers, body and type.
|
||||
* @param body the body
|
||||
* @param headers the headers
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @param type the type used for generic type resolution
|
||||
* @since 7.0
|
||||
*/
|
||||
public RequestEntity(@Nullable T body, @Nullable HttpHeaders headers,
|
||||
@Nullable HttpMethod method, @Nullable URI url, @Nullable Type type) {
|
||||
|
||||
super(body, headers);
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with method, URL and headers but without body.
|
||||
* @param headers the headers
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @deprecated Use {@link #RequestEntity(HttpHeaders, HttpMethod, URI)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RequestEntity(MultiValueMap<String, String> headers, HttpMethod method, URI url) {
|
||||
this(null, headers, method, url, null);
|
||||
}
|
||||
@@ -120,7 +165,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param headers the headers
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @deprecated Use {@link #RequestEntity(Object, HttpHeaders, HttpMethod, URI)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers,
|
||||
@Nullable HttpMethod method, URI url) {
|
||||
|
||||
@@ -135,7 +182,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param url the URL
|
||||
* @param type the type used for generic type resolution
|
||||
* @since 4.3
|
||||
* @deprecated Use {@link #RequestEntity(Object, HttpHeaders, HttpMethod, URI, Type)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers,
|
||||
@Nullable HttpMethod method, @Nullable URI url, @Nullable Type type) {
|
||||
|
||||
@@ -694,7 +743,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
private final @Nullable Map<String, ?> uriVarsMap;
|
||||
|
||||
UriTemplateRequestEntity(
|
||||
@Nullable T body, @Nullable MultiValueMap<String, String> headers,
|
||||
@Nullable T body, @Nullable HttpHeaders headers,
|
||||
@Nullable HttpMethod method, @Nullable Type type, String uriTemplate,
|
||||
Object @Nullable [] uriVarsArray, @Nullable Map<String, ?> uriVarsMap) {
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param status the status code
|
||||
*/
|
||||
public ResponseEntity(HttpStatusCode status) {
|
||||
this(null, null, status);
|
||||
this(null, (HttpHeaders) null, status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,14 +97,51 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param status the status code
|
||||
*/
|
||||
public ResponseEntity(@Nullable T body, HttpStatusCode status) {
|
||||
this(body, null, status);
|
||||
this(body, (HttpHeaders) null, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseEntity} with headers and a status code.
|
||||
* @param headers the entity headers
|
||||
* @param status the status code
|
||||
* @since 7.0
|
||||
*/
|
||||
public ResponseEntity(HttpHeaders headers, HttpStatusCode status) {
|
||||
this(null, headers, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseEntity} with a body, headers, and a raw status code.
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @param rawStatus the status code value
|
||||
* @since 7.0
|
||||
*/
|
||||
public ResponseEntity(@Nullable T body, @Nullable HttpHeaders headers, int rawStatus) {
|
||||
this(body, headers, HttpStatusCode.valueOf(rawStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseEntity} with a body, headers, and a status code.
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @param statusCode the status code
|
||||
* @since 7.0
|
||||
*/
|
||||
public ResponseEntity(@Nullable T body, @Nullable HttpHeaders headers, HttpStatusCode statusCode) {
|
||||
super(body, headers);
|
||||
Assert.notNull(statusCode, "HttpStatusCode must not be null");
|
||||
|
||||
this.status = statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseEntity} with headers and a status code.
|
||||
* @param headers the entity headers
|
||||
* @param status the status code
|
||||
* @deprecated Use {@link #ResponseEntity(HttpHeaders, HttpStatusCode)}
|
||||
*/
|
||||
@Deprecated
|
||||
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatusCode status) {
|
||||
this(null, headers, status);
|
||||
}
|
||||
@@ -115,7 +152,9 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param headers the entity headers
|
||||
* @param rawStatus the status code value
|
||||
* @since 5.3.2
|
||||
* @deprecated Use {@link #ResponseEntity(Object, HttpHeaders, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, int rawStatus) {
|
||||
this(body, headers, HttpStatusCode.valueOf(rawStatus));
|
||||
}
|
||||
@@ -125,7 +164,9 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @param statusCode the status code
|
||||
* @deprecated Use {@link #ResponseEntity(Object, HttpHeaders, HttpStatusCode)}
|
||||
*/
|
||||
@Deprecated
|
||||
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatusCode statusCode) {
|
||||
super(body, headers);
|
||||
Assert.notNull(statusCode, "HttpStatusCode must not be null");
|
||||
|
||||
@@ -366,7 +366,7 @@ public final class MultipartBodyBuilder {
|
||||
private final ResolvableType resolvableType;
|
||||
|
||||
PublisherEntity(
|
||||
@Nullable MultiValueMap<String, String> headers, P publisher, ResolvableType resolvableType) {
|
||||
@Nullable HttpHeaders headers, P publisher, ResolvableType resolvableType) {
|
||||
|
||||
super(publisher, headers);
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
|
||||
@@ -125,7 +125,7 @@ class HttpComponentsClientHttpRequest extends AbstractClientHttpRequest {
|
||||
protected void applyHeaders() {
|
||||
HttpHeaders headers = getHeaders();
|
||||
|
||||
headers.entrySet()
|
||||
headers.headerSet()
|
||||
.stream()
|
||||
.filter(entry -> !HttpHeaders.CONTENT_LENGTH.equals(entry.getKey()))
|
||||
.forEach(entry -> entry.getValue().forEach(v -> this.httpRequest.addHeader(entry.getKey(), v)));
|
||||
|
||||
@@ -99,7 +99,7 @@ class JdkClientHttpRequest extends AbstractClientHttpRequest {
|
||||
|
||||
@Override
|
||||
protected void applyHeaders() {
|
||||
for (Map.Entry<String, List<String>> entry : getHeaders().entrySet()) {
|
||||
for (Map.Entry<String, List<String>> entry : getHeaders().headerSet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH)) {
|
||||
// content-length is specified when writing
|
||||
continue;
|
||||
@@ -108,7 +108,7 @@ class JdkClientHttpRequest extends AbstractClientHttpRequest {
|
||||
this.builder.header(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (!getHeaders().containsKey(HttpHeaders.ACCEPT)) {
|
||||
if (!getHeaders().containsHeader(HttpHeaders.ACCEPT)) {
|
||||
this.builder.header(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ class JettyClientHttpRequest extends AbstractClientHttpRequest {
|
||||
HttpHeaders headers = getHeaders();
|
||||
this.jettyRequest.headers(fields -> {
|
||||
headers.forEach((key, value) -> value.forEach(v -> fields.add(key, v)));
|
||||
if (!headers.containsKey(HttpHeaders.ACCEPT)) {
|
||||
if (!headers.containsHeader(HttpHeaders.ACCEPT)) {
|
||||
fields.add(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ public class BasicAuthenticationInterceptor implements ClientHttpRequestIntercep
|
||||
HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
|
||||
if (!headers.containsHeader(HttpHeaders.AUTHORIZATION)) {
|
||||
headers.setBasicAuth(this.encodedCredentials);
|
||||
}
|
||||
return execution.execute(request, body);
|
||||
|
||||
@@ -261,7 +261,7 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
|
||||
resolvableType = ResolvableType.forClass(body.getClass());
|
||||
}
|
||||
|
||||
if (!headers.containsKey(HttpHeaders.CONTENT_DISPOSITION)) {
|
||||
if (!headers.containsHeader(HttpHeaders.CONTENT_DISPOSITION)) {
|
||||
if (body instanceof Resource resource) {
|
||||
headers.setContentDispositionFormData(name, resource.getFilename());
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public class MultipartWriterSupport extends LoggingCodecSupport {
|
||||
return Mono.fromCallable(() -> {
|
||||
@SuppressWarnings("resource")
|
||||
FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
for (Map.Entry<String, List<String>> entry : headers.headerSet()) {
|
||||
byte[] headerName = entry.getKey().getBytes(getCharset());
|
||||
for (String headerValueString : entry.getValue()) {
|
||||
byte[] headerValue = headerValueString.getBytes(getCharset());
|
||||
|
||||
@@ -94,7 +94,7 @@ public class PartHttpMessageWriter extends MultipartWriterSupport implements Htt
|
||||
HttpHeaders headers = new HttpHeaders(part.headers());
|
||||
|
||||
String name = part.name();
|
||||
if (!headers.containsKey(HttpHeaders.CONTENT_DISPOSITION)) {
|
||||
if (!headers.containsHeader(HttpHeaders.CONTENT_DISPOSITION)) {
|
||||
headers.setContentDispositionFormData(name,
|
||||
(part instanceof FilePart filePart ? filePart.filename() : null));
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
|
||||
headers.setContentType(contentTypeToUse);
|
||||
}
|
||||
}
|
||||
if (headers.getContentLength() < 0 && !headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
|
||||
if (headers.getContentLength() < 0 && !headers.containsHeader(HttpHeaders.TRANSFER_ENCODING)) {
|
||||
Long contentLength = getContentLength(t, headers.getContentType());
|
||||
if (contentLength != null) {
|
||||
headers.setContentLength(contentLength);
|
||||
|
||||
@@ -645,7 +645,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
|
||||
private void writeHeaders() throws IOException {
|
||||
if (!this.headersWritten) {
|
||||
for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
|
||||
for (Map.Entry<String, List<String>> entry : this.headers.headerSet()) {
|
||||
byte[] headerName = getBytes(entry.getKey());
|
||||
for (String headerValueString : entry.getValue()) {
|
||||
byte[] headerValue = getBytes(headerValueString);
|
||||
|
||||
@@ -291,7 +291,7 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
||||
writer.flush();
|
||||
|
||||
byte[] bytes = bos.toByteArray();
|
||||
if (bytes.length > 0 && getHeaders().containsKey(HttpHeaders.CONTENT_LENGTH)) {
|
||||
if (bytes.length > 0 && getHeaders().containsHeader(HttpHeaders.CONTENT_LENGTH)) {
|
||||
getHeaders().setContentLength(bytes.length);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,8 +151,8 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
||||
private static final long serialVersionUID = 3410708522401046302L;
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return (super.containsKey(key) || (get(key) != null));
|
||||
public boolean containsHeader(String key) {
|
||||
return (super.containsHeader(key) || (get(key) != null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,10 +169,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> get(Object key) {
|
||||
Assert.isInstanceOf(String.class, key, "Key must be a String-based header name");
|
||||
|
||||
String headerName = (String) key;
|
||||
public @Nullable List<String> get(String headerName) {
|
||||
if (headerName.equalsIgnoreCase(CONTENT_TYPE)) {
|
||||
// Content-Type is written as an override so don't merge
|
||||
String value = getFirst(headerName);
|
||||
@@ -185,7 +182,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
||||
}
|
||||
boolean isEmpty1 = CollectionUtils.isEmpty(values1);
|
||||
|
||||
List<String> values2 = super.get(key);
|
||||
List<String> values2 = super.get(headerName);
|
||||
boolean isEmpty2 = CollectionUtils.isEmpty(values2);
|
||||
|
||||
if (isEmpty1 && isEmpty2) {
|
||||
|
||||
@@ -79,9 +79,24 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
* @param contextPath the context path for the request
|
||||
* @param headers the headers for the request (as {@link MultiValueMap})
|
||||
* @since 6.0.8
|
||||
* @deprecated Use {@link #AbstractServerHttpRequest(HttpMethod, URI, String, HttpHeaders)}
|
||||
*/
|
||||
@Deprecated
|
||||
public AbstractServerHttpRequest(HttpMethod method, URI uri, @Nullable String contextPath,
|
||||
MultiValueMap<String, String> headers) {
|
||||
this(method, uri, contextPath, new HttpHeaders(headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with the method, URI and headers for the request.
|
||||
* @param method the HTTP method for the request
|
||||
* @param uri the URI for the request
|
||||
* @param contextPath the context path for the request
|
||||
* @param headers the headers for the request (as {@link MultiValueMap})
|
||||
* @since 7.0
|
||||
*/
|
||||
public AbstractServerHttpRequest(HttpMethod method, URI uri, @Nullable String contextPath,
|
||||
HttpHeaders headers) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
Assert.notNull(uri, "Uri must not be null");
|
||||
|
||||
@@ -37,6 +37,7 @@ import reactor.netty5.http.server.HttpServerRequest;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.Netty5DataBufferFactory;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpLogging;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.support.Netty5HeadersAdapter;
|
||||
@@ -70,7 +71,7 @@ class ReactorNetty2ServerHttpRequest extends AbstractServerHttpRequest {
|
||||
throws URISyntaxException {
|
||||
|
||||
super(HttpMethod.valueOf(request.method().name()), initUri(request), "",
|
||||
new Netty5HeadersAdapter(request.requestHeaders()));
|
||||
new HttpHeaders(new Netty5HeadersAdapter(request.requestHeaders())));
|
||||
Assert.notNull(bufferFactory, "DataBufferFactory must not be null");
|
||||
this.request = request;
|
||||
this.bufferFactory = bufferFactory;
|
||||
|
||||
@@ -35,6 +35,7 @@ import reactor.netty.http.server.HttpServerRequest;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpLogging;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.support.Netty4HeadersAdapter;
|
||||
@@ -67,7 +68,7 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest {
|
||||
|
||||
super(HttpMethod.valueOf(request.method().name()),
|
||||
ReactorUriHelper.createUri(request), request.forwardedPrefix(),
|
||||
new Netty4HeadersAdapter(request.requestHeaders()));
|
||||
new HttpHeaders(new Netty4HeadersAdapter(request.requestHeaders())));
|
||||
Assert.notNull(bufferFactory, "DataBufferFactory must not be null");
|
||||
this.request = request;
|
||||
this.bufferFactory = bufferFactory;
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.AsyncContext;
|
||||
@@ -47,7 +46,6 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -89,7 +87,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||
this(createDefaultHttpHeaders(request), request, asyncContext, servletPath, bufferFactory, bufferSize);
|
||||
}
|
||||
|
||||
public ServletServerHttpRequest(MultiValueMap<String, String> headers, HttpServletRequest request,
|
||||
public ServletServerHttpRequest(HttpHeaders headers, HttpServletRequest request,
|
||||
AsyncContext asyncContext, String servletPath, DataBufferFactory bufferFactory, int bufferSize)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
@@ -112,9 +110,8 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
|
||||
private static MultiValueMap<String, String> createDefaultHttpHeaders(HttpServletRequest request) {
|
||||
MultiValueMap<String, String> headers =
|
||||
CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ROOT));
|
||||
private static HttpHeaders createDefaultHttpHeaders(HttpServletRequest request) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
for (Enumeration<?> names = request.getHeaderNames(); names.hasMoreElements(); ) {
|
||||
String name = (String) names.nextElement();
|
||||
for (Enumeration<?> values = request.getHeaders(name); values.hasMoreElements(); ) {
|
||||
@@ -163,8 +160,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private static MultiValueMap<String, String> initHeaders(
|
||||
MultiValueMap<String, String> headerValues, HttpServletRequest request) {
|
||||
private static HttpHeaders initHeaders(HttpHeaders headerValues, HttpServletRequest request) {
|
||||
|
||||
HttpHeaders headers = null;
|
||||
MediaType contentType = null;
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.apache.coyote.Response;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -91,13 +90,13 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
super(createTomcatHttpHeaders(request), request, context, servletPath, factory, bufferSize);
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> createTomcatHttpHeaders(HttpServletRequest request) {
|
||||
private static HttpHeaders createTomcatHttpHeaders(HttpServletRequest request) {
|
||||
RequestFacade requestFacade = getRequestFacade(request);
|
||||
org.apache.catalina.connector.Request connectorRequest = (org.apache.catalina.connector.Request)
|
||||
ReflectionUtils.getField(COYOTE_REQUEST_FIELD, requestFacade);
|
||||
Assert.state(connectorRequest != null, "No Tomcat connector request");
|
||||
Request tomcatRequest = connectorRequest.getCoyoteRequest();
|
||||
return new TomcatHeadersAdapter(tomcatRequest.getMimeHeaders());
|
||||
return new HttpHeaders(new TomcatHeadersAdapter(tomcatRequest.getMimeHeaders()));
|
||||
}
|
||||
|
||||
private static RequestFacade getRequestFacade(HttpServletRequest request) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import reactor.core.publisher.Flux;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -65,7 +66,7 @@ class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||
throws URISyntaxException {
|
||||
|
||||
super(HttpMethod.valueOf(exchange.getRequestMethod().toString()), initUri(exchange), "",
|
||||
new UndertowHeadersAdapter(exchange.getRequestHeaders()));
|
||||
new HttpHeaders(new UndertowHeadersAdapter(exchange.getRequestHeaders())));
|
||||
this.exchange = exchange;
|
||||
this.body = new RequestBodyPublisher(exchange, bufferFactory);
|
||||
this.body.registerListeners(exchange);
|
||||
|
||||
@@ -623,10 +623,10 @@ final class DefaultRestClient implements RestClient {
|
||||
|
||||
private @Nullable HttpHeaders initHeaders() {
|
||||
HttpHeaders defaultHeaders = DefaultRestClient.this.defaultHeaders;
|
||||
if (CollectionUtils.isEmpty(this.headers)) {
|
||||
if (this.headers == null || this.headers.isEmpty()) {
|
||||
return defaultHeaders;
|
||||
}
|
||||
else if (CollectionUtils.isEmpty(defaultHeaders)) {
|
||||
else if (defaultHeaders == null || defaultHeaders.isEmpty()) {
|
||||
return this.headers;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -220,7 +220,7 @@ public class DefaultCorsProcessor implements CorsProcessor {
|
||||
|
||||
private List<String> getHeadersToUse(ServerHttpRequest request, boolean isPreFlight) {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
return (isPreFlight ? headers.getAccessControlRequestHeaders() : new ArrayList<>(headers.keySet()));
|
||||
return (isPreFlight ? headers.getAccessControlRequestHeaders() : new ArrayList<>(headers.headerNames()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class CorsUtils {
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isCorsRequest(ServerHttpRequest request) {
|
||||
return request.getHeaders().containsKey(HttpHeaders.ORIGIN) && !isSameOrigin(request);
|
||||
return request.getHeaders().containsHeader(HttpHeaders.ORIGIN) && !isSameOrigin(request);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,8 +52,8 @@ public abstract class CorsUtils {
|
||||
public static boolean isPreFlightRequest(ServerHttpRequest request) {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
return (request.getMethod() == HttpMethod.OPTIONS
|
||||
&& headers.containsKey(HttpHeaders.ORIGIN)
|
||||
&& headers.containsKey(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD));
|
||||
&& headers.containsHeader(HttpHeaders.ORIGIN)
|
||||
&& headers.containsHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,7 +217,7 @@ public class DefaultCorsProcessor implements CorsProcessor {
|
||||
|
||||
private List<String> getHeadersToUse(ServerHttpRequest request, boolean isPreFlight) {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
return (isPreFlight ? headers.getAccessControlRequestHeaders() : new ArrayList<>(headers.keySet()));
|
||||
return (isPreFlight ? headers.getAccessControlRequestHeaders() : new ArrayList<>(headers.headerNames()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.method.annotation;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -33,13 +34,14 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
|
||||
* For individual header values annotated with {@code @RequestHeader} see
|
||||
* Resolves {@link Map}, {@link MultiValueMap} and {@link HttpHeaders} method
|
||||
* arguments annotated with {@code @RequestHeader}. For individual header values
|
||||
* annotated with {@code @RequestHeader} see
|
||||
* {@link RequestHeaderMethodArgumentResolver} instead.
|
||||
*
|
||||
* <p>The created {@link Map} contains all request header name/value pairs.
|
||||
* The method parameter type may be a {@link MultiValueMap} to receive all
|
||||
* values for a header, not only the first one.
|
||||
* The method parameter type may be a {@link HttpHeaders} or a {@link MultiValueMap}
|
||||
* to receive all values for a header, not only the first one.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -50,7 +52,8 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
|
||||
Map.class.isAssignableFrom(parameter.getParameterType()));
|
||||
(Map.class.isAssignableFrom(parameter.getParameterType()) ||
|
||||
HttpHeaders.class.isAssignableFrom(parameter.getParameterType())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,23 +61,15 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
if (MultiValueMap.class.isAssignableFrom(paramType)) {
|
||||
MultiValueMap<String, String> result;
|
||||
if (HttpHeaders.class.isAssignableFrom(paramType)) {
|
||||
result = new HttpHeaders();
|
||||
}
|
||||
else {
|
||||
result = new LinkedMultiValueMap<>();
|
||||
}
|
||||
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
|
||||
String headerName = iterator.next();
|
||||
String[] headerValues = webRequest.getHeaderValues(headerName);
|
||||
if (headerValues != null) {
|
||||
for (String headerValue : headerValues) {
|
||||
result.add(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HttpHeaders.class.isAssignableFrom(paramType)) {
|
||||
HttpHeaders result = new HttpHeaders();
|
||||
copyHeaderValues(webRequest, result::add);
|
||||
return result;
|
||||
}
|
||||
else if (MultiValueMap.class.isAssignableFrom(paramType)) {
|
||||
MultiValueMap<Object, Object> result = new LinkedMultiValueMap<>();
|
||||
copyHeaderValues(webRequest, result::add);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
@@ -90,4 +85,16 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
|
||||
}
|
||||
}
|
||||
|
||||
void copyHeaderValues(NativeWebRequest webRequest, BiConsumer<String, String> consumer) {
|
||||
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
|
||||
String headerName = iterator.next();
|
||||
String[] headerValues = webRequest.getHeaderValues(headerName);
|
||||
if (headerValues != null) {
|
||||
for (String headerValue : headerValues) {
|
||||
consumer.accept(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.MissingRequestHeaderException;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
@@ -61,7 +62,8 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
|
||||
!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
|
||||
!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) &&
|
||||
!HttpHeaders.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -144,7 +144,7 @@ public class ForwardedHeaderTransformer implements Function<ServerHttpRequest, S
|
||||
protected boolean hasForwardedHeaders(ServerHttpRequest request) {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
for (String headerName : FORWARDED_HEADER_NAMES) {
|
||||
if (headers.containsKey(headerName)) {
|
||||
if (headers.containsHeader(headerName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class HttpEntityTests {
|
||||
String body = "foo";
|
||||
HttpEntity<String> entity = new HttpEntity<>(body);
|
||||
assertThat(entity.getBody()).isSameAs(body);
|
||||
assertThat(entity.getHeaders()).isEmpty();
|
||||
assertThat(entity.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -62,25 +62,25 @@ class HttpEntityTests {
|
||||
|
||||
@Test
|
||||
void testEquals() {
|
||||
MultiValueMap<String, String> map1 = new LinkedMultiValueMap<>();
|
||||
map1.set("Content-Type", "text/plain");
|
||||
HttpHeaders headers1 = new HttpHeaders();
|
||||
headers1.set("Content-Type", "text/plain");
|
||||
|
||||
MultiValueMap<String, String> map2 = new LinkedMultiValueMap<>();
|
||||
map2.set("Content-Type", "application/json");
|
||||
HttpHeaders headers2 = new HttpHeaders();
|
||||
headers2.set("Content-Type", "application/json");
|
||||
|
||||
assertThat(new HttpEntity<>().equals(new HttpEntity<>())).isTrue();
|
||||
assertThat(new HttpEntity<>(map1).equals(new HttpEntity<>())).isFalse();
|
||||
assertThat(new HttpEntity<>().equals(new HttpEntity<>(map2))).isFalse();
|
||||
assertThat(new HttpEntity<>(headers1).equals(new HttpEntity<>())).isFalse();
|
||||
assertThat(new HttpEntity<>().equals(new HttpEntity<>(headers2))).isFalse();
|
||||
|
||||
assertThat(new HttpEntity<>(map1).equals(new HttpEntity<>(map1))).isTrue();
|
||||
assertThat(new HttpEntity<>(map1).equals(new HttpEntity<>(map2))).isFalse();
|
||||
assertThat(new HttpEntity<>(headers1).equals(new HttpEntity<>(headers1))).isTrue();
|
||||
assertThat(new HttpEntity<>(headers1).equals(new HttpEntity<>(headers2))).isFalse();
|
||||
|
||||
assertThat(new HttpEntity<String>(null, null).equals(new HttpEntity<>(null, null))).isTrue();
|
||||
assertThat(new HttpEntity<>("foo", null).equals(new HttpEntity<>(null, null))).isFalse();
|
||||
assertThat(new HttpEntity<String>(null, null).equals(new HttpEntity<>("bar", null))).isFalse();
|
||||
assertThat(new HttpEntity<String>(null, (HttpHeaders) null).equals(new HttpEntity<>(null, (HttpHeaders) null))).isTrue();
|
||||
assertThat(new HttpEntity<>("foo", (HttpHeaders) null).equals(new HttpEntity<>(null, (HttpHeaders) null))).isFalse();
|
||||
assertThat(new HttpEntity<String>(null, (HttpHeaders) null).equals(new HttpEntity<>("bar", (HttpHeaders) null))).isFalse();
|
||||
|
||||
assertThat(new HttpEntity<>("foo", map1).equals(new HttpEntity<>("foo", map1))).isTrue();
|
||||
assertThat(new HttpEntity<>("foo", map1).equals(new HttpEntity<>("bar", map1))).isFalse();
|
||||
assertThat(new HttpEntity<>("foo", headers1).equals(new HttpEntity<>("foo", headers1))).isTrue();
|
||||
assertThat(new HttpEntity<>("foo", headers1).equals(new HttpEntity<>("bar", headers1))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -645,7 +645,7 @@ class HttpHeadersTests {
|
||||
void keySetOperations() {
|
||||
headers.add("Alpha", "apple");
|
||||
headers.add("Bravo", "banana");
|
||||
Set<String> keySet = headers.keySet();
|
||||
Set<String> keySet = headers.headerNames();
|
||||
|
||||
// Please DO NOT simplify the following with AssertJ's fluent API.
|
||||
//
|
||||
@@ -677,17 +677,17 @@ class HttpHeadersTests {
|
||||
// remove()
|
||||
assertThat(keySet.remove("Alpha")).isTrue();
|
||||
assertThat(keySet).hasSize(1);
|
||||
assertThat(headers).hasSize(1);
|
||||
assertThat(headers.size()).isOne();
|
||||
assertThat(keySet.remove("Alpha")).isFalse();
|
||||
assertThat(keySet).hasSize(1);
|
||||
assertThat(headers).hasSize(1);
|
||||
assertThat(headers.size()).isOne();
|
||||
|
||||
// clear()
|
||||
keySet.clear();
|
||||
assertThat(keySet).isEmpty();
|
||||
assertThat(keySet).isEmpty();
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
|
||||
// Unsupported operations
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class)
|
||||
@@ -705,10 +705,10 @@ class HttpHeadersTests {
|
||||
// --- Given ---
|
||||
headers.add("Alpha", "apple");
|
||||
headers.add("Bravo", "banana");
|
||||
assertThat(headers).containsOnlyKeys("Alpha", "Bravo");
|
||||
assertThat(headers.headerNames()).containsOnly("Alpha", "Bravo");
|
||||
|
||||
// --- When ---
|
||||
boolean removed = headers.keySet().remove("Alpha");
|
||||
boolean removed = headers.headerNames().remove("Alpha");
|
||||
|
||||
// --- Then ---
|
||||
|
||||
@@ -718,12 +718,12 @@ class HttpHeadersTests {
|
||||
// the behavior of the entire contract.
|
||||
|
||||
assertThat(removed).isTrue();
|
||||
assertThat(headers.keySet().remove("Alpha")).isFalse();
|
||||
assertThat(headers).hasSize(1);
|
||||
assertThat(headers.containsKey("Alpha")).as("Alpha should have been removed").isFalse();
|
||||
assertThat(headers.containsKey("Bravo")).as("Bravo should be present").isTrue();
|
||||
assertThat(headers.keySet()).containsOnly("Bravo");
|
||||
assertThat(headers.entrySet()).containsOnly(entry("Bravo", List.of("banana")));
|
||||
assertThat(headers.headerNames().remove("Alpha")).isFalse();
|
||||
assertThat(headers.size()).isOne();
|
||||
assertThat(headers.containsHeader("Alpha")).as("Alpha should have been removed").isFalse();
|
||||
assertThat(headers.containsHeader("Bravo")).as("Bravo should be present").isTrue();
|
||||
assertThat(headers.headerNames()).containsOnly("Bravo");
|
||||
assertThat(headers.headerSet()).containsOnly(entry("Bravo", List.of("banana")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -731,11 +731,11 @@ class HttpHeadersTests {
|
||||
String headerName = "MyHeader";
|
||||
String headerValue = "value";
|
||||
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
headers.add(headerName, headerValue);
|
||||
assertThat(headers.containsKey(headerName)).isTrue();
|
||||
headers.keySet().removeIf(key -> key.equals(headerName));
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers.containsHeader(headerName)).isTrue();
|
||||
headers.headerNames().removeIf(key -> key.equals(headerName));
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
headers.add(headerName, headerValue);
|
||||
assertThat(headers.get(headerName)).containsExactly(headerValue);
|
||||
}
|
||||
@@ -745,11 +745,11 @@ class HttpHeadersTests {
|
||||
String headerName = "MyHeader";
|
||||
String headerValue = "value";
|
||||
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
headers.add(headerName, headerValue);
|
||||
assertThat(headers.containsKey(headerName)).isTrue();
|
||||
headers.entrySet().removeIf(entry -> entry.getKey().equals(headerName));
|
||||
assertThat(headers).isEmpty();
|
||||
assertThat(headers.containsHeader(headerName)).isTrue();
|
||||
headers.headerSet().removeIf(entry -> entry.getKey().equals(headerName));
|
||||
assertThat(headers.isEmpty()).as("isEmpty").isTrue();
|
||||
headers.add(headerName, headerValue);
|
||||
assertThat(headers.get(headerName)).containsExactly(headerValue);
|
||||
}
|
||||
@@ -764,10 +764,10 @@ class HttpHeadersTests {
|
||||
|
||||
String[] expectedKeys = new String[] { "aardvark", "beaver", "cat", "dog", "elephant" };
|
||||
|
||||
assertThat(headers.entrySet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
assertThat(headers.headerSet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
|
||||
HttpHeaders readOnlyHttpHeaders = HttpHeaders.readOnlyHttpHeaders(headers);
|
||||
assertThat(readOnlyHttpHeaders.entrySet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
assertThat(readOnlyHttpHeaders.headerSet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -784,15 +784,15 @@ class HttpHeadersTests {
|
||||
|
||||
HttpHeaders forEachHeaders = new HttpHeaders();
|
||||
readOnlyHttpHeaders.forEach(forEachHeaders::putIfAbsent);
|
||||
assertThat(forEachHeaders.entrySet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
assertThat(forEachHeaders.headerSet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
|
||||
HttpHeaders putAllHeaders = new HttpHeaders();
|
||||
putAllHeaders.putAll(readOnlyHttpHeaders);
|
||||
assertThat(putAllHeaders.entrySet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
assertThat(putAllHeaders.headerSet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
|
||||
HttpHeaders addAllHeaders = new HttpHeaders();
|
||||
addAllHeaders.addAll(readOnlyHttpHeaders);
|
||||
assertThat(addAllHeaders.entrySet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
assertThat(addAllHeaders.headerSet()).extracting(Entry::getKey).containsExactly(expectedKeys);
|
||||
}
|
||||
|
||||
@Test // gh-25034
|
||||
|
||||
@@ -52,7 +52,7 @@ class RequestEntityTests {
|
||||
|
||||
assertThat(requestEntity).isNotNull();
|
||||
assertThat(requestEntity.getMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(requestEntity.getHeaders().containsKey(headerName)).isTrue();
|
||||
assertThat(requestEntity.getHeaders().containsHeader(headerName)).isTrue();
|
||||
assertThat(requestEntity.getHeaders().getFirst(headerName)).isEqualTo(headerValue);
|
||||
assertThat(requestEntity.getBody()).isEqualTo(entity);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ class RequestEntityTests {
|
||||
|
||||
assertThat(requestEntity).isNotNull();
|
||||
assertThat(requestEntity.getMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(requestEntity.getHeaders().containsKey(HttpHeaders.ACCEPT)).isTrue();
|
||||
assertThat(requestEntity.getHeaders().containsHeader(HttpHeaders.ACCEPT)).isTrue();
|
||||
assertThat(requestEntity.getHeaders().getFirst(HttpHeaders.ACCEPT)).isEqualTo("image/gif, image/jpeg, image/png");
|
||||
assertThat(requestEntity.getBody()).isNull();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ class RequestEntityTests {
|
||||
ifNoneMatch(ifNoneMatch).
|
||||
contentLength(contentLength).
|
||||
contentType(contentType).
|
||||
headers(headers -> assertThat(headers).hasSize(6)).
|
||||
headers(headers -> assertThat(headers.size()).isEqualTo(6)).
|
||||
build();
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
|
||||
@@ -44,7 +44,7 @@ class ResponseEntityTests {
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getHeaders().containsKey(headerName)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().containsHeader(headerName)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().get(headerName)).containsExactly(headerValue1, headerValue2);
|
||||
assertThat(responseEntity.getBody()).isEqualTo(entity);
|
||||
}
|
||||
@@ -113,7 +113,7 @@ class ResponseEntityTests {
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.CREATED);
|
||||
assertThat(responseEntity.getHeaders().containsKey(HttpHeaders.LOCATION)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().containsHeader(HttpHeaders.LOCATION)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().getFirst(HttpHeaders.LOCATION)).isEqualTo(location.toString());
|
||||
assertThat(responseEntity.getBody()).isNull();
|
||||
|
||||
@@ -195,7 +195,7 @@ class ResponseEntityTests {
|
||||
location(location).
|
||||
contentLength(contentLength).
|
||||
contentType(contentType).
|
||||
headers(headers -> assertThat(headers).hasSize(5)).
|
||||
headers(headers -> assertThat(headers.size()).isEqualTo(5)).
|
||||
build();
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
@@ -236,7 +236,7 @@ class ResponseEntityTests {
|
||||
HttpHeaders responseHeaders = responseEntity.getHeaders();
|
||||
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseHeaders).hasSize(1);
|
||||
assertThat(responseHeaders.size()).isOne();
|
||||
assertThat(responseHeaders.get("X-CustomHeader")).hasSize(1);
|
||||
assertThat(responseHeaders.getFirst("X-CustomHeader")).isEqualTo("vale");
|
||||
|
||||
@@ -250,7 +250,7 @@ class ResponseEntityTests {
|
||||
ResponseEntity.ok().headers((HttpHeaders) null).build();
|
||||
|
||||
assertThat(responseEntityWithEmptyHeaders.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntityWithEmptyHeaders.getHeaders()).isEmpty();
|
||||
assertThat(responseEntityWithEmptyHeaders.getHeaders().isEmpty()).isTrue();
|
||||
assertThat(responseEntityWithNullHeaders.toString()).isEqualTo(responseEntityWithEmptyHeaders.toString());
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ class ResponseEntityTests {
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getHeaders().containsKey(HttpHeaders.CACHE_CONTROL)).isFalse();
|
||||
assertThat(responseEntity.getHeaders().containsHeader(HttpHeaders.CACHE_CONTROL)).isFalse();
|
||||
assertThat(responseEntity.getBody()).isEqualTo(entity);
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ class ResponseEntityTests {
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getHeaders().containsKey(HttpHeaders.CACHE_CONTROL)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().containsHeader(HttpHeaders.CACHE_CONTROL)).isTrue();
|
||||
assertThat(responseEntity.getBody()).isEqualTo(entity);
|
||||
String cacheControlHeader = responseEntity.getHeaders().getCacheControl();
|
||||
assertThat(cacheControlHeader).isEqualTo(
|
||||
@@ -299,7 +299,7 @@ class ResponseEntityTests {
|
||||
|
||||
assertThat(responseEntity).isNotNull();
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getHeaders().containsKey(HttpHeaders.CACHE_CONTROL)).isTrue();
|
||||
assertThat(responseEntity.getHeaders().containsHeader(HttpHeaders.CACHE_CONTROL)).isTrue();
|
||||
assertThat(responseEntity.getBody()).isEqualTo(entity);
|
||||
|
||||
String cacheControlHeader = responseEntity.getHeaders().getCacheControl();
|
||||
|
||||
@@ -98,9 +98,11 @@ abstract class AbstractHttpRequestFactoryTests extends AbstractMockWebServerTest
|
||||
|
||||
try (ClientHttpResponse response = request.execute()) {
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getHeaders()).as("Header not found").containsKey(headerName);
|
||||
assertThat(response.getHeaders()).as("Header value not found")
|
||||
.containsEntry(headerName, Arrays.asList(headerValue1, headerValue2));
|
||||
assertThat(response.getHeaders().containsHeader(headerName))
|
||||
.as("Header not found").isTrue();
|
||||
assertThat(response.getHeaders().hasHeaderValues(headerName, Arrays.asList(headerValue1, headerValue2)))
|
||||
.as("Header value not found")
|
||||
.isTrue();
|
||||
byte[] result = FileCopyUtils.copyToByteArray(response.getBody());
|
||||
assertThat(Arrays.equals(body, result)).as("Invalid body").isTrue();
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ class BufferingClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryT
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatus.OK);
|
||||
|
||||
assertThat(response.getHeaders().containsKey(headerName)).as("Header not found").isTrue();
|
||||
assertThat(response.getHeaders().containsKey(headerName)).as("Header not found").isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(headerName)).as("Header not found").isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(headerName)).as("Header not found").isTrue();
|
||||
|
||||
assertThat(response.getHeaders().get(headerName)).as("Header value not found").isEqualTo(Arrays.asList(headerValue1, headerValue2));
|
||||
assertThat(response.getHeaders().get(headerName)).as("Header value not found").isEqualTo(Arrays.asList(headerValue1, headerValue2));
|
||||
|
||||
@@ -103,7 +103,7 @@ class DefaultPartHttpMessageReaderTests {
|
||||
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(part -> {
|
||||
assertThat(part.headers()).isEmpty();
|
||||
assertThat(part.headers().isEmpty()).isTrue();
|
||||
part.content().subscribe(DataBufferUtils::release);
|
||||
})
|
||||
.verifyComplete();
|
||||
@@ -266,7 +266,7 @@ class DefaultPartHttpMessageReaderTests {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(part -> {
|
||||
assertThat(part.headers()).containsEntry("Føø", Collections.singletonList("Bår"));
|
||||
assertThat(part.headers().hasHeaderValues("Føø", Collections.singletonList("Bår"))).isTrue();
|
||||
testPart(part, null, "This is plain ASCII text.", latch);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
@@ -175,7 +175,7 @@ class MultipartHttpMessageWriterTests extends AbstractLeakCheckingTests {
|
||||
part = requestParts.getFirst("filePublisher");
|
||||
assertThat(part).isNotNull();
|
||||
assertThat(part.name()).isEqualTo("filePublisher");
|
||||
assertThat(part.headers()).containsEntry("foo", Collections.singletonList("bar"));
|
||||
assertThat(part.headers().hasHeaderValues("foo", Collections.singletonList("bar"))).isTrue();
|
||||
assertThat(((FilePart) part).filename()).isEqualTo("file.txt");
|
||||
value = decodeToString(part);
|
||||
assertThat(value).isEqualTo("AaBbCc");
|
||||
|
||||
@@ -42,7 +42,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.entry;
|
||||
import static org.springframework.core.ResolvableType.forClass;
|
||||
|
||||
/**
|
||||
@@ -72,7 +71,7 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = this.reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(form(headers -> assertThat(headers).isEmpty(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
|
||||
.assertNext(form(headers -> assertThat(headers.isEmpty()).isTrue(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
|
||||
.assertNext(form(headers -> assertThat(headers.getContentType()).isEqualTo(TEXT_PLAIN_ASCII),
|
||||
"This is explicitly typed plain ASCII text.\r\nIt DOES end with a linebreak.\r\n"))
|
||||
.verifyComplete();
|
||||
@@ -85,7 +84,7 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = this.reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(data(headers -> assertThat(headers).isEmpty(), bodyText("a"), true))
|
||||
.assertNext(data(headers -> assertThat(headers.isEmpty()).isTrue(), bodyText("a"), true))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@@ -143,8 +142,8 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = this.reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(form(headers -> assertThat(headers).contains(entry("Part", List.of("1"))), ""))
|
||||
.assertNext(data(headers -> assertThat(headers).contains(entry("Part", List.of("2"))), bodyText("a"), true))
|
||||
.assertNext(form(headers -> assertThat(headers.hasHeaderValues("Part", List.of("1"))).isTrue(), ""))
|
||||
.assertNext(data(headers -> assertThat(headers.hasHeaderValues("Part", List.of("2"))).isTrue(), bodyText("a"), true))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@@ -156,7 +155,7 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = this.reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result, 3)
|
||||
.assertNext(form(headers -> assertThat(headers).isEmpty(),
|
||||
.assertNext(form(headers -> assertThat(headers.isEmpty()).isTrue(),
|
||||
"This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
|
||||
.thenCancel()
|
||||
.verify();
|
||||
@@ -238,7 +237,7 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(form(headers -> assertThat(headers).isEmpty(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
|
||||
.assertNext(form(headers -> assertThat(headers.isEmpty()).isTrue(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
|
||||
.expectError(DecodingException.class)
|
||||
.verify();
|
||||
}
|
||||
@@ -283,7 +282,7 @@ class PartEventHttpMessageReaderTests {
|
||||
Flux<PartEvent> result = this.reader.read(forClass(PartEvent.class), request, emptyMap());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(data(headers -> assertThat(headers).containsEntry("Føø", List.of("Bår")),
|
||||
.assertNext(data(headers -> assertThat(headers.hasHeaderValues("Føø", List.of("Bår"))).isTrue(),
|
||||
bodyText("This is plain ASCII text."), true))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class ServletServerHttpRequestTests {
|
||||
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
assertThat(headers).as("No HttpHeaders returned").isNotNull();
|
||||
assertThat(headers.containsKey(headerName)).as("Invalid headers returned").isTrue();
|
||||
assertThat(headers.containsHeader(headerName)).as("Invalid headers returned").isTrue();
|
||||
List<String> headerValues = headers.get(headerName);
|
||||
assertThat(headerValues).as("No header values returned").isNotNull();
|
||||
assertThat(headerValues.size()).as("Invalid header values returned").isEqualTo(2);
|
||||
@@ -150,7 +150,7 @@ class ServletServerHttpRequestTests {
|
||||
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
assertThat(headers).as("No HttpHeaders returned").isNotNull();
|
||||
assertThat(headers.containsKey(headerName)).as("Invalid headers returned").isTrue();
|
||||
assertThat(headers.containsHeader(headerName)).as("Invalid headers returned").isTrue();
|
||||
List<String> headerValues = headers.get(headerName);
|
||||
assertThat(headerValues.size()).as("Invalid header values returned").isEqualTo(2);
|
||||
assertThat(headerValues.contains(headerValue1)).as("Invalid header values returned").isTrue();
|
||||
@@ -162,7 +162,7 @@ class ServletServerHttpRequestTests {
|
||||
void getHeadersWithWildcardContentType() {
|
||||
mockRequest.setContentType("*/*");
|
||||
mockRequest.removeHeader("Content-Type");
|
||||
assertThat(request.getHeaders()).as("Invalid content-type should not raise exception").isEmpty();
|
||||
assertThat(request.getHeaders().isEmpty()).as("Invalid content-type should not raise exception").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -99,7 +99,7 @@ class ServletServerHttpResponseTests {
|
||||
|
||||
assertThat(this.response.getHeaders().getFirst(headerName)).isEqualTo(headerValue);
|
||||
assertThat(this.response.getHeaders().get(headerName)).containsExactly(headerValue);
|
||||
assertThat(this.response.getHeaders()).containsKey(headerName);
|
||||
assertThat(this.response.getHeaders().containsHeader(headerName)).isTrue();
|
||||
assertThat(this.response.getHeaders().getAccessControlAllowOrigin()).isEqualTo(headerValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class HeadersAdaptersTests {
|
||||
assertThat(headers2.get("TestHeader")).as("TestHeader")
|
||||
.containsExactly("first", "second", "third");
|
||||
// Using the headerSet approach, we keep the first encountered casing of any given key
|
||||
assertThat(headers2.keySet()).as("first casing variant").containsExactlyInAnyOrder("TestHeader", "SecondHeader");
|
||||
assertThat(headers2.headerNames()).as("first casing variant").containsExactlyInAnyOrder("TestHeader", "SecondHeader");
|
||||
assertThat(headers2.toString()).as("similar toString, no 'with native headers' dump")
|
||||
.isEqualTo(headers.toString().substring(0, headers.toString().indexOf(']') + 1));
|
||||
}
|
||||
@@ -132,7 +132,7 @@ class HeadersAdaptersTests {
|
||||
assertThat(headers2.get("TestHeader")).as("TestHeader")
|
||||
.containsExactly("first", "second", "third");
|
||||
// Ordering and casing are not guaranteed using the entrySet+put approach
|
||||
assertThat(headers2).as("two keys")
|
||||
assertThat(headers2.asMultiValueMap()).as("two keys")
|
||||
.containsKey("testheader")
|
||||
.containsKey("secondheader")
|
||||
.hasSize(2);
|
||||
@@ -148,7 +148,10 @@ class HeadersAdaptersTests {
|
||||
assertThat(headers2.get("TestHeader")).as("TestHeader")
|
||||
.containsExactly("first", "second", "third");
|
||||
// Ordering and casing are not guaranteed using the putAll approach
|
||||
assertThat(headers2).as("two keys").containsOnlyKeys("testheader", "secondheader");
|
||||
assertThat(headers2.asMultiValueMap()).as("two keys")
|
||||
.containsKey("testheader")
|
||||
.containsKey("secondheader")
|
||||
.hasSize(2);
|
||||
assertThat(headers2.toString()).as("similar toString, no 'with native headers' dump")
|
||||
.isEqualToIgnoringCase(headers.toString().substring(0, headers.toString().indexOf(']') + 1));
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ class ServerHttpResponseTests {
|
||||
assertThat(response.statusCodeWritten).isFalse();
|
||||
assertThat(response.headersWritten).isFalse();
|
||||
assertThat(response.cookiesWritten).isFalse();
|
||||
assertThat(headers).doesNotContainKeys(HttpHeaders.CONTENT_TYPE, HttpHeaders.CONTENT_LENGTH,
|
||||
assertThat(headers.headerNames()).doesNotContain(HttpHeaders.CONTENT_TYPE, HttpHeaders.CONTENT_LENGTH,
|
||||
HttpHeaders.CONTENT_ENCODING);
|
||||
assertThat(response.body).isEmpty();
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class ServerHttpResponseTests {
|
||||
assertThat(response.headersWritten).isFalse();
|
||||
assertThat(response.cookiesWritten).isFalse();
|
||||
assertThat(response.isCommitted()).isFalse();
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).isTrue();
|
||||
|
||||
// Handle the error
|
||||
response.setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
|
||||
|
||||
@@ -104,7 +104,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Could not parse Content-Type.");
|
||||
assertDetailMessageCode(ex, "parseError", null);
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,7 +117,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Acceptable representations: [application/json, application/cbor].");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getSupportedMediaTypes()});
|
||||
|
||||
assertThat(ex.getHeaders()).hasSize(1);
|
||||
assertThat(ex.getHeaders().size()).isOne();
|
||||
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Could not parse Accept header.");
|
||||
assertDetailMessageCode(ex, "parseError", null);
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -143,7 +143,7 @@ class ErrorResponseExceptionTests {
|
||||
assertStatus(ex, HttpStatus.SERVICE_UNAVAILABLE);
|
||||
assertDetail(ex, null);
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -156,7 +156,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Method 'PUT' is not supported.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getMethod(), ex.getSupportedHttpMethods()});
|
||||
|
||||
assertThat(ex.getHeaders()).hasSize(1);
|
||||
assertThat(ex.getHeaders().size()).isOne();
|
||||
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST);
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required header 'Authorization' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getHeaderName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,7 +181,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required parameter 'query' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getParameterName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -194,7 +194,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required path parameter 'region' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getVariableName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -206,7 +206,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required path variable 'id' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getVariableName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -218,7 +218,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required cookie 'oreo' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getCookieName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -231,7 +231,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Invalid request parameters.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {List.of("\"foo=bar, bar=baz\"")});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -243,7 +243,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required part 'file' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getRequestPartName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -258,7 +258,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Invalid request content.");
|
||||
testHelper.assertMessages(ex, ex.getAllErrors());
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -306,7 +306,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Could not parse Content-Type.");
|
||||
assertDetailMessageCode(ex, "parseError", null);
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -319,7 +319,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Acceptable representations: [application/json, application/cbor].");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getSupportedMediaTypes()});
|
||||
|
||||
assertThat(ex.getHeaders()).hasSize(1);
|
||||
assertThat(ex.getHeaders().size()).isOne();
|
||||
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes);
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Could not parse Accept header.");
|
||||
assertDetailMessageCode(ex, "parseError", null);
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -345,7 +345,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Failure");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getReason()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -358,7 +358,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Required header 'foo' is not present.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getLabel(), ex.getName()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -373,7 +373,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Invalid request parameters.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getConditions()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -388,7 +388,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Invalid request content.");
|
||||
testHelper.assertMessages(ex, ex.getAllErrors());
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -401,7 +401,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Supported methods: [GET, POST]");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getHttpMethod(), supportedMethods});
|
||||
|
||||
assertThat(ex.getHeaders()).hasSize(1);
|
||||
assertThat(ex.getHeaders().size()).isOne();
|
||||
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST);
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ class ErrorResponseExceptionTests {
|
||||
assertDetail(ex, "Request method 'PUT' is not supported.");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getHttpMethod(), Collections.emptyList()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
assertThat(ex.getHeaders().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-30300
|
||||
|
||||
@@ -36,7 +36,7 @@ class ErrorResponseTests {
|
||||
void createWithHttpHeader() {
|
||||
ErrorResponse response = ErrorResponse.builder(new IllegalStateException(), HttpStatus.BAD_REQUEST, "test")
|
||||
.header("header", "value").build();
|
||||
assertThat(response.getHeaders()).containsOnly(entry("header", List.of("value")));
|
||||
assertThat(response.getHeaders().asMultiValueMap()).containsOnly(entry("header", List.of("value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -47,7 +47,7 @@ class ErrorResponseTests {
|
||||
headers.add("header", "value2");
|
||||
headers.add("another", "value3");
|
||||
}).build();
|
||||
assertThat(response.getHeaders()).containsOnly(entry("header", List.of("value", "value2")),
|
||||
assertThat(response.getHeaders().asMultiValueMap()).containsOnly(entry("header", List.of("value", "value2")),
|
||||
entry("another", List.of("value3")));
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class RestClientResponseExceptionTests {
|
||||
|
||||
HttpHeaders responseHeaders = ex.getResponseHeaders();
|
||||
assertThat(responseHeaders).isNotNull();
|
||||
assertThat(responseHeaders).hasSize(1);
|
||||
assertThat(responseHeaders.size()).isOne();
|
||||
assertThat(responseHeaders.getFirst("FOO")).isEqualTo("bar");
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
@@ -81,7 +81,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
@@ -93,7 +93,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
@@ -105,7 +105,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(null, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
}
|
||||
|
||||
@@ -116,10 +116,10 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("*");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE)).isFalse();
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
@@ -135,9 +135,9 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isEqualTo("true");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
@@ -156,9 +156,9 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isEqualTo("true");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
@@ -173,7 +173,7 @@ class DefaultCorsProcessorTests {
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-26892
|
||||
@@ -187,7 +187,7 @@ class DefaultCorsProcessorTests {
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-33682
|
||||
@@ -202,7 +202,7 @@ class DefaultCorsProcessorTests {
|
||||
|
||||
assertThat(result).isFalse();
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -214,9 +214,9 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).contains("header1");
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)).contains("header2");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
@@ -271,7 +271,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
@@ -284,7 +284,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
@@ -299,7 +299,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
@@ -320,11 +320,11 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("*");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)).isEqualTo("GET,PUT");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
@@ -345,9 +345,9 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)).isEqualTo("true");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
@@ -372,7 +372,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
@@ -398,8 +398,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://domain2.com");
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
@@ -420,8 +420,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).contains("Header1");
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).contains("Header2");
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).doesNotContain("Header3");
|
||||
@@ -442,8 +442,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_HEADERS)).isTrue();
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).contains("Header1");
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).contains("Header2");
|
||||
assertThat(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS)).doesNotContain("*");
|
||||
@@ -464,8 +464,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_HEADERS)).isFalse();
|
||||
assertThat(response.getHeaders().get(VARY)).contains(ORIGIN,
|
||||
ACCESS_CONTROL_REQUEST_METHOD, ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
@@ -479,7 +479,7 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(null, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@@ -513,8 +513,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isFalse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
}
|
||||
|
||||
@@ -530,8 +530,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isFalse();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isFalse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
}
|
||||
|
||||
@@ -548,8 +548,8 @@ class DefaultCorsProcessorTests {
|
||||
this.processor.process(this.conf, exchange);
|
||||
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsKey(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
|
||||
assertThat(response.getHeaders().containsHeader(DefaultCorsProcessor.ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK)).isTrue();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ class ForwardedHeaderTransformerTests {
|
||||
|
||||
private void assertForwardedHeadersRemoved(ServerHttpRequest request) {
|
||||
ForwardedHeaderTransformer.FORWARDED_HEADER_NAMES
|
||||
.forEach(name -> assertThat(request.getHeaders().containsKey(name)).isFalse());
|
||||
.forEach(name -> assertThat(request.getHeaders().containsHeader(name)).isFalse());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -170,7 +170,8 @@ class KotlinSerializationCborHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -181,7 +182,8 @@ class KotlinSerializationCborHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -191,7 +193,8 @@ class KotlinSerializationCborHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBeanArray, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -202,7 +205,8 @@ class KotlinSerializationCborHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(listOf(serializableBean), ResolvableType.forType(typeOf<List<SerializableBean>>().javaType), null, outputMessage, null)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
|
||||
@@ -258,7 +258,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result)
|
||||
.contains("\"bytes\":[1,2]")
|
||||
.contains("\"array\":[\"Foo\",\"Bar\"]")
|
||||
@@ -277,7 +278,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result)
|
||||
.contains("\"bytes\":[1,2]")
|
||||
.contains("\"array\":[\"Foo\",\"Bar\"]")
|
||||
@@ -299,7 +301,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result).isEqualTo(expectedJson)
|
||||
}
|
||||
|
||||
@@ -317,7 +320,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result).isEqualTo(expectedJson)
|
||||
}
|
||||
|
||||
@@ -331,7 +335,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_16BE)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf(contentType.toString()))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf(contentType.toString()))
|
||||
assertThat(result).isEqualTo("\"H\u00e9llo W\u00f6rld\"")
|
||||
}
|
||||
|
||||
@@ -367,7 +372,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result).isEqualTo("1.0")
|
||||
}
|
||||
|
||||
@@ -384,7 +390,8 @@ class KotlinSerializationJsonHttpMessageConverterTests {
|
||||
|
||||
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/json"))
|
||||
assertThat(result).isEqualTo(expectedJson)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -197,7 +198,8 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -207,7 +209,8 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(serializableBeanArray, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@@ -218,7 +221,8 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
|
||||
|
||||
this.converter.write(listOf(serializableBean), ResolvableType.forType(typeOf<List<SerializableBean>>().javaType), null, outputMessage, null)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
@Suppress("DEPRECATION")
|
||||
assertThat(outputMessage.headers.asMultiValueMap()).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
|
||||
@@ -299,9 +299,18 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||
/**
|
||||
* Add the given header values.
|
||||
* @param headers the header values
|
||||
* @deprecated Use {@link #headers(HttpHeaders)}
|
||||
*/
|
||||
@Deprecated
|
||||
B headers(MultiValueMap<String, String> headers);
|
||||
|
||||
/**
|
||||
* Add the given header values.
|
||||
* @param headers the header values
|
||||
* @since 7.0
|
||||
*/
|
||||
B headers(HttpHeaders headers);
|
||||
|
||||
/**
|
||||
* Set the list of acceptable {@linkplain MediaType media types}, as
|
||||
* specified by the {@code Accept} header.
|
||||
@@ -491,11 +500,18 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public BodyBuilder headers(MultiValueMap<String, String> headers) {
|
||||
this.headers.putAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyBuilder headers(HttpHeaders headers) {
|
||||
this.headers.putAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyBuilder accept(MediaType... acceptableMediaTypes) {
|
||||
this.headers.setAccept(Arrays.asList(acceptableMediaTypes));
|
||||
|
||||
@@ -129,7 +129,7 @@ public class MockPart implements Part {
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaderNames() {
|
||||
return this.headers.keySet();
|
||||
return this.headers.headerNames();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user