Skip to content

Commit 29f33a2

Browse files
committed
Handle multipart request errors in optout service to return 400 instead of 500
1 parent 49f6b2a commit 29f33a2

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.uid2.optout.vertx;
2+
3+
import io.vertx.core.Handler;
4+
import io.vertx.core.http.HttpClosedException;
5+
import io.vertx.core.http.HttpServerResponse;
6+
import io.vertx.ext.web.RoutingContext;
7+
import org.apache.http.impl.EnglishReasonPhraseCatalog;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
public class GenericFailureHandler implements Handler<RoutingContext> {
12+
private static final Logger LOGGER = LoggerFactory.getLogger(GenericFailureHandler.class);
13+
14+
@Override
15+
public void handle(RoutingContext ctx) {
16+
int statusCode = ctx.statusCode();
17+
HttpServerResponse response = ctx.response();
18+
String url = ctx.normalizedPath();
19+
Throwable t = ctx.failure();
20+
21+
String errorMsg = t.getMessage();
22+
String className = t.getClass().getName();
23+
24+
// Handle multipart method mismatch (IllegalStateException)
25+
if (t instanceof IllegalStateException &&
26+
errorMsg != null &&
27+
errorMsg.equalsIgnoreCase(
28+
"Request method must be one of POST, PUT, PATCH or DELETE to decode a multipart request")) {
29+
if (!response.ended() && !response.closed()) {
30+
response.setStatusCode(400)
31+
.end("Bad Request: multipart content not allowed with this HTTP method");
32+
}
33+
LOGGER.warn("URL: [{}] - Multipart method mismatch - Error:", url, t);
34+
return;
35+
}
36+
37+
// Handle TooManyFormFieldsException
38+
if (className.contains("TooManyFormFieldsException")) {
39+
if (!response.ended() && !response.closed()) {
40+
response.setStatusCode(400)
41+
.end("Bad Request: Too many form fields");
42+
}
43+
LOGGER.warn("URL: [{}] - Too many form fields - Error:", url, t);
44+
return;
45+
}
46+
47+
// Handle HttpClosedException - ignore as it's usually caused by users and has no impact
48+
if (t instanceof HttpClosedException) {
49+
LOGGER.warn("Ignoring exception - URL: [{}] - Error:", url, t);
50+
if (!response.ended() && !response.closed()) {
51+
response.end();
52+
}
53+
return;
54+
}
55+
56+
// Handle other exceptions based on status code
57+
// If no status code was set, default to 500
58+
int finalStatusCode = statusCode == -1 ? 500 : statusCode;
59+
60+
if (finalStatusCode >= 500 && finalStatusCode < 600) { // 5xx is server error, so error
61+
LOGGER.error("URL: [{}] - Error response code: [{}] - Error:", url, finalStatusCode, t);
62+
} else if (finalStatusCode >= 400 && finalStatusCode < 500) { // 4xx is user error, so just warn
63+
LOGGER.warn("URL: [{}] - Error response code: [{}] - Error:", url, finalStatusCode, t);
64+
} else {
65+
// Status code not in 4xx or 5xx range, log as error
66+
LOGGER.error("URL: [{}] - Unexpected status code: [{}] - Error:", url, finalStatusCode, t);
67+
}
68+
69+
if (!response.ended() && !response.closed()) {
70+
response.setStatusCode(finalStatusCode)
71+
.end(EnglishReasonPhraseCatalog.INSTANCE.getReason(finalStatusCode, null));
72+
}
73+
}
74+
}

src/main/java/com/uid2/optout/vertx/OptOutServiceVerticle.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ private Router createRouter() {
231231
//// if enabled, this would add handler for exposing prometheus metrics
232232
// router.route("/metrics").handler(PrometheusScrapingHandler.create());
233233

234+
router.route().failureHandler(new GenericFailureHandler());
235+
234236
return router;
235237
}
236238

0 commit comments

Comments
 (0)