Skip to content

Commit a629e0f

Browse files
committed
Pass in a context with an optional logger and request object for additional context for the handler.
1 parent 797caa3 commit a629e0f

File tree

5 files changed

+51
-26
lines changed

5 files changed

+51
-26
lines changed

src/main/java/io/fusionauth/http/server/DefaultHTTPUnexpectedExceptionHandler.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,14 @@
1515
*/
1616
package io.fusionauth.http.server;
1717

18-
import io.fusionauth.http.log.Logger;
19-
import io.fusionauth.http.log.LoggerFactory;
20-
2118
/**
2219
* THe default HTTP unexpected exception handler.
2320
*
2421
* @author Daniel DeGroff
2522
*/
2623
public class DefaultHTTPUnexpectedExceptionHandler implements HTTPUnexpectedExceptionHandler {
27-
private final Logger logger;
28-
29-
public DefaultHTTPUnexpectedExceptionHandler(LoggerFactory loggerFactory) {
30-
this.logger = loggerFactory.getLogger(DefaultHTTPUnexpectedExceptionHandler.class);
31-
}
32-
3324
@Override
34-
public int handle(Throwable t) {
35-
int internalServerError = 500;
36-
logger.error(String.format("[%s] Closing socket with status [%d]. An HTTP worker threw an exception while processing a request.", Thread.currentThread().threadId(), internalServerError), t);
37-
return internalServerError;
25+
public void handle(ExceptionHandlerContext context) {
26+
context.logger.error(String.format("[%s] Closing socket with status [%d]. An HTTP worker threw an exception while processing a request.", Thread.currentThread().threadId(), context.statusCode), context.throwable);
3827
}
3928
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2025, FusionAuth, All Rights Reserved
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an
12+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
* either express or implied. See the License for the specific
14+
* language governing permissions and limitations under the License.
15+
*/
16+
package io.fusionauth.http.server;
17+
18+
import io.fusionauth.http.log.Logger;
19+
20+
/**
21+
* Provide context to the exception handler.
22+
*
23+
* @author Daniel DeGroff
24+
*/
25+
public class ExceptionHandlerContext {
26+
public Logger logger;
27+
28+
public HTTPRequest request;
29+
30+
public int statusCode;
31+
32+
public Throwable throwable;
33+
34+
public ExceptionHandlerContext(Logger logger, HTTPRequest request, int statusCode, Throwable throwable) {
35+
this.logger = logger;
36+
this.request = request; // may be null
37+
this.statusCode = statusCode;
38+
this.throwable = throwable;
39+
}
40+
}

src/main/java/io/fusionauth/http/server/HTTPServerConfiguration.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public class HTTPServerConfiguration implements Configurable<HTTPServerConfigura
7979

8080
private Duration shutdownDuration = Duration.ofSeconds(10);
8181

82-
private HTTPUnexpectedExceptionHandler unexpectedExceptionHandler;
82+
private HTTPUnexpectedExceptionHandler unexpectedExceptionHandler = new DefaultHTTPUnexpectedExceptionHandler();
8383

8484
private Duration writeThroughputCalculationDelayDuration = Duration.ofSeconds(5);
8585

@@ -281,11 +281,6 @@ public Duration getShutdownDuration() {
281281
* @return The HTTP unexpected exception handler for this server. Never null.
282282
*/
283283
public HTTPUnexpectedExceptionHandler getUnexpectedExceptionHandler() {
284-
// Lazily construct a default so we can use the configured loggerFactory.
285-
if (unexpectedExceptionHandler == null) {
286-
unexpectedExceptionHandler = new DefaultHTTPUnexpectedExceptionHandler(loggerFactory);
287-
}
288-
289284
return unexpectedExceptionHandler;
290285
}
291286

src/main/java/io/fusionauth/http/server/HTTPUnexpectedExceptionHandler.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ public interface HTTPUnexpectedExceptionHandler {
2828
* The intent is that this provides additional flexibility on the status code and the logging behavior when an unexpected exception
2929
* caught.
3030
*
31-
* @param t the unexpected exception to handle.
32-
* @return the desired HTTP status code. Note that if the response has already been committed this will be ignored.
31+
* @param context the exception context
3332
*/
34-
int handle(Throwable t);
33+
void handle(ExceptionHandlerContext context);
3534
}

src/main/java/io/fusionauth/http/server/internal/HTTPWorker.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.fusionauth.http.io.MultipartConfiguration;
3232
import io.fusionauth.http.io.PushbackInputStream;
3333
import io.fusionauth.http.log.Logger;
34+
import io.fusionauth.http.server.ExceptionHandlerContext;
3435
import io.fusionauth.http.server.HTTPHandler;
3536
import io.fusionauth.http.server.HTTPListenerConfiguration;
3637
import io.fusionauth.http.server.HTTPRequest;
@@ -104,6 +105,7 @@ public long getStartInstant() {
104105
@Override
105106
public void run() {
106107
HTTPInputStream httpInputStream;
108+
HTTPRequest request = null;
107109
HTTPResponse response = null;
108110

109111
try {
@@ -113,7 +115,7 @@ public void run() {
113115

114116
while (true) {
115117
logger.trace("[{}] Running HTTP worker. Block while we wait to read the preamble", Thread.currentThread().threadId());
116-
var request = new HTTPRequest(configuration.getContextPath(), listener.getCertificate() != null ? "https" : "http", listener.getPort(), socket.getInetAddress().getHostAddress());
118+
request = new HTTPRequest(configuration.getContextPath(), listener.getCertificate() != null ? "https" : "http", listener.getPort(), socket.getInetAddress().getHostAddress());
117119

118120
// Create a deep copy of the MultipartConfiguration so that the request may optionally modify the configuration on a per-request basis.
119121
request.getMultiPartStreamProcessor().setMultipartConfiguration(new MultipartConfiguration(configuration.getMultipartConfiguration()));
@@ -268,14 +270,14 @@ public void run() {
268270
logger.debug(String.format("[%s] Closing socket with status [%d]. An IO exception was thrown during processing. These are pretty common.", Thread.currentThread().threadId(), Status.InternalServerError), e);
269271
closeSocketOnError(response, Status.InternalServerError);
270272
} catch (Throwable e) {
271-
var status = Status.InternalServerError;
273+
ExceptionHandlerContext context = new ExceptionHandlerContext(logger, request, Status.InternalServerError, e);
272274
try {
273-
status = configuration.getUnexpectedExceptionHandler().handle(e);
275+
configuration.getUnexpectedExceptionHandler().handle(context);
274276
} catch (Throwable ignore) {
275277
}
276278

277279
// Signal an error
278-
closeSocketOnError(response, status);
280+
closeSocketOnError(response, context.statusCode);
279281
} finally {
280282
if (instrumenter != null) {
281283
instrumenter.workerStopped();

0 commit comments

Comments
 (0)