Author: markt
Date: Mon Aug 15 16:36:27 2011
New Revision: 1157904

URL: http://svn.apache.org/viewvc?rev=1157904&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51653
Move application level error page handling from the Host to the Context. This 
ensures that application error page handling is completed before the 
requestDestroyed event of any ServletRequestListener is fired.

Added:
    
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContextValve.java
      - copied, changed from r1157810, 
tomcat/trunk/test/org/apache/catalina/core/TestStandardContextValve.java
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 Mon Aug 15 16:36:27 2011
@@ -1 +1 @@
-/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018
+/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157810,1157832,1157834,1157847

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=1157904&r1=1157903&r2=1157904&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 
Mon Aug 15 16:36:27 2011
@@ -21,16 +21,24 @@ 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;
 
 /**
@@ -44,8 +52,9 @@ import org.apache.tomcat.util.buf.Messag
  * @version $Id$
  */
 
-final class StandardContextValve
-    extends ValveBase {
+final class StandardContextValve extends ValveBase {
+    
+    private static final Log log = LogFactory.getLog(StandardHostValve.class);
 
     //------------------------------------------------------ Constructor
     public StandardContextValve() {
@@ -112,10 +121,10 @@ final class StandardContextValve
         // Disallow any direct access to resources under WEB-INF or META-INF
         MessageBytes requestPathMB = request.getRequestPathMB();
         if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
-            || (requestPathMB.equalsIgnoreCase("/META-INF"))
-            || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
-            || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
-            error(response, HttpServletResponse.SC_NOT_FOUND);
+                || (requestPathMB.equalsIgnoreCase("/META-INF"))
+                || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
+                || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
+            error(request, response, HttpServletResponse.SC_NOT_FOUND);
             return;
         }
 
@@ -142,13 +151,13 @@ final class StandardContextValve
         // Select the Wrapper to be used for this Request
         Wrapper wrapper = request.getWrapper();
         if (wrapper == null) {
-            error(response, HttpServletResponse.SC_NOT_FOUND);
+            error(request, response, 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(response, HttpServletResponse.SC_NOT_FOUND);
+                error(request, response, HttpServletResponse.SC_NOT_FOUND);
                 return;
             }
         }
@@ -160,7 +169,8 @@ final class StandardContextValve
             container.getLogger().error(sm.getString(
                     "standardContextValve.acknowledgeException"), ioe);
             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
-            error(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            error(request, response,
+                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
             return;
         }
         
@@ -184,6 +194,18 @@ final class StandardContextValve
                 // 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);
                 }
             }
@@ -210,14 +232,19 @@ final class StandardContextValve
         // Select the Wrapper to be used for this Request
         Wrapper wrapper = request.getWrapper();
 
-        // Normal request processing
-        // FIXME: Firing request listeners could be an addition to the core
-        // comet API
-        
-        //if (context.fireRequestInitEvent(request)) {
-            wrapper.getPipeline().getFirst().event(request, response, event);
-        //    context.fireRequestDestroyEvent(request);
-        //}
+        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);
+        }
     }
 
 
@@ -225,15 +252,14 @@ final class StandardContextValve
 
 
     /**
-     * Report an error for the specified resource.  FIXME:  We
-     * should really be using the error reporting settings for this web
-     * application, but currently that code runs at the wrapper level rather
-     * than the context level.
+     * Report an error for the specified resource.
      *
      * @param response The response we are creating
      */
-    private void error(HttpServletResponse response, int status) {
+    private void error(Request request, Response response, int status) {
 
+        context.fireRequestInitEvent(request);
+        
         try {
             response.sendError(status);
         } catch (IllegalStateException e) {
@@ -242,7 +268,238 @@ final class StandardContextValve
             // 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=1157904&r1=1157903&r2=1157904&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 
Mon Aug 15 16:36:27 2011
@@ -23,24 +23,15 @@ 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;
 
 
@@ -56,11 +47,7 @@ import org.apache.tomcat.util.res.String
  * @version $Id$
  */
 
-final class StandardHostValve
-    extends ValveBase {
-
-
-    private static final Log log = LogFactory.getLog(StandardHostValve.class);
+final class StandardHostValve extends ValveBase {
 
     protected static final boolean STRICT_SERVLET_COMPLIANCE;
 
@@ -169,18 +156,6 @@ final class StandardHostValve
             request.getSession(false);
         }
 
-        // 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);
-        }
-
         // Restore the context classloader
         if (Globals.IS_SECURITY_ENABLED) {
             PrivilegedAction<Void> pa = new PrivilegedSetTccl(
@@ -228,18 +203,6 @@ final class StandardHostValve
             request.getSession(false);
         }
 
-        // 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);
-        }
-
         // Restore the context classloader
         Thread.currentThread().setContextClassLoader
             (StandardHostValve.class.getClassLoader());
@@ -247,242 +210,6 @@ final class StandardHostValve
     }
 
 
-    // ------------------------------------------------------ Protected Methods
-
-
-    /**
-     * 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
-     */
-    protected 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 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
-     */
-    protected 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);
-                }
-            }
-        }
-
-    }
-
-
-    /**
-     * 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
-     */
-    protected 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);
-
-    }
-
-
-    /**
-     * 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
-     */
-    protected 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);
-
-        }
-
-    }
-
-    
     private static class PrivilegedSetTccl implements PrivilegedAction<Void> {
 
         private ClassLoader cl;

Copied: 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContextValve.java
 (from r1157810, 
tomcat/trunk/test/org/apache/catalina/core/TestStandardContextValve.java)
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContextValve.java?p2=tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContextValve.java&p1=tomcat/trunk/test/org/apache/catalina/core/TestStandardContextValve.java&r1=1157810&r2=1157904&rev=1157904&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TestStandardContextValve.java 
(original)
+++ 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContextValve.java
 Mon Aug 15 16:36:27 2011
@@ -70,6 +70,17 @@ public class TestStandardContextValve ex
         int rc = getUrl("http://localhost:"; + getPort() + "/invalid",
                 new ByteChunk(), null);
 
+        // Need to allow time (but not too long in case the test fails) for
+        // ServletRequestListener to complete
+        int i = 20;
+        while (i > 0) {
+            if (trace.toString().endsWith("Destroy")) {
+                break;
+            }
+            Thread.sleep(250);
+            i--;
+        }
+
         assertEquals(Response.SC_NOT_FOUND, rc);
         assertEquals("InitErrorDestroy", trace.toString());
     }
@@ -110,6 +121,17 @@ public class TestStandardContextValve ex
         int rc = getUrl("http://localhost:"; + getPort() + "/test",
                 new ByteChunk(), null);
 
+        // Need to allow time (but not too long in case the test fails) for
+        // ServletRequestListener to complete
+        int i = 20;
+        while (i > 0) {
+            if (trace.toString().endsWith("Destroy")) {
+                break;
+            }
+            Thread.sleep(250);
+            i--;
+        }
+
         assertEquals(Response.SC_NOT_FOUND, rc);
         assertEquals("InitErrorDestroy", trace.toString());
     }

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=1157904&r1=1157903&r2=1157904&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Mon Aug 15 16:36:27 2011
@@ -82,6 +82,12 @@
         <bug>51650</bug>: Code clean-up. Patch provided by Felix Schumacher.
         (markt)
       </fix>
+      <fix>
+        <bug>51653</bug>: Move application level error page handling from the
+        Host to the Context. This ensures that application error page handling
+        is completed before the requestDestroyed event of any
+        ServletRequestListener is fired. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">



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

Reply via email to