diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/org.springframework.web/src/main/java/org/springframework/web/util/UrlPathHelper.java index 10349f91fce..43059c09c6a 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/util/UrlPathHelper.java +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UrlPathHelper.java @@ -18,6 +18,7 @@ package org.springframework.web.util; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.util.Properties; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; @@ -47,8 +48,10 @@ public class UrlPathHelper { */ private static final String WEBSPHERE_URI_ATTRIBUTE = "com.ibm.websphere.servlet.uri_non_decoded"; + private static final Log logger = LogFactory.getLog(UrlPathHelper.class); + + static volatile Boolean websphereComplianceFlag; - private final Log logger = LogFactory.getLog(getClass()); private boolean alwaysUseFullPath = false; @@ -234,9 +237,10 @@ public class UrlPathHelper { servletPath = request.getServletPath(); } if (servletPath.length() > 1 && servletPath.endsWith("/") && - request.getAttribute(WEBSPHERE_URI_ATTRIBUTE) != null) { - // On WebSphere, for a "/foo/" case that would be "/foo" on all other servlet containers: - // removing trailing slash, proceeding with that slash as final path mapping... + shouldRemoveTrailingServletPathSlash(request)) { + // On WebSphere, in non-compliant mode, for a "/foo/" case that would be "/foo" + // on all other servlet containers: removing trailing slash, proceeding with + // that remaining slash as final lookup path... servletPath = servletPath.substring(0, servletPath.length() - 1); } return servletPath; @@ -347,4 +351,35 @@ public class UrlPathHelper { return enc; } + + private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request) { + if (request.getAttribute(WEBSPHERE_URI_ATTRIBUTE) == null) { + // Regular servlet container: behaves as expected in any case, + // so the trailing slash is the result of a "/" url-pattern mapping. + // Don't remove that slash. + return false; + } + if (websphereComplianceFlag == null) { + ClassLoader classLoader = UrlPathHelper.class.getClassLoader(); + String className = "com.ibm.ws.webcontainer.WebContainer"; + String methodName = "getWebContainerProperties"; + String propName = "com.ibm.ws.webcontainer.removetrailingservletpathslash"; + boolean flag = false; + try { + Class cl = classLoader.loadClass(className); + Properties prop = (Properties) cl.getMethod(methodName).invoke(null); + flag = Boolean.parseBoolean(prop.getProperty(propName)); + } + catch (Throwable ex) { + if (logger.isDebugEnabled()) { + logger.debug("Could not introspect WebSphere web container properties: " + ex); + } + } + websphereComplianceFlag = flag; + } + // Don't bother if WebSphere is configured to be fully Servlet compliant. + // However, if it is not compliant, do remove the improper trailing slash! + return !websphereComplianceFlag; + } + } diff --git a/org.springframework.web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java b/org.springframework.web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java index d7d2f325e04..a08168fd2fe 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java @@ -16,10 +16,11 @@ package org.springframework.web.util; -import static org.junit.Assert.assertEquals; - +import static org.junit.Assert.*; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; + import org.springframework.mock.web.MockHttpServletRequest; /** @@ -146,12 +147,11 @@ public class UrlPathHelperTests { } @Test - public void tomcatDefaultServletFileWithCompliantSetting() throws Exception { + public void wasDefaultServletFileWithCompliantSetting() throws Exception { request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/test/foo"); tomcatDefaultServletFile(); } - @Test public void wasDefaultServletFolder() throws Exception { request.setContextPath("/test"); @@ -163,10 +163,16 @@ public class UrlPathHelperTests { assertEquals("/foo/", helper.getLookupPathForRequest(request)); } - // @Test + @Test public void wasDefaultServletFolderWithCompliantSetting() throws Exception { - request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/test/foo/"); - tomcatDefaultServletFolder(); + UrlPathHelper.websphereComplianceFlag = true; + try { + request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/test/foo/"); + tomcatDefaultServletFolder(); + } + finally { + UrlPathHelper.websphereComplianceFlag = false; + } } @@ -185,7 +191,7 @@ public class UrlPathHelperTests { } // test the root mapping for /foo/* w/o a trailing slash - //foo - // @Test + @Test @Ignore public void tomcatCasualServletRootWithMissingSlash() throws Exception { request.setContextPath("/test"); request.setPathInfo(null); @@ -226,14 +232,14 @@ public class UrlPathHelperTests { assertEquals("/", helper.getLookupPathForRequest(request)); } - // @Test + @Test public void wasCasualServletRootWithCompliantSetting() throws Exception { request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/test/foo/"); tomcatCasualServletRoot(); } // test the root mapping for /foo/* w/o a trailing slash - //foo - // @Test + @Test @Ignore public void wasCasualServletRootWithMissingSlash() throws Exception { request.setContextPath("/test"); request.setPathInfo(null); @@ -244,7 +250,7 @@ public class UrlPathHelperTests { assertEquals("/", helper.getLookupPathForRequest(request)); } - // @Test + @Test @Ignore public void wasCasualServletRootWithMissingSlashWithCompliantSetting() throws Exception { request.setAttribute(WEBSPHERE_URI_ATTRIBUTE, "/test/foo"); tomcatCasualServletRootWithMissingSlash();