This is an automated email from the ASF dual-hosted git repository. dsoumis pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit e08caccd72c2025e7aa0ad64b3f74483d279fc6c Author: Dimitris Soumis <[email protected]> AuthorDate: Tue Jun 9 14:08:10 2026 +0300 Add showReport attribute in JsonErrorReportValve. --- .../catalina/valves/JsonErrorReportValve.java | 124 +++++++++++---------- .../catalina/valves/TestJsonErrorReportValve.java | 74 ++++++++++++ webapps/docs/config/valve.xml | 9 ++ 3 files changed, 149 insertions(+), 58 deletions(-) diff --git a/java/org/apache/catalina/valves/JsonErrorReportValve.java b/java/org/apache/catalina/valves/JsonErrorReportValve.java index a5b0a58747..cf6622d907 100644 --- a/java/org/apache/catalina/valves/JsonErrorReportValve.java +++ b/java/org/apache/catalina/valves/JsonErrorReportValve.java @@ -61,73 +61,81 @@ public class JsonErrorReportValve extends ErrorReportValve { return; } - StringManager smClient = StringManager.getManager(Constants.Package, request.getLocales()); - response.setLocale(smClient.getLocale()); - String type; - if (throwable != null) { - type = smClient.getString("errorReportValve.exceptionReport"); - } else { - type = smClient.getString("errorReportValve.statusReport"); - } - String message = response.getMessage(); - if (message == null && throwable != null) { - message = throwable.getMessage(); - } - if (message == null) { - message = ""; - } - String description = smClient.getString("http." + statusCode + ".desc"); - if (description == null) { - if (message.isEmpty()) { - return; + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + sb.append(" \"status\": ").append(statusCode); + + if (isShowReport()) { + StringManager smClient = StringManager.getManager(Constants.Package, request.getLocales()); + response.setLocale(smClient.getLocale()); + String type; + if (throwable != null) { + type = smClient.getString("errorReportValve.exceptionReport"); } else { - description = smClient.getString("errorReportValve.noDescription"); + type = smClient.getString("errorReportValve.statusReport"); } - } - StringBuilder sb = new StringBuilder(); - sb.append("{\n \"type\": \"").append(JSONFilter.escape(type)).append("\",\n"); - sb.append(" \"status\": ").append(statusCode).append(",\n"); - sb.append(" \"message\": \"").append(JSONFilter.escape(message)).append("\",\n"); - sb.append(" \"description\": \"").append(JSONFilter.escape(description)); - - if (throwable != null) { - sb.append("\",\n"); - - // Stack trace - sb.append(" \"throwable\": ["); - int loops = 0; - boolean first = true; - do { - if (!first) { - sb.append(','); + String message = response.getMessage(); + if (message == null && throwable != null) { + message = throwable.getMessage(); + } + if (message == null) { + message = ""; + } + String description = smClient.getString("http." + statusCode + ".desc"); + if (description == null) { + if (message.isEmpty()) { + return; } else { - first = false; + description = smClient.getString("errorReportValve.noDescription"); } - sb.append('\"').append(JSONFilter.escape(throwable.toString())).append('\"'); - - StackTraceElement[] elements = throwable.getStackTrace(); - int pos = elements.length; - for (int i = elements.length - 1; i >= 0; i--) { - if ((elements[i].getClassName().startsWith("org.apache.catalina.core.ApplicationFilterChain")) && - (elements[i].getMethodName().equals("internalDoFilter"))) { - pos = i; - break; + } + sb.append(",\n"); + sb.append(" \"type\": \"").append(JSONFilter.escape(type)).append("\",\n"); + sb.append(" \"message\": \"").append(JSONFilter.escape(message)).append("\",\n"); + sb.append(" \"description\": \"").append(JSONFilter.escape(description)); + + if (throwable != null) { + sb.append("\",\n"); + + // Stack trace + sb.append(" \"throwable\": ["); + int loops = 0; + boolean first = true; + do { + if (!first) { + sb.append(','); + } else { + first = false; } - } - for (int i = 0; i < pos; i++) { - if (!(elements[i].getClassName().startsWith("org.apache.catalina.core."))) { - sb.append(',').append('\"').append(' ').append(JSONFilter.escape(elements[i].toString())) - .append('\"'); + sb.append('\"').append(JSONFilter.escape(throwable.toString())).append('\"'); + + StackTraceElement[] elements = throwable.getStackTrace(); + int pos = elements.length; + for (int i = elements.length - 1; i >= 0; i--) { + if (elements[i].getClassName() + .startsWith("org.apache.catalina.core.ApplicationFilterChain") && + elements[i].getMethodName().equals("internalDoFilter")) { + pos = i; + break; + } + } + for (int i = 0; i < pos; i++) { + if (!elements[i].getClassName().startsWith("org.apache.catalina.core.")) { + sb.append(',').append('\"').append(' ') + .append(JSONFilter.escape(elements[i].toString())).append('\"'); + } } - } - throwable = throwable.getCause(); - loops++; - } while (throwable != null && (loops < 10)); - sb.append("]\n}"); + throwable = throwable.getCause(); + loops++; + } while (throwable != null && loops < 10); + sb.append("]\n}"); + } else { + sb.append("\"\n}"); + } } else { - sb.append("\"\n}"); + sb.append("\n}"); } try { diff --git a/test/org/apache/catalina/valves/TestJsonErrorReportValve.java b/test/org/apache/catalina/valves/TestJsonErrorReportValve.java index 4770a93802..5115c0c5ba 100644 --- a/test/org/apache/catalina/valves/TestJsonErrorReportValve.java +++ b/test/org/apache/catalina/valves/TestJsonErrorReportValve.java @@ -34,6 +34,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.Valve; import org.apache.catalina.core.StandardHost; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; @@ -338,6 +339,79 @@ public class TestJsonErrorReportValve extends TomcatBaseTest { Assert.assertEquals(unicodeMessage, json.get("message")); } + @Test + public void testJsonErrorShowReportFalse() throws Exception { + Tomcat tomcat = getTomcatInstance(); + StandardHost host = (StandardHost) tomcat.getHost(); + host.setErrorReportValveClass(JSON_VALVE); + + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "sendError", new SendErrorServlet( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server broke")); + ctx.addServletMappingDecoded("/", "sendError"); + + tomcat.start(); + + for (Valve valve : host.getPipeline().getValves()) { + if (valve instanceof JsonErrorReportValve) { + ((JsonErrorReportValve) valve).setShowReport(false); + break; + } + } + + ByteChunk res = new ByteChunk(); + int rc = getUrl("http://localhost:" + getPort(), res, null); + + Assert.assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc); + + String body = res.toString(); + JSONParser parser = new JSONParser(body); + LinkedHashMap<String, Object> json = parser.parseObject(); + + Assert.assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ((Number) json.get("status")).intValue()); + Assert.assertNull(json.get("type")); + Assert.assertNull(json.get("message")); + Assert.assertNull(json.get("description")); + } + + + @Test + public void testJsonErrorWithThrowableShowReportFalse() throws Exception { + Tomcat tomcat = getTomcatInstance(); + StandardHost host = (StandardHost) tomcat.getHost(); + host.setErrorReportValveClass(JSON_VALVE); + + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "exception", new ExceptionServlet("Something went wrong")); + ctx.addServletMappingDecoded("/", "exception"); + + tomcat.start(); + + for (Valve valve : host.getPipeline().getValves()) { + if (valve instanceof JsonErrorReportValve) { + ((JsonErrorReportValve) valve).setShowReport(false); + break; + } + } + + ByteChunk res = new ByteChunk(); + int rc = getUrl("http://localhost:" + getPort(), res, null); + + Assert.assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc); + + String body = res.toString(); + JSONParser parser = new JSONParser(body); + LinkedHashMap<String, Object> json = parser.parseObject(); + + Assert.assertEquals(500, ((Number) json.get("status")).intValue()); + Assert.assertNull(json.get("throwable")); + Assert.assertNull(json.get("message")); + Assert.assertNull(json.get("description")); + } + + @Test public void testNoJsonForUnknownStatusWithoutMessage() throws Exception { Tomcat tomcat = getTomcatInstance(); diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml index b73a554d06..659f2b4c4d 100644 --- a/webapps/docs/config/valve.xml +++ b/webapps/docs/config/valve.xml @@ -2449,6 +2449,15 @@ <strong>org.apache.catalina.valves.JsonErrorReportValve</strong>.</p> </attribute> + <attribute name="showReport" required="false"> + <p>Flag to determine if the error report (custom error message, + description and/or stack trace) is included in the JSON response + when an error occurs. If set to <code>false</code>, then the JSON + response will only contain the HTTP status code. + Default value: <code>true</code> + </p> + </attribute> + </attributes> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
