You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/04/30 17:23:41 UTC

svn commit: r1477686 - in /cxf/trunk/rt/frontend/jaxrs/src: main/java/org/apache/cxf/jaxrs/utils/ test/java/org/apache/cxf/jaxrs/impl/ test/java/org/apache/cxf/jaxrs/utils/

Author: sergeyb
Date: Tue Apr 30 15:23:40 2013
New Revision: 1477686

URL: http://svn.apache.org/r1477686
Log:
[CXF-4919] Fixing UriInfo/HttpUtils relativize implementation, quality patch from Stian Soiland-Reyes applied

Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/LinkBuilderImplTest.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java?rev=1477686&r1=1477685&r2=1477686&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java Tue Apr 30 15:23:40 2013
@@ -495,44 +495,51 @@ public final class HttpUtils {
         return uri;
     }
     
-    public static URI relativize(URI requestURI, URI resolved) {
-        if (!getUriPrefix(resolved).equals(getUriPrefix(requestURI))) {
-            return resolved;
+    public static URI relativize(URI base, URI uri) {
+        // quick bail-out
+        if (!(base.isAbsolute()) || !(uri.isAbsolute())) {
+            return uri;
+        }
+        if (base.isOpaque() || uri.isOpaque()) {
+            // Unlikely case of an URN which can't deal with
+            // relative path, such as urn:isbn:0451450523
+            return uri;
+        }
+        // Check for common root
+        URI root = base.resolve("/");
+        if (!(root.equals(uri.resolve("/")))) {
+            // Different protocol/auth/host/port, return as is
+            return uri;
         }
-        List<PathSegment> resolvedSegments = JAXRSUtils.getPathSegments(resolved.getRawPath(), false);
-        List<PathSegment> requestSegments = JAXRSUtils.getPathSegments(requestURI.getRawPath(), false);
         
-        int count = 0;
-        for (int i = resolvedSegments.size() - 1; i >= 0; i--) {
-            if (i <= requestSegments.size() - 1) {
-                String resolvedPath = resolvedSegments.get(i).getPath();
-                String requestPath = requestSegments.get(i).getPath();
-                if (!resolvedPath.equals(requestPath)) {
-                    count++;
-                }
-            }
+        // Ignore hostname bits for the following , but add "/" in the beginning
+        // so that in worst case we'll still return "/fred" rather than
+        // "http://example.com/fred".
+        URI baseRel = URI.create("/").resolve(root.relativize(base));
+        URI uriRel = URI.create("/").resolve(root.relativize(uri));
+        
+        // Is it same path?
+        if (baseRel.getPath().equals(uriRel.getPath())) {
+            return baseRel.relativize(uriRel);
         }
-        StringBuilder sb = new StringBuilder();
         
-        for (int i = 0; i < count; i++) {
-            if (i != 0) {
-                sb.append("/");
-            }
-            sb.append(PARENT_PATH_SEGMENT);
-        }
-        for (int i = count + 1; i < resolvedSegments.size(); i++) {
-            if (i != 0) {
-                sb.append("/");
-            }
-            sb.append(resolvedSegments.get(i).getPath());
+        // Direct siblings? (ie. in same folder)
+        URI commonBase = baseRel.resolve("./");
+        if (commonBase.equals(uriRel.resolve("./"))) {
+            return commonBase.relativize(uriRel);
         }
-        return URI.create(sb.toString());
-    }
-    
-    private static String getUriPrefix(URI uri) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(uri.getScheme()).append(uri.getHost()).append(uri.getPort());
         
-        return sb.toString();
+        // No, then just keep climbing up until we find a common base.
+        URI relative = URI.create("");
+        while (!(uriRel.getPath().startsWith(commonBase.getPath())) && !(commonBase.getPath().equals("/"))) {
+            commonBase = commonBase.resolve("../");
+            relative = relative.resolve("../");
+        }
+
+        // Now we can use URI.relativize
+        URI relToCommon = commonBase.relativize(uriRel);
+        // and prepend the needed ../
+        return relative.resolve(relToCommon);
+        
     }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/LinkBuilderImplTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/LinkBuilderImplTest.java?rev=1477686&r1=1477685&r2=1477686&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/LinkBuilderImplTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/LinkBuilderImplTest.java Tue Apr 30 15:23:40 2013
@@ -22,7 +22,6 @@ import java.net.URI;
 
 import javax.ws.rs.core.Link;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -37,7 +36,6 @@ public class LinkBuilderImplTest {
         assertEquals("<http://example.com/page1>;rel=\"previous\"", prevLink.toString());
     }
 
-    @Ignore("Ignored due to CXF-4919")
     @Test
     public void relativeBuild() throws Exception {
         Link.Builder linkBuilder = new LinkBuilderImpl();
@@ -64,7 +62,6 @@ public class LinkBuilderImplTest {
         assertEquals("<http://example.com/page3>;rel=\"next\"", nextLink.toString());
     }
 
-    @Ignore("Ignored due to CXF-4919")
     @Test
     public void copyOnRelativeBuild() throws Exception {
         Link.Builder linkBuilder = new LinkBuilderImpl();

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java?rev=1477686&r1=1477685&r2=1477686&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java Tue Apr 30 15:23:40 2013
@@ -75,10 +75,131 @@ public class UriInfoImplTest extends Ass
         assertEquals("Wrong Request Uri", "http://localhost:8080/app/root/a/b/c", 
                      u.getRequestUri().toString());
         URI relativized = u.relativize(URI.create("http://localhost:8080/app/root/a/d/e"));
-        assertEquals("../../d/e", relativized.toString());
+        assertEquals("../d/e", relativized.toString());
     }
     
     @Test
+    public void testRelativizeAlreadyRelative() throws Exception {
+        Message mockMessage = mockMessage("http://localhost:8080/app/root/",
+                "/soup/");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        assertEquals("http://localhost:8080/app/root/soup/", u.getRequestUri()
+                .toString());
+        URI x = URI.create("x/");
+        assertEquals("http://localhost:8080/app/root/x/", u.resolve(x)
+                .toString());
+        assertEquals("../x/", u.relativize(x).toString());
+    }
+
+    @Test
+    public void testRelativizeNoCommonPrefix() throws Exception {
+        Message mockMessage = mockMessage("http://localhost:8080/app/root/",
+                "/soup");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        assertEquals("http://localhost:8080/app/root/soup", u.getRequestUri()
+                .toString());
+        URI otherHost = URI.create("http://localhost:8081/app/root/x");
+        assertEquals(otherHost, u.resolve(otherHost));
+
+        // port/host is different!
+        assertEquals(otherHost, u.relativize(otherHost));
+    }
+
+    @Test
+    public void testRelativizeChild() throws Exception {
+        /** From UriInfo.relativize() javadoc (2013-04-21):
+*
+* <br/><b>Request URI:</b> <tt>http://host:port/app/root/a/b/c</tt>
+* <br/><b>Supplied URI:</b> <tt>a/b/c/d/e</tt>
+* <br/><b>Returned URI:</b> <tt>d/e</tt>
+*
+* NOTE: Although the above is correct JAX-RS API-wise (as of 2013-04-21),
+* it is WRONG URI-wise (but correct API wise)
+* as the request URI is missing the trailing / -- if the request returned HTML at
+* that location, then resolving "d/e" would end up instead at /app/root/a/b/d/e
+* -- see URI.create("/app/root/a/b/c").resolve("d/e"). Therefore the below tests
+* use the slightly modified request URI http://example.com/app/root/a/b/c/ with a trailing /
+*
+* See the test testRelativizeSibling for a non-slash-ending request URI
+*/
+        Message mockMessage = mockMessage("http://example.com/app/root/",
+                "/a/b/c/");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        assertEquals("http://example.com/app/root/a/b/c/", u.getRequestUri()
+                .toString());
+        URI absolute = URI.create("http://example.com/app/root/a/b/c/d/e");
+        assertEquals("d/e", u.relativize(absolute).toString());
+
+        URI relativeToBase = URI.create("a/b/c/d/e");
+        assertEquals("d/e", u.relativize(relativeToBase).toString());
+    }
+    
+    @Test
+    public void testRelativizeSibling() throws Exception {
+        Message mockMessage = mockMessage("http://example.com/app/root/",
+                "/a/b/c.html");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        // NOTE: No slash in the end!
+        assertEquals("http://example.com/app/root/a/b/c.html", u
+                .getRequestUri().toString());
+        URI absolute = URI.create("http://example.com/app/root/a/b/c.pdf");
+        assertEquals("c.pdf", u.relativize(absolute).toString());
+
+        URI relativeToBase = URI.create("a/b/c.pdf");
+        assertEquals("c.pdf", u.relativize(relativeToBase).toString());
+    }
+    
+    @Test
+    public void testRelativizeGrandParent() throws Exception {
+        Message mockMessage = mockMessage("http://example.com/app/root/",
+                "/a/b/c/");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        // NOTE: All end with slashes (imagine they are folders)
+        assertEquals("http://example.com/app/root/a/b/c/", u.getRequestUri()
+                .toString());
+        URI absolute = URI.create("http://example.com/app/root/a/");
+        // Need to go two levels up from /a/b/c/ to /a/
+        assertEquals("../../", u.relativize(absolute).toString());
+
+        URI relativeToBase = URI.create("a/");
+        assertEquals("../../", u.relativize(relativeToBase).toString());
+    }
+
+    @Test
+    public void testRelativizeCousin() throws Exception {
+        Message mockMessage = mockMessage("http://example.com/app/root/",
+                "/a/b/c/");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        // NOTE: All end with slashes (imagine they are folders)
+        assertEquals("http://example.com/app/root/a/b/c/", u.getRequestUri()
+                .toString());
+        URI absolute = URI.create("http://example.com/app/root/a/b2/c2/");
+        // Need to go two levels up from /a/b/c/ to /a/
+        assertEquals("../../b2/c2/", u.relativize(absolute).toString());
+
+        URI relativeToBase = URI.create("a/b2/c2/");
+        assertEquals("../../b2/c2/", u.relativize(relativeToBase).toString());
+    }
+
+    @Test
+    public void testRelativizeOutsideBase() throws Exception {
+        Message mockMessage = mockMessage("http://example.com/app/root/",
+                "/a/b/c/");
+        UriInfoImpl u = new UriInfoImpl(mockMessage, null);
+        // NOTE: All end with slashes (imagine they are folders)
+        assertEquals("http://example.com/app/root/a/b/c/", u.getRequestUri()
+                .toString());
+        URI absolute = URI.create("http://example.com/otherapp/fred.txt");
+
+        assertEquals("../../../../../otherapp/fred.txt", u.relativize(absolute)
+                .toString());
+
+        URI relativeToBase = URI.create("../../otherapp/fred.txt");
+        assertEquals("../../../../../otherapp/fred.txt",
+                u.relativize(relativeToBase).toString());
+    }
+
+    @Test
     public void testResolveNormalizeComplex() throws Exception {
         UriInfoImpl u = new UriInfoImpl(mockMessage("http://localhost:8080/baz/1/2/3/", null), null);
         assertEquals("Wrong base path", "http://localhost:8080/baz/1/2/3/", 

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java?rev=1477686&r1=1477685&r2=1477686&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java Tue Apr 30 15:23:40 2013
@@ -45,6 +45,17 @@ public class HttpUtilsTest extends Asser
     }
     
     @Test
+    public void testRelativize() throws Exception {
+        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6226081
+        URI a = new URI("file:/c:/abc/def/myDocument/doc.xml");
+        URI b = new URI("file:/c:/abc/def/images/subdir/image.png");
+        
+        URI c = HttpUtils.relativize(a, b);
+        
+        assertEquals("../images/subdir/image.png", c.toString());
+    }
+    
+    @Test
     public void testIsDateHeader() {
         assertFalse(HttpUtils.isDateRelatedHeader(HttpHeaders.ETAG));
         assertTrue(HttpUtils.isDateRelatedHeader(HttpHeaders.EXPIRES));