Refactor HTTP Cookie support
There is now an HttpCookie (simple name-value pair) and separately a ServerHttpCookie sub-class with additional attributes that a server can send to clients. HttpHeaders is no longer the place to access cookies. Instead there is a read-only HttpCookie map on ServerHttpRequest and a mutable ServerHttpCookie map on ServerHttpResponse. Cookies are stored in a map that preserves their order.
This commit is contained in:
@@ -15,54 +15,28 @@
|
||||
*/
|
||||
package org.springframework.http;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Representation for an HTTP Cookie.
|
||||
* Represents an HTTP Cookie with a name and value.
|
||||
*
|
||||
* <p>Use the {@link #clientCookie} factory method to create a client-to-server,
|
||||
* name-value pair cookie and the {@link #serverCookie} factory method to build
|
||||
* a server-to-client cookie with additional attributes.
|
||||
* <p>The {@link ServerHttpCookie} sub-class exposes the extra attributes that
|
||||
* a server can include in a Set-Cookie response header.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>
|
||||
*/
|
||||
public final class HttpCookie {
|
||||
public class HttpCookie {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final Duration maxAge;
|
||||
|
||||
private final String domain;
|
||||
|
||||
private final String path;
|
||||
|
||||
private final boolean secure;
|
||||
|
||||
private final boolean httpOnly;
|
||||
|
||||
|
||||
private HttpCookie(String name, String value) {
|
||||
this(name, value, Duration.ofSeconds(-1), null, null, false, false);
|
||||
}
|
||||
|
||||
private HttpCookie(String name, String value, Duration maxAge, String domain, String path,
|
||||
boolean secure, boolean httpOnly) {
|
||||
|
||||
public HttpCookie(String name, String value) {
|
||||
Assert.hasLength(name, "'name' is required and must not be empty.");
|
||||
Assert.notNull(maxAge);
|
||||
this.name = name;
|
||||
this.value = (value != null ? value : "");
|
||||
this.maxAge = maxAge;
|
||||
this.domain = domain;
|
||||
this.path = path;
|
||||
this.secure = secure;
|
||||
this.httpOnly = httpOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,59 +47,16 @@ public final class HttpCookie {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie value.
|
||||
* Return the cookie value or an empty string, never {@code null}.
|
||||
*/
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Max-Age" attribute in seconds.
|
||||
*
|
||||
* <p>A positive value indicates when the cookie expires relative to the
|
||||
* current time. A value of 0 means the cookie should expire immediately.
|
||||
* A negative value means no "Max-Age" attribute in which case the cookie
|
||||
* is removed when the browser is closed.
|
||||
*/
|
||||
public Duration getMaxAge() {
|
||||
return this.maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Domain" attribute.
|
||||
*/
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Path" attribute.
|
||||
*/
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the cookie has the "Secure" attribute.
|
||||
*/
|
||||
public boolean isSecure() {
|
||||
return this.secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the cookie has the "HttpOnly" attribute.
|
||||
* @see <a href="http://www.owasp.org/index.php/HTTPOnly">http://www.owasp.org/index.php/HTTPOnly</a>
|
||||
*/
|
||||
public boolean isHttpOnly() {
|
||||
return this.httpOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.name.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.domain);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.path);
|
||||
return result;
|
||||
return this.name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,122 +68,7 @@ public final class HttpCookie {
|
||||
return false;
|
||||
}
|
||||
HttpCookie otherCookie = (HttpCookie) other;
|
||||
return (this.name.equalsIgnoreCase(otherCookie.getName()) &&
|
||||
ObjectUtils.nullSafeEquals(this.path, otherCookie.getPath()) &&
|
||||
ObjectUtils.nullSafeEquals(this.domain, otherCookie.getDomain()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a cookie sent from a client to a server.
|
||||
* Client cookies are name-value pairs only without attributes.
|
||||
* @param name the cookie name
|
||||
* @param value the cookie value
|
||||
* @return the created cookie instance
|
||||
*/
|
||||
public static HttpCookie clientCookie(String name, String value) {
|
||||
return new HttpCookie(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to obtain a builder for a server-defined cookie that starts
|
||||
* with a name-value pair and may also include attributes.
|
||||
* @param name the cookie name
|
||||
* @param value the cookie value
|
||||
* @return the created cookie instance
|
||||
*/
|
||||
public static HttpCookieBuilder serverCookie(final String name, final String value) {
|
||||
|
||||
return new HttpCookieBuilder() {
|
||||
|
||||
private Duration maxAge = Duration.ofSeconds(-1);
|
||||
|
||||
private String domain;
|
||||
|
||||
private String path;
|
||||
|
||||
private boolean secure;
|
||||
|
||||
private boolean httpOnly;
|
||||
|
||||
|
||||
@Override
|
||||
public HttpCookieBuilder maxAge(Duration maxAge) {
|
||||
this.maxAge = maxAge;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCookieBuilder domain(String domain) {
|
||||
this.domain = domain;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCookieBuilder path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCookieBuilder secure() {
|
||||
this.secure = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCookieBuilder httpOnly() {
|
||||
this.httpOnly = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpCookie build() {
|
||||
return new HttpCookie(name, value, this.maxAge, this.domain, this.path,
|
||||
this.secure, this.httpOnly);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a server-defined HttpCookie with attributes.
|
||||
*/
|
||||
public interface HttpCookieBuilder {
|
||||
|
||||
/**
|
||||
* Set the cookie "Max-Age" attribute.
|
||||
*
|
||||
* <p>A positive value indicates when the cookie should expire relative
|
||||
* to the current time. A value of 0 means the cookie should expire
|
||||
* immediately. A negative value results in no "Max-Age" attribute in
|
||||
* which case the cookie is removed when the browser is closed.
|
||||
*/
|
||||
HttpCookieBuilder maxAge(Duration maxAge);
|
||||
|
||||
/**
|
||||
* Set the cookie "Path" attribute.
|
||||
*/
|
||||
HttpCookieBuilder path(String path);
|
||||
|
||||
/**
|
||||
* Set the cookie "Domain" attribute.
|
||||
*/
|
||||
HttpCookieBuilder domain(String domain);
|
||||
|
||||
/**
|
||||
* Add the "Secure" attribute to the cookie.
|
||||
*/
|
||||
HttpCookieBuilder secure();
|
||||
|
||||
/**
|
||||
* Add the "HttpOnly" attribute to the cookie.
|
||||
* @see <a href="http://www.owasp.org/index.php/HTTPOnly">http://www.owasp.org/index.php/HTTPOnly</a>
|
||||
*/
|
||||
HttpCookieBuilder httpOnly();
|
||||
|
||||
/**
|
||||
* Create the HttpCookie.
|
||||
*/
|
||||
HttpCookie build();
|
||||
return (this.name.equalsIgnoreCase(otherCookie.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represents a server-side cookie with extra attributes that a server can
|
||||
* include in a Set-Cookie response header.
|
||||
*
|
||||
* <p>Use {@link #with} to create a {@code ServerHttpCookie}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>
|
||||
*/
|
||||
public final class ServerHttpCookie extends HttpCookie {
|
||||
|
||||
private final Duration maxAge;
|
||||
|
||||
private final Optional<String> domain;
|
||||
|
||||
private final Optional<String> path;
|
||||
|
||||
private final boolean secure;
|
||||
|
||||
private final boolean httpOnly;
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor. See {@link #with(String, String)}.
|
||||
*/
|
||||
private ServerHttpCookie(String name, String value, Duration maxAge, String domain,
|
||||
String path, boolean secure, boolean httpOnly) {
|
||||
|
||||
super(name, value);
|
||||
Assert.notNull(maxAge);
|
||||
this.maxAge = maxAge;
|
||||
this.domain = Optional.ofNullable(domain);
|
||||
this.path = Optional.ofNullable(path);
|
||||
this.secure = secure;
|
||||
this.httpOnly = httpOnly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the cookie "Max-Age" attribute in seconds.
|
||||
*
|
||||
* <p>A positive value indicates when the cookie expires relative to the
|
||||
* current time. A value of 0 means the cookie should expire immediately.
|
||||
* A negative value means no "Max-Age" attribute in which case the cookie
|
||||
* is removed when the browser is closed.
|
||||
*/
|
||||
public Duration getMaxAge() {
|
||||
return this.maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Domain" attribute.
|
||||
*/
|
||||
public Optional<String> getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Path" attribute.
|
||||
*/
|
||||
public Optional<String> getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the cookie has the "Secure" attribute.
|
||||
*/
|
||||
public boolean isSecure() {
|
||||
return this.secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the cookie has the "HttpOnly" attribute.
|
||||
* @see <a href="http://www.owasp.org/index.php/HTTPOnly">http://www.owasp.org/index.php/HTTPOnly</a>
|
||||
*/
|
||||
public boolean isHttpOnly() {
|
||||
return this.httpOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.domain);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.path);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ServerHttpCookie)) {
|
||||
return false;
|
||||
}
|
||||
ServerHttpCookie otherCookie = (ServerHttpCookie) other;
|
||||
return (getName().equalsIgnoreCase(otherCookie.getName()) &&
|
||||
ObjectUtils.nullSafeEquals(this.path, otherCookie.getPath()) &&
|
||||
ObjectUtils.nullSafeEquals(this.domain, otherCookie.getDomain()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method to obtain a builder for a server-defined cookie that starts
|
||||
* with a name-value pair and may also include attributes.
|
||||
* @param name the cookie name
|
||||
* @param value the cookie value
|
||||
* @return the created cookie instance
|
||||
*/
|
||||
public static ServerHttpCookieBuilder with(final String name, final String value) {
|
||||
|
||||
return new ServerHttpCookieBuilder() {
|
||||
|
||||
private Duration maxAge = Duration.ofSeconds(-1);
|
||||
|
||||
private String domain;
|
||||
|
||||
private String path;
|
||||
|
||||
private boolean secure;
|
||||
|
||||
private boolean httpOnly;
|
||||
|
||||
|
||||
@Override
|
||||
public ServerHttpCookieBuilder maxAge(Duration maxAge) {
|
||||
this.maxAge = maxAge;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpCookieBuilder domain(String domain) {
|
||||
this.domain = domain;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpCookieBuilder path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpCookieBuilder secure() {
|
||||
this.secure = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpCookieBuilder httpOnly() {
|
||||
this.httpOnly = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpCookie build() {
|
||||
return new ServerHttpCookie(name, value, this.maxAge, this.domain, this.path,
|
||||
this.secure, this.httpOnly);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a server-defined HttpCookie with attributes.
|
||||
*/
|
||||
public interface ServerHttpCookieBuilder {
|
||||
|
||||
/**
|
||||
* Set the cookie "Max-Age" attribute.
|
||||
*
|
||||
* <p>A positive value indicates when the cookie should expire relative
|
||||
* to the current time. A value of 0 means the cookie should expire
|
||||
* immediately. A negative value results in no "Max-Age" attribute in
|
||||
* which case the cookie is removed when the browser is closed.
|
||||
*/
|
||||
ServerHttpCookieBuilder maxAge(Duration maxAge);
|
||||
|
||||
/**
|
||||
* Set the cookie "Path" attribute.
|
||||
*/
|
||||
ServerHttpCookieBuilder path(String path);
|
||||
|
||||
/**
|
||||
* Set the cookie "Domain" attribute.
|
||||
*/
|
||||
ServerHttpCookieBuilder domain(String domain);
|
||||
|
||||
/**
|
||||
* Add the "Secure" attribute to the cookie.
|
||||
*/
|
||||
ServerHttpCookieBuilder secure();
|
||||
|
||||
/**
|
||||
* Add the "HttpOnly" attribute to the cookie.
|
||||
* @see <a href="http://www.owasp.org/index.php/HTTPOnly">http://www.owasp.org/index.php/HTTPOnly</a>
|
||||
*/
|
||||
ServerHttpCookieBuilder httpOnly();
|
||||
|
||||
/**
|
||||
* Create the HttpCookie.
|
||||
*/
|
||||
ServerHttpCookie build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,14 +17,14 @@ package org.springframework.http.server.reactive;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Common base class for {@link ServerHttpRequest} implementations.
|
||||
@@ -37,6 +37,8 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
|
||||
private HttpHeaders headers;
|
||||
|
||||
private MultiValueMap<String, HttpCookie> cookies;
|
||||
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
@@ -61,7 +63,7 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
if (this.headers == null) {
|
||||
this.headers = new HttpHeaders(new HttpCookieInputMap());
|
||||
this.headers = new HttpHeaders();
|
||||
initHeaders(this.headers);
|
||||
}
|
||||
return this.headers;
|
||||
@@ -74,89 +76,20 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
*/
|
||||
protected abstract void initHeaders(HttpHeaders headers);
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, HttpCookie> getCookies() {
|
||||
if (this.cookies == null) {
|
||||
this.cookies = new LinkedMultiValueMap<String, HttpCookie>();
|
||||
initCookies(this.cookies);
|
||||
}
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the cookies from the underlying request. Invoked lazily on the
|
||||
* first access to cookies via {@link #getHeaders()} and then cached.
|
||||
* @param cookies the map to add cookies to
|
||||
*/
|
||||
protected abstract void initCookies(Map<String, List<HttpCookie>> cookies);
|
||||
|
||||
|
||||
/**
|
||||
* Read-only map of input cookies with lazy initialization.
|
||||
*/
|
||||
private class HttpCookieInputMap implements Map<String, List<HttpCookie>> {
|
||||
|
||||
private Map<String, List<HttpCookie>> cookies;
|
||||
|
||||
|
||||
private Map<String, List<HttpCookie>> getCookies() {
|
||||
if (this.cookies == null) {
|
||||
this.cookies = new LinkedCaseInsensitiveMap<>();
|
||||
initCookies(this.cookies);
|
||||
}
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return getCookies().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return getCookies().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return getCookies().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return getCookies().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> get(Object key) {
|
||||
return getCookies().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return getCookies().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<List<HttpCookie>> values() {
|
||||
return getCookies().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, List<HttpCookie>>> entrySet() {
|
||||
return getCookies().entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> put(String key, List<HttpCookie> value) {
|
||||
throw new UnsupportedOperationException("Can't modify client sent cookies.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> remove(Object key) {
|
||||
throw new UnsupportedOperationException("Can't modify client sent cookies.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<HttpCookie>> map) {
|
||||
throw new UnsupportedOperationException("Can't modify client sent cookies.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException("Can't modify client sent cookies.");
|
||||
}
|
||||
}
|
||||
protected abstract void initCookies(MultiValueMap<String, HttpCookie> cookies);
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.http.server.reactive;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -24,8 +25,13 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,6 +43,8 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
private final MultiValueMap<String, ServerHttpCookie> cookies;
|
||||
|
||||
private AtomicReference<State> state = new AtomicReference<>(State.NEW);
|
||||
|
||||
private final List<Supplier<? extends Mono<Void>>> beforeCommitActions = new ArrayList<>(4);
|
||||
@@ -44,6 +52,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
|
||||
protected AbstractServerHttpResponse() {
|
||||
this.headers = new HttpHeaders();
|
||||
this.cookies = new LinkedMultiValueMap<String, ServerHttpCookie>();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +64,14 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, ServerHttpCookie> getCookies() {
|
||||
if (State.COMITTED.equals(this.state.get())) {
|
||||
return CollectionUtils.unmodifiableMultiValueMap(this.cookies);
|
||||
}
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> setBody(Publisher<DataBuffer> publisher) {
|
||||
return new WriteWithOperator<>(publisher, writePublisher ->
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.http.server.reactive;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.io.buffer.Buffer;
|
||||
@@ -33,6 +30,7 @@ import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Adapt {@link ServerHttpRequest} to the Reactor Net {@link HttpChannel}.
|
||||
@@ -76,15 +74,11 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCookies(Map<String, List<HttpCookie>> cookies) {
|
||||
protected void initCookies(MultiValueMap<String, HttpCookie> cookies) {
|
||||
for (String name : this.channel.cookies().keySet()) {
|
||||
List<HttpCookie> list = cookies.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
cookies.put(name, list);
|
||||
}
|
||||
for (Cookie cookie : this.channel.cookies().get(name)) {
|
||||
list.add(HttpCookie.clientCookie(name, cookie.value()));
|
||||
HttpCookie httpCookie = new HttpCookie(name, cookie.value());
|
||||
cookies.add(name, httpCookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -26,8 +27,8 @@ import reactor.io.net.http.model.Cookie;
|
||||
import reactor.io.net.http.model.Status;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -73,10 +74,10 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
@Override
|
||||
protected void writeCookies() {
|
||||
for (String name : getHeaders().getCookies().keySet()) {
|
||||
for (HttpCookie httpCookie : getHeaders().getCookies().get(name)) {
|
||||
Cookie reactorCookie = new ReactorCookie(httpCookie);
|
||||
this.channel.addResponseCookie(name, reactorCookie);
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ServerHttpCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new ReactorCookie(httpCookie);
|
||||
this.channel.addResponseCookie(name, cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,10 +88,10 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse {
|
||||
*/
|
||||
private final static class ReactorCookie extends Cookie {
|
||||
|
||||
private final HttpCookie httpCookie;
|
||||
private final ServerHttpCookie httpCookie;
|
||||
|
||||
|
||||
public ReactorCookie(HttpCookie httpCookie) {
|
||||
public ReactorCookie(ServerHttpCookie httpCookie) {
|
||||
this.httpCookie = httpCookie;
|
||||
}
|
||||
|
||||
@@ -117,12 +118,14 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
@Override
|
||||
public String domain() {
|
||||
return this.httpCookie.getDomain();
|
||||
Optional<String> domain = this.httpCookie.getDomain();
|
||||
return (domain.isPresent() ? domain.get() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return this.httpCookie.getPath();
|
||||
Optional<String> path = this.httpCookie.getPath();
|
||||
return (path.isPresent() ? path.get() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.http.server.reactive;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
@@ -35,6 +32,7 @@ import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Adapt {@link ServerHttpRequest} to the RxNetty {@link HttpServerRequest}.
|
||||
@@ -79,15 +77,11 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCookies(Map<String, List<HttpCookie>> map) {
|
||||
protected void initCookies(MultiValueMap<String, HttpCookie> cookies) {
|
||||
for (String name : this.request.getCookies().keySet()) {
|
||||
List<HttpCookie> list = map.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
map.put(name, list);
|
||||
}
|
||||
for (Cookie cookie : this.request.getCookies().get(name)) {
|
||||
list.add(HttpCookie.clientCookie(name, cookie.value()));
|
||||
HttpCookie httpCookie = new HttpCookie(name, cookie.value());
|
||||
cookies.add(name, httpCookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import rx.Observable;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.NettyDataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -85,14 +85,18 @@ public class RxNettyServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
@Override
|
||||
protected void writeCookies() {
|
||||
for (String name : getHeaders().getCookies().keySet()) {
|
||||
for (HttpCookie httpCookie : getHeaders().getCookies().get(name)) {
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ServerHttpCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new DefaultCookie(name, httpCookie.getValue());
|
||||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge(httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
if (httpCookie.getDomain().isPresent()) {
|
||||
cookie.setDomain(httpCookie.getDomain().get());
|
||||
}
|
||||
if (httpCookie.getPath().isPresent()) {
|
||||
cookie.setPath(httpCookie.getPath().get());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.ReactiveHttpInputMessage;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Represents a reactive server-side HTTP request
|
||||
@@ -26,4 +31,9 @@ import org.springframework.http.ReactiveHttpInputMessage;
|
||||
*/
|
||||
public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
|
||||
|
||||
/**
|
||||
* Return a read-only map of cookies sent by the client.
|
||||
*/
|
||||
MultiValueMap<String, HttpCookie> getCookies();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,16 @@
|
||||
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Represents a reactive server-side HTTP response.
|
||||
@@ -34,6 +40,11 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
|
||||
*/
|
||||
void setStatusCode(HttpStatus status);
|
||||
|
||||
/**
|
||||
* Return a mutable map with cookies to be sent to the client.
|
||||
*/
|
||||
MultiValueMap<String, ServerHttpCookie> getCookies();
|
||||
|
||||
/**
|
||||
* Indicate that request handling is complete, allowing for any cleanup or
|
||||
* end-of-processing tasks to be performed such as applying header changes
|
||||
|
||||
@@ -20,9 +20,7 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import javax.servlet.ReadListener;
|
||||
@@ -45,6 +43,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -127,17 +126,13 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCookies(Map<String, List<HttpCookie>> map) {
|
||||
protected void initCookies(MultiValueMap<String, HttpCookie> httpCookies) {
|
||||
Cookie[] cookies = this.request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
String name = cookie.getName();
|
||||
List<HttpCookie> list = map.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
map.put(name, list);
|
||||
}
|
||||
list.add(HttpCookie.clientCookie(name, cookie.getValue()));
|
||||
HttpCookie httpCookie = new HttpCookie(name, cookie.getValue());
|
||||
httpCookies.add(name, httpCookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ import org.reactivestreams.Subscription;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -98,17 +98,17 @@ public class ServletServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
@Override
|
||||
protected void writeCookies() {
|
||||
for (String name : getHeaders().getCookies().keySet()) {
|
||||
for (HttpCookie httpCookie : getHeaders().getCookies().get(name)) {
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ServerHttpCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new Cookie(name, httpCookie.getValue());
|
||||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
if (httpCookie.getDomain().isPresent()) {
|
||||
cookie.setDomain(httpCookie.getDomain().get());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
if (httpCookie.getPath().isPresent()) {
|
||||
cookie.setPath(httpCookie.getPath().get());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.http.server.reactive;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.handlers.Cookie;
|
||||
@@ -33,6 +30,7 @@ import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Adapt {@link ServerHttpRequest} to the Underow {@link HttpServerExchange}.
|
||||
@@ -79,15 +77,11 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCookies(Map<String, List<HttpCookie>> map) {
|
||||
protected void initCookies(MultiValueMap<String, HttpCookie> cookies) {
|
||||
for (String name : this.exchange.getRequestCookies().keySet()) {
|
||||
List<HttpCookie> list = map.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
map.put(name, list);
|
||||
}
|
||||
Cookie cookie = this.exchange.getRequestCookies().get(name);
|
||||
list.add(HttpCookie.clientCookie(name, cookie.getValue()));
|
||||
HttpCookie httpCookie = new HttpCookie(name, cookie.getValue());
|
||||
cookies.add(name, httpCookie);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -80,14 +80,18 @@ public class UndertowServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
@Override
|
||||
protected void writeCookies() {
|
||||
for (String name : getHeaders().getCookies().keySet()) {
|
||||
for (HttpCookie httpCookie : getHeaders().getCookies().get(name)) {
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ServerHttpCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new CookieImpl(name, httpCookie.getValue());
|
||||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
if (httpCookie.getDomain().isPresent()) {
|
||||
cookie.setDomain(httpCookie.getDomain().get());
|
||||
}
|
||||
if (httpCookie.getPath().isPresent()) {
|
||||
cookie.setPath(httpCookie.getPath().get());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.exchange.getResponseCookies().putIfAbsent(name, cookie);
|
||||
|
||||
@@ -18,12 +18,14 @@ package org.springframework.web.server.session;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
@@ -58,7 +60,7 @@ public class CookieWebSessionIdResolver implements WebSessionIdResolver {
|
||||
|
||||
/**
|
||||
* Set the value for the "Max-Age" attribute of the cookie that holds the
|
||||
* session id. For the range of values see {@link HttpCookie#getMaxAge()}.
|
||||
* session id. For the range of values see {@link ServerHttpCookie#getMaxAge()}.
|
||||
* <p>By default set to -1.
|
||||
* @param maxAge the maxAge duration value
|
||||
*/
|
||||
@@ -76,18 +78,17 @@ public class CookieWebSessionIdResolver implements WebSessionIdResolver {
|
||||
|
||||
@Override
|
||||
public Optional<String> resolveSessionId(ServerWebExchange exchange) {
|
||||
HttpHeaders headers = exchange.getRequest().getHeaders();
|
||||
List<HttpCookie> cookies = headers.getCookies().get(getCookieName());
|
||||
return (CollectionUtils.isEmpty(cookies) ?
|
||||
Optional.empty() : Optional.of(cookies.get(0).getValue()));
|
||||
MultiValueMap<String, HttpCookie> cookieMap = exchange.getRequest().getCookies();
|
||||
HttpCookie cookie = cookieMap.getFirst(getCookieName());
|
||||
return (cookie != null ? Optional.of(cookie.getValue()) : Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionId(ServerWebExchange exchange, String id) {
|
||||
Duration maxAge = (StringUtils.hasText(id) ? getCookieMaxAge() : Duration.ofSeconds(0));
|
||||
HttpCookie cookie = HttpCookie.serverCookie(getCookieName(), id).maxAge(maxAge).build();
|
||||
HttpHeaders headers = exchange.getResponse().getHeaders();
|
||||
headers.getCookies().put(getCookieName(), Collections.singletonList(cookie));
|
||||
ServerHttpCookie cookie = ServerHttpCookie.with(getCookieName(), id).maxAge(maxAge).build();
|
||||
MultiValueMap<String, ServerHttpCookie> cookieMap = exchange.getResponse().getCookies();
|
||||
cookieMap.set(getCookieName(), cookie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
@@ -98,12 +99,12 @@ public class CookieIntegrationTests extends AbstractHttpHandlerIntegrationTests
|
||||
@Override
|
||||
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
this.requestCookies = request.getHeaders().getCookies();
|
||||
this.requestCookies = request.getCookies();
|
||||
this.requestCookies.size(); // Cause lazy loading
|
||||
|
||||
response.getHeaders().addCookie(HttpCookie.serverCookie("SID", "31d4d96e407aad42")
|
||||
response.getCookies().add("SID", ServerHttpCookie.with("SID", "31d4d96e407aad42")
|
||||
.path("/").secure().httpOnly().build());
|
||||
response.getHeaders().addCookie(HttpCookie.serverCookie("lang", "en-US")
|
||||
response.getCookies().add("lang", ServerHttpCookie.with("lang", "en-US")
|
||||
.domain("example.com").path("/").build());
|
||||
|
||||
return response.setComplete();
|
||||
|
||||
@@ -21,8 +21,11 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -35,6 +38,8 @@ public class MockServerHttpRequest implements ServerHttpRequest {
|
||||
|
||||
private HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();
|
||||
|
||||
private Flux<DataBuffer> body;
|
||||
|
||||
|
||||
@@ -74,8 +79,9 @@ public class MockServerHttpRequest implements ServerHttpRequest {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
public void setHeaders(HttpHeaders headers) {
|
||||
this.headers = headers;
|
||||
@Override
|
||||
public MultiValueMap<String, HttpCookie> getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,9 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -34,6 +37,8 @@ public class MockServerHttpResponse implements ServerHttpResponse {
|
||||
|
||||
private HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private MultiValueMap<String, ServerHttpCookie> cookies = new LinkedMultiValueMap<>();
|
||||
|
||||
private Publisher<DataBuffer> body;
|
||||
|
||||
|
||||
@@ -51,6 +56,11 @@ public class MockServerHttpResponse implements ServerHttpResponse {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, ServerHttpCookie> getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
public Publisher<DataBuffer> getBody() {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ServerHttpCookie;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -81,17 +81,17 @@ public class ServerHttpResponseTests {
|
||||
|
||||
@Test
|
||||
public void beforeCommitWithSetBody() throws Exception {
|
||||
HttpCookie cookie = HttpCookie.serverCookie("ID", "123").build();
|
||||
ServerHttpCookie cookie = ServerHttpCookie.with("ID", "123").build();
|
||||
TestServerHttpResponse response = new TestServerHttpResponse();
|
||||
response.beforeCommit(() -> {
|
||||
response.getHeaders().addCookie(cookie);
|
||||
response.getCookies().add(cookie.getName(), cookie);
|
||||
return Mono.empty();
|
||||
});
|
||||
response.setBody(Flux.just(wrap("a"), wrap("b"), wrap("c"))).get();
|
||||
|
||||
assertTrue(response.headersWritten);
|
||||
assertTrue(response.cookiesWritten);
|
||||
assertSame(cookie, response.getHeaders().getCookies().get("ID").get(0));
|
||||
assertSame(cookie, response.getCookies().getFirst("ID"));
|
||||
|
||||
assertEquals(3, response.content.size());
|
||||
assertEquals("a", new String(response.content.get(0).asByteBuffer().array(), UTF_8));
|
||||
@@ -108,7 +108,7 @@ public class ServerHttpResponseTests {
|
||||
|
||||
assertTrue("beforeCommit action errors should be ignored", response.headersWritten);
|
||||
assertTrue("beforeCommit action errors should be ignored", response.cookiesWritten);
|
||||
assertNull(response.getHeaders().getCookies().get("ID"));
|
||||
assertNull(response.getCookies().get("ID"));
|
||||
|
||||
assertEquals(3, response.content.size());
|
||||
assertEquals("a", new String(response.content.get(0).asByteBuffer().array(), UTF_8));
|
||||
@@ -118,10 +118,10 @@ public class ServerHttpResponseTests {
|
||||
|
||||
@Test
|
||||
public void beforeCommitActionWithSetComplete() throws Exception {
|
||||
HttpCookie cookie = HttpCookie.serverCookie("ID", "123").build();
|
||||
ServerHttpCookie cookie = ServerHttpCookie.with("ID", "123").build();
|
||||
TestServerHttpResponse response = new TestServerHttpResponse();
|
||||
response.beforeCommit(() -> {
|
||||
response.getHeaders().addCookie(cookie);
|
||||
response.getCookies().add(cookie.getName(), cookie);
|
||||
return Mono.empty();
|
||||
});
|
||||
response.setComplete().get();
|
||||
@@ -129,7 +129,7 @@ public class ServerHttpResponseTests {
|
||||
assertTrue(response.headersWritten);
|
||||
assertTrue(response.cookiesWritten);
|
||||
assertTrue(response.content.isEmpty());
|
||||
assertSame(cookie, response.getHeaders().getCookies().get("ID").get(0));
|
||||
assertSame(cookie, response.getCookies().getFirst("ID"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user