|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2024 the original author or authors. |
| 2 | + * Copyright 2002-2025 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.web.context.request.async;
|
18 | 18 |
|
| 19 | +import java.io.IOException; |
19 | 20 | import java.util.concurrent.Callable;
|
20 | 21 |
|
21 | 22 | import jakarta.servlet.AsyncEvent;
|
@@ -152,6 +153,22 @@ void startCallableProcessingAfterException() throws Exception {
|
152 | 153 | verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable);
|
153 | 154 | }
|
154 | 155 |
|
| 156 | + @Test // gh-34363 |
| 157 | + void startCallableProcessingDisconnectedClient() throws Exception { |
| 158 | + StubCallable callable = new StubCallable(); |
| 159 | + this.asyncManager.startCallableProcessing(callable); |
| 160 | + |
| 161 | + IOException ex = new IOException("broken pipe"); |
| 162 | + AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), ex); |
| 163 | + this.asyncWebRequest.onError(event); |
| 164 | + |
| 165 | + MockAsyncContext asyncContext = (MockAsyncContext) this.servletRequest.getAsyncContext(); |
| 166 | + assertThat(this.asyncManager.hasConcurrentResult()).isTrue(); |
| 167 | + assertThat(this.asyncManager.getConcurrentResult()) |
| 168 | + .as("Disconnected client error not wrapped AsyncRequestNotUsableException") |
| 169 | + .isOfAnyClassIn(AsyncRequestNotUsableException.class); |
| 170 | + } |
| 171 | + |
155 | 172 | @Test
|
156 | 173 | void startDeferredResultProcessingErrorAndComplete() throws Exception {
|
157 | 174 |
|
@@ -259,6 +276,21 @@ public <T> boolean handleError(NativeWebRequest request, DeferredResult<T> resul
|
259 | 276 | assertThat(((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()).isEqualTo("/test");
|
260 | 277 | }
|
261 | 278 |
|
| 279 | + @Test // gh-34363 |
| 280 | + void startDeferredResultProcessingDisconnectedClient() throws Exception { |
| 281 | + DeferredResult<Object> deferredResult = new DeferredResult<>(); |
| 282 | + this.asyncManager.startDeferredResultProcessing(deferredResult); |
| 283 | + |
| 284 | + IOException ex = new IOException("broken pipe"); |
| 285 | + AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), ex); |
| 286 | + this.asyncWebRequest.onError(event); |
| 287 | + |
| 288 | + assertThat(this.asyncManager.hasConcurrentResult()).isTrue(); |
| 289 | + assertThat(deferredResult.getResult()) |
| 290 | + .as("Disconnected client error not wrapped AsyncRequestNotUsableException") |
| 291 | + .isOfAnyClassIn(AsyncRequestNotUsableException.class); |
| 292 | + } |
| 293 | + |
262 | 294 |
|
263 | 295 | private static final class StubCallable implements Callable<Object> {
|
264 | 296 | @Override
|
|
0 commit comments