Skip to content

Commit dd32f95

Browse files
committed
Dispatch in UndertowHttpHandlerAdapter
This ensures that the reactive handling of the request is dispatched from the Undertow IO thread, marking the exchange as async rather than ending it once the Undertow `handleRequest` method returns. See gh-33885 Closes gh-33969
1 parent 75a920b commit dd32f95

File tree

2 files changed

+35
-16
lines changed

2 files changed

+35
-16
lines changed

spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHttpHandlerAdapter.java

+18-16
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,27 @@ public DataBufferFactory getDataBufferFactory() {
6666

6767
@Override
6868
public void handleRequest(HttpServerExchange exchange) {
69-
UndertowServerHttpRequest request = null;
70-
try {
71-
request = new UndertowServerHttpRequest(exchange, getDataBufferFactory());
72-
}
73-
catch (URISyntaxException ex) {
74-
if (logger.isWarnEnabled()) {
75-
logger.debug("Failed to get request URI: " + ex.getMessage());
69+
exchange.dispatch(() -> {
70+
UndertowServerHttpRequest request = null;
71+
try {
72+
request = new UndertowServerHttpRequest(exchange, getDataBufferFactory());
7673
}
77-
exchange.setStatusCode(400);
78-
return;
79-
}
80-
ServerHttpResponse response = new UndertowServerHttpResponse(exchange, getDataBufferFactory(), request);
74+
catch (URISyntaxException ex) {
75+
if (logger.isWarnEnabled()) {
76+
logger.debug("Failed to get request URI: " + ex.getMessage());
77+
}
78+
exchange.setStatusCode(400);
79+
return;
80+
}
81+
ServerHttpResponse response = new UndertowServerHttpResponse(exchange, getDataBufferFactory(), request);
8182

82-
if (request.getMethod() == HttpMethod.HEAD) {
83-
response = new HttpHeadResponseDecorator(response);
84-
}
83+
if (request.getMethod() == HttpMethod.HEAD) {
84+
response = new HttpHeadResponseDecorator(response);
85+
}
8586

86-
HandlerResultSubscriber resultSubscriber = new HandlerResultSubscriber(exchange, request);
87-
this.httpHandler.handle(request, response).subscribe(resultSubscriber);
87+
HandlerResultSubscriber resultSubscriber = new HandlerResultSubscriber(exchange, request);
88+
this.httpHandler.handle(request, response).subscribe(resultSubscriber);
89+
});
8890
}
8991

9092

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.web.reactive.result.method.annotation;
1818

1919
import java.nio.ByteBuffer;
20+
import java.time.Duration;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Collections;
@@ -331,6 +332,17 @@ void personTransformWithFlux(HttpServer httpServer) throws Exception {
331332
assertThat(performPost("/person-transform/flux", JSON, req, JSON, PERSON_LIST).getBody()).isEqualTo(res);
332333
}
333334

335+
@ParameterizedHttpServerTest // see gh-33885
336+
void personTransformWithFluxDelayed(HttpServer httpServer) throws Exception {
337+
startServer(httpServer);
338+
339+
List<?> req = asList(new Person("Robert"), new Person("Marie"));
340+
List<?> res = asList(new Person("ROBERT"), new Person("MARIE"));
341+
assertThat(performPost("/person-transform/flux-delayed", JSON, req, JSON, PERSON_LIST))
342+
.satisfies(r -> assertThat(r.getBody()).isEqualTo(res))
343+
.satisfies(r -> assertThat(r.getHeaders().getContentLength()).isNotZero());
344+
}
345+
334346
@ParameterizedHttpServerTest
335347
void personTransformWithObservable(HttpServer httpServer) throws Exception {
336348
startServer(httpServer);
@@ -632,6 +644,11 @@ Flux<Person> transformFlux(@RequestBody Flux<Person> persons) {
632644
return persons.map(person -> new Person(person.getName().toUpperCase()));
633645
}
634646

647+
@PostMapping("/flux-delayed")
648+
Flux<Person> transformDelayed(@RequestBody Flux<Person> persons) {
649+
return transformFlux(persons).delayElements(Duration.ofMillis(10));
650+
}
651+
635652
@PostMapping("/observable")
636653
Observable<Person> transformObservable(@RequestBody Observable<Person> persons) {
637654
return persons.map(person -> new Person(person.getName().toUpperCase()));

0 commit comments

Comments
 (0)