You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by as...@apache.org on 2015/04/02 11:49:39 UTC

svn commit: r1670869 - in /sling/trunk/contrib/extensions/security: pom.xml src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java

Author: asanso
Date: Thu Apr  2 09:49:38 2015
New Revision: 1670869

URL: http://svn.apache.org/r1670869
Log:
SLING-3829 - Add support for Content-Disposition attachment 

Added:
    sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java
    sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java
Modified:
    sling/trunk/contrib/extensions/security/pom.xml

Modified: sling/trunk/contrib/extensions/security/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/pom.xml?rev=1670869&r1=1670868&r2=1670869&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/security/pom.xml (original)
+++ sling/trunk/contrib/extensions/security/pom.xml Thu Apr  2 09:49:38 2015
@@ -73,6 +73,12 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.osgi</artifactId>
             <version>2.1.0</version>
             <scope>provided</scope>
@@ -111,5 +117,22 @@
             <version>1.8.2</version>
             <scope>test</scope>
         </dependency>
+        <!--  Testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jmock</groupId>
+            <artifactId>jmock-junit4</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit-addons</groupId>
+            <artifactId>junit-addons</artifactId>
+            <version>1.4</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
+    
 </project>

Added: sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java?rev=1670869&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java (added)
+++ sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java Thu Apr  2 09:49:38 2015
@@ -0,0 +1,224 @@
+/*
+ * 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.security.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(metatype = true,
+description = "Request filter adding Content Disposition attachment for certain paths/content types",
+label=" Apache Sling Content Disposition Filter")
+@Service(value = Filter.class)
+@Properties({
+        @Property(name = "sling.filter.scope", value = { "request" }, propertyPrivate = true),
+        @Property(name = "service.ranking", intValue = -25000, propertyPrivate = true) })
+public class ContentDispositionFilter implements Filter {
+    
+    /** Logger. */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    
+    @Property(label = "Content Disposition Paths", 
+            description = "These paths are filtered by the filter. "+
+                    "Each entry is of the form 'path [ \":\" CSV of excluded content types ]'. " +
+                    "Invalid entries are logged and ignored."
+                    , unbounded = PropertyUnbounded.ARRAY, value = { "" })
+    private static final String PROP_CONTENT_DISPOSTION_PATHS = "sling.content.disposition.paths";
+   
+    /**
+     * Set of paths
+     */
+    Set<String> contentDispositionPaths;
+
+    /**
+     * Array of prefixes of paths
+     */
+    private String[] contentDispositionPathsPfx;
+
+    private Map<String, Set<String>> contentTypesMapping;
+    
+    @Activate
+    private void activate(final ComponentContext ctx) {
+        final Dictionary props = ctx.getProperties();
+        
+        String[] contentDispostionProps = PropertiesUtil.toStringArray(props.get(PROP_CONTENT_DISPOSTION_PATHS));
+        
+        Set<String> paths = new HashSet<String>();
+        List<String> pfxs = new ArrayList<String>();
+        Map<String, Set<String>> contentTypesMap = new HashMap<String, Set<String>>();
+        
+        for (String path : contentDispostionProps) {
+            path = path.trim();
+            if (path.length() > 0) {
+                int idx = path.indexOf('*');
+                int colonIdx = path.indexOf(":");
+                
+                if (colonIdx > -1 && colonIdx < idx) {
+                    // ':'  in paths is not allowed
+                    logger.info("':' in paths is not allowed.");
+                } else {
+                    String p = null;
+                    if (idx >= 0) {
+                        if (idx > 0) {
+                            p = path.substring(0, idx);
+                            pfxs.add(p);
+                        } else {
+                            // we don't allow "*" - that would defeat the
+                            // purpose.
+                            logger.info("catch-all wildcard for paths not allowed.");
+                        }
+                    } else {
+                        if (colonIdx > -1) {
+                            p = path.substring(0, colonIdx);
+                        } else {
+                            p = path;
+                        }
+                        paths.add(p);
+                    }                   
+                    if (colonIdx != -1 && p != null) {
+                        Set <String> contentTypes = getContentTypes(path.substring(colonIdx+1));
+                        contentTypesMap.put(p, contentTypes);
+                    }
+                }
+
+            }
+        }
+        
+        contentDispositionPaths = paths.isEmpty() ? Collections.<String>emptySet() : paths;
+        contentDispositionPathsPfx = pfxs.toArray(new String[pfxs.size()]);
+        contentTypesMapping = contentTypesMap.isEmpty()?Collections.<String, Set<String>>emptyMap(): contentTypesMap;
+        
+        logger.info("Initialized. content disposition paths: {}, content disposition paths-pfx {}", new Object[]{
+                contentDispositionPaths, contentDispositionPathsPfx}
+        );
+    }
+    
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // nothing to do
+    }
+
+    public void destroy() {
+        // nothing to do
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response,
+            FilterChain chain) throws IOException, ServletException {
+  
+        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
+        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
+
+        final RewriterResponse rewriterResponse = new RewriterResponse(slingRequest, slingResponse);
+
+        chain.doFilter(request, rewriterResponse);
+    }
+    
+    //---------- PRIVATE METHODS ---------
+    
+    private static Set<String> getContentTypes(String contentTypes) {
+        Set<String> contentTypesSet = new HashSet<String>();
+        if (contentTypes != null && contentTypes.length() > 0) {
+            String[] contentTypesArray = contentTypes.split(",");
+            for (String contentType : contentTypesArray) {
+                contentTypesSet.add(contentType);
+            }
+        }
+        return contentTypesSet;
+    }
+    
+    //----------- INNER CLASSES ------------ 
+
+    protected class RewriterResponse extends SlingHttpServletResponseWrapper {
+        
+        private static final String CONTENT_DISPOSTION = "Content-Disposition";
+
+        private static final String CONTENT_DISPOSTION_ATTACHMENT = "attachment";
+        
+        /** The current request. */
+        private final SlingHttpServletRequest request;
+
+        public RewriterResponse(SlingHttpServletRequest request, SlingHttpServletResponse wrappedResponse) {
+            super(wrappedResponse);            
+            this.request = request;
+        }
+        
+        /**
+         * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String)
+         */
+        public void setContentType(String type) { 
+            String pathInfo = request.getPathInfo();
+
+            if (contentDispositionPaths.contains(pathInfo)) {
+
+                if (contentTypesMapping.containsKey(pathInfo)) {
+                    Set exceptions = contentTypesMapping.get(pathInfo);
+                    if (!exceptions.contains(type)) {
+                        setContentDisposition();
+                    }
+                } else {
+                    setContentDisposition();
+                }
+            }
+            
+            for (String path : contentDispositionPathsPfx) {
+                if (request.getPathInfo().startsWith(path)) {
+                    if (contentTypesMapping.containsKey(path)) {
+                        Set exceptions = contentTypesMapping.get(path);
+                        if (!exceptions.contains(type)) {
+                            setContentDisposition();
+                            break;
+                        }
+                    } else {
+                        setContentDisposition();
+                        break;
+                    }
+
+                }
+            }
+            super.setContentType(type);
+        }    
+        
+        private void setContentDisposition() {
+            this.addHeader(CONTENT_DISPOSTION, CONTENT_DISPOSTION_ATTACHMENT);
+        }
+    }
+}

Added: sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java?rev=1670869&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java (added)
+++ sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java Thu Apr  2 09:49:38 2015
@@ -0,0 +1,653 @@
+/*
+ * 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.security.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import junitx.util.PrivateAccessor;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.service.component.ComponentContext;
+
+public class ContentDispositionFilterTest {
+    
+    private ContentDispositionFilter contentDispositionFilter;
+    private final Mockery context = new JUnit4Mockery();
+
+    @Test
+    public void test_activator1() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(1, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(0, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(0, contentTypesMapping.size());           
+    }
+    
+    @Test
+    public void test_activator2() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(0, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(1, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(0, contentTypesMapping.size());           
+    }
+    
+    @Test
+    public void test_activator3() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/libs", "/content/usergenerated/*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(1, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(1, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(0, contentTypesMapping.size());           
+    }
+    
+    @Test
+    public void test_activator5() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(0, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(0, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(0, contentTypesMapping.size());           
+    }
+    
+    @Test
+    public void test_activator6() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/libs:*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(0, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(0, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(0, contentTypesMapping.size());           
+    }
+    
+    @Test
+    public void test_activator7() throws Throwable{
+        contentDispositionFilter = new ContentDispositionFilter();
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/libs:text/html,text/plain","/content/usergenerated/*:image/jpeg"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        Set<String> contentDispositionPaths = ( Set<String> ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPaths");
+        Assert.assertEquals(1, contentDispositionPaths.size());   
+        String[] contentDispositionPathsPfx = ( String[] ) PrivateAccessor.getField(contentDispositionFilter, "contentDispositionPathsPfx");
+        Assert.assertEquals(1, contentDispositionPathsPfx.length);   
+        Map <String, Set<String>> contentTypesMapping = ( Map <String, Set<String>> ) PrivateAccessor.getField(contentDispositionFilter, "contentTypesMapping");
+        Assert.assertEquals(2, contentTypesMapping.size()); 
+        Set<String> libsMapping = contentTypesMapping.get("/libs");
+        Assert.assertEquals(2, libsMapping.size());
+        libsMapping.contains("text/html");
+        libsMapping.contains("text/plain");
+ 
+        Set<String> userGeneratedMapping = contentTypesMapping.get("/content/usergenerated/");
+        Assert.assertEquals(1, userGeneratedMapping.size()); 
+        userGeneratedMapping.contains("image/jpeg");
+     }
+    
+    @Test
+    public void test_getContentTypes() throws Throwable{
+        // null content types
+        String contentType = null;
+        Set <String> contentTypesSet = ( Set <String>) PrivateAccessor.invoke(ContentDispositionFilter.class,"getContentTypes",  new Class[]{String.class},new Object[]{contentType});
+        Assert.assertEquals(0, contentTypesSet.size());   
+        // empty content types
+        contentType = "";
+        contentTypesSet = ( Set <String>) PrivateAccessor.invoke(ContentDispositionFilter.class,"getContentTypes",  new Class[]{String.class},new Object[]{contentType});
+        Assert.assertEquals(0, contentTypesSet.size());  
+        contentType = "text/html";
+        contentTypesSet = ( Set <String>) PrivateAccessor.invoke(ContentDispositionFilter.class,"getContentTypes",  new Class[]{String.class},new Object[]{contentType});
+        Assert.assertEquals(1, contentTypesSet.size()); 
+        contentType = "text/html,text/plain";
+        contentTypesSet = ( Set <String>) PrivateAccessor.invoke(ContentDispositionFilter.class,"getContentTypes",  new Class[]{String.class},new Object[]{contentType});
+        Assert.assertEquals(2, contentTypesSet.size()); 
+    }
+    
+    @Test
+    public void test_doFilter1() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/libs"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+                
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter2() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter3() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter4() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/libs"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+                
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter5() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter6() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter7() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/libs"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+                
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter8() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter9() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter10() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated"));
+                allowing(response).setContentType("image/jpeg");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("image/jpeg");
+    }
+    
+    @Test
+    public void test_doFilter11() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/libs"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+                
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter12() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter13() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("text/html");
+                //CONTENT DISPOSITION MUST NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+    }
+    
+    @Test
+    public void test_doFilter14() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated/*:text/html,text/plain"});
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(request).getPathInfo();
+                will(returnValue("/content/usergenerated/author"));
+                allowing(response).setContentType("image/jpeg");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("image/jpeg");
+    }
+}