Provide simple way to create ServerRequest

This commit introduces support for creating a new `ServerRequest` from
an existing instance. This is especially useful when filtering requests
in a HandlerFilterFunction.

Issue: SPR-16707
This commit is contained in:
Arjen Poutsma
2018-04-23 11:12:40 +02:00
parent f8c2d7ab51
commit 22edab852d
8 changed files with 786 additions and 9 deletions

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2002-2018 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.web.reactive.function.server;
import java.nio.charset.StandardCharsets;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseCookie;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange;
import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
*/
public class DefaultServerRequestBuilderTests {
private DataBufferFactory dataBufferFactory;
@Before
public void createBufferFactory() {
this.dataBufferFactory = new DefaultDataBufferFactory();
}
@Test
public void from() throws Exception {
MockServerHttpRequest request = MockServerHttpRequest.post("http://example.com")
.header("foo", "bar")
.build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
ServerRequest other =
ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Flux<DataBuffer> body = Flux.just("baz")
.map(s -> s.getBytes(StandardCharsets.UTF_8))
.map(dataBufferFactory::wrap);
ServerRequest result = ServerRequest.from(other)
.method(HttpMethod.HEAD)
.headers(httpHeaders -> httpHeaders.set("foo", "baar"))
.cookies(cookies -> cookies.set("baz", ResponseCookie.from("baz", "quux").build()))
.body(body)
.build();
assertEquals(HttpMethod.HEAD, result.method());
assertEquals(1, result.headers().asHttpHeaders().size());
assertEquals("baar", result.headers().asHttpHeaders().getFirst("foo"));
assertEquals(1, result.cookies().size());
assertEquals("quux", result.cookies().getFirst("baz").getValue());
StepVerifier.create(result.bodyToFlux(String.class))
.expectNext("baz")
.verifyComplete();
}
}

View File

@@ -40,6 +40,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRange;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.RequestPath;
@@ -50,6 +51,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyExtractor;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriComponentsBuilder;
@@ -90,12 +92,18 @@ public class MockServerRequest implements ServerRequest {
@Nullable
private final InetSocketAddress remoteAddress;
private final List<HttpMessageReader<?>> messageReaders;
@Nullable
private final ServerWebExchange exchange;
private MockServerRequest(HttpMethod method, URI uri, String contextPath, MockHeaders headers,
MultiValueMap<String, HttpCookie> cookies, @Nullable Object body,
Map<String, Object> attributes, MultiValueMap<String, String> queryParams,
Map<String, String> pathVariables, @Nullable WebSession session, @Nullable Principal principal,
@Nullable InetSocketAddress remoteAddress) {
@Nullable InetSocketAddress remoteAddress, List<HttpMessageReader<?>> messageReaders,
@Nullable ServerWebExchange exchange) {
this.method = method;
this.uri = uri;
@@ -109,6 +117,8 @@ public class MockServerRequest implements ServerRequest {
this.session = session;
this.principal = principal;
this.remoteAddress = remoteAddress;
this.messageReaders = messageReaders;
this.exchange = exchange;
}
@@ -152,6 +162,11 @@ public class MockServerRequest implements ServerRequest {
return Optional.ofNullable(this.remoteAddress);
}
@Override
public List<HttpMessageReader<?>> messageReaders() {
return this.messageReaders;
}
@Override
@SuppressWarnings("unchecked")
public <S> S body(BodyExtractor<S, ? super ServerHttpRequest> extractor) {
@@ -233,6 +248,12 @@ public class MockServerRequest implements ServerRequest {
return (Mono<MultiValueMap<String, Part>>) this.body;
}
@Override
public ServerWebExchange exchange() {
Assert.state(this.exchange != null, "No exchange");
return this.exchange;
}
public static Builder builder() {
return new BuilderImpl();
}
@@ -271,7 +292,7 @@ public class MockServerRequest implements ServerRequest {
Builder session(WebSession session);
/**
* @deprecated in favor of {@link #principal(Principal)}
* @deprecated in favor of {@link #principal(Principal)}
*/
@Deprecated
Builder session(Principal principal);
@@ -280,6 +301,10 @@ public class MockServerRequest implements ServerRequest {
Builder remoteAddress(InetSocketAddress remoteAddress);
Builder messageReaders(List<HttpMessageReader<?>> messageReaders);
Builder exchange(ServerWebExchange exchange);
MockServerRequest body(Object body);
MockServerRequest build();
@@ -316,6 +341,11 @@ public class MockServerRequest implements ServerRequest {
@Nullable
private InetSocketAddress remoteAddress;
private List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
@Nullable
private ServerWebExchange exchange;
@Override
public Builder method(HttpMethod method) {
Assert.notNull(method, "'method' must not be null");
@@ -419,6 +449,7 @@ public class MockServerRequest implements ServerRequest {
}
@Override
@Deprecated
public Builder session(Principal principal) {
return principal(principal);
}
@@ -437,19 +468,35 @@ public class MockServerRequest implements ServerRequest {
return this;
}
@Override
public Builder messageReaders(List<HttpMessageReader<?>> messageReaders) {
Assert.notNull(messageReaders, "'messageReaders' must not be null");
this.messageReaders = messageReaders;
return this;
}
@Override
public Builder exchange(ServerWebExchange exchange) {
Assert.notNull(exchange, "'exchange' must not be null");
this.exchange = exchange;
return this;
}
@Override
public MockServerRequest body(Object body) {
this.body = body;
return new MockServerRequest(this.method, this.uri, this.contextPath, this.headers,
this.cookies, this.body, this.attributes, this.queryParams, this.pathVariables,
this.session, this.principal, this.remoteAddress);
this.session, this.principal, this.remoteAddress, this.messageReaders,
this.exchange);
}
@Override
public MockServerRequest build() {
return new MockServerRequest(this.method, this.uri, this.contextPath, this.headers,
this.cookies, null, this.attributes, this.queryParams, this.pathVariables,
this.session, this.principal, this.remoteAddress);
this.session, this.principal, this.remoteAddress, this.messageReaders,
this.exchange);
}
}