16
16
17
17
package org .springframework .web .server .adapter ;
18
18
19
- import java .util .Set ;
20
19
import java .util .concurrent .atomic .AtomicBoolean ;
21
20
22
21
import io .micrometer .observation .Observation ;
29
28
import reactor .util .context .Context ;
30
29
31
30
import org .springframework .context .ApplicationContext ;
32
- import org .springframework .core .NestedExceptionUtils ;
33
31
import org .springframework .core .log .LogFormatUtils ;
34
32
import org .springframework .http .HttpHeaders ;
35
33
import org .springframework .http .HttpStatus ;
54
52
import org .springframework .web .server .i18n .LocaleContextResolver ;
55
53
import org .springframework .web .server .session .DefaultWebSessionManager ;
56
54
import org .springframework .web .server .session .WebSessionManager ;
55
+ import org .springframework .web .util .DisconnectedClientHelper ;
57
56
58
57
/**
59
58
* Default adapter of {@link WebHandler} to the {@link HttpHandler} contract.
69
68
public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
70
69
71
70
/**
72
- * Dedicated log category for disconnected client exceptions.
73
- * <p>Servlet containers don't expose a client disconnected callback; see
74
- * <a href="https://github.com/eclipse-ee4j/servlet-api/issues/44">eclipse-ee4j/servlet-api#44</a>.
75
- * <p>To avoid filling logs with unnecessary stack traces, we make an
76
- * effort to identify such network failures on a per-server basis, and then
77
- * log under a separate log category a simple one-line message at DEBUG level
78
- * or a full stack trace only at TRACE level.
71
+ * Log category to use for network failure after a client has gone away.
72
+ * @see DisconnectedClientHelper
79
73
*/
80
74
private static final String DISCONNECTED_CLIENT_LOG_CATEGORY =
81
75
"org.springframework.web.server.DisconnectedClient" ;
82
76
83
- // Similar declaration exists in AbstractSockJsSession.
84
- private static final Set <String > DISCONNECTED_CLIENT_EXCEPTIONS =
85
- Set .of ("AbortedException" , "ClientAbortException" , "EOFException" , "EofException" );
77
+ private static final DisconnectedClientHelper disconnectedClientHelper =
78
+ new DisconnectedClientHelper (DISCONNECTED_CLIENT_LOG_CATEGORY );
86
79
87
80
private static final ServerRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION =
88
81
new DefaultServerRequestObservationConvention ();
89
82
90
83
91
84
private static final Log logger = LogFactory .getLog (HttpWebHandlerAdapter .class );
92
85
93
- private static final Log lostClientLogger = LogFactory .getLog (DISCONNECTED_CLIENT_LOG_CATEGORY );
94
-
95
86
96
87
private WebSessionManager sessionManager = new DefaultWebSessionManager ();
97
88
@@ -341,7 +332,9 @@ private String formatHeaders(HttpHeaders responseHeaders) {
341
332
responseHeaders .toString () : responseHeaders .isEmpty () ? "{}" : "{masked}" ;
342
333
}
343
334
344
- private Mono <Void > handleUnresolvedError (ServerWebExchange exchange , ServerRequestObservationContext observationContext , Throwable ex ) {
335
+ private Mono <Void > handleUnresolvedError (
336
+ ServerWebExchange exchange , ServerRequestObservationContext observationContext , Throwable ex ) {
337
+
345
338
ServerHttpRequest request = exchange .getRequest ();
346
339
ServerHttpResponse response = exchange .getResponse ();
347
340
String logPrefix = exchange .getLogPrefix ();
@@ -353,14 +346,7 @@ private Mono<Void> handleUnresolvedError(ServerWebExchange exchange, ServerReque
353
346
logger .error (logPrefix + "500 Server Error for " + formatRequest (request ), ex );
354
347
return Mono .empty ();
355
348
}
356
- else if (isDisconnectedClientError (ex )) {
357
- if (lostClientLogger .isTraceEnabled ()) {
358
- lostClientLogger .trace (logPrefix + "Client went away" , ex );
359
- }
360
- else if (lostClientLogger .isDebugEnabled ()) {
361
- lostClientLogger .debug (logPrefix + "Client went away: " + ex +
362
- " (stacktrace at TRACE level for '" + DISCONNECTED_CLIENT_LOG_CATEGORY + "')" );
363
- }
349
+ else if (disconnectedClientHelper .checkAndLogClientDisconnectedException (ex )) {
364
350
observationContext .setConnectionAborted (true );
365
351
return Mono .empty ();
366
352
}
@@ -372,16 +358,6 @@ else if (lostClientLogger.isDebugEnabled()) {
372
358
}
373
359
}
374
360
375
- private boolean isDisconnectedClientError (Throwable ex ) {
376
- String message = NestedExceptionUtils .getMostSpecificCause (ex ).getMessage ();
377
- if (message != null ) {
378
- String text = message .toLowerCase ();
379
- if (text .contains ("broken pipe" ) || text .contains ("connection reset by peer" )) {
380
- return true ;
381
- }
382
- }
383
- return DISCONNECTED_CLIENT_EXCEPTIONS .contains (ex .getClass ().getSimpleName ());
384
- }
385
361
386
362
private final class ObservationSignalListener extends DefaultSignalListener <Void > {
387
363
0 commit comments