You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ja...@apache.org on 2014/05/07 18:19:55 UTC

svn commit: r1593051 - in /felix/trunk/http/base/src: main/java/org/apache/felix/http/base/internal/util/UriUtils.java test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java

Author: jawi
Date: Wed May  7 16:19:54 2014
New Revision: 1593051

URL: http://svn.apache.org/r1593051
Log:
FELIX-4440 - dots in pathinfo's incorrectly removed:

- use an alternative implementation of the algorithm of RFC3986;
- added some additional test cases that prove the new implementation
  is working correctly.


Modified:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java?rev=1593051&r1=1593050&r2=1593051&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java Wed May  7 16:19:54 2014
@@ -33,7 +33,9 @@ import java.nio.charset.CodingErrorActio
  */
 public class UriUtils
 {
-    private static final String SLASH = "/";
+    private static final String SLASH_STR = "/";
+    private static final char DOT = '.';
+    private static final char SLASH = '/';
 
     /**
      * Concatenates two paths keeping their respective path-parts into consideration.
@@ -82,9 +84,9 @@ public class UriUtils
             // need a slash?
         }
 
-        if (endsWith(sb, SLASH))
+        if (endsWith(sb, SLASH_STR))
         {
-            if (path2.startsWith(SLASH))
+            if (path2.startsWith(SLASH_STR))
             {
                 sb.append(path2.substring(1));
             }
@@ -95,13 +97,13 @@ public class UriUtils
         }
         else
         {
-            if (path2.startsWith(SLASH))
+            if (path2.startsWith(SLASH_STR))
             {
                 sb.append(path2);
             }
             else if (sb.length() > 0 && !isEmpty(path2))
             {
-                sb.append(SLASH).append(path2);
+                sb.append(SLASH_STR).append(path2);
             }
             else
             {
@@ -203,75 +205,108 @@ public class UriUtils
 
         StringBuilder scratch = new StringBuilder(path);
         StringBuilder sb = new StringBuilder();
-        char ch, la = 0, laa = 0;
+        char l, la = 0, laa = 0, laaa = 0;
 
         while (scratch.length() > 0)
         {
-            int len = scratch.length();
-            ch = scratch.charAt(0);
-            if (ch == '.')
+            l = la(scratch, 0);
+            la = la(scratch, 1);
+            laa = la(scratch, 2);
+
+            if (l == DOT)
             {
-                if (len > 1)
+                if (la == 0)
                 {
-                    la = scratch.charAt(1);
+                    // (D) found '.' at the end of the URL
+                    break;
                 }
-                if (la == '.' && (len > 2))
+                else if (la == DOT && laa == SLASH)
                 {
-                    laa = scratch.charAt(2);
+                    // (A) found '../', remove it from the input...
+                    scratch.delete(0, 3);
+                    continue;
                 }
-
-                if (la == '/' || laa == '/')
+                else if (la == DOT && laa == 0)
                 {
-                    // Step A: remove '../' or './' from input...
-                    scratch.delete(0, (laa == '/') ? 3 : 2);
-                    la = laa = 0;
-                    continue;
+                    // (D) found '..' at the end of the URL
+                    break;
                 }
-                else
+                else if (la == SLASH)
                 {
-                    // Step D: remove '..' or '.' from input...
-                    scratch.delete(0, (laa == '/') ? 2 : 1);
-                    la = laa = 0;
+                    // (A) found './', remove it from the input...
+                    scratch.delete(0, 2);
                     continue;
                 }
             }
-            else if (ch == '/')
+            else if (l == SLASH && la == DOT)
             {
-                if (len > 1)
-                {
-                    la = scratch.charAt(1);
-                }
-                if (la == '.' && (len > 2))
+                if (laa == SLASH)
                 {
-                    laa = scratch.charAt(2);
+                    // (B) found '/./', remove the leading '/.'...
+                    scratch.delete(0, 2);
+                    continue;
                 }
-
-                if (la == '.' && laa == '.')
+                else if (laa == 0)
                 {
-                    // Step C: remove '/../' or '/..' from input...
-                    char laaa = (len > 3) ? scratch.charAt(3) : 0;
-                    int lastSegment = sb.lastIndexOf(SLASH);
-                    scratch.replace(0, laaa == '/' ? 4 : 3, "/");
-                    sb.setLength(Math.max(0, lastSegment));
-                    la = laa = 0;
-                    continue;
+                    // (B) found '/.' as last part of the URL
+                    sb.append(SLASH);
+                    // we're done...
+                    break;
                 }
-                if ((la == '.' && laa == '/') || (la == '.' && laa != '/'))
+                else if (laa == DOT)
                 {
-                    // Step B: remove '/./' or '/.' from input...
-                    scratch.replace(0, laa == '/' ? 3 : 2, "/");
-                    la = laa = 0;
-                    continue;
+                    laaa = la(scratch, 3);
+                    if (laaa == SLASH)
+                    {
+                        // (C) found '/../', remove the '/..' part from the input...
+                        scratch.delete(0, 3);
+
+                        // go back one segment in the output, including the last '/'...
+                        sb.setLength(lb(sb, 0));
+                        continue;
+                    }
+                    else if (laaa == 0)
+                    {
+                        // (C) found '/..' as last part of the URL, go back one segment in the output, excluding the last '/'...
+                        sb.setLength(lb(sb, -1));
+                        // we're done...
+                        break;
+                    }
                 }
             }
 
-            sb.append(ch);
-            scratch.delete(0, 1);
+            // (E) Copy everything up to (but not including) the next '/'...
+            do
+            {
+                sb.append(l);
+                scratch.delete(0, 1);
+                l = la(scratch, 0);
+            }
+            while (l != SLASH && l != 0);
         }
 
         return sb.toString();
     }
 
+    private static char la(CharSequence sb, int idx)
+    {
+        if (sb.length() > idx)
+        {
+            return sb.charAt(idx);
+        }
+        return 0;
+    }
+
+    private static int lb(CharSequence sb, int offset)
+    {
+        int pos = sb.length() - 1 - offset;
+        while (pos > 0 && sb.charAt(pos + offset) != SLASH)
+        {
+            pos--;
+        }
+        return pos;
+    }
+
     private static String decode(ByteBuffer bb, CharsetDecoder decoder)
     {
         CharBuffer cb = CharBuffer.allocate(128);

Modified: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java?rev=1593051&r1=1593050&r2=1593051&view=diff
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java (original)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java Wed May  7 16:19:54 2014
@@ -102,7 +102,11 @@ public class UriUtilsTest
     {
         assertEquals(null, removeDotSegments(null));
         assertEquals("", removeDotSegments(""));
+        assertEquals("", removeDotSegments("."));
+        assertEquals("", removeDotSegments(".."));
         assertEquals("/", removeDotSegments("/"));
+        assertEquals("/", removeDotSegments("/."));
+        assertEquals("", removeDotSegments("/.."));
         assertEquals("foo", removeDotSegments("./foo"));
         assertEquals("/bar/", removeDotSegments("./foo/../bar/"));
         assertEquals("foo", removeDotSegments("../foo"));
@@ -111,9 +115,25 @@ public class UriUtilsTest
         assertEquals("/foo/bar", removeDotSegments("/foo/./bar"));
         assertEquals("/bar", removeDotSegments("/foo/../bar"));
         assertEquals("/bar", removeDotSegments("/foo/./../bar"));
+        assertEquals("/foo/bar", removeDotSegments("/foo/././bar"));
+        assertEquals("/qux", removeDotSegments("/foo/bar/../../qux"));
+        assertEquals("/foo/qux/quu", removeDotSegments("/foo/bar/../qux/././quu"));
         assertEquals("/bar//", removeDotSegments("/foo/./../bar//"));
         assertEquals("/", removeDotSegments("/foo/../bar/.."));
         assertEquals("/foo/quu", removeDotSegments("/foo/bar/qux/./../../quu"));
         assertEquals("mid/6", removeDotSegments("mid/content=5/../6"));
+        assertEquals("//bar/qux/file.ext", removeDotSegments("foo/.././/bar/qux/file.ext"));
+        // weird cases
+        assertEquals("..foo", removeDotSegments("..foo"));
+        assertEquals("foo..", removeDotSegments("foo.."));
+        assertEquals("foo.", removeDotSegments("foo."));
+        assertEquals("/.foo", removeDotSegments("/.foo"));
+        assertEquals("/..foo", removeDotSegments("/..foo"));        
+
+        // FELIX-4440
+        assertEquals("foo.bar", removeDotSegments("foo.bar"));
+        assertEquals("/test.jsp", removeDotSegments("/test.jsp"));
+        assertEquals("http://foo/bar./qux.quu", removeDotSegments("http://foo/bar./qux.quu"));
+        assertEquals("http://foo/bar.qux/quu", removeDotSegments("http://foo/bar.qux/quu"));
     }
 }