Author: musachy Date: Wed Aug 19 04:23:45 2009 New Revision: 805661 URL: http://svn.apache.org/viewvc?rev=805661&view=rev Log: WW-3142 Convention plugin support for default actionless dispatcher results exposes raw source code of index.jsp files on Google AppEngine
Thanks to Kent R. Spillner for the patch Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/ConventionUnknownHandlerTest.java Modified: struts/struts2/trunk/plugins/convention/pom.xml struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/ConventionUnknownHandler.java Modified: struts/struts2/trunk/plugins/convention/pom.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/pom.xml?rev=805661&r1=805660&r2=805661&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/pom.xml (original) +++ struts/struts2/trunk/plugins/convention/pom.xml Wed Aug 19 04:23:45 2009 @@ -66,6 +66,12 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymockclassextension</artifactId> + <version>2.3</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> @@ -78,4 +84,4 @@ <scope>provided</scope> </dependency> </dependencies> -</project> \ No newline at end of file +</project> Modified: struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/ConventionUnknownHandler.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/ConventionUnknownHandler.java?rev=805661&r1=805660&r2=805661&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/ConventionUnknownHandler.java (original) +++ struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/ConventionUnknownHandler.java Wed Aug 19 04:23:45 2009 @@ -185,24 +185,32 @@ */ protected Resource findResource(Map<String, ResultTypeConfig> resultsByExtension, String... parts) { for (String ext : resultsByExtension.keySet()) { - String path = string(parts) + "." + ext; + String canonicalPath = canonicalize(string(parts) + "." + ext); if (LOG.isTraceEnabled()) { - LOG.trace("Checking for [#0]", path); + LOG.trace("Checking for [#0]", canonicalPath); } try { - if (servletContext.getResource(path) != null) { - return new Resource(path, ext); + if (servletContext.getResource(canonicalPath) != null) { + return new Resource(canonicalPath, ext); } } catch (MalformedURLException e) { if (LOG.isErrorEnabled()) - LOG.error("Unable to parse path to the web application resource [#0] skipping...", path); + LOG.error("Unable to parse path to the web application resource [#0] skipping...", canonicalPath); } } return null; } + protected String canonicalize(final String path) { + if (path == null) { + return null; + } + + return path.replaceAll("/+", "/"); + } + protected ActionConfig buildActionConfig(String path, ResultTypeConfig resultTypeConfig) { Map<String, ResultConfig> results = new HashMap<String,ResultConfig>(); HashMap<String, String> params = new HashMap<String, String>(); @@ -413,4 +421,4 @@ this.ext = ext; } } -} \ No newline at end of file +} Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/ConventionUnknownHandlerTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/ConventionUnknownHandlerTest.java?rev=805661&view=auto ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/ConventionUnknownHandlerTest.java (added) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/ConventionUnknownHandlerTest.java Wed Aug 19 04:23:45 2009 @@ -0,0 +1,174 @@ +/* + * $Id$ + * + * 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.struts2.convention; + +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.entities.PackageConfig; +import com.opensymphony.xwork2.config.entities.ResultTypeConfig; +import com.opensymphony.xwork2.inject.Container; +import junit.framework.TestCase; +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.createNiceMock; +import static org.easymock.classextension.EasyMock.createStrictMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; + +import javax.servlet.ServletContext; +import java.net.URL; +import java.util.Map; +import java.util.Set; +import java.util.Iterator; + +public class ConventionUnknownHandlerTest extends TestCase { + public void testCanonicalizeShouldReturnNullWhenPathIsNull() throws Exception { + final ConventionUnknownHandler handler = conventionUnknownHandler(); + + assertEquals(null, handler.canonicalize(null)); + } + + public void testCanonicalizeShouldCollapseMultipleConsecutiveSlashesIntoJustOne() throws Exception { + final ConventionUnknownHandler handler = conventionUnknownHandler(); + + assertEquals("/should/condense/multiple/consecutive/slashes/into/just-one.ext", + handler.canonicalize("//should///condense////multiple/////consecutive////slashes///into//just-one.ext")); + } + + public void testCanonicalizeShouldNotModifySingleSlashes() throws Exception { + final ConventionUnknownHandler handler = conventionUnknownHandler(); + + assertEquals("/should/not/modify/single/slashes.ext", + handler.canonicalize("/should/not/modify/single/slashes.ext")); + } + + public void testFindResourceShouldReturnNullAfterTryingEveryExtensionWithoutSuccess() throws Exception { + final ServletContext servletContext = createStrictMock(ServletContext.class); // Verifies method call order + + expect(servletContext.getResource("/some/path/which/does/not/exist/for/any/file/with.default_extension")) + .andReturn(null); + expect(servletContext.getResource("/some/path/which/does/not/exist/for/any/file/with.non_default_extension")) + .andReturn(null); + expect(servletContext.getResource("/some/path/which/does/not/exist/for/any/file/with.some_other_extension")) + .andReturn(null); + + replay(servletContext); + + final ConventionUnknownHandler handler = conventionUnknownHandler(servletContext); + + final ConventionUnknownHandler.Resource resource = handler.findResource(defaultResultsByExtension(), + "/some/path/which/does/not/exist/for/any/file/with"); + + verify(servletContext); + + assertNull(resource); + } + + public void testFindResourceShouldLookupResourceWithCanonicalPath() throws Exception { + final ServletContext servletContext = createStrictMock(ServletContext.class); // Verifies method call order + + final URL url = new URL("http://localhost"); + expect(servletContext.getResource("/canonicalized/path.default_extension")).andReturn(url); + + replay(servletContext); + + final ConventionUnknownHandler handler = conventionUnknownHandler(servletContext); + handler.findResource(defaultResultsByExtension(), "///canonicalized//path"); + + verify(servletContext); + } + + public void testFindResourceShouldSetCanonicalizedPathOnResource() throws Exception { + final ServletContext servletContext = createMock(ServletContext.class); + + final URL url = new URL("http://localhost"); + expect(servletContext.getResource("/canonicalized/path.default_extension")).andReturn(url); + + replay(servletContext); + + final ConventionUnknownHandler handler = conventionUnknownHandler(servletContext); + + final ConventionUnknownHandler.Resource resource = handler.findResource(defaultResultsByExtension(), + "///canonicalized//path"); + + assertEquals("/canonicalized/path.default_extension", resource.path); + } + + private Configuration configuration(final String packageName) { + final Configuration mock = createNiceMock(Configuration.class); + + final PackageConfig packageConfiguration = packageConfiguration(); + expect(mock.getPackageConfig(packageName)).andStubReturn(packageConfiguration); + + replay(mock); + + return mock; + } + + private Container container() { + final Container mock = createNiceMock(Container.class); + + replay(mock); + + return mock; + } + + private ConventionUnknownHandler conventionUnknownHandler() { + return conventionUnknownHandler(null); + } + + private ConventionUnknownHandler conventionUnknownHandler(final ServletContext servletContext) { + final String defaultParentPackageName = "DEFAULT PARENT PACKAGE NAME"; + + final Configuration configuration = configuration(defaultParentPackageName); + final Container container = container(); + + return new ConventionUnknownHandler(configuration, null, servletContext, container, defaultParentPackageName, + null, null); + } + + private Map<String, ResultTypeConfig> defaultResultsByExtension() { + final Iterator<String> extensions = createMock(Iterator.class); + final Set<String> keys = createMock(Set.class); + final Map<String, ResultTypeConfig> mock = createMock(Map.class); + + expect(extensions.hasNext()).andReturn(true).times(3).andReturn(false); + expect(extensions.next()).andReturn("default_extension").andReturn("non_default_extension") + .andReturn("some_other_extension"); + + expect(keys.iterator()).andReturn(extensions); + + expect(mock.keySet()).andReturn(keys); + + replay(extensions); + replay(keys); + replay(mock); + + return mock; + } + + private PackageConfig packageConfiguration() { + final PackageConfig mock = createNiceMock(PackageConfig.class); + + replay(mock); + + return mock; + } +}