diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-10-11 11:22:53 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-10-11 11:24:36 +0200 |
commit | 1ccc097ab3d5ddbf468b1b34aa6ebbb46fac7445 (patch) | |
tree | 38ed71c589d25e91474a57962d06f1d0c1729f79 /container-core | |
parent | 0df7964c882d9b22ab99cfa8645afb8ca5b96ba0 (diff) |
Fail servlet output stream writer once request is finished with failure
Fail out any queued response content once request has been failed out
through callback from Jetty's AsyncListener interface.
Improve naming of methods in ServletResponseController.
Diffstat (limited to 'container-core')
2 files changed, 12 insertions, 6 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java index 01689453314..779a5f65673 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java @@ -85,12 +85,12 @@ class HttpRequestDispatch { } catch (Throwable t) { servletResponseController.finishedFuture() .whenComplete((__, ___) -> requestCompletion.completeExceptionally(t)); - servletResponseController.fail(t); + servletResponseController.trySendErrorResponse(t); return; } servletRequestReader.finishedFuture().whenComplete((__, t) -> { - if (t != null) servletResponseController.fail(t); + if (t != null) servletResponseController.trySendErrorResponse(t); }); servletResponseController.finishedFuture().whenComplete((__, t) -> { if (t != null) servletRequestReader.fail(t); @@ -104,7 +104,6 @@ class HttpRequestDispatch { ContentChannel dispatchFilterRequest(Response response) { try { - CompletableFuture<Void> requestCompletion = startServletAsyncExecution(); jettyRequest.getInputStream().close(); ContentChannel responseContentChannel = servletResponseController.responseHandler().handleResponse(response); @@ -140,6 +139,9 @@ class HttpRequestDispatch { private void onRequestFinished(AsyncContext asyncCtx, Throwable error) { boolean reportedError = false; if (error != null) { + // It's too late to write any error response and response writer must therefore be forcefully closed + servletResponseController.forceClose(error); + if (isErrorOfType(error, EofException.class, IOException.class)) { log.log(Level.FINE, error, diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java index e78b50215bb..ffa31a9e8de 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java @@ -67,10 +67,11 @@ class ServletResponseController { this.out = new ServletOutputStreamWriter(servletResponse.getOutputStream(), janitor, metricReporter); } - void fail(Throwable t) { + /** Try to send an error response (assuming failure is recoverable) */ + void trySendErrorResponse(Throwable t) { synchronized (monitor) { try { - trySendError(t); + sendErrorResponseIfUncommitted(t); } catch (Throwable suppressed) { t.addSuppressed(suppressed); } finally { @@ -79,6 +80,9 @@ class ServletResponseController { } } + /** Close response writer and fail out any queued response content */ + void forceClose(Throwable t) { out.fail(t); } + /** * When this future completes there will be no more calls against the servlet output stream or servlet response. * The framework is still allowed to invoke us though. @@ -89,7 +93,7 @@ class ServletResponseController { ResponseHandler responseHandler() { return responseHandler; } - private void trySendError(Throwable t) { + private void sendErrorResponseIfUncommitted(Throwable t) { if (!responseCommitted) { responseCommitted = true; servletResponse.setHeader(HttpHeaders.Names.EXPIRES, null); |