You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by ma...@apache.org on 2009/07/15 14:51:41 UTC

svn commit: r794252 - in /incubator/wink/trunk: src/doc/DeveloperGuide/ wink-common/src/main/java/org/apache/wink/common/internal/uri/ wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/ wink-common/src/main/java/org/apache/wink/comm...

Author: martins
Date: Wed Jul 15 12:51:40 2009
New Revision: 794252

URL: http://svn.apache.org/viewvc?rev=794252&view=rev
Log:
Fix JIRA [WINK-94] and [WINK-96]

Removed:
    incubator/wink/trunk/src/doc/DeveloperGuide/Apache_Wink_0.1_Features_List.docx
    incubator/wink/trunk/src/doc/DeveloperGuide/Apache_Wink_0.1_Features_List.pdf
Modified:
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uri/UriEncoder.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/UriTemplateProcessor.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/UriHelper.java
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/UriHelperTest.java
    incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/UriInfoImpl.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/jaxrs/UriInfoImplTest.java

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uri/UriEncoder.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uri/UriEncoder.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uri/UriEncoder.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uri/UriEncoder.java Wed Jul 15 12:51:40 2009
@@ -20,6 +20,7 @@
  
 package org.apache.wink.common.internal.uri;
 
+import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.Arrays;
@@ -44,6 +45,8 @@
     /** Hexadecimal digits for escaping. */
     private static final char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
             'F'};
+    
+    private static final byte[] normalizedHexDigits = new byte[128];
 
     private static final boolean[] isHexDigit = new boolean[128];
 
@@ -51,16 +54,16 @@
      * Unreserved characters according to RFC 3986. Each character below ASCII 128 has single array
      * item with true if it is unreserved and false if it is reserved.
      */
-    private static final boolean[] unreservedChars = new boolean[128];
-    private static final boolean[] userInfoChars = new boolean[128];
-    private static final boolean[] segmentChars = new boolean[128];
-    private static final boolean[] matrixChars = new boolean[128];
-    private static final boolean[] pathChars = new boolean[128];
-    private static final boolean[] queryChars = new boolean[128];
-    private static final boolean[] queryParamChars = new boolean[128];
-    private static final boolean[] fragmentChars = new boolean[128];
-    private static final boolean[] uriChars = new boolean[128];
-    private static final boolean[] uriTemplateChars = new boolean[128];
+    public static final boolean[] unreservedChars = new boolean[128];
+    public static final boolean[] userInfoChars = new boolean[128];
+    public static final boolean[] segmentChars = new boolean[128];
+    public static final boolean[] matrixChars = new boolean[128];
+    public static final boolean[] pathChars = new boolean[128];
+    public static final boolean[] queryChars = new boolean[128];
+    public static final boolean[] queryParamChars = new boolean[128];
+    public static final boolean[] fragmentChars = new boolean[128];
+    public static final boolean[] uriChars = new boolean[128];
+    public static final boolean[] uriTemplateChars = new boolean[128];
 
     static {
         // unreserved - ALPHA / DIGIT / "-" / "." / "_" / "~"
@@ -132,6 +135,31 @@
         Arrays.fill(isHexDigit, '0', '9' + 1, true);
         Arrays.fill(isHexDigit, 'a', 'f' + 1, true);
         Arrays.fill(isHexDigit, 'A', 'F' + 1, true);
+        
+        // fill the normalizedHexDigits array
+        normalizedHexDigits['0'] = '0';
+        normalizedHexDigits['1'] = '1';
+        normalizedHexDigits['2'] = '2';
+        normalizedHexDigits['3'] = '3';
+        normalizedHexDigits['4'] = '4';
+        normalizedHexDigits['5'] = '5';
+        normalizedHexDigits['6'] = '6';
+        normalizedHexDigits['7'] = '7';
+        normalizedHexDigits['8'] = '8';
+        normalizedHexDigits['9'] = '9';
+        normalizedHexDigits['A'] = 'A';
+        normalizedHexDigits['B'] = 'B';
+        normalizedHexDigits['C'] = 'C';
+        normalizedHexDigits['D'] = 'D';
+        normalizedHexDigits['E'] = 'E';
+        normalizedHexDigits['F'] = 'F';
+        normalizedHexDigits['a'] = 'A';
+        normalizedHexDigits['b'] = 'B';
+        normalizedHexDigits['c'] = 'C';
+        normalizedHexDigits['d'] = 'D';
+        normalizedHexDigits['e'] = 'E';
+        normalizedHexDigits['f'] = 'F';
+        
     }
 
     private static int decodeHexDigit(char c) {
@@ -384,7 +412,7 @@
      * @return decoded query
      */
     public static String decodeQuery(String string) {
-        return decodeString(string, true);
+        return decodeString(string, true, null);
     }
 
     /**
@@ -395,10 +423,22 @@
      * @return decoded uri
      */
     public static String decodeString(String string) {
-        return decodeString(string, false);
+        return decodeString(string, false, null);
+    }
+    
+    /**
+     * Decodes only the unreserved chars, according to <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>
+     * section 6.2.2.2  
+     * 
+     * @param string
+     *            US-ASCII uri to decode
+     * @return decoded uri
+     */
+    public static String normalize(String string){
+        return decodeString(string, false, unreservedChars);
     }
 
-    private static String decodeString(String string, boolean query) {
+    private static String decodeString(String string, boolean query, boolean[] decodeChars) {
         if (string == null) {
             return null;
         }
@@ -420,8 +460,15 @@
                 if (d1 >= 0 && d2 >= 0) {
                     v = d1;
                     v = v << 4 | d2;
-                    buffer.put((byte)v);
-                    i += 2;
+                    if(decodeChars != null && !decodeChars[v]){
+                        buffer.put((byte)string.charAt(i));
+                        buffer.put(normalizedHexDigits[string.charAt(i + 1)]);
+                        buffer.put(normalizedHexDigits[string.charAt(i + 2)]);
+                    }
+                    else{
+                        buffer.put((byte)v);
+                    }
+                    i+=2;
                 } else {
                     buffer.put((byte)c);
                 }

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/UriTemplateProcessor.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/UriTemplateProcessor.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/UriTemplateProcessor.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/uritemplate/UriTemplateProcessor.java Wed Jul 15 12:51:40 2009
@@ -34,7 +34,7 @@
 import org.apache.wink.common.http.HttpStatus;
 import org.apache.wink.common.internal.MultivaluedMapImpl;
 import org.apache.wink.common.internal.uri.UriEncoder;
-import org.apache.wink.common.internal.uri.UriPathNormalizer;
+import org.apache.wink.common.internal.utils.UriHelper;
 
 
 /**
@@ -262,16 +262,14 @@
     public static String normalizeUri(String uri) {
         String normalizedUri;
         if (uri != null) {
-            normalizedUri = UriPathNormalizer.normalize(uri);
+            normalizedUri = UriHelper.normalize(uri);
         } else {
             normalizedUri = "";
         }
         if (normalizedUri.startsWith("/")) {
             normalizedUri = normalizedUri.substring(1);
         }
-//        if (normalizedUri.endsWith("/")) {
-//            normalizedUri = normalizedUri.substring(0, normalizedUri.length() - 1);
-//        }
+
         return normalizedUri;
     }
 

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/UriHelper.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/UriHelper.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/UriHelper.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/UriHelper.java Wed Jul 15 12:51:40 2009
@@ -475,5 +475,21 @@
         }
         return query;
     }
-
+    
+    /**
+     * Normalize input uri according to <a> href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>
+     * section 6.2.2. - Syntax-Based Normalization
+     * @param string
+     * @return normalized instance of uri
+     */
+    public static String normalize(String uri){
+        
+        // Path Segment Normalization
+        uri = UriPathNormalizer.normalize(uri);
+        
+        // Percent-Encoding Normalization & Case Normalization
+        uri = UriEncoder.normalize(uri);
+        
+        return uri;
+    }
 }

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/UriHelperTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/UriHelperTest.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/UriHelperTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/UriHelperTest.java Wed Jul 15 12:51:40 2009
@@ -285,4 +285,9 @@
         assertNull(parsedQuery.getFirst("e"));
     }
     
+    public void testNormalize(){
+        // test URI Syntax-Based Normalization according to RFC 3986, section 6.2.2
+        String normalize = UriHelper.normalize("ab%72c%2F123/d%2fdef/a/../b/./c%20sss");
+        assertEquals("abrc%2F123/d%2Fdef/b/c%20sss", normalize);
+    }
 }

Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/UriInfoImpl.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/UriInfoImpl.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/UriInfoImpl.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/UriInfoImpl.java Wed Jul 15 12:51:40 2009
@@ -39,6 +39,7 @@
 import org.apache.wink.common.internal.MultivaluedMapImpl;
 import org.apache.wink.common.internal.PathSegmentImpl;
 import org.apache.wink.common.internal.uri.UriEncoder;
+import org.apache.wink.common.internal.uri.UriPathNormalizer;
 import org.apache.wink.common.internal.utils.UriHelper;
 import org.apache.wink.server.handlers.MessageContext;
 import org.apache.wink.server.internal.handlers.SearchResult;
@@ -325,7 +326,10 @@
     private String buildRequestPath(HttpServletRequest request) {
         // we cannot use request.getPathInfo() since it cuts off the ';' parameters on Tomcat
         String requestPath = request.getRequestURI();
-
+        
+        // Syntax-Based Normalization (RFC 3986, section 6.2.2)
+        requestPath = UriHelper.normalize(requestPath);
+        
         // cut off the context path from the beginning
         if (request.getContextPath() != null) {
             requestPath = requestPath.substring(request.getContextPath().length());

Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/jaxrs/UriInfoImplTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/jaxrs/UriInfoImplTest.java?rev=794252&r1=794251&r2=794252&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/jaxrs/UriInfoImplTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/jaxrs/UriInfoImplTest.java Wed Jul 15 12:51:40 2009
@@ -34,12 +34,11 @@
 import org.junit.Test;
 import org.springframework.mock.web.MockHttpServletRequest;
 
-
 public class UriInfoImplTest extends MockServletInvocationTest {
 
     @Override
     protected Class<?>[] getClasses() {
-        return new Class[] { FooResource.class, TestResource.class};
+        return new Class[] {FooResource.class, TestResource.class};
     }
 
     @Path("/te st/{id}")
@@ -48,20 +47,20 @@
         @Produces("text/plain")
         public void getFoo(@Context UriInfo uriInfo) {
             assertNotNull(uriInfo.getAbsolutePath());
-            assertEquals("http://localhost:80/te%20st/5", uriInfo.getAbsolutePath().toString()); 
+            assertEquals("http://localhost:80/te%20st/5", uriInfo.getAbsolutePath().toString());
             assertNotNull(uriInfo.getBaseUri());
-            assertEquals("http://localhost:80/",  uriInfo.getBaseUri().toString());
+            assertEquals("http://localhost:80/", uriInfo.getBaseUri().toString());
             assertNotNull(uriInfo.getPath());
-            assertEquals("te st/5",  uriInfo.getPath().toString());
-            assertEquals("te%20st/5",  uriInfo.getPath(false).toString());
+            assertEquals("te st/5", uriInfo.getPath().toString());
+            assertEquals("te%20st/5", uriInfo.getPath(false).toString());
             MultivaluedMap<String, String> pathParameters = uriInfo.getPathParameters();
             assertNotNull(pathParameters);
             assertEquals(1, pathParameters.size());
             List<String> paramValue = pathParameters.get("id");
             assertNotNull(paramValue);
             assertEquals(1, paramValue.size());
-            assertEquals("5",  paramValue.get(0));
-            
+            assertEquals("5", paramValue.get(0));
+
             List<PathSegment> pathSegmentsDecoded = uriInfo.getPathSegments();
             assertNotNull(pathSegmentsDecoded);
             assertEquals(2, pathSegmentsDecoded.size());
@@ -72,22 +71,20 @@
             assertEquals(2, pathSegmentsEncoded.size());
             assertEquals("5", pathSegmentsEncoded.get(1).getPath());
 
-            
             MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
             assertNotNull(queryParameters);
             assertEquals(1, queryParameters.size());
             List<String> queryParam = queryParameters.get("abc");
             assertNotNull(queryParam);
             assertEquals(1, queryParam.size());
-            assertEquals("6",queryParam.get(0));
-            
+            assertEquals("6", queryParam.get(0));
+
             assertEquals("http://localhost:80/te%20st/5?abc=6", uriInfo.getRequestUri().toString());
-            
+
             return;
         }
     }
-    
-    
+
     @Path("/foo")
     public static class FooResource {
         @GET
@@ -99,7 +96,7 @@
             assertNotNull(uriInfo.getMatchedURIs());
             assertEquals(1, uriInfo.getMatchedURIs().size());
             assertEquals("foo", uriInfo.getMatchedURIs().get(0));
-            
+
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(1, uriInfo.getMatchedResources().size());
@@ -118,17 +115,17 @@
             String firstUri = uriInfo.getMatchedURIs().get(0);
             assertEquals("foo/bar", firstUri);
             String secondUri = uriInfo.getMatchedURIs().get(1);
-            assertEquals("foo",secondUri);
-            
+            assertEquals("foo", secondUri);
+
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(1, uriInfo.getMatchedResources().size());
             Object matchedResource = uriInfo.getMatchedResources().get(0);
             assertNotNull(matchedResource);
             assertTrue(matchedResource instanceof FooResource);
-           return new BarResource();
+            return new BarResource();
         }
-        
+
         @GET
         @Path("bar1")
         public String getBar1Resource(@Context UriInfo uriInfo) {
@@ -139,25 +136,24 @@
             String firstUri = uriInfo.getMatchedURIs().get(0);
             assertEquals("foo/bar1", firstUri);
             String secondUri = uriInfo.getMatchedURIs().get(1);
-            assertEquals("foo",secondUri);
-            
+            assertEquals("foo", secondUri);
+
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(1, uriInfo.getMatchedResources().size());
             Object matchedResource = uriInfo.getMatchedResources().get(0);
             assertNotNull(matchedResource);
             assertTrue(matchedResource instanceof FooResource);
-           return "Bar Resource";
+            return "Bar Resource";
         }
-        
-        
+
     }
 
     public static class BarResource {
         @GET
         @Produces("text/plain")
         public String getBar(@Context UriInfo uriInfo) {
-            
+
             // test matched URIs
             assertNotNull(uriInfo);
             assertNotNull(uriInfo.getMatchedURIs());
@@ -165,24 +161,24 @@
             String firstUri = uriInfo.getMatchedURIs().get(0);
             assertEquals("foo/bar", firstUri);
             String secondUri = uriInfo.getMatchedURIs().get(1);
-            assertEquals("foo",secondUri);
-            
+            assertEquals("foo", secondUri);
+
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(2, uriInfo.getMatchedResources().size());
             Object matchedResource = uriInfo.getMatchedResources().get(0);
             assertTrue(matchedResource instanceof BarResource);
-            
+
             matchedResource = uriInfo.getMatchedResources().get(1);
             assertTrue(matchedResource instanceof FooResource);
-            
+
             return "Bar Resurse";
         }
-        
+
         @Path("level3")
         @Produces("text/plain")
         public BarResourceLevel3 getBarLevel3(@Context UriInfo uriInfo) {
-            
+
             // test matched URIs
             assertNotNull(uriInfo);
             assertNotNull(uriInfo.getMatchedURIs());
@@ -190,28 +186,28 @@
             String firstUri = uriInfo.getMatchedURIs().get(0);
             assertEquals("foo/bar/level3", firstUri);
             String secondUri = uriInfo.getMatchedURIs().get(1);
-            assertEquals("foo/bar",secondUri);
+            assertEquals("foo/bar", secondUri);
             String thirdUri = uriInfo.getMatchedURIs().get(2);
-            assertEquals("foo",thirdUri);
-            
+            assertEquals("foo", thirdUri);
+
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(2, uriInfo.getMatchedResources().size());
             Object matchedResource = uriInfo.getMatchedResources().get(0);
             assertTrue(matchedResource instanceof BarResource);
-            
+
             matchedResource = uriInfo.getMatchedResources().get(1);
             assertTrue(matchedResource instanceof FooResource);
-            
+
             return new BarResourceLevel3();
         }
     }
-    
+
     public static class BarResourceLevel3 {
         @GET
         @Produces("text/plain")
         public String getBar(@Context UriInfo uriInfo) {
-            
+
             // test matched URIs
             assertNotNull(uriInfo);
             assertNotNull(uriInfo.getMatchedURIs());
@@ -219,11 +215,10 @@
             String firstUri = uriInfo.getMatchedURIs().get(0);
             assertEquals("foo/bar/level3", firstUri);
             String secondUri = uriInfo.getMatchedURIs().get(1);
-            assertEquals("foo/bar",secondUri);
+            assertEquals("foo/bar", secondUri);
             String thirdUri = uriInfo.getMatchedURIs().get(2);
-            assertEquals("foo",thirdUri);
+            assertEquals("foo", thirdUri);
 
-            
             // test matched Resources
             assertNotNull(uriInfo.getMatchedResources());
             assertEquals(3, uriInfo.getMatchedResources().size());
@@ -233,39 +228,58 @@
 
             matchedResource = uriInfo.getMatchedResources().get(1);
             assertTrue(matchedResource instanceof BarResource);
-            
+
             matchedResource = uriInfo.getMatchedResources().get(2);
             assertTrue(matchedResource instanceof FooResource);
-            
+
             return "Bar Resourse Level 3";
         }
     }
-    
-    
 
     @Test
     public void testUriInfoMatchedResourcesAndURIs() throws Exception {
 
-        MockHttpServletRequest servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo", "text/plain");
+        MockHttpServletRequest servletRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/foo", "text/plain");
         invoke(servletRequest);
-        
+
         servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo/bar", "text/plain");
         invoke(servletRequest);
-        
+
         servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo/bar1", "text/plain");
         invoke(servletRequest);
-        
+
         servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo/bar/level3", "text/plain");
         invoke(servletRequest);
-        
 
     }
-    
+
     @Test
     public void testUriInfo() throws Exception {
-        MockHttpServletRequest servletRequest = MockRequestConstructor.constructMockRequest("GET", "/te%20st/5", "text/plain");
+        MockHttpServletRequest servletRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/te%20st/5", "text/plain");
         servletRequest.setQueryString("abc=6");
         invoke(servletRequest);
     }
 
+    @Test
+    public void testUriInfoNormalization() throws Exception {
+
+        MockHttpServletRequest servletRequest =
+            MockRequestConstructor.constructMockRequest("GET", "/foo/../foo", "text/plain");
+        invoke(servletRequest);
+
+        servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo/../foo/bar", "text/plain");
+        invoke(servletRequest);
+
+        servletRequest = MockRequestConstructor.constructMockRequest("GET", "/foo/bar1/../bar1", "text/plain");
+        invoke(servletRequest);
+
+        servletRequest =
+            MockRequestConstructor.constructMockRequest("GET",
+                                                        "/foo/../foo/bar/../bar/level3/../level3/nonsense/..",
+                                                        "text/plain");
+        invoke(servletRequest);
+    }
+
 }