Handle AsyncListener.onComplete in Servlet adapter

Typically the Mono<Void> from the HttpHandler also reflects the
completion of the request and response body processors and at that
point invoking AsyncContext#complete() from HandlerResultSubscriber
should be sufficient.

This commit explicitly propagates the AsyncListener.onComplete event
to the request and response body processors for added safety.
Technically as mentioned those processors should have completed but
depending on how the controller is written there is a possibility
the body processors may not have completed.

Issue: SPR-14772
This commit is contained in:
Violeta Georgieva
2016-10-19 10:42:32 +03:00
committed by Rossen Stoyanchev
parent 139eb9a580
commit 25e7cd577d
3 changed files with 24 additions and 4 deletions

View File

@@ -91,7 +91,7 @@ public class ServletHttpHandlerAdapter extends HttpServlet {
servletRequest, this.dataBufferFactory, this.bufferSize);
ServletServerHttpResponse response = new ServletServerHttpResponse(
servletResponse, this.dataBufferFactory, this.bufferSize);
asyncContext.addListener(new ErrorHandlingAsyncListener(request, response));
asyncContext.addListener(new EventHandlingAsyncListener(request, response));
HandlerResultSubscriber resultSubscriber = new HandlerResultSubscriber(asyncContext);
this.handler.handle(request, response).subscribe(resultSubscriber);
}
@@ -131,14 +131,14 @@ public class ServletHttpHandlerAdapter extends HttpServlet {
}
private static final class ErrorHandlingAsyncListener implements AsyncListener {
private static final class EventHandlingAsyncListener implements AsyncListener {
private final ServletServerHttpRequest request;
private final ServletServerHttpResponse response;
public ErrorHandlingAsyncListener(ServletServerHttpRequest request,
public EventHandlingAsyncListener(ServletServerHttpRequest request,
ServletServerHttpResponse response) {
this.request = request;
@@ -169,7 +169,8 @@ public class ServletHttpHandlerAdapter extends HttpServlet {
@Override
public void onComplete(AsyncEvent event) {
// no op
this.request.handleAsyncListenerComplete();
this.response.handleAsyncListenerComplete();
}
}

View File

@@ -177,6 +177,13 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
}
}
/** Handle a complete callback from the Servlet container */
void handleAsyncListenerComplete() {
if (this.bodyPublisher != null) {
this.bodyPublisher.onAllDataRead();
}
}
private RequestBodyPublisher createBodyPublisher() throws IOException {
RequestBodyPublisher bodyPublisher = new RequestBodyPublisher(
this.request.getInputStream(), this.dataBufferFactory, this.bufferSize);

View File

@@ -166,6 +166,18 @@ public class ServletServerHttpResponse extends AbstractListenerServerHttpRespons
}
}
/** Handle a complete callback from the Servlet container */
void handleAsyncListenerComplete() {
if (this.bodyFlushProcessor != null) {
this.bodyFlushProcessor.cancel();
this.bodyFlushProcessor.onComplete();
}
if (this.bodyProcessor != null) {
this.bodyProcessor.cancel();
this.bodyProcessor.onComplete();
}
}
private class ResponseBodyProcessor extends AbstractResponseBodyProcessor {