Author: fmeschbe
Date: Wed Jan 28 12:48:33 2009
New Revision: 738470

URL: http://svn.apache.org/viewvc?rev=738470&view=rev
Log:
SLING-601 Add RecursionTooDeepException, thrown when recursion reaches a 
configurable
limit, and TooManyCallsException, thrown when number of calls readches a 
configurable
limit. And add implementation of limit configuration and checking

Added:
    
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
   (with props)
    
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
   (with props)
Modified:
    
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
    
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java
    
incubator/sling/trunk/engine/src/main/resources/OSGI-INF/metatype/metatype.properties

Added: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java?rev=738470&view=auto
==============================================================================
--- 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
 (added)
+++ 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
 Wed Jan 28 12:48:33 2009
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.api.request;
+
+import org.apache.sling.api.SlingException;
+
+/**
+ * The <code>RecursionTooDeepException</code> is thrown by the Sling
+ * implementation if to many recursive content inclusions take place. The limit
+ * of recursive inclusions is implementation dependent.
+ */
+public class RecursionTooDeepException extends SlingException {
+
+    /**
+     * Creates a new instance of this class reporting the exception occurred
+     * while trying to include the output for rendering the resource at the
+     * given path.
+     * <p>
+     * The resource path is the actual message of the exception.
+     * 
+     * @param resourcePath The path of the resource whose output inclusion
+     *            causes this exception.
+     */
+    public RecursionTooDeepException(String resourcePath) {
+        super(resourcePath);
+    }
+
+}

Propchange: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/RecursionTooDeepException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Added: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java?rev=738470&view=auto
==============================================================================
--- 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
 (added)
+++ 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
 Wed Jan 28 12:48:33 2009
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.api.request;
+
+import org.apache.sling.api.SlingException;
+
+/**
+ * The <code>TooManyCallsException</code> is thrown by the Sling implementation
+ * if to many inclusions have been called for during a single request. The 
limit
+ * of inclusions is implementation dependent.
+ */
+public class TooManyCallsException extends SlingException {
+
+    /**
+     * Creates an instance of this exception naming the Servlet (or Script)
+     * whose call caused this exception to be thrown.
+     * <p>
+     * The servlet name is the actual message of the exception.
+     * 
+     * @param servletName The name of the Servlet (or Script) causing this
+     *            exception.
+     */
+    public TooManyCallsException(String servletName) {
+        super(servletName);
+    }
+    
+}

Propchange: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
incubator/sling/trunk/api/src/main/java/org/apache/sling/api/request/TooManyCallsException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java?rev=738470&r1=738469&r2=738470&view=diff
==============================================================================
--- 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
 (original)
+++ 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
 Wed Jan 28 12:48:33 2009
@@ -39,7 +39,6 @@
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.GenericServlet;
-import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -58,6 +57,7 @@
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.servlets.ServletResolver;
 import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.commons.osgi.OsgiUtil;
 import org.apache.sling.engine.ResponseUtil;
 import org.apache.sling.engine.impl.auth.MissingRepositoryException;
 import org.apache.sling.engine.impl.auth.SlingAuthenticator;
@@ -86,7 +86,8 @@
 /**
  * The <code>SlingMainServlet</code> TODO
  * 
- * @scr.component immediate="true" metatype="no"
+ * @scr.component immediate="true" label="%sling.name"
+ *                description="%sling.description"
  * @scr.property name="service.vendor" value="The Apache Software Foundation"
  * @scr.property name="service.description" value="Sling Servlet"
  * @scr.reference name="Filter" interface="javax.servlet.Filter"
@@ -95,6 +96,12 @@
 public class SlingMainServlet extends GenericServlet implements ErrorHandler,
         HttpContext {
 
+    /** @scr.property valueRef="RequestData.DEFAULT_MAX_CALL_COUNTER" */
+    public static final String PROP_MAX_CALL_COUNTER = "sling.max.calls"; 
+
+    /** @scr.property valueRef="RequestData.DEFAULT_MAX_INCLUSION_COUNTER" */
+    public static final String PROP_MAX_INCLUSION_COUNTER = 
"sling.max.inclusions"; 
+    
     /** default log */
     private static final Logger log = 
LoggerFactory.getLogger(SlingMainServlet.class);
 
@@ -157,17 +164,6 @@
 
     private SlingAuthenticator slingAuthenticator;
 
-    private static final String INCLUDE_COUNTER = 
"Sling.ScriptHelper.include.counter";
-
-    private static final int MAX_INCLUDE_RECURSION_LEVEL = 50;
-
-    public static class InfiniteIncludeLoopException extends SlingException {
-        InfiniteIncludeLoopException(String path) {
-            super("Infinite include loop (> " + MAX_INCLUDE_RECURSION_LEVEL
-                + " levels) for path '" + path + "'");
-        }
-    }
-
     // ---------- Servlet API -------------------------------------------------
 
     public void service(ServletRequest req, ServletResponse res)
@@ -369,84 +365,28 @@
 
     // ---------- Generic Content Request processor 
----------------------------
 
-    public void includeServlet(ServletRequest request,
-            ServletResponse response, String path) throws IOException,
-            ServletException {
-
-        checkRecursionLevel(request, path);
-
-        // check type of response, don't care actually for the response itself
-        RequestData.unwrap(response);
-
-        // get the request data (and btw check the correct type
-        RequestData requestData = RequestData.getRequestData(request);
-
-        RequestDispatcher rd = 
requestData.getServletRequest().getRequestDispatcher(
-            path);
-        if (rd != null) {
-            rd.include(request, response);
-        } else {
-            log.error("includeServlet: Got no request dispatcher for {}", 
path);
-        }
-    }
-
     public void includeContent(ServletRequest request,
             ServletResponse response, Resource resource,
             RequestPathInfo resolvedURL) throws IOException, ServletException {
 
-        checkRecursionLevel(request, resolvedURL.getResourcePath());
+        // we need a SlingHttpServletRequest/SlingHttpServletResponse tupel
+        // to continue
+        SlingHttpServletRequest cRequest = 
RequestData.toSlingHttpServletRequest(request);
+        SlingHttpServletResponse cResponse = 
RequestData.toSlingHttpServletResponse(response);
+
+        // get the request data (and btw check the correct type)
+        RequestData requestData = RequestData.getRequestData(cRequest);
+        ContentData contentData = requestData.pushContent(resource,
+            resolvedURL);
 
         try {
-            // we need a SlingHttpServletRequest/SlingHttpServletResponse tupel
-            // to continue
-            SlingHttpServletRequest cRequest = 
RequestData.toSlingHttpServletRequest(request);
-            SlingHttpServletResponse cResponse = 
RequestData.toSlingHttpServletResponse(response);
-
-            // get the request data (and btw check the correct type)
-            RequestData requestData = RequestData.getRequestData(cRequest);
-            ContentData contentData = requestData.pushContent(resource,
-                resolvedURL);
-
-            try {
-                // resolve the servlet
-                Servlet servlet = 
getServletResolver().resolveServlet(cRequest);
-                contentData.setServlet(servlet);
+            // resolve the servlet
+            Servlet servlet = getServletResolver().resolveServlet(cRequest);
+            contentData.setServlet(servlet);
 
-                processRequest(cRequest, cResponse);
-            } finally {
-                requestData.popContent();
-            }
+            processRequest(cRequest, cResponse);
         } finally {
-            decreaseRecursionLevel(request);
-        }
-    }
-
-    /** Add a recursion counter to req and fail if it's too high */
-    protected void checkRecursionLevel(ServletRequest request, String info)
-            throws InfiniteIncludeLoopException {
-        // Detect infinite loops
-        Integer recursionLevel = (Integer) 
request.getAttribute(INCLUDE_COUNTER);
-        if (recursionLevel == null) {
-            recursionLevel = new Integer(1);
-        } else if (recursionLevel.intValue() > MAX_INCLUDE_RECURSION_LEVEL) {
-            throw new InfiniteIncludeLoopException(info);
-        } else {
-            recursionLevel = new Integer(recursionLevel.intValue() + 1);
-        }
-        request.setAttribute(INCLUDE_COUNTER, recursionLevel);
-    }
-
-    /** Decrease the recursion counter */
-    protected void decreaseRecursionLevel(ServletRequest request) {
-        // this should never be null, but we better do a sanity check
-        final Integer recursionLevel = (Integer) 
request.getAttribute(INCLUDE_COUNTER);
-        if (recursionLevel != null) {
-            if (recursionLevel == 1) {
-                request.removeAttribute(INCLUDE_COUNTER);
-            } else {
-                request.setAttribute(INCLUDE_COUNTER, new Integer(
-                    recursionLevel.intValue() - 1));
-            }
+            requestData.popContent();
         }
     }
 
@@ -619,6 +559,14 @@
                 + productVersion);
         }
 
+        // configure the request limits
+        RequestData.setMaxIncludeCounter(OsgiUtil.toInteger(
+            componentConfig.get(PROP_MAX_INCLUSION_COUNTER),
+            RequestData.DEFAULT_MAX_INCLUSION_COUNTER));
+        RequestData.setMaxCallCounter(OsgiUtil.toInteger(
+            componentConfig.get(PROP_MAX_CALL_COUNTER),
+            RequestData.DEFAULT_MAX_CALL_COUNTER));
+        
         // setup servlet request processing helpers
         SlingServletContext tmpServletContext = new SlingServletContext(this);
         slingAuthenticator = new SlingAuthenticator(bundleContext);

Modified: 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java?rev=738470&r1=738469&r2=738470&view=diff
==============================================================================
--- 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java
 (original)
+++ 
incubator/sling/trunk/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java
 Wed Jan 28 12:48:33 2009
@@ -42,8 +42,10 @@
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.request.RecursionTooDeepException;
 import org.apache.sling.api.request.RequestPathInfo;
 import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.api.request.TooManyCallsException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.servlets.ServletResolver;
@@ -78,6 +80,35 @@
     /** default log */
     private final Logger log = LoggerFactory.getLogger(RequestData.class);
 
+    /**
+     * The default value for the number of recursive inclusions for a single
+     * instance of this class (value is 50).
+     */
+    public static final int DEFAULT_MAX_INCLUSION_COUNTER = 50;
+
+    /**
+     * The default value for the number of calls to the
+     * {...@link #service(SlingHttpServletRequest, SlingHttpServletResponse)}
+     * method for a single instance of this class (value is 1000).
+     */
+    public static final int DEFAULT_MAX_CALL_COUNTER = 1000;
+
+    /**
+     * The maximum inclusion depth (default
+     * {...@link #DEFAULT_MAX_INCLUSION_COUNTER}). This value is compared to 
the
+     * number of entries in the {...@link #contentDataStack} when the
+     * {...@link #pushContent(Resource, RequestPathInfo)} method is called.
+     */
+    private static int maxInclusionCounter = DEFAULT_MAX_INCLUSION_COUNTER;
+
+    /**
+     * The maximum number of scripts which may be included through the
+     * {...@link #service(SlingHttpServletRequest, SlingHttpServletResponse)}
+     * method (default {...@link #DEFAULT_MAX_CALL_COUNTER}). This number 
should
+     * not be too small to prevent request aborts.
+     */
+    private static int maxCallCounter = DEFAULT_MAX_CALL_COUNTER;
+    
     /** The SlingMainServlet used for request dispatching and other stuff */
     private final SlingMainServlet slingMainServlet;
 
@@ -114,15 +145,30 @@
 
     /**
      * The name of the currently active serlvet.
-     *
+     * 
      * @see #setActiveServletName(String)
      * @see #getActiveServletName()
      */
     private String activeServletName;
 
+    public static void setMaxCallCounter(int maxCallCounter) {
+        RequestData.maxCallCounter = maxCallCounter;
+    }
+
+    public static int getMaxCallCounter() {
+        return maxCallCounter;
+    }
+
+    public static void setMaxIncludeCounter(int maxInclusionCounter) {
+        RequestData.maxInclusionCounter = maxInclusionCounter;
+    }
+
+    public static int getMaxIncludeCounter() {
+        return maxInclusionCounter;
+    }
+
     public RequestData(SlingMainServlet slingMainServlet,
-            HttpServletRequest request,
-            HttpServletResponse response) {
+            HttpServletRequest request, HttpServletResponse response) {
 
         this.slingMainServlet = slingMainServlet;
 
@@ -452,9 +498,17 @@
         } else {
 
             String name = RequestUtil.getServletName(servlet);
+
+            // verify the number of service calls in this request
+            if (requestData.servletCallCounter >= maxCallCounter) {
+                throw new TooManyCallsException(name);
+            }
+            
+            // replace the current servlet name in the request
             Object oldValue = request.getAttribute(SLING_CURRENT_SERVLET_NAME);
             request.setAttribute(SLING_CURRENT_SERVLET_NAME, name);
 
+            // setup the tracker for this service call
             String timerName = name + "#" + requestData.servletCallCounter;
             requestData.servletCallCounter++;
             requestData.getRequestProgressTracker().startTimer(timerName);
@@ -486,6 +540,9 @@
         if (currentContentData != null) {
             if (contentDataStack == null) {
                 contentDataStack = new LinkedList<ContentData>();
+            } else if (contentDataStack.size() >= maxInclusionCounter) {
+                throw new RecursionTooDeepException(
+                    requestPathInfo.getResourcePath());
             }
 
             // set the request attributes of the include content data

Modified: 
incubator/sling/trunk/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/engine/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=738470&r1=738469&r2=738470&view=diff
==============================================================================
--- 
incubator/sling/trunk/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
 (original)
+++ 
incubator/sling/trunk/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
 Wed Jan 28 12:48:33 2009
@@ -24,6 +24,25 @@
 # the Sling SCR plugin
 
 #
+# SlingMainServlet. The configuration of the SlingMainServlet
+sling.name = Apache Sling Main Servlet
+sling.description = Main processor of the Sling framework controlling all \
+ aspects of processing requests inside of Sling, namely authentication, \
+ resource resolution, servlet/script resolution and execution of servlets \
+ and scripts.
+sling.max.calls.name = Number of Calls per Request
+sling.max.calls.description = Defines the maximum number of Servlet and Script 
\
+ calls while processing a single client request. This number should be high \
+ enough to not limit request processing artificially. On the other hand it \
+ should not be too high to allow the mechanism to limit the resources required 
\
+ to process a request in case of errors. The default value is 1000.
+sling.max.inclusions.name = Recursion Depth
+sling.max.inclusions.description = The maximum number of recursive Servlet and 
\
+ Script calls while processing a single client request. This number should not 
\
+ be too high, otherwise StackOverflowErrors may occurr in case of erroneous \
+ scripts and servlets. The default value is 50.
+ 
+#
 # Request Authenticator. Uses AuthenticationHandlers for the
 # actual work of extracting user details from the request.
 auth.name = Apache Sling Request Authenticator


Reply via email to