Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/main/java/com/uid2/optout/vertx/GenericFailureHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.uid2.optout.vertx;

import io.vertx.core.Handler;
import io.vertx.core.http.HttpClosedException;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;
import org.apache.http.impl.EnglishReasonPhraseCatalog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GenericFailureHandler implements Handler<RoutingContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(GenericFailureHandler.class);

@Override
public void handle(RoutingContext ctx) {
int statusCode = ctx.statusCode();
HttpServerResponse response = ctx.response();
String url = ctx.normalizedPath();
Throwable t = ctx.failure();

// Handle case where failure() is null (e.g., when rc.fail(401) is called without exception)
// In this case, just use the status code that was set
if (t == null) {
int finalStatusCode = statusCode == -1 ? 500 : statusCode;
if (finalStatusCode >= 500 && finalStatusCode < 600) {
LOGGER.error("URL: [{}] - Error response code: [{}]", url, finalStatusCode);
} else if (finalStatusCode >= 400 && finalStatusCode < 500) {
LOGGER.warn("URL: [{}] - Error response code: [{}]", url, finalStatusCode);
}
if (!response.ended() && !response.closed()) {
response.setStatusCode(finalStatusCode)
.end(EnglishReasonPhraseCatalog.INSTANCE.getReason(finalStatusCode, null));
}
return;
}

String errorMsg = t.getMessage();
String className = t.getClass().getName();

// Handle multipart method mismatch (IllegalStateException)
if (t instanceof IllegalStateException &&
errorMsg != null &&
errorMsg.equalsIgnoreCase(
"Request method must be one of POST, PUT, PATCH or DELETE to decode a multipart request")) {
if (!response.ended() && !response.closed()) {
response.setStatusCode(400).end(errorMsg);
}
LOGGER.warn("URL: [{}] - Multipart method mismatch - Error:", url, t);
return;
}

// Handle TooManyFormFieldsException
if (className.contains("TooManyFormFieldsException")) {
if (!response.ended() && !response.closed()) {
response.setStatusCode(400)
.end("Bad Request: Too many form fields");
}
LOGGER.warn("URL: [{}] - Too many form fields - Error:", url, t);
return;
}

// Handle HttpClosedException - ignore as it's usually caused by users and has no impact
if (t instanceof HttpClosedException) {
LOGGER.warn("Ignoring exception - URL: [{}] - Error:", url, t);
if (!response.ended() && !response.closed()) {
response.end();
}
return;
}

// Handle other exceptions based on status code
// If no status code was set, default to 500
int finalStatusCode = statusCode == -1 ? 500 : statusCode;

if (finalStatusCode >= 500 && finalStatusCode < 600) { // 5xx is server error, so error
LOGGER.error("URL: [{}] - Error response code: [{}] - Error:", url, finalStatusCode, t);
} else if (finalStatusCode >= 400 && finalStatusCode < 500) { // 4xx is user error, so just warn
LOGGER.warn("URL: [{}] - Error response code: [{}] - Error:", url, finalStatusCode, t);
}

if (!response.ended() && !response.closed()) {
response.setStatusCode(finalStatusCode)
.end(EnglishReasonPhraseCatalog.INSTANCE.getReason(finalStatusCode, null));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ private Router createRouter() {
//// if enabled, this would add handler for exposing prometheus metrics
// router.route("/metrics").handler(PrometheusScrapingHandler.create());

router.route().failureHandler(new GenericFailureHandler());

return router;
}

Expand Down
Loading
Loading