tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1164481 - in /tomcat/tc7.0.x/trunk: ./ java/org/apache/catalina/core/StandardContextValve.java java/org/apache/catalina/core/StandardHostValve.java webapps/docs/changelog.xml
Date Fri, 02 Sep 2011 11:30:56 GMT
Author: markt
Date: Fri Sep  2 11:30:56 2011
New Revision: 1164481

URL: http://svn.apache.org/viewvc?rev=1164481&view=rev
Log:
Fix a regression with the fix for 51653 that broke custom error page handling for error status
codes return by the authenticators.
This moves error page handling back to the host valve and also moves request listener handling
to the host valve. This ensures that everything at a context level happens inside the listeners
and that custom error pages are available for all context errors.

Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContextValve.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java
    tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Sep  2 11:30:56 2011
@@ -1 +1 @@
-/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438
+/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContextValve.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContextValve.java?rev=1164481&r1=1164480&r2=1164481&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContextValve.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContextValve.java Fri Sep 
2 11:30:56 2011
@@ -21,24 +21,16 @@ package org.apache.catalina.core;
 
 import java.io.IOException;
 
-import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Container;
-import org.apache.catalina.Context;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.comet.CometEvent;
-import org.apache.catalina.connector.ClientAbortException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
-import org.apache.catalina.deploy.ErrorPage;
 import org.apache.catalina.valves.ValveBase;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.buf.MessageBytes;
 
 /**
@@ -54,8 +46,6 @@ import org.apache.tomcat.util.buf.Messag
 
 final class StandardContextValve extends ValveBase {
     
-    private static final Log log = LogFactory.getLog(StandardHostValve.class);
-
     //------------------------------------------------------ Constructor
     public StandardContextValve() {
         super(true);
@@ -124,7 +114,7 @@ final class StandardContextValve extends
                 || (requestPathMB.equalsIgnoreCase("/META-INF"))
                 || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
                 || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
-            error(request, response, HttpServletResponse.SC_NOT_FOUND);
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
         }
 
@@ -151,13 +141,13 @@ final class StandardContextValve extends
         // Select the Wrapper to be used for this Request
         Wrapper wrapper = request.getWrapper();
         if (wrapper == null) {
-            error(request, response, HttpServletResponse.SC_NOT_FOUND);
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
         } else if (wrapper.isUnavailable()) {
             // May be as a result of a reload, try and find the new wrapper
             wrapper = (Wrapper) container.findChild(wrapper.getName());
             if (wrapper == null) {
-                error(request, response, HttpServletResponse.SC_NOT_FOUND);
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                 return;
             }
         }
@@ -169,47 +159,14 @@ final class StandardContextValve extends
             container.getLogger().error(sm.getString(
                     "standardContextValve.acknowledgeException"), ioe);
             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
-            error(request, response,
-                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
             return;
         }
         
-        // Don't fire listeners during async processing
-        // If a request init listener throws an exception, the request is
-        // aborted
-        boolean asyncAtStart = request.isAsync(); 
-        if (asyncAtStart || context.fireRequestInitEvent(request)) {
-            if (request.isAsyncSupported()) {
-                request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
-            }
-            wrapper.getPipeline().getFirst().invoke(request, response);
-
-            // If the request was async at the start and an error occurred then
-            // the async error handling will kick-in and that will fire the
-            // request destroyed event *after* the error handling has taken
-            // place
-            if (!(request.isAsync() || (asyncAtStart && request.getAttribute(
-                        RequestDispatcher.ERROR_EXCEPTION) != null))) {
-                // Protect against NPEs if context was destroyed during a long
-                // running request.
-                StandardContext c = context;
-                if (c != null && c.getState().isAvailable()) {
-                    // Error page processing
-                    response.setSuspended(false);
-
-                    Throwable t = (Throwable) request.getAttribute(
-                            RequestDispatcher.ERROR_EXCEPTION);
-
-                    if (t != null) {
-                        throwable(request, response, t);
-                    } else {
-                        status(request, response);
-                    }
-
-                    context.fireRequestDestroyEvent(request);
-                }
-            }
+        if (request.isAsyncSupported()) {
+            request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
         }
+        wrapper.getPipeline().getFirst().invoke(request, response);
     }
 
 
@@ -233,273 +190,5 @@ final class StandardContextValve extends
         Wrapper wrapper = request.getWrapper();
 
         wrapper.getPipeline().getFirst().event(request, response, event);
-            
-        // Error page processing
-        response.setSuspended(false);
-
-        Throwable t = (Throwable) request.getAttribute(
-                RequestDispatcher.ERROR_EXCEPTION);
-
-        if (t != null) {
-            throwable(request, response, t);
-        } else {
-            status(request, response);
-        }
-    }
-
-
-    // -------------------------------------------------------- Private Methods
-
-
-    /**
-     * Report an error for the specified resource.
-     *
-     * @param response The response we are creating
-     */
-    private void error(Request request, Response response, int status) {
-
-        context.fireRequestInitEvent(request);
-        
-        try {
-            response.sendError(status);
-        } catch (IllegalStateException e) {
-            // Ignore
-        } catch (IOException e) {
-            // Ignore
-        }
-
-        response.setSuspended(false);
-        status(request, response);
-        
-        context.fireRequestDestroyEvent(request);
-    }
-
-
-    /**
-     * Handle the HTTP status code (and corresponding message) generated
-     * while processing the specified Request to produce the specified
-     * Response.  Any exceptions that occur during generation of the error
-     * report are logged and swallowed.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     */
-    private void status(Request request, Response response) {
-
-        int statusCode = response.getStatus();
-
-        // Handle a custom error page for this status code
-        Context context = request.getContext();
-        if (context == null)
-            return;
-
-        /* Only look for error pages when isError() is set.
-         * isError() is set when response.sendError() is invoked. This
-         * allows custom error pages without relying on default from
-         * web.xml.
-         */
-        if (!response.isError())
-            return;
-
-        ErrorPage errorPage = context.findErrorPage(statusCode);
-        if (errorPage != null) {
-            response.setAppCommitted(false);
-            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
-                              Integer.valueOf(statusCode));
-
-            String message = response.getMessage();
-            if (message == null)
-                message = "";
-            request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
-            request.setAttribute
-                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-                 errorPage.getLocation());
-            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                              DispatcherType.ERROR);
-
-
-            Wrapper wrapper = request.getWrapper();
-            if (wrapper != null)
-                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
-                                  wrapper.getName());
-            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
-                                 request.getRequestURI());
-            if (custom(request, response, errorPage)) {
-                try {
-                    response.flushBuffer();
-                } catch (ClientAbortException e) {
-                    // Ignore
-                } catch (IOException e) {
-                    container.getLogger().warn("Exception Processing " + errorPage, e);
-                }
-            }
-        }
-    }
-
-    
-    /**
-     * Handle the specified Throwable encountered while processing
-     * the specified Request to produce the specified Response.  Any
-     * exceptions that occur during generation of the exception report are
-     * logged and swallowed.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     * @param throwable The exception that occurred (which possibly wraps
-     *  a root cause exception
-     */
-    private void throwable(Request request, Response response,
-                             Throwable throwable) {
-        Context context = request.getContext();
-        if (context == null)
-            return;
-
-        Throwable realError = throwable;
-
-        if (realError instanceof ServletException) {
-            realError = ((ServletException) realError).getRootCause();
-            if (realError == null) {
-                realError = throwable;
-            }
-        }
-
-        // If this is an aborted request from a client just log it and return
-        if (realError instanceof ClientAbortException ) {
-            if (log.isDebugEnabled()) {
-                log.debug
-                    (sm.getString("standardHost.clientAbort",
-                        realError.getCause().getMessage()));
-            }
-            return;
-        }
-
-        ErrorPage errorPage = findErrorPage(context, throwable);
-        if ((errorPage == null) && (realError != throwable)) {
-            errorPage = findErrorPage(context, realError);
-        }
-
-        if (errorPage != null) {
-            response.setAppCommitted(false);
-            request.setAttribute
-                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-                 errorPage.getLocation());
-            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                              DispatcherType.ERROR);
-            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
-                    new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
-            request.setAttribute(RequestDispatcher.ERROR_MESSAGE,
-                              throwable.getMessage());
-            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,
-                              realError);
-            Wrapper wrapper = request.getWrapper();
-            if (wrapper != null)
-                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
-                                  wrapper.getName());
-            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
-                                 request.getRequestURI());
-            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,
-                              realError.getClass());
-            if (custom(request, response, errorPage)) {
-                try {
-                    response.flushBuffer();
-                } catch (IOException e) {
-                    container.getLogger().warn("Exception Processing " + errorPage, e);
-                }
-            }
-        } else {
-            // A custom error-page has not been defined for the exception
-            // that was thrown during request processing. Check if an
-            // error-page for error code 500 was specified and if so,
-            // send that page back as the response.
-            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            // The response is an error
-            response.setError();
-
-            status(request, response);
-        }
-    }
-
-
-    /**
-     * Handle an HTTP status code or Java exception by forwarding control
-     * to the location included in the specified errorPage object.  It is
-     * assumed that the caller has already recorded any request attributes
-     * that are to be forwarded to this page.  Return <code>true</code> if
-     * we successfully utilized the specified error page location, or
-     * <code>false</code> if the default error report should be rendered.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     * @param errorPage The errorPage directive we are obeying
-     */
-    private boolean custom(Request request, Response response,
-                             ErrorPage errorPage) {
-
-        if (container.getLogger().isDebugEnabled())
-            container.getLogger().debug("Processing " + errorPage);
-
-        request.setPathInfo(errorPage.getLocation());
-
-        try {
-            // Forward control to the specified location
-            ServletContext servletContext =
-                request.getContext().getServletContext();
-            RequestDispatcher rd =
-                servletContext.getRequestDispatcher(errorPage.getLocation());
-
-            if (response.isCommitted()) {
-                // Response is committed - including the error page is the
-                // best we can do 
-                rd.include(request.getRequest(), response.getResponse());
-            } else {
-                // Reset the response (keeping the real error code and message)
-                response.resetBuffer(true);
-
-                rd.forward(request.getRequest(), response.getResponse());
-
-                // If we forward, the response is suspended again
-                response.setSuspended(false);
-            }
-
-            // Indicate that we have successfully processed this custom page
-            return (true);
-
-        } catch (Throwable t) {
-            ExceptionUtils.handleThrowable(t);
-            // Report our failure to process this custom page
-            container.getLogger().error("Exception Processing " + errorPage, t);
-            return (false);
-
-        }
-    }
-
-    
-    /**
-     * Find and return the ErrorPage instance for the specified exception's
-     * class, or an ErrorPage instance for the closest superclass for which
-     * there is such a definition.  If no associated ErrorPage instance is
-     * found, return <code>null</code>.
-     *
-     * @param context The Context in which to search
-     * @param exception The exception for which to find an ErrorPage
-     */
-    private static ErrorPage findErrorPage
-        (Context context, Throwable exception) {
-
-        if (exception == null)
-            return (null);
-        Class<?> clazz = exception.getClass();
-        String name = clazz.getName();
-        while (!Object.class.equals(clazz)) {
-            ErrorPage errorPage = context.findErrorPage(name);
-            if (errorPage != null)
-                return (errorPage);
-            clazz = clazz.getSuperclass();
-            if (clazz == null)
-                break;
-            name = clazz.getName();
-        }
-        return (null);
-
     }
 }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java?rev=1164481&r1=1164480&r2=1164481&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java Fri Sep  2 11:30:56
2011
@@ -23,15 +23,24 @@ import java.io.IOException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
 import org.apache.catalina.comet.CometEvent;
+import org.apache.catalina.connector.ClientAbortException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.ErrorPage;
 import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.res.StringManager;
 
 
@@ -49,6 +58,8 @@ import org.apache.tomcat.util.res.String
 
 final class StandardHostValve extends ValveBase {
 
+    private static final Log log = LogFactory.getLog(StandardHostValve.class);
+
     protected static final boolean STRICT_SERVLET_COMPLIANCE;
 
     protected static final boolean ACCESS_SESSION;
@@ -146,9 +157,40 @@ final class StandardHostValve extends Va
             request.setAsyncSupported(context.getPipeline().isAsyncSupported());
         }
 
-
-        // Ask this Context to process this request
-        context.getPipeline().getFirst().invoke(request, response);
+        // Don't fire listeners during async processing
+        // If a request init listener throws an exception, the request is
+        // aborted
+        boolean asyncAtStart = request.isAsync(); 
+        if (asyncAtStart || context.fireRequestInitEvent(request)) {
+
+            // Ask this Context to process this request
+            context.getPipeline().getFirst().invoke(request, response);
+    
+            // If the request was async at the start and an error occurred then
+            // the async error handling will kick-in and that will fire the
+            // request destroyed event *after* the error handling has taken
+            // place
+            if (!(request.isAsync() || (asyncAtStart && request.getAttribute(
+                        RequestDispatcher.ERROR_EXCEPTION) != null))) {
+                // Protect against NPEs if context was destroyed during a long
+                // running request.
+                if (context.getState().isAvailable()) {
+                    // Error page processing
+                    response.setSuspended(false);
+    
+                    Throwable t = (Throwable) request.getAttribute(
+                            RequestDispatcher.ERROR_EXCEPTION);
+    
+                    if (t != null) {
+                        throwable(request, response, t);
+                    } else {
+                        status(request, response);
+                    }
+    
+                    context.fireRequestDestroyEvent(request);
+                }
+            }
+        }
 
         // Access a session (if present) to update last accessed time, based on a
         // strict interpretation of the specification
@@ -165,7 +207,6 @@ final class StandardHostValve extends Va
             Thread.currentThread().setContextClassLoader
                     (StandardHostValve.class.getClassLoader());
         }
-
     }
 
 
@@ -197,6 +238,19 @@ final class StandardHostValve extends Va
         // Ask this Context to process this request
         context.getPipeline().getFirst().event(request, response, event);
 
+        
+        // Error page processing
+        response.setSuspended(false);
+
+        Throwable t = (Throwable) request.getAttribute(
+                RequestDispatcher.ERROR_EXCEPTION);
+
+        if (t != null) {
+            throwable(request, response, t);
+        } else {
+            status(request, response);
+        }
+
         // Access a session (if present) to update last accessed time, based on a
         // strict interpretation of the specification
         if (ACCESS_SESSION) {
@@ -210,6 +264,237 @@ final class StandardHostValve extends Va
     }
 
 
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Handle the HTTP status code (and corresponding message) generated
+     * while processing the specified Request to produce the specified
+     * Response.  Any exceptions that occur during generation of the error
+     * report are logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     */
+    private void status(Request request, Response response) {
+
+        int statusCode = response.getStatus();
+
+        // Handle a custom error page for this status code
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        /* Only look for error pages when isError() is set.
+         * isError() is set when response.sendError() is invoked. This
+         * allows custom error pages without relying on default from
+         * web.xml.
+         */
+        if (!response.isError())
+            return;
+
+        ErrorPage errorPage = context.findErrorPage(statusCode);
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
+                              Integer.valueOf(statusCode));
+
+            String message = response.getMessage();
+            if (message == null)
+                message = "";
+            request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              DispatcherType.ERROR);
+
+
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
+                                  wrapper.getName());
+            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
+                                 request.getRequestURI());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (ClientAbortException e) {
+                    // Ignore
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Handle the specified Throwable encountered while processing
+     * the specified Request to produce the specified Response.  Any
+     * exceptions that occur during generation of the exception report are
+     * logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param throwable The exception that occurred (which possibly wraps
+     *  a root cause exception
+     */
+    private void throwable(Request request, Response response,
+                             Throwable throwable) {
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        Throwable realError = throwable;
+
+        if (realError instanceof ServletException) {
+            realError = ((ServletException) realError).getRootCause();
+            if (realError == null) {
+                realError = throwable;
+            }
+        }
+
+        // If this is an aborted request from a client just log it and return
+        if (realError instanceof ClientAbortException ) {
+            if (log.isDebugEnabled()) {
+                log.debug
+                    (sm.getString("standardHost.clientAbort",
+                        realError.getCause().getMessage()));
+            }
+            return;
+        }
+
+        ErrorPage errorPage = findErrorPage(context, throwable);
+        if ((errorPage == null) && (realError != throwable)) {
+            errorPage = findErrorPage(context, realError);
+        }
+
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              DispatcherType.ERROR);
+            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
+                    new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
+            request.setAttribute(RequestDispatcher.ERROR_MESSAGE,
+                              throwable.getMessage());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,
+                              realError);
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
+                                  wrapper.getName());
+            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
+                                 request.getRequestURI());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,
+                              realError.getClass());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        } else {
+            // A custom error-page has not been defined for the exception
+            // that was thrown during request processing. Check if an
+            // error-page for error code 500 was specified and if so,
+            // send that page back as the response.
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            // The response is an error
+            response.setError();
+
+            status(request, response);
+        }
+    }
+
+
+    /**
+     * Handle an HTTP status code or Java exception by forwarding control
+     * to the location included in the specified errorPage object.  It is
+     * assumed that the caller has already recorded any request attributes
+     * that are to be forwarded to this page.  Return <code>true</code> if
+     * we successfully utilized the specified error page location, or
+     * <code>false</code> if the default error report should be rendered.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param errorPage The errorPage directive we are obeying
+     */
+    private boolean custom(Request request, Response response,
+                             ErrorPage errorPage) {
+
+        if (container.getLogger().isDebugEnabled())
+            container.getLogger().debug("Processing " + errorPage);
+
+        request.setPathInfo(errorPage.getLocation());
+
+        try {
+            // Forward control to the specified location
+            ServletContext servletContext =
+                request.getContext().getServletContext();
+            RequestDispatcher rd =
+                servletContext.getRequestDispatcher(errorPage.getLocation());
+
+            if (response.isCommitted()) {
+                // Response is committed - including the error page is the
+                // best we can do 
+                rd.include(request.getRequest(), response.getResponse());
+            } else {
+                // Reset the response (keeping the real error code and message)
+                response.resetBuffer(true);
+
+                rd.forward(request.getRequest(), response.getResponse());
+
+                // If we forward, the response is suspended again
+                response.setSuspended(false);
+            }
+
+            // Indicate that we have successfully processed this custom page
+            return (true);
+
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            // Report our failure to process this custom page
+            container.getLogger().error("Exception Processing " + errorPage, t);
+            return (false);
+
+        }
+    }
+
+
+    /**
+     * Find and return the ErrorPage instance for the specified exception's
+     * class, or an ErrorPage instance for the closest superclass for which
+     * there is such a definition.  If no associated ErrorPage instance is
+     * found, return <code>null</code>.
+     *
+     * @param context The Context in which to search
+     * @param exception The exception for which to find an ErrorPage
+     */
+    private static ErrorPage findErrorPage
+        (Context context, Throwable exception) {
+
+        if (exception == null)
+            return (null);
+        Class<?> clazz = exception.getClass();
+        String name = clazz.getName();
+        while (!Object.class.equals(clazz)) {
+            ErrorPage errorPage = context.findErrorPage(name);
+            if (errorPage != null)
+                return (errorPage);
+            clazz = clazz.getSuperclass();
+            if (clazz == null)
+                break;
+            name = clazz.getName();
+        }
+        return (null);
+
+    }
+
+
     private static class PrivilegedSetTccl implements PrivilegedAction<Void> {
 
         private ClassLoader cl;

Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1164481&r1=1164480&r2=1164481&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Fri Sep  2 11:30:56 2011
@@ -65,6 +65,12 @@
         publishing" feature where applications failed to access resources when using
         getResource() on the classloader. (slaurent)
       </add>
+      <fix>
+        Correct a regression with the fix for <bug>51653</bug> that broke custom
+        error pages for 4xx responses from the Authenticators. Error handling
+        and request listeners are now handled in the StandardHostValve to ensure
+        they wrap all Context level activity. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">



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


Mime
View raw message