Author: bpontarelli Date: Sun Jan 27 15:43:31 2008 New Revision: 615679 URL: http://svn.apache.org/viewvc?rev=615679&view=rev Log: Added better handling for extensionless URLs that contain dots in directory names
Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java?rev=615679&r1=615678&r2=615679&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java Sun Jan 27 15:43:31 2008 @@ -169,11 +169,11 @@ protected boolean allowDynamicMethodCalls = true; protected boolean allowSlashesInActionNames = false; - + protected boolean alwaysSelectFullNamespace = false; protected PrefixTrie prefixTrie = null; - + protected List<String> extensions = new ArrayList<String>() {{ add("action"); add("");}}; protected Container container; @@ -242,17 +242,17 @@ protected void addParameterAction(String prefix, ParameterAction parameterAction) { prefixTrie.put(prefix, parameterAction); } - + @Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION) public void setAllowDynamicMethodCalls(String allow) { allowDynamicMethodCalls = "true".equals(allow); } - + @Inject(StrutsConstants.STRUTS_ENABLE_SLASHES_IN_ACTION_NAMES) public void setSlashesInActionNames(String allow) { allowSlashesInActionNames = "true".equals(allow); } - + @Inject(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE) public void setAlwaysSelectFullNamespace(String val) { this.alwaysSelectFullNamespace = "true".equals(val); @@ -262,7 +262,7 @@ public void setContainer(Container container) { this.container = container; } - + @Inject(StrutsConstants.STRUTS_ACTION_EXTENSION) public void setExtensions(String extensions) { if (extensions != null && !"".equals(extensions)) { @@ -285,7 +285,7 @@ mapping.setName(actionName); return parseActionName(mapping); } - + /* * (non-Javadoc) * @@ -295,10 +295,10 @@ ConfigurationManager configManager) { ActionMapping mapping = new ActionMapping(); String uri = getUri(request); - + int indexOfSemicolon = uri.indexOf(";"); uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri; - + uri = dropExtension(uri, mapping); if (uri == null) { return null; @@ -350,12 +350,12 @@ for (Iterator iterator = parameterMap.keySet().iterator(); iterator .hasNext();) { String key = (String) iterator.next(); - + // Strip off the image button location info, if found if (key.endsWith(".x") || key.endsWith(".y")) { key = key.substring(0, key.length() - 2); } - + // Ensure a parameter doesn't get processed twice if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) prefixTrie @@ -435,13 +435,13 @@ protected String dropExtension(String name) { return dropExtension(name, new ActionMapping()); } - + /** * Drops the extension from the action name, storing it in the mapping for later use * * @param name * The action name - * @param mapping The action mapping to store the extension in + * @param mapping The action mapping to store the extension in * @return The action name without its extension */ protected String dropExtension(String name, ActionMapping mapping) { @@ -450,7 +450,11 @@ } for (String ext : extensions) { if ("".equals(ext)) { - if (name.indexOf('.') == -1) { + // This should also handle cases such as /foo/bar-1.0/description. It is tricky to + // distinquish /foo/bar-1.0 but perhaps adding a numeric check in the future could + // work + int index = name.indexOf('.'); + if (index == -1 || name.indexOf('/', index) >= 0) { return name; } } else { @@ -460,7 +464,7 @@ mapping.setExtension(ext); return name; } - } + } } return null; } @@ -538,9 +542,9 @@ } } } - + if (extension != null) { - + if (extension.length() == 0 || (extension.length() > 0 && uri.indexOf('.' + extension) == -1)) { if (extension.length() > 0) { uri.append(".").append(extension); @@ -553,10 +557,10 @@ return uri.toString(); } - + public boolean isSlashesInActionNames() { return allowSlashesInActionNames; } - + } Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java?rev=615679&r1=615678&r2=615679&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java Sun Jan 27 15:43:31 2008 @@ -20,31 +20,27 @@ */ package org.apache.struts2.dispatcher.mapper; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.Arrays; -import org.apache.struts2.StrutsConstants; -import org.apache.struts2.StrutsTestCase; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsTestCase; import org.apache.struts2.dispatcher.ServletRedirectResult; import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest; import org.apache.struts2.views.jsp.StrutsMockHttpServletResponse; -import com.mockobjects.servlet.MockHttpServletRequest; import com.mockobjects.dynamic.Mock; -import com.opensymphony.xwork2.Result; -import com.opensymphony.xwork2.DefaultActionInvocation; -import com.opensymphony.xwork2.ActionInvocation; +import com.mockobjects.servlet.MockHttpServletRequest; import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationManager; import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; -import javax.servlet.http.HttpServletResponse; - /** * DefaultActionMapper test case. * @@ -116,9 +112,9 @@ assertEquals("/my", mapping.getNamespace()); assertEquals("foo/actionName", mapping.getName()); - assertNull(mapping.getMethod()); + assertNull(mapping.getMethod()); } - + public void testGetMappingWithNamespaceSlash() throws Exception { req.setupGetRequestURI("/my.hh/abc.action"); @@ -131,7 +127,7 @@ assertEquals("", mapping.getNamespace()); assertEquals("abc", mapping.getName()); - + req.setupGetAttribute(null); req.addExpectedGetAttributeName("javax.servlet.include.servlet_path"); mapper = new DefaultActionMapper(); @@ -155,7 +151,7 @@ assertEquals("actionName", mapping.getName()); assertNull(mapping.getMethod()); } - + public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() throws Exception { req.setupGetRequestURI("/bo/foo/actionName.action"); req.setupGetServletPath("/bo/foo/actionName.action"); @@ -211,7 +207,7 @@ ActionMapping mapping = mapper.getMapping(req, configManager); assertEquals("/my/namespace/actionName.action", mapper.getUriFromActionMapping(mapping)); } - + public void testGetUriWithSemicolonPresent() throws Exception { req.setupGetParameterMap(new HashMap()); req.setupGetRequestURI("/my/namespace/actionName.action;abc=123rty56"); @@ -236,14 +232,14 @@ assertEquals("/my/namespace/actionName!add.action", mapper.getUriFromActionMapping(mapping)); } - + public void testGetUriWithOriginalExtension() throws Exception { ActionMapping mapping = new ActionMapping("actionName", "/ns", null, new HashMap()); - + ActionMapping orig = new ActionMapping(); orig.setExtension("foo"); ActionContext.getContext().put(ServletActionContext.ACTION_MAPPING, orig); - + DefaultActionMapper mapper = new DefaultActionMapper(); assertEquals("/ns/actionName.foo", mapper.getUriFromActionMapping(mapping)); } @@ -263,7 +259,7 @@ assertEquals("actionName", mapping.getName()); assertNull(mapping.getMethod()); } - + public void testGetMappingWithNoExtensionButUriHasExtension() throws Exception { req.setupGetParameterMap(new HashMap()); req.setupGetRequestURI("/my/namespace/actionName.html"); @@ -370,7 +366,7 @@ assertEquals(actionMapping.getName(), "myAction"); } - + public void testActionPrefix_fromIEImageButton() throws Exception { Map parameterMap = new HashMap(); parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction.x", ""); @@ -426,17 +422,17 @@ DefaultActionMapper defaultActionMapper = new DefaultActionMapper(); defaultActionMapper.setContainer(container); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - + StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); assertNotNull(result); assertTrue(result instanceof ServletRedirectResult); - + assertEquals("myAction.action", result.getLocation()); // TODO: need to test location but there's noaccess to the property/method, unless we use reflection } - + public void testRedirectActionPrefixWithEmptyExtension() throws Exception { Map parameterMap = new HashMap(); parameterMap.put(DefaultActionMapper.REDIRECT_ACTION_PREFIX + "myAction", ""); @@ -449,12 +445,12 @@ defaultActionMapper.setContainer(container); defaultActionMapper.setExtensions(",,"); ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager); - + StrutsResultSupport result = (StrutsResultSupport) actionMapping.getResult(); assertNotNull(result); assertTrue(result instanceof ServletRedirectResult); - + assertEquals("myAction", result.getLocation()); // TODO: need to test location but there's noaccess to the property/method, unless we use reflection @@ -488,7 +484,7 @@ assertTrue("Name not right: "+name, "foo.action".equals(name)); } - + public void testDropExtensionWhenBlank() throws Exception { DefaultActionMapper mapper = new DefaultActionMapper(); mapper.setExtensions("action,,"); @@ -500,6 +496,17 @@ assertNull(mapper.dropExtension("foo.")); } + public void testDropExtensionEmbeddedDot() throws Exception { + DefaultActionMapper mapper = new DefaultActionMapper(); + mapper.setExtensions("action,,"); + + String name = mapper.dropExtension("/foo/bar-1.0/baz.action"); + assertTrue("Name not right: "+name, "/foo/bar-1.0/baz".equals(name)); + + name = mapper.dropExtension("/foo/bar-1.0/baz"); + assertTrue("Name not right: "+name, "/foo/bar-1.0/baz".equals(name)); + } + public void testGetUriFromActionMapper1() throws Exception { DefaultActionMapper mapper = new DefaultActionMapper(); ActionMapping actionMapping = new ActionMapping(); @@ -639,7 +646,7 @@ assertEquals("myActionName!myMethod", uri); } - + public void testGetUriFromActionMapperWhenBlankExtension() throws Exception { DefaultActionMapper mapper = new DefaultActionMapper(); mapper.setExtensions(",,");