diff --git a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java index c6f0d361ad..2894475d9c 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java @@ -20,6 +20,7 @@ import java.net.InetSocketAddress; import java.net.URI; import java.nio.charset.Charset; import java.security.Principal; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -32,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -59,6 +61,8 @@ public class MockServerRequest implements ServerRequest { private final MockHeaders headers; + private final MultiValueMap cookies; + @Nullable private final Object body; @@ -75,13 +79,15 @@ public class MockServerRequest implements ServerRequest { private Principal principal; - private MockServerRequest(HttpMethod method, URI uri, MockHeaders headers, @Nullable Object body, + private MockServerRequest(HttpMethod method, URI uri, MockHeaders headers, + MultiValueMap cookies, @Nullable Object body, Map attributes, MultiValueMap queryParams, Map pathVariables, @Nullable WebSession session, @Nullable Principal principal) { this.method = method; this.uri = uri; this.headers = headers; + this.cookies = cookies; this.body = body; this.attributes = attributes; this.queryParams = queryParams; @@ -106,6 +112,11 @@ public class MockServerRequest implements ServerRequest { return this.headers; } + @Override + public MultiValueMap cookies() { + return this.cookies; + } + @Override @SuppressWarnings("unchecked") public S body(BodyExtractor extractor) { @@ -182,6 +193,10 @@ public class MockServerRequest implements ServerRequest { Builder headers(HttpHeaders headers); + Builder cookie(HttpCookie... cookies); + + Builder cookies(MultiValueMap cookies); + Builder attribute(String name, Object value); Builder attributes(Map attributes); @@ -212,6 +227,8 @@ public class MockServerRequest implements ServerRequest { private MockHeaders headers = new MockHeaders(new HttpHeaders()); + private MultiValueMap cookies = new LinkedMultiValueMap<>(); + @Nullable private Object body; @@ -241,6 +258,19 @@ public class MockServerRequest implements ServerRequest { return this; } + @Override + public Builder cookie(HttpCookie... cookies) { + Arrays.stream(cookies).forEach(cookie -> this.cookies.add(cookie.getName(), cookie)); + return this; + } + + @Override + public Builder cookies(MultiValueMap cookies) { + Assert.notNull(cookies, "'cookies' must not be null"); + this.cookies = cookies; + return this; + } + @Override public Builder header(String key, String value) { Assert.notNull(key, "'key' must not be null"); @@ -318,14 +348,14 @@ public class MockServerRequest implements ServerRequest { @Override public MockServerRequest body(Object body) { this.body = body; - return new MockServerRequest(this.method, this.uri, this.headers, this.body, - this.attributes, this.queryParams, this.pathVariables, this.session, + return new MockServerRequest(this.method, this.uri, this.headers, this.cookies, + this.body, this.attributes, this.queryParams, this.pathVariables, this.session, this.principal); } @Override public MockServerRequest build() { - return new MockServerRequest(this.method, this.uri, this.headers, null, + return new MockServerRequest(this.method, this.uri, this.headers, this.cookies, null, this.attributes, this.queryParams, this.pathVariables, this.session, this.principal); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java index 38235b187c..26d16d9b17 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java @@ -32,6 +32,7 @@ import java.util.function.Function; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -40,6 +41,7 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.reactive.function.BodyExtractors; import org.springframework.web.reactive.function.UnsupportedMediaTypeException; @@ -95,6 +97,11 @@ class DefaultServerRequest implements ServerRequest { return this.headers; } + @Override + public MultiValueMap cookies() { + return request().getCookies(); + } + @Override public T body(BodyExtractor extractor) { return body(extractor, Collections.emptyMap()); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java index 46e6d24a35..3b2d4e1ba1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java @@ -34,11 +34,13 @@ import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.server.WebSession; import org.springframework.web.util.UriUtils; @@ -490,6 +492,11 @@ public abstract class RequestPredicates { return this.request.headers(); } + @Override + public MultiValueMap cookies() { + return this.request.cookies(); + } + @Override public T body(BodyExtractor extractor) { return this.request.body(extractor); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java index 15e5fc17ea..c5e0b1ab36 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java @@ -29,6 +29,7 @@ import java.util.OptionalLong; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -37,6 +38,7 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.json.Jackson2CodecSupport; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebSession; @@ -75,6 +77,11 @@ public interface ServerRequest { */ Headers headers(); + /** + * Return the cookies of this request. + */ + MultiValueMap cookies(); + /** * Extract the body with the given {@code BodyExtractor}. * @param extractor the {@code BodyExtractor} that reads from the request diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java index 4b88a66733..8b87c87d05 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java @@ -29,12 +29,14 @@ import java.util.OptionalLong; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.Assert; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerRequest; @@ -90,6 +92,11 @@ public class ServerRequestWrapper implements ServerRequest { return this.delegate.headers(); } + @Override + public MultiValueMap cookies() { + return this.delegate.cookies(); + } + @Override public T body(BodyExtractor extractor) { return this.delegate.body(extractor); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java index 303cb6dc02..3fe775d9ef 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java @@ -37,6 +37,7 @@ import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DefaultDataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -45,6 +46,8 @@ import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.HttpMessageReader; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerWebExchange; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.server.UnsupportedMediaTypeStatusException; import static org.junit.Assert.*; @@ -176,6 +179,22 @@ public class DefaultServerRequestTests { assertEquals(httpHeaders, headers.asHttpHeaders()); } + @Test + public void cookies() { + HttpCookie cookie = new HttpCookie("foo", "bar"); + MockServerHttpRequest mockRequest = MockServerHttpRequest.method(HttpMethod.GET, "http://example.com"). + cookie(cookie).build(); + MockServerWebExchange exchange = new MockServerWebExchange(mockRequest); + + DefaultServerRequest request = new DefaultServerRequest(exchange, messageReaders); + + MultiValueMap expected = new LinkedMultiValueMap<>(); + expected.add("foo", cookie); + + assertEquals(expected, request.cookies()); + + } + @Test public void body() throws Exception { DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java index d8b0f3b7e9..929dc6b1b7 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java @@ -20,6 +20,7 @@ import java.net.InetSocketAddress; import java.net.URI; import java.nio.charset.Charset; import java.security.Principal; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -32,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -57,6 +59,9 @@ public class MockServerRequest implements ServerRequest { private final MockHeaders headers; + private final MultiValueMap cookies; + + @Nullable private final Object body; private final Map attributes; @@ -65,18 +70,21 @@ public class MockServerRequest implements ServerRequest { private final Map pathVariables; + @Nullable private final WebSession session; + @Nullable private Principal principal; private MockServerRequest(HttpMethod method, URI uri, - MockHeaders headers, @Nullable Object body, Map attributes, - MultiValueMap queryParams, - Map pathVariables, WebSession session, Principal principal) { + MockHeaders headers, MultiValueMap cookies, @Nullable Object body, + Map attributes, MultiValueMap queryParams, + Map pathVariables, @Nullable WebSession session, @Nullable Principal principal) { this.method = method; this.uri = uri; this.headers = headers; + this.cookies = cookies; this.body = body; this.attributes = attributes; this.queryParams = queryParams; @@ -101,27 +109,36 @@ public class MockServerRequest implements ServerRequest { return this.headers; } + @Override + public MultiValueMap cookies() { + return this.cookies; + } + @Override @SuppressWarnings("unchecked") public S body(BodyExtractor extractor){ + Assert.state(this.body != null, "No body"); return (S) this.body; } @Override @SuppressWarnings("unchecked") public S body(BodyExtractor extractor, Map hints) { + Assert.state(this.body != null, "No body"); return (S) this.body; } @Override @SuppressWarnings("unchecked") public Mono bodyToMono(Class elementClass) { + Assert.state(this.body != null, "No body"); return (Mono) this.body; } @Override @SuppressWarnings("unchecked") public Flux bodyToFlux(Class elementClass) { + Assert.state(this.body != null, "No body"); return (Flux) this.body; } @@ -173,6 +190,10 @@ public class MockServerRequest implements ServerRequest { Builder headers(HttpHeaders headers); + Builder cookie(HttpCookie... cookies); + + Builder cookies(MultiValueMap cookies); + Builder attribute(String name, Object value); Builder attributes(Map attributes); @@ -203,6 +224,9 @@ public class MockServerRequest implements ServerRequest { private MockHeaders headers = new MockHeaders(new HttpHeaders()); + private MultiValueMap cookies = new LinkedMultiValueMap<>(); + + @Nullable private Object body; private Map attributes = new ConcurrentHashMap<>(); @@ -211,8 +235,10 @@ public class MockServerRequest implements ServerRequest { private Map pathVariables = new LinkedHashMap<>(); + @Nullable private WebSession session; + @Nullable private Principal principal; @Override @@ -244,6 +270,19 @@ public class MockServerRequest implements ServerRequest { return this; } + @Override + public Builder cookie(HttpCookie... cookies) { + Arrays.stream(cookies).forEach(cookie -> this.cookies.add(cookie.getName(), cookie)); + return this; + } + + @Override + public Builder cookies(MultiValueMap cookies) { + Assert.notNull(cookies, "'cookies' must not be null"); + this.cookies = cookies; + return this; + } + @Override public Builder attribute(String name, Object value) { Assert.notNull(name, "'name' must not be null"); @@ -306,14 +345,14 @@ public class MockServerRequest implements ServerRequest { @Override public MockServerRequest body(Object body) { this.body = body; - return new MockServerRequest(this.method, this.uri, this.headers, this.body, - this.attributes, this.queryParams, this.pathVariables, this.session, + return new MockServerRequest(this.method, this.uri, this.headers, this.cookies, + this.body, this.attributes, this.queryParams, this.pathVariables, this.session, this.principal); } @Override public MockServerRequest build() { - return new MockServerRequest(this.method, this.uri, this.headers, null, + return new MockServerRequest(this.method, this.uri, this.headers, this.cookies, null, this.attributes, this.queryParams, this.pathVariables, this.session, this.principal); }