Skip to content

Commit

Permalink
INT-4462: WebFluxInbound: cope with empty body
Browse files Browse the repository at this point in the history
JIRA: https://jira.spring.io/browse/INT-4462

When the HTTP request body is empty, the `HttpMessageReader` ends up
with the empty `Mono` which can't be evaluated to any reasonable value.

* Add fallback to `requestParams` when `Mono` for body is empty and
also when `payloadExpression` returns null

**Cherry-pick to 5.0.x**
  • Loading branch information
artembilan authored and garyrussell committed May 7, 2018
1 parent 0714130 commit a14514a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public Mono<Void> handle(ServerWebExchange exchange) {
private Mono<Void> doHandle(ServerWebExchange exchange) {
return extractRequestBody(exchange)
.doOnSubscribe(s -> this.activeCount.incrementAndGet())
.switchIfEmpty(Mono.just(exchange.getRequest().getQueryParams()))
.map(body -> new HttpEntity<>(body, exchange.getRequest().getHeaders()))
.map(entity -> buildMessage(entity, exchange))
.flatMap(requestMessage -> {
Expand Down Expand Up @@ -267,10 +268,6 @@ private Message<?> buildMessage(HttpEntity<?> httpEntity, ServerWebExchange exch
Object payload;
if (getPayloadExpression() != null) {
payload = getPayloadExpression().getValue(evaluationContext);
if (payload == null) {
throw new IllegalStateException("The payload expression '" + getPayloadExpression().getExpressionString()
+ "' returned null.");
}
}
else {
payload = httpEntity.getBody();
Expand All @@ -288,6 +285,10 @@ private Message<?> buildMessage(HttpEntity<?> httpEntity, ServerWebExchange exch
}
}

if (payload == null) {
payload = requestParams;
}

AbstractIntegrationMessageBuilder<?> messageBuilder;

if (payload instanceof Message<?>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-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.
Expand All @@ -25,6 +25,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -95,6 +96,16 @@ public void testServerInternalErrorRequest() {
.is5xxServerError();
}

@Test
public void testPostWithEmptyBody() {
this.webTestClient
.post()
.uri("/post?foo=foo")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("{foo=[foo]}");
}

@Configuration
@EnableWebFlux
@EnableIntegration
Expand Down Expand Up @@ -156,6 +167,22 @@ public ResponseEntity<String> processHttpRequest() {
return new ResponseEntity<>("<500 Internal Server Error,{}>", HttpStatus.INTERNAL_SERVER_ERROR);
}

@Bean
public WebFluxInboundEndpoint postInboundEndpoint() {
WebFluxInboundEndpoint endpoint = new WebFluxInboundEndpoint();
RequestMapping requestMapping = new RequestMapping();
requestMapping.setPathPatterns("/post");
requestMapping.setMethods(HttpMethod.POST);
endpoint.setRequestMapping(requestMapping);
endpoint.setRequestChannelName("postServiceChannel");
return endpoint;
}

@ServiceActivator(inputChannel = "postServiceChannel")
String service(Object payload) {
return payload.toString();
}

}


Expand Down
4 changes: 3 additions & 1 deletion src/reference/asciidoc/webflux.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

The WebFlux Spring Integration module (`spring-integration-webflux`) allows for the execution of HTTP requests and the processing of inbound HTTP requests in Reactive manner.
The WebFlux support consists of the following gateway implementations: `WebFluxInboundEndpoint`, `WebFluxRequestExecutingMessageHandler`.
The implementation is fully based on the Spring http://docs.spring.io/spring/docs/5.0.0.RC3/spring-framework-reference/web.html#web-reactive[WebFlux] and https://projectreactor.io/[Project Reactor] foundations.
The implementation is fully based on the Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux[WebFlux] and https://projectreactor.io/[Project Reactor] foundations.
Also see <<http>> for more information since many options are shared between reactive and regular HTTP components.

[[webflux-inbound]]
Expand Down Expand Up @@ -65,6 +65,8 @@ public IntegrationFlow sseFlow() {

Also see <<http-request-mapping>> and <<http-cors>> for more possible configuration options.

When the request body is empty, or `payloadExpression` returns `null`, the request params `MultiValueMap<String, String>` is used for a `payload` of the target message to process.

[[webflux-outbound]]
=== WebFlux Outbound Components

Expand Down

0 comments on commit a14514a

Please sign in to comment.