Browse Source

Add formData() and multipartData() to ServerRequest

Issue: SPR-16551
pull/1745/merge
Arjen Poutsma 8 years ago
parent
commit
c56317928f
  1. 18
      spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java
  2. 13
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java
  3. 13
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java
  4. 24
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java
  5. 11
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java
  6. 70
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java
  7. 17
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java

18
spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@ -40,6 +40,7 @@ import org.springframework.http.HttpMethod; @@ -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.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -209,6 +210,21 @@ public class MockServerRequest implements ServerRequest { @@ -209,6 +210,21 @@ public class MockServerRequest implements ServerRequest {
return Mono.justOrEmpty(this.principal);
}
@Override
@SuppressWarnings("unchecked")
public Mono<MultiValueMap<String, String>> formData() {
Assert.state(this.body != null, "No body");
return (Mono<MultiValueMap<String, String>>) this.body;
}
@Override
@SuppressWarnings("unchecked")
public Mono<MultiValueMap<String, Part>> multipartData() {
Assert.state(this.body != null, "No body");
return (Mono<MultiValueMap<String, Part>>) this.body;
}
public static Builder builder() {
return new BuilderImpl();
}

13
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@ -39,6 +39,7 @@ import org.springframework.http.HttpRange; @@ -39,6 +39,7 @@ 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.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@ -190,6 +191,16 @@ class DefaultServerRequest implements ServerRequest { @@ -190,6 +191,16 @@ class DefaultServerRequest implements ServerRequest {
return this.exchange.getPrincipal();
}
@Override
public Mono<MultiValueMap<String, String>> formData() {
return this.exchange.getFormData();
}
@Override
public Mono<MultiValueMap<String, Part>> multipartData() {
return this.exchange.getMultipartData();
}
private ServerHttpRequest request() {
return this.exchange.getRequest();
}

13
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@ -39,6 +39,7 @@ import org.springframework.core.ParameterizedTypeReference; @@ -39,6 +39,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
@ -582,6 +583,16 @@ public abstract class RequestPredicates { @@ -582,6 +583,16 @@ public abstract class RequestPredicates {
return this.request.principal();
}
@Override
public Mono<MultiValueMap<String, String>> formData() {
return this.request.formData();
}
@Override
public Mono<MultiValueMap<String, Part>> multipartData() {
return this.request.multipartData();
}
@Override
public String toString() {
return method() + " " + path();

24
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@ -37,6 +37,7 @@ import org.springframework.http.HttpRange; @@ -37,6 +37,7 @@ import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.json.Jackson2CodecSupport;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
@ -244,6 +245,27 @@ public interface ServerRequest { @@ -244,6 +245,27 @@ public interface ServerRequest {
*/
Mono<? extends Principal> principal();
/**
* Return the form data from the body of the request if the Content-Type is
* {@code "application/x-www-form-urlencoded"} or an empty map otherwise.
*
* <p><strong>Note:</strong> calling this method causes the request body to
* be read and parsed in full and the resulting {@code MultiValueMap} is
* cached so that this method is safe to call more than once.
*/
Mono<MultiValueMap<String, String>> formData();
/**
* Return the parts of a multipart request if the Content-Type is
* {@code "multipart/form-data"} or an empty map otherwise.
*
* <p><strong>Note:</strong> calling this method causes the request body to
* be read and parsed in full and the resulting {@code MultiValueMap} is
* cached so that this method is safe to call more than once.
*/
Mono<MultiValueMap<String, Part>> multipartData();
/**
* Create a new {@code ServerRequest} based on the given {@code ServerWebExchange} and

11
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java

@ -35,6 +35,7 @@ import org.springframework.http.HttpHeaders; @@ -35,6 +35,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
@ -185,6 +186,16 @@ public class ServerRequestWrapper implements ServerRequest { @@ -185,6 +186,16 @@ public class ServerRequestWrapper implements ServerRequest {
return this.delegate.principal();
}
@Override
public Mono<MultiValueMap<String, String>> formData() {
return this.delegate.formData();
}
@Override
public Mono<MultiValueMap<String, Part>> multipartData() {
return this.delegate.multipartData();
}
/**
* Implementation of the {@code Headers} interface that can be subclassed
* to adapt the headers in a

70
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DefaultServerRequestTests.java

@ -44,13 +44,15 @@ import org.springframework.http.HttpRange; @@ -44,13 +44,15 @@ import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.springframework.web.reactive.function.BodyExtractors.toMono;
/**
@ -336,4 +338,70 @@ public class DefaultServerRequestTests { @@ -336,4 +338,70 @@ public class DefaultServerRequestTests {
.verify();
}
@Test
public void formData() throws Exception {
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
DefaultDataBuffer dataBuffer =
factory.wrap(ByteBuffer.wrap("foo=bar&baz=qux".getBytes(StandardCharsets.UTF_8)));
Flux<DataBuffer> body = Flux.just(dataBuffer);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MockServerHttpRequest mockRequest = MockServerHttpRequest
.method(HttpMethod.GET, "http://example.com")
.headers(httpHeaders)
.body(body);
DefaultServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), Collections.emptyList());
Mono<MultiValueMap<String, String>> resultData = request.formData();
StepVerifier.create(resultData)
.consumeNextWith(formData -> {
assertEquals(2, formData.size());
assertEquals("bar", formData.getFirst("foo"));
assertEquals("qux", formData.getFirst("baz"));
})
.verifyComplete();
}
@Test
public void multipartData() throws Exception {
String data = "--12345\r\n" +
"Content-Disposition: form-data; name=\"foo\"\r\n" +
"\r\n" +
"bar\r\n" +
"--12345\r\n" +
"Content-Disposition: form-data; name=\"baz\"\r\n" +
"\r\n" +
"qux\r\n" +
"--12345--\r\n";
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
DefaultDataBuffer dataBuffer =
factory.wrap(ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8)));
Flux<DataBuffer> body = Flux.just(dataBuffer);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=12345");
MockServerHttpRequest mockRequest = MockServerHttpRequest
.method(HttpMethod.GET, "http://example.com")
.headers(httpHeaders)
.body(body);
DefaultServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), Collections.emptyList());
Mono<MultiValueMap<String, Part>> resultData = request.multipartData();
StepVerifier.create(resultData)
.consumeNextWith(formData -> {
assertEquals(2, formData.size());
Part part = formData.getFirst("foo");
assertTrue(part instanceof FormFieldPart);
FormFieldPart formFieldPart = (FormFieldPart) part;
assertEquals("bar", formFieldPart.value());
part = formData.getFirst("baz");
assertTrue(part instanceof FormFieldPart);
formFieldPart = (FormFieldPart) part;
assertEquals("qux", formFieldPart.value());
})
.verifyComplete();
}
}

17
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@ -40,6 +40,7 @@ import org.springframework.http.HttpMethod; @@ -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.multipart.Part;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -208,6 +209,20 @@ public class MockServerRequest implements ServerRequest { @@ -208,6 +209,20 @@ public class MockServerRequest implements ServerRequest {
return Mono.justOrEmpty(this.principal);
}
@Override
@SuppressWarnings("unchecked")
public Mono<MultiValueMap<String, String>> formData() {
Assert.state(this.body != null, "No body");
return (Mono<MultiValueMap<String, String>>) this.body;
}
@Override
@SuppressWarnings("unchecked")
public Mono<MultiValueMap<String, Part>> multipartData() {
Assert.state(this.body != null, "No body");
return (Mono<MultiValueMap<String, Part>>) this.body;
}
public static Builder builder() {
return new BuilderImpl();
}

Loading…
Cancel
Save