Index: src/impl/com/sun/ws/rest/impl/container/servlet/HttpRequestAdaptor.java =================================================================== --- src/impl/com/sun/ws/rest/impl/container/servlet/HttpRequestAdaptor.java (revision 110) +++ src/impl/com/sun/ws/rest/impl/container/servlet/HttpRequestAdaptor.java (working copy) @@ -25,10 +25,11 @@ import com.sun.ws.rest.impl.HttpRequestContextImpl; import java.io.IOException; import java.net.URI; -import java.net.URLEncoder; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MultivaluedMap; @@ -81,9 +82,25 @@ protected void setURIs() { this.uri = URI.create(request.getRequestURL().toString()); - this.uriPath = (request.getPathInfo() != null) + String uriPathCandidate = (request.getPathInfo() != null) ? request.getPathInfo().substring(1) : request.getServletPath().substring(1); + this.uriPath = ensureStringIsPartOfURI(uriPathCandidate, this.uri); this.baseURI = getBaseURI(this.uri, this.uriPath); } + + private String ensureStringIsPartOfURI(String uriPath, URI uri) { + // TODO: maybe uri.toAsciiString() ??? + String uriAsString = uri.toString(); + if (-1 != uriAsString.indexOf(uriPath)){ + return uriPath; + } + Pattern uriPathPattern = Pattern.compile(uriPath.replaceAll("\\+", "\\\\+").replaceAll("/", "/+")); + Matcher uriPathMatcher = uriPathPattern.matcher(uriAsString); + int lastStart = -1; + while (uriPathMatcher.find()) { + lastStart = uriPathMatcher.start(); + } + return uriAsString.substring(lastStart); + } } Index: src/impl/com/sun/ws/rest/impl/application/WebApplicationImpl.java =================================================================== --- src/impl/com/sun/ws/rest/impl/application/WebApplicationImpl.java (revision 110) +++ src/impl/com/sun/ws/rest/impl/application/WebApplicationImpl.java (working copy) @@ -55,6 +55,8 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.PersistenceUnit; @@ -157,7 +159,7 @@ final URI uri = request.getURI(); final URI normalizedUri = uri.normalize(); - if (uri != normalizedUri) { + if ((uri != normalizedUri) && (!differsInRedundantSlashesOnly(uri.toString(), normalizedUri.toString()))) { response.setResponse(ResponseBuilderImpl.temporaryRedirect(normalizedUri).build()); return; } @@ -181,6 +183,12 @@ } } + private boolean differsInRedundantSlashesOnly(String uri, String normalizedUri) { + Pattern pattern = Pattern.compile(normalizedUri.replaceAll("\\+", "\\\\+").replaceAll("/", "/+")); + Matcher matcher = pattern.matcher(uri); + return matcher.matches(); + } + /** * Strip the matrix parameters from a path */ Index: examples/Bookmark/src/java/com/sun/ws/rest/samples/bookmark/resources/BookmarksResource.java =================================================================== --- examples/Bookmark/src/java/com/sun/ws/rest/samples/bookmark/resources/BookmarksResource.java (revision 110) +++ examples/Bookmark/src/java/com/sun/ws/rest/samples/bookmark/resources/BookmarksResource.java (working copy) @@ -66,8 +66,9 @@ return userResource.getUserEntity().getBookmarkEntityCollection(); } - @UriTemplate("{bmid}/") + @UriTemplate(value = "{bmid}", limited = false) public BookmarkResource getBookmark(@UriParam("bmid") String bmid) { + System.out.println("BMID = " + bmid); return new BookmarkResource(uriInfo, em, userResource.getUserEntity(), bmid); }