Author: markt
Date: Wed Feb 14 10:17:19 2018
New Revision: 1824210

URL: http://svn.apache.org/viewvc?rev=1824210&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=41007
Add the ability to specify static HTML responses for specific error codes 
and/or exception types with the ErrorReportValve.

Modified:
    tomcat/trunk/java/org/apache/catalina/util/ErrorPageSupport.java
    tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java
    tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/valve.xml

Modified: tomcat/trunk/java/org/apache/catalina/util/ErrorPageSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/util/ErrorPageSupport.java?rev=1824210&r1=1824209&r2=1824210&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/util/ErrorPageSupport.java (original)
+++ tomcat/trunk/java/org/apache/catalina/util/ErrorPageSupport.java Wed Feb 14 
10:17:19 2018
@@ -68,11 +68,7 @@ public class ErrorPageSupport {
      *
      * @return The ErrorPage for the named exception type, or {@code null} if
      *         none is configured
-     *
-     * @deprecated Unused. Will be removed in Tomcat 10.
-     *             Use {@link #find(Throwable)} instead.
      */
-    @Deprecated
     public ErrorPage find(String exceptionType) {
         return exceptionPages.get(exceptionType);
     }

Modified: tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java?rev=1824210&r1=1824209&r2=1824210&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java Wed Feb 
14 10:17:19 2018
@@ -16,7 +16,11 @@
  */
 package org.apache.catalina.valves;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.Writer;
 import java.util.Scanner;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -27,10 +31,13 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.ErrorPageSupport;
+import org.apache.catalina.util.IOTools;
 import org.apache.catalina.util.ServerInfo;
 import org.apache.catalina.util.TomcatCSS;
 import org.apache.coyote.ActionCode;
 import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.descriptor.web.ErrorPage;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.util.security.Escape;
 
@@ -54,7 +61,11 @@ public class ErrorReportValve extends Va
 
     private boolean showServerInfo = true;
 
+    private final ErrorPageSupport errorPageSupport = new ErrorPageSupport();
+
+
     //------------------------------------------------------ Constructor
+
     public ErrorReportValve() {
         super(true);
     }
@@ -159,6 +170,27 @@ public class ErrorReportValve extends Va
             return;
         }
 
+        ErrorPage errorPage = null;
+        if (throwable != null) {
+            errorPage = errorPageSupport.find(throwable);
+        }
+        if (errorPage == null) {
+            errorPage = errorPageSupport.find(statusCode);
+        }
+        if (errorPage == null) {
+            // Default error page
+            errorPage = errorPageSupport.find(0);
+        }
+
+
+        if (errorPage != null) {
+            if (sendErrorPage(errorPage.getLocation(), response)) {
+                // If the page was sent successfully, don't write the standard
+                // error page.
+                return;
+            }
+        }
+
         String message = Escape.htmlElementContent(response.getMessage());
         if (message == null) {
             if (throwable != null) {
@@ -322,6 +354,37 @@ public class ErrorReportValve extends Va
         return trace.toString();
     }
 
+
+    private boolean sendErrorPage(String location, Response response) {
+        File file = new File(location);
+        if (!file.isAbsolute()) {
+            file = new File(getContainer().getCatalinaBase(), location);
+        }
+        if (!file.isFile() || !file.canRead()) {
+            getContainer().getLogger().warn(
+                    sm.getString("errorReportValve.errorPageNotFound", 
location));
+            return false;
+        }
+
+        // Hard coded for now. Consider making this optional. At Valve level or
+        // page level?
+        response.setContentType("text/html");
+        response.setCharacterEncoding("UTF-8");
+
+        try {
+            OutputStream os = response.getOutputStream();
+            InputStream is = new FileInputStream(file);
+            IOTools.flow(is, os);
+        } catch (IOException e) {
+            getContainer().getLogger().warn(
+                    sm.getString("errorReportValve.errorPageIOException", 
location), e);
+            return false;
+        }
+
+        return true;
+    }
+
+
     /**
      * Enables/Disables full error reports
      *
@@ -347,4 +410,48 @@ public class ErrorReportValve extends Va
     public boolean isShowServerInfo() {
         return showServerInfo;
     }
+
+
+    public boolean setProperty(String name, String value) {
+        if (name.startsWith("errorCode.")) {
+            int code = Integer.parseInt(name.substring(10));
+            ErrorPage ep = new ErrorPage();
+            ep.setErrorCode(code);
+            ep.setLocation(value);
+            errorPageSupport.add(ep);
+            return true;
+        } else if (name.startsWith("exceptionType.")) {
+            String className = name.substring(14);
+            ErrorPage ep = new ErrorPage();
+            ep.setExceptionType(className);
+            ep.setLocation(value);
+            errorPageSupport.add(ep);
+            return true;
+        }
+        return false;
+    }
+
+    public String getProperty(String name) {
+        String result;
+        if (name.startsWith("errorCode.")) {
+            int code = Integer.parseInt(name.substring(10));
+            ErrorPage ep = errorPageSupport.find(code);
+            if (ep == null) {
+                result = null;
+            } else {
+                result = ep.getLocation();
+            }
+        } else if (name.startsWith("exceptionType.")) {
+            String className = name.substring(14);
+            ErrorPage ep = errorPageSupport.find(className);
+            if (ep == null) {
+                result = null;
+            } else {
+                result = ep.getLocation();
+            }
+        } else {
+            result = null;
+        }
+        return result;
+    }
 }

Modified: tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties?rev=1824210&r1=1824209&r2=1824210&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties Wed 
Feb 14 10:17:19 2018
@@ -43,6 +43,8 @@ errorReportValve.note=Note
 errorReportValve.rootCauseInLogs=The full stack trace of the root cause is 
available in the server logs.
 errorReportValve.unknownReason=Unknown Reason
 errorReportValve.noDescription=No description available
+errorReportValve.errorPageIOException=Unable to display error page at [{0}] 
due to an exception
+errorReportValve.errorPageNotFound=Unable to find a static error page at [{0}]
 
 # Remote IP valve
 remoteIpValve.invalidPortHeader=Invalid value [{0}] found for port in HTTP 
header [{1}]

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1824210&r1=1824209&r2=1824210&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Feb 14 10:17:19 2018
@@ -55,6 +55,11 @@
         application provided error handling and/or the container provided error
         handling (<code>ErrorReportValve</code>) as appropriate. (markt)
       </add>
+      <add>
+        <bug>41007</bug>: Add the ability to specify static HTML responses for
+        specific error codes and/or exception types with the
+        <code>ErrorReportValve</code>. (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=1824210&r1=1824209&r2=1824210&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Wed Feb 14 10:17:19 2018
@@ -1710,10 +1710,13 @@
   <subsection name="Introduction">
 
     <p>The <strong>Error Report Valve</strong> is a simple error handler
-    for HTTP status codes that will generate and return HTML error pages.</p>
+    for HTTP status codes that will generate and return HTML error pages. It 
can
+    also be configured to return pre-defined static HTML pages for specific
+    status codes and/or exception types.</p>
 
     <p><strong>NOTE:</strong> Disabling both showServerInfo and showReport will
-    only return the HTTP status code and remove all CSS.</p>
+    only return the HTTP status code and remove all CSS from the default
+    response.</p>
 
   </subsection>
 
@@ -1730,6 +1733,31 @@
         default error report valve.</p>
       </attribute>
 
+      <attribute name="errorCode.nnn" required="false">
+        <p>The location of the UTF-8 encoded HTML file to return for the HTTP
+        error code represented by <code>nnn</code>. For example,
+        <code>errorCode.404</code> specifies the file to return for an HTTP 404
+        error. The location may be relative or absolule. If relative, it must 
be
+        relative to <code>$CATALINA_BASE</code>. The special value of
+        <code>errorCode.0</code> may be used to define a default error page to
+        be used if no error page is defined for a status code. If no matching
+        error page is found, the default <strong>Error Report Valve</strong>
+        response will be returned.</p>
+      </attribute>
+
+      <attribute name="exceptionType.fullyQualifiedClassName" required="false">
+        <p>The location of the UTF-8 encoded HTML file to return if an error 
has
+        occurred and the <code>javax.servlet.error.exception</code> request
+        attribute has been set to an instance of
+        <code>fullyQualifiedClassName</code> or a sub-class of it. For example,
+        <code>errorCode.java.io.IOException</code> specifies the file to return
+        for an <code>IOException</code>. The location may be relative or
+        absolule. If relative, it must be relative to
+        <code>$CATALINA_BASE</code>. If no matching error page is found, the
+        default <strong>Error Report Valve</strong> response will be
+        returned.</p>
+      </attribute>
+
       <attribute name="showReport" required="false">
         <p>Flag to determine if the error report is presented when an error
            occurs. If set to <code>false</code>, then the error report is not 
in



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to