Port fix bug 39088 that prevents infinite loops when an exception is thrown the retur...
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 28 Jan 2007 00:55:24 +0000 (00:55 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 28 Jan 2007 00:55:24 +0000 (00:55 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@500716 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/core/StandardWrapper.java
java/org/apache/catalina/valves/ErrorReportValve.java
webapps/docs/changelog.xml

index ed0003e..9dc8d4b 100644 (file)
@@ -31,6 +31,8 @@ import java.util.Stack;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.sql.SQLException;
+
 import javax.servlet.Servlet;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
@@ -60,6 +62,7 @@ import org.apache.catalina.Wrapper;
 import org.apache.catalina.security.SecurityUtil;
 import org.apache.catalina.util.Enumerator;
 import org.apache.catalina.util.InstanceSupport;
+import org.apache.tomcat.util.IntrospectionUtils;
 import org.apache.tomcat.util.log.SystemLogHandler;
 import org.apache.tomcat.util.modeler.Registry;
 
@@ -291,7 +294,19 @@ public class StandardWrapper
      */
     protected static Properties restrictedServlets = null;
     
+
+    private static Class jspExceptionClazz;
     
+    static {
+        try {
+            jspExceptionClazz = Class.forName("javax.servlet.jsp.JspException");
+        } catch (ClassNotFoundException e) {
+            // Expected if jsp-api not on classpath, eg when embedding
+            jspExceptionClazz = null;
+        }
+    }
+
+
     // ------------------------------------------------------------- Properties
 
 
@@ -675,20 +690,43 @@ public class StandardWrapper
      * @param e The servlet exception
      */
     public static Throwable getRootCause(ServletException e) {
-        Throwable rootCause = e;
-        Throwable rootCauseCheck = null;
-        // Extra aggressive rootCause finding
-        int loops = 0;
-        do {
-            loops++;
-            rootCauseCheck = rootCause.getCause();
-            if (rootCauseCheck != null)
-                rootCause = rootCauseCheck;
-        } while (rootCauseCheck != null && (loops < 20));
-        return rootCause;
+        Throwable rootCause = e.getRootCause();
+        return findRootCause(e, rootCause);
     }
 
 
+    /*
+     * Work through the root causes using specific methods for well known types
+     * and getCause() for the rest. Stop when the next rootCause is null or
+     * an exception is found that has itself as its own rootCause. 
+     */
+    private static final Throwable findRootCause(Throwable theException,
+            Throwable theRootCause) {
+        
+        Throwable deeperRootCause = null;
+
+        if (theRootCause == null || theRootCause == theException) {
+            return theException;
+        }
+        
+        if (theRootCause instanceof ServletException) {
+            deeperRootCause = ((ServletException) theRootCause).getRootCause();
+        } else if (jspExceptionClazz!=null &&
+                jspExceptionClazz.isAssignableFrom(theRootCause.getClass())) {
+            deeperRootCause = (Throwable)IntrospectionUtils.getProperty(
+                    theRootCause, "rootCause"); 
+        } else if (theRootCause instanceof SQLException) {
+            deeperRootCause = ((SQLException) theRootCause).getNextException();
+        }
+        if (deeperRootCause == null) {
+            deeperRootCause = theRootCause.getCause();
+        }
+        
+        return findRootCause(theRootCause, deeperRootCause);
+    }
+
+
+
     /**
      * Refuse to add a child Container, because Wrappers are the lowest level
      * of the Container hierarchy.
index a703add..1a2d622 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.catalina.valves;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.sql.SQLException;
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -33,6 +34,7 @@ import org.apache.catalina.connector.Response;
 import org.apache.catalina.util.RequestUtil;
 import org.apache.catalina.util.ServerInfo;
 import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.IntrospectionUtils;
 
 /**
  * <p>Implementation of a Valve that outputs HTML error pages.</p>
@@ -71,6 +73,18 @@ public class ErrorReportValve
         StringManager.getManager(Constants.Package);
 
 
+    private static Class jspExceptionClazz;
+
+    static {
+        try {
+            jspExceptionClazz = Class.forName("javax.servlet.jsp.JspException");
+        } catch (ClassNotFoundException e) {
+            // Expected if jsp-api not on classpath, eg when embedding
+            jspExceptionClazz = null;
+        }
+    }
+    
+    
     // ------------------------------------------------------------- Properties
 
 
@@ -216,9 +230,9 @@ public class ErrorReportValve
             sb.append(RequestUtil.filter(stackTrace));
             sb.append("</pre></p>");
 
-            int loops = 0;
             Throwable rootCause = throwable.getCause();
-            while (rootCause != null && (loops < 10)) {
+            Throwable nestedRootCause = null;
+            while (rootCause != null) {
                 stackTrace = getPartialServletStackTrace(rootCause);
                 sb.append("<p><b>");
                 sb.append(sm.getString("errorReportValve.rootCause"));
@@ -226,10 +240,33 @@ public class ErrorReportValve
                 sb.append(RequestUtil.filter(stackTrace));
                 sb.append("</pre></p>");
                 // In case root cause is somehow heavily nested
-                rootCause = rootCause.getCause();
-                loops++;
+                try {
+                    if (rootCause instanceof ServletException) {
+                        nestedRootCause =
+                            ((ServletException) rootCause).getRootCause();
+                    } else if (jspExceptionClazz!=null &&
+                            jspExceptionClazz.isAssignableFrom(
+                                    rootCause.getClass())) {
+                        nestedRootCause = (Throwable)IntrospectionUtils.
+                                getProperty(rootCause, "rootCause"); 
+                    } else if (rootCause instanceof SQLException) {
+                        nestedRootCause = ((SQLException) rootCause).
+                                getNextException();
+                    }
+                    if (nestedRootCause == null) {
+                        nestedRootCause = rootCause.getCause();
+                    }
+
+                    if (rootCause == nestedRootCause)
+                        rootCause = null;
+                    else {
+                        rootCause = nestedRootCause;
+                        nestedRootCause = null;
+                    }
+                } catch (ClassCastException e) {
+                    rootCause = null;
+                }
             }
-
             sb.append("<p><b>");
             sb.append(sm.getString("errorReportValve.note"));
             sb.append("</b> <u>");
index 5fcab1f..2dd0dd9 100644 (file)
         web.xml. (markt)
       </fix>
       <fix>
+        <bug>39088</bug>: Prevent infinte loops when an exception is thrown
+        that returns itself for getRootCause(). (markt)
+      </fix>
+      <fix>
         <bug>41217</bug>: Set secure attribute on SSO cookie when cookie is
         created during a secure request. Patch provided by Chris Halstead.
         (markt)