directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From seelm...@apache.org
Subject svn commit: r689638 - in /directory/shared/trunk/ldap/src: main/java/org/apache/directory/shared/ldap/util/LdapURL.java test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java
Date Wed, 27 Aug 2008 22:03:27 GMT
Author: seelmann
Date: Wed Aug 27 15:03:27 2008
New Revision: 689638

URL: http://svn.apache.org/viewvc?rev=689638&view=rev
Log:
Fixed URL encoding according to RFC 4516.

Modified:
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/LdapURL.java
    directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java

Modified: directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/LdapURL.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/LdapURL.java?rev=689638&r1=689637&r2=689638&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/LdapURL.java
(original)
+++ directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/LdapURL.java
Wed Aug 27 15:03:27 2008
@@ -32,6 +32,7 @@
 import javax.naming.InvalidNameException;
 import javax.naming.directory.SearchControls;
 
+import org.apache.directory.shared.asn1.codec.binary.Hex;
 import org.apache.directory.shared.ldap.codec.util.HttpClientError;
 import org.apache.directory.shared.ldap.codec.util.LdapURLEncodingException;
 import org.apache.directory.shared.ldap.codec.util.URIException;
@@ -695,11 +696,7 @@
         {
             int b = bytes[i];
 
-            if ( b == '+' )
-            {
-                buffer.write( ' ' );
-            }
-            else if ( b == '%' )
+            if ( b == '%' )
             {
                 try
                 {
@@ -1098,6 +1095,12 @@
                 }
                 else if ( StringTools.isCharASCII( chars, i, '!' ) )
                 {
+                    if ( hasValue )
+                    {
+                        // We may have two '!' in the value
+                        continue;
+                    }
+
                     if ( !isNewExtension )
                     {
                         // '!' must appears first
@@ -1135,13 +1138,45 @@
 
 
     /**
-     * Encode a String to avoid special characters 
+     * Encode a String to avoid special characters.
+     *
+     * 
+     * RFC 4516, section 2.1. (Percent-Encoding)
+     *
+     * A generated LDAP URL MUST consist only of the restricted set of
+     * characters included in one of the following three productions defined
+     * in [RFC3986]:
+     *
+     *   <reserved>
+     *   <unreserved>
+     *   <pct-encoded>
+     *
+     * Implementations SHOULD accept other valid UTF-8 strings [RFC3629] as
+     * input.  An octet MUST be encoded using the percent-encoding mechanism
+     * described in section 2.1 of [RFC3986] in any of these situations:
+     * 
+     *  The octet is not in the reserved set defined in section 2.2 of
+     *  [RFC3986] or in the unreserved set defined in section 2.3 of
+     *  [RFC3986].
+     *
+     *  It is the single Reserved character '?' and occurs inside a <dn>,
+     *  <filter>, or other element of an LDAP URL.
+     *
+     *  It is a comma character ',' that occurs inside an <exvalue>.
+     *
+     *
+     * RFC 3986, section 2.2 (Reserved Characters)
      * 
-     * *NOTE* : this is an ugly function, just needed because the RFC 2255 
-     * is VERY unclear about the way LDAP searches are to be encoded. 
+     * reserved    = gen-delims / sub-delims
+     * gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+     * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+     *              / "*" / "+" / "," / ";" / "="
+     *             
+     *             
+     * RFC 3986, section 2.3 (Unreserved Characters)
      * 
-     * Some references to RFC 1738 are made, but they are really useless 
-     * and inadequat.
+     * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     *
      * 
      * @param url The String to encode
      * @param doubleEncode Set if we need to encode the comma
@@ -1156,20 +1191,112 @@
             char c = url.charAt( i );
 
             switch ( c )
+
             {
-                case ' ':
-                    sb.append( "%20" );
-                    break;
+                // reserved and unreserved characters:
+                // just append to the buffer
 
-                case '?':
-                    sb.append( "%3f" );
-                    break;
+                // reserved gen-delims, excluding '?'
+                // gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+                case ':':
+                case '/':
+                case '#':
+                case '[':
+                case ']':
+                case '@':
+
+                    // reserved sub-delims, excluding ','
+                    // sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+                    //               / "*" / "+" / "," / ";" / "="
+                case '!':
+                case '$':
+                case '&':
+                case '\'':
+                case '(':
+                case ')':
+                case '*':
+                case '+':
+                case ';':
+                case '=':
+
+                    // unreserved
+                    // unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                case 'g':
+                case 'h':
+                case 'i':
+                case 'j':
+                case 'k':
+                case 'l':
+                case 'm':
+                case 'n':
+                case 'o':
+                case 'p':
+                case 'q':
+                case 'r':
+                case 's':
+                case 't':
+                case 'u':
+                case 'v':
+                case 'w':
+                case 'x':
+                case 'y':
+                case 'z':
+
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
+                case 'G':
+                case 'H':
+                case 'I':
+                case 'J':
+                case 'K':
+                case 'L':
+                case 'M':
+                case 'N':
+                case 'O':
+                case 'P':
+                case 'Q':
+                case 'R':
+                case 'S':
+                case 'T':
+                case 'U':
+                case 'V':
+                case 'W':
+                case 'X':
+                case 'Y':
+                case 'Z':
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+
+                case '-':
+                case '.':
+                case '_':
+                case '~':
 
-                case '\\':
-                    sb.append( "%5c" );
+                    sb.append( c );
                     break;
 
                 case ',':
+
+                    // special case for comma
                     if ( doubleEncode )
                     {
                         sb.append( "%2c" );
@@ -1181,7 +1308,20 @@
                     break;
 
                 default:
-                    sb.append( c );
+
+                    // percent encoding
+                    byte[] bytes = StringTools.charToBytes( c );
+                    char[] hex = Hex.encodeHex( bytes );
+                    for ( int j = 0; j < hex.length; j++ )
+                    {
+                        if ( j % 2 == 0 )
+                        {
+                            sb.append( '%' );
+                        }
+                        sb.append( hex[j] );
+
+                    }
+
                     break;
             }
         }

Modified: directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java?rev=689638&r1=689637&r2=689638&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java
(original)
+++ directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/LdapUrlTest.java
Wed Aug 27 15:03:27 2008
@@ -2052,4 +2052,107 @@
         }
     }
 
+
+    /**
+     * Test UTF-8 values in extension values.
+     */
+    @Test
+    public void testLdapURLExtensionWithUtf8Values() throws Exception
+    {
+        String germanChars = new String(
+            new byte[]
+                { ( byte ) 0xC3, ( byte ) 0x84, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3,
( byte ) 0x9C,
+                    ( byte ) 0xC3, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0xA4, ( byte )
0xC3, ( byte ) 0xB6,
+                    ( byte ) 0xC3, ( byte ) 0xBC }, "UTF-8" );
+
+        LdapURL url1 = new LdapURL();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( LdapDN.EMPTY_LDAPDN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", germanChars
) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%c3%84%c3%96%c3%9c%c3%9f%c3%a4%c3%b6%c3%bc",
url1
+            .toString() );
+
+        LdapURL url2 = new LdapURL(
+            "ldap://localhost:123/????X-CONNECTION-NAME=%c3%84%c3%96%c3%9c%c3%9f%c3%a4%c3%b6%c3%bc"
);
+        assertEquals( germanChars, url1.getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%c3%84%c3%96%c3%9c%c3%9f%c3%a4%c3%b6%c3%bc",
url2
+            .toString() );
+    }
+
+
+    /**
+     * Test comma in extension value.
+     */
+    @Test
+    public void testLdapURLExtensionWithCommaValue() throws Exception
+    {
+        LdapURL url1 = new LdapURL();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( LdapDN.EMPTY_LDAPDN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", "," ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%2c", url1.toString() );
+
+        LdapURL url2 = new LdapURL( "ldap://localhost:123/????X-CONNECTION-NAME=%2c" );
+        assertEquals( ",", url1.getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%2c", url2.toString() );
+    }
+
+
+    /**
+     * Test with RFC 3986 reserved characters in extension value.
+     * 
+     *   reserved    = gen-delims / sub-delims
+     *   gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+     *   sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+     *                 / "*" / "+" / "," / ";" / "="
+     *              
+     * RFC 4516 specifies that '?' and a ',' must be percent encoded.
+     * 
+     */
+    @Test
+    public void testLdapURLExtensionWithRFC3986ReservedCharsAndRFC4616Exception() throws
Exception
+    {
+        LdapURL url1 = new LdapURL();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( LdapDN.EMPTY_LDAPDN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", ":/?#[]@!$&'()*+,;="
) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3f#[]@!$&'()*+%2c;=",
url1.toString() );
+
+        LdapURL url2 = new LdapURL( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3f#[]@!$&'()*+%2c;="
);
+        assertEquals( ":/?#[]@!$&'()*+,;=", url1.getExtensionValue( "X-CONNECTION-NAME"
) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3f#[]@!$&'()*+%2c;=",
url2.toString() );
+    }
+
+
+    /**
+     * Test with RFC 3986 unreserved characters in extension value.
+     * 
+     *   unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     */
+    @Test
+    public void testLdapURLExtensionWithRFC3986UnreservedChars() throws Exception
+    {
+        LdapURL url1 = new LdapURL();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( LdapDN.EMPTY_LDAPDN );
+        url1.getExtensions().add(
+            new Extension( false, "X-CONNECTION-NAME",
+                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~" ) );
+        assertEquals(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~",
+            url1.toString() );
+
+        LdapURL url2 = new LdapURL(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"
);
+        assertEquals( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~",
url1
+            .getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~",
+            url2.toString() );
+    }
+
 }



Mime
View raw message