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