This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.security-1.0.12 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-security.git
commit bdc96884cd9694180f0e239b68cc5ce06af00170 Author: Antonio Sanso <[email protected]> AuthorDate: Tue Jul 14 12:17:17 2015 +0000 SLING-4604 - Multiple Content-Disposition headers added * added patch from Rob Ryan (thanks) git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/security@1690911 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/impl/ContentDispositionFilter.java | 13 +- .../impl/ContentDispositionFilterTest.java | 150 ++++++++++++++++++++- 2 files changed, 159 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java b/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java index aae95dc..9c0999d 100644 --- a/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java +++ b/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java @@ -173,6 +173,9 @@ public class ContentDispositionFilter implements Filter { private static final String CONTENT_DISPOSTION_ATTACHMENT = "attachment"; + static final String ATTRIBUTE_NAME = + "org.apache.sling.security.impl.ContentDispositionFilter.RewriterResponse.contentType"; + /** The current request. */ private final SlingHttpServletRequest request; @@ -185,8 +188,14 @@ public class ContentDispositionFilter implements Filter { * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String) */ public void setContentType(String type) { - String pathInfo = request.getPathInfo(); + String previousContentType = (String) request.getAttribute(ATTRIBUTE_NAME); + + if (previousContentType != null && previousContentType.equals(type)) { + return; + } + request.setAttribute(ATTRIBUTE_NAME, type); + String pathInfo = request.getPathInfo(); if (contentDispositionPaths.contains(pathInfo)) { if (contentTypesMapping.containsKey(pathInfo)) { @@ -218,7 +227,9 @@ public class ContentDispositionFilter implements Filter { } private void setContentDisposition() { + if (!this.containsHeader(CONTENT_DISPOSTION)) { this.addHeader(CONTENT_DISPOSTION, CONTENT_DISPOSTION_ATTACHMENT); } } } +} diff --git a/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java b/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java index 91d26b1..7c989e7 100644 --- a/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java +++ b/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java @@ -20,9 +20,12 @@ 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.apache.sling.security.impl.ContentDispositionFilter.RewriterResponse; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; @@ -221,6 +224,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/libs")); allowing(response).setContentType("text/html"); @@ -254,6 +260,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("text/html"); @@ -282,10 +291,15 @@ public class ContentDispositionFilterTest { } }); PrivateAccessor.invoke(contentDispositionFilter,"activate", new Class[]{ComponentContext.class},new Object[]{ctx}); - ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); + final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); context.checking(new Expectations() { { + allowing(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated")); allowing(response).setContentType("text/html"); @@ -318,6 +332,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/libs")); allowing(response).setContentType("text/html"); @@ -347,10 +364,15 @@ public class ContentDispositionFilterTest { } }); PrivateAccessor.invoke(contentDispositionFilter,"activate", new Class[]{ComponentContext.class},new Object[]{ctx}); - ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); + final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); context.checking(new Expectations() { { + allowing(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("text/html"); @@ -383,6 +405,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated")); allowing(response).setContentType("text/html"); @@ -415,6 +440,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/libs")); allowing(response).setContentType("text/html"); @@ -448,6 +476,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("text/html"); @@ -480,6 +511,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated")); allowing(response).setContentType("text/html"); @@ -508,10 +542,15 @@ public class ContentDispositionFilterTest { } }); PrivateAccessor.invoke(contentDispositionFilter,"activate", new Class[]{ComponentContext.class},new Object[]{ctx}); - ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); + final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); context.checking(new Expectations() { { + allowing(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "image/jpeg"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated")); allowing(response).setContentType("image/jpeg"); @@ -544,6 +583,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/libs")); allowing(response).setContentType("text/html"); @@ -577,6 +619,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("text/html"); @@ -609,6 +654,9 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("text/html"); @@ -641,6 +689,11 @@ public class ContentDispositionFilterTest { context.checking(new Expectations() { { + allowing(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + allowing(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "image/jpeg"); allowing(request).getPathInfo(); will(returnValue("/content/usergenerated/author")); allowing(response).setContentType("image/jpeg"); @@ -650,4 +703,95 @@ public class ContentDispositionFilterTest { }); rewriterResponse.setContentType("image/jpeg"); } + + /** + * Test repeated setContentType calls don't add multiple headers, case 1 resetting the same mimetype + * @throws Throwable + */ + @Test + public void test_doFilter15() 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}); + final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); + + context.checking(new Expectations() { + { + allowing(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue("text/html")); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); + 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"); + rewriterResponse.setContentType("text/html"); + } + /** + * Test repeated setContentType calls don't add multiple headers, case 2 changing mime type + * @throws Throwable + */ + @Test + public void test_doFilter16() 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}); + final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response); + + context.checking(new Expectations() { + { + exactly(1).of(response).containsHeader("Content-Disposition"); + will(returnValue(false)); + exactly(1).of(response).containsHeader("Content-Disposition"); + will(returnValue(true)); + exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue(null)); + exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME); + will(returnValue("text/html")); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/xml"); + allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html"); + allowing(request).getPathInfo(); + will(returnValue("/content/usergenerated")); + allowing(response).setContentType("text/html"); + allowing(response).setContentType("text/xml"); + //CONTENT DISPOSITION IS SET + exactly(1).of(response).addHeader("Content-Disposition", "attachment"); + } + }); + rewriterResponse.setContentType("text/html"); + rewriterResponse.setContentType("text/xml"); + } +} \ No newline at end of file -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
