You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2016/02/23 16:45:12 UTC

svn commit: r1731890 - in /sling/trunk/contrib/extensions/bgservlets: engine/ engine/src/main/java/org/apache/sling/bgservlets/impl/ engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/ engine/src/main/resources/OSGI-INF/metatype/ engine/src...

Author: bdelacretaz
Date: Tue Feb 23 15:45:12 2016
New Revision: 1731890

URL: http://svn.apache.org/viewvc?rev=1731890&view=rev
Log:
SLING-5553 - Start background servlet jobs for POST, PUT and DELETE only by default

Added:
    sling/trunk/contrib/extensions/bgservlets/engine/src/test/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilterTest.java
Modified:
    sling/trunk/contrib/extensions/bgservlets/engine/pom.xml
    sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
    sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/BackgroundTestServlet.java
    sling/trunk/contrib/extensions/bgservlets/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
    sling/trunk/contrib/extensions/bgservlets/testing/src/main/provisioning/test-model.txt
    sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/BackgroundRequestIT.java
    sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/JobConsoleIT.java

Modified: sling/trunk/contrib/extensions/bgservlets/engine/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/engine/pom.xml?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/engine/pom.xml (original)
+++ sling/trunk/contrib/extensions/bgservlets/engine/pom.xml Tue Feb 23 15:45:12 2016
@@ -112,6 +112,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.commons.osgi</artifactId>
+      <version>2.1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
       <artifactId>org.apache.sling.jcr.api</artifactId>
       <version>2.0.6</version>
     </dependency>

Modified: sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java (original)
+++ sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java Tue Feb 23 15:45:12 2016
@@ -19,6 +19,9 @@
 package org.apache.sling.bgservlets.impl;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -37,6 +40,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.bgservlets.ExecutionEngine;
 import org.apache.sling.bgservlets.JobStorage;
+import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.engine.SlingRequestProcessor;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
@@ -67,25 +71,56 @@ public class BackgroundServletStarterFil
     @Reference
     private JobStorage jobStorage;
 
+    /** Default value of the "put in background" parameter */
+    public static final String DEFAULT_BG_PARAM = "sling:bg";
+    
     /** Name of the property that defines the request parameter name to
      *  use to start a servlet in the background.
      */
-    @Property(value="sling:bg")
+    @Property(value=DEFAULT_BG_PARAM)
     public static final String PROP_BG_PARAM = "background.parameter.name";
 
+    /** Default list of HTTP method names that can trigger background requests */
+    public static final String [] DEFAULT_ALLOWED_METHODS = {"POST", "PUT", "DELETE"};
+    
+    /** Name of the property that defines the list of allowed HTTP methods
+     *  to trigger background jobs
+     */
+    @Property()
+    public static final String PROP_ALLOWED_METHODS = "allowed.http.methods";
+    
+    private Set<String> allowedHttpMethods;
+
     /**
      * Request runs in the background if this request parameter is present
      */
     private String bgParamName;
 
     protected void activate(ComponentContext ctx) {
-        bgParamName = (String)ctx.getProperties().get(PROP_BG_PARAM);
-        if(bgParamName == null || bgParamName.length() == 0) {
-            throw new IllegalStateException("Missing " + PROP_BG_PARAM + " in ComponentContext");
+        bgParamName = PropertiesUtil.toString(ctx.getProperties().get(PROP_BG_PARAM), DEFAULT_BG_PARAM);
+        
+        final String [] cfgMethods = PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_ALLOWED_METHODS), DEFAULT_ALLOWED_METHODS);
+        allowedHttpMethods = new HashSet<String>();
+        allowedHttpMethods.addAll(Arrays.asList(cfgMethods));
+        
+        if(allowedHttpMethods.isEmpty()) {
+            log.error("{} defines no allowed HTTP methods, background servlets cannot be started", PROP_ALLOWED_METHODS);
         }
-        log.info("Request parameter {} will run servlets in the background", bgParamName);
+        
+        log.info(
+                "Request parameter {} will run servlets in the background for HTTP methods {}", 
+                    bgParamName,
+                    allowedHttpMethods);
     }
-
+    
+    private boolean startBackgroundRequest(HttpServletRequest req) throws ServletException {
+        boolean result = Boolean.valueOf(req.getParameter(bgParamName));
+        if(result && ! allowedHttpMethods.contains(req.getMethod())) {
+            throw new ServletException("Background requests cannot be started with a " + req.getMethod() + " request");
+        }
+        return result;
+    }
+ 
     public void doFilter(final ServletRequest sreq,
             final ServletResponse sresp, final FilterChain chain)
             throws IOException, ServletException {
@@ -102,8 +137,7 @@ public class BackgroundServletStarterFil
         final SlingHttpServletRequest slingRequest =
             (request instanceof SlingHttpServletRequest ? (SlingHttpServletRequest) request : null);
         final HttpServletResponse response = (HttpServletResponse) sresp;
-        final String bgParam = sreq.getParameter(bgParamName);
-        if (Boolean.valueOf(bgParam)) {
+        if (startBackgroundRequest(request)) {
             try {
                 final BackgroundRequestExecutionJob job = new BackgroundRequestExecutionJob(
                     slingRequestProcessor, jobStorage, slingRequest, response,

Modified: sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/BackgroundTestServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/BackgroundTestServlet.java?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/BackgroundTestServlet.java (original)
+++ sling/trunk/contrib/extensions/bgservlets/engine/src/main/java/org/apache/sling/bgservlets/impl/servlets/BackgroundTestServlet.java Tue Feb 23 15:45:12 2016
@@ -29,7 +29,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
 import org.apache.sling.bgservlets.RuntimeState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,11 +42,18 @@ import org.slf4j.LoggerFactory;
 @Service
 @SuppressWarnings("serial")
 @Property(name = "sling.servlet.paths", value = "/system/bgservlets/test")
-public class BackgroundTestServlet extends SlingSafeMethodsServlet {
+public class BackgroundTestServlet extends SlingAllMethodsServlet {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     @Override
+    protected void doPost(SlingHttpServletRequest request,
+            SlingHttpServletResponse response) throws ServletException,
+            IOException {
+        doGet(request, response);
+    }
+    
+    @Override
     protected void doGet(SlingHttpServletRequest request,
             SlingHttpServletResponse response) throws ServletException,
             IOException {
@@ -92,7 +99,7 @@ public class BackgroundTestServlet exten
             w.println("All done.");
             w.flush();
         } catch (Throwable t) {
-            log.info("Exception in doGet", t);
+            log.info("Exception in service method", t);
         }
     }
 

Modified: sling/trunk/contrib/extensions/bgservlets/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/engine/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/engine/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ sling/trunk/contrib/extensions/bgservlets/engine/src/main/resources/OSGI-INF/metatype/metatype.properties Tue Feb 23 15:45:12 2016
@@ -57,4 +57,9 @@ max.pool.size.name = Maximum ThreadPoolE
 max.pool.size.description = See ThreadPoolExecutor documentation for more info.
 
 keep.alive.time.seconds.name = Keep alive time for ThreadPoolExecutor (seconds)
-keep.alive.time.seconds.description = See ThreadPoolExecutor documentation for more info.
\ No newline at end of file
+keep.alive.time.seconds.description = See ThreadPoolExecutor documentation for more info.
+
+allowed.http.methods.name = HTTP methods that can start background jobs
+allowed.http.methods.description = List of allowed HTTP methods for starting background \
+    jobs. Including GET and HEAD is not recommended, background jobs are not meant to be \
+    used for this "safe" category of HTTP methods.
\ No newline at end of file

Added: sling/trunk/contrib/extensions/bgservlets/engine/src/test/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/engine/src/test/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilterTest.java?rev=1731890&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/engine/src/test/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilterTest.java (added)
+++ sling/trunk/contrib/extensions/bgservlets/engine/src/test/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilterTest.java Tue Feb 23 15:45:12 2016
@@ -0,0 +1,92 @@
+/*
+ * 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.bgservlets.impl;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.component.ComponentContext;
+
+public class BackgroundServletStarterFilterTest {
+    private BackgroundServletStarterFilter filter;
+    private Mockery mockery;
+    private SlingHttpServletRequest request;
+    private HttpServletResponse response;
+    private FilterChain chain;
+    
+    @SuppressWarnings("serial")
+    static class BackgroundJobIsStarting extends RuntimeException {
+    }
+    
+    @Before
+    public void setup() {
+        mockery = new Mockery();
+        request = mockery.mock(SlingHttpServletRequest.class);
+        response = mockery.mock(HttpServletResponse.class);
+        chain = mockery.mock(FilterChain.class);
+
+        final ComponentContext ctx = mockery.mock(ComponentContext.class);
+        final Dictionary<String, Object> props = new Hashtable<String, Object>(); 
+        
+        filter = new BackgroundServletStarterFilter();
+        
+        mockery.checking(new Expectations() {{
+            allowing(request).getParameter("sling:bg");
+            will(returnValue("true"));
+            
+            // If this method is called it means the BackgroundHttpServletRequest
+            // is being created to start a background job, that's all we need to know
+            allowing(request).getContextPath();
+            will(throwException(new BackgroundJobIsStarting()));
+            
+            allowing(ctx).getProperties();
+            will(returnValue(props));
+        }});
+        
+        filter.activate(ctx);
+    }
+    
+    private void testWithMethod(final String method) throws IOException, ServletException {
+        mockery.checking(new Expectations() {{
+            allowing(request).getMethod();
+            will(returnValue(method));
+        }});
+        filter.doFilter(request, response, chain);
+    }
+    
+    @Test(expected=ServletException.class)
+    public void testGetRequest() throws IOException, ServletException {
+        testWithMethod("GET");
+    }
+    
+    @Test(expected=BackgroundJobIsStarting.class)
+    public void testPostRequest() throws IOException, ServletException {
+        testWithMethod("POST");
+    }
+}
\ No newline at end of file

Modified: sling/trunk/contrib/extensions/bgservlets/testing/src/main/provisioning/test-model.txt
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/testing/src/main/provisioning/test-model.txt?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/testing/src/main/provisioning/test-model.txt (original)
+++ sling/trunk/contrib/extensions/bgservlets/testing/src/main/provisioning/test-model.txt Tue Feb 23 15:45:12 2016
@@ -20,7 +20,8 @@
 # Dependencies
 [artifacts]
   org.apache.sling/org.apache.sling.launchpad/8/slingstart
-  org.apache.sling/org.apache.sling.bgservlets/1.0.3-SNAPSHOT
+  org.apache.sling/org.apache.sling.extensions.webconsolesecurityprovider/1.1.6
+  org.apache.sling/org.apache.sling.bgservlets/1.0.5-SNAPSHOT
 
 # additional configuration for testing
 [configurations]

Modified: sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/BackgroundRequestIT.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/BackgroundRequestIT.java?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/BackgroundRequestIT.java (original)
+++ sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/BackgroundRequestIT.java Tue Feb 23 15:45:12 2016
@@ -63,10 +63,15 @@ public class BackgroundRequestIT {
     }
     
     @Test
+    public void testGetRequestFails() throws IOException,InterruptedException, JSONException {
+        T.assertHttpStatus(HttpTest.HTTP_BASE_URL + "/tmp.json?sling:bg=true", 500);
+    }
+    
+    @Test
     public void testTmpRequestCreatesJob() throws IOException,InterruptedException, JSONException {
         final int initialJobs = countStoredJobs();
-        T.getContent(HttpTest.HTTP_BASE_URL + "/tmp.json?sling:bg=true", "application/json");
-        
+        T.assertPostStatus(HttpTest.HTTP_BASE_URL + "/tmp.json?sling:bg=true", 302, null, null);
+
         // Request must have created a job
         final long timeout = System.currentTimeMillis() + 10000L;
         while(true) {

Modified: sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/JobConsoleIT.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/JobConsoleIT.java?rev=1731890&r1=1731889&r2=1731890&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/JobConsoleIT.java (original)
+++ sling/trunk/contrib/extensions/bgservlets/testing/src/test/java/org/apache/sling/bgservlets/it/JobConsoleIT.java Tue Feb 23 15:45:12 2016
@@ -23,7 +23,6 @@ import static org.junit.Assert.fail;
 import java.io.IOException;
 import java.util.regex.Pattern;
 
-import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.testing.integration.HttpTest;
 import org.junit.Before;
 import org.junit.Test;
@@ -38,9 +37,9 @@ public class JobConsoleIT {
     }
     
     @Test
-    public void testJobConsoleOutput() throws IOException,InterruptedException, JSONException {
+    public void testJobConsoleOutput() throws IOException,InterruptedException {
         // Create a job
-        T.getContent(HttpTest.HTTP_BASE_URL + "/tmp.json?sling:bg=true", "application/json");
+        T.assertPostStatus(HttpTest.HTTP_BASE_URL + "/tmp.json?sling:bg=true", 302, null, null);
         
         // Request must have created a job
         final long timeout = System.currentTimeMillis() + 10000L;