Author: davsclaus Date: Tue Jun 12 09:27:14 2012 New Revision: 1349208 URL: http://svn.apache.org/viewvc?rev=1349208&view=rev Log: CAMEL-5357: Fixed uri normalization to support % sign itself to be encoded as %25. Added explict % decimal encoding to normalization logic.
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/UnsafeUriCharactersEncoder.java camel/trunk/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/UnsafeUriCharactersEncoder.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/UnsafeUriCharactersEncoder.java?rev=1349208&r1=1349207&r2=1349208&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/util/UnsafeUriCharactersEncoder.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/UnsafeUriCharactersEncoder.java Tue Jun 12 09:27:14 2012 @@ -20,6 +20,8 @@ import java.util.BitSet; /** * Encoder for unsafe URI characters. + * <p/> + * A good source for details is <a href="http://en.wikipedia.org/wiki/Url_encode">wikipedia url encode</a> article. */ public final class UnsafeUriCharactersEncoder { private static BitSet unsafeCharacters; @@ -33,7 +35,7 @@ public final class UnsafeUriCharactersEn unsafeCharacters.set('<'); unsafeCharacters.set('>'); unsafeCharacters.set('#'); - // unsafeCharacters.set('%'); + unsafeCharacters.set('%'); unsafeCharacters.set('{'); unsafeCharacters.set('}'); unsafeCharacters.set('|'); @@ -70,16 +72,32 @@ public final class UnsafeUriCharactersEn } // okay there are some unsafe characters so we do need to encode + // see details at: http://en.wikipedia.org/wiki/Url_encode StringBuilder sb = new StringBuilder(); - for (char ch : chars) { + for (int i = 0; i < chars.length; i++) { + char ch = chars[i]; if (ch > 0 && ch < 128 && unsafeCharacters.get(ch)) { - appendEscape(sb, (byte)ch); + // special for % sign as it may be a decimal encoded value + if (ch == '%') { + char next = i + 1 < chars.length ? chars[i + 1] : ' '; + char next2 = i + 2 < chars.length ? chars[i + 2] : ' '; + + if (isHexDigit(next) && isHexDigit(next2)) { + // its already encoded (decimal encoded) so just append as is + sb.append(ch); + } else { + // must escape then, as its an unsafe character + appendEscape(sb, (byte)ch); + } + } else { + // must escape then, as its an unsafe character + appendEscape(sb, (byte)ch); + } } else { sb.append(ch); } } return sb.toString(); - } private static void appendEscape(StringBuilder sb, byte b) { @@ -88,4 +106,13 @@ public final class UnsafeUriCharactersEn sb.append(HEX_DIGITS[(b >> 0) & 0x0f]); } + private static boolean isHexDigit(char ch) { + for (char hex : HEX_DIGITS) { + if (hex == ch) { + return true; + } + } + return false; + } + } Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java?rev=1349208&r1=1349207&r2=1349208&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java (original) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java Tue Jun 12 09:27:14 2012 @@ -19,9 +19,10 @@ package org.apache.camel.util; import junit.framework.TestCase; public class UnsafeCharactersEncoderTest extends TestCase { + private void testEncoding(String before, String after) { String result = UnsafeUriCharactersEncoder.encode(before); - assertEquals("Get the wrong encoding result", result, after); + assertEquals("Get the wrong encoding result", after, result); } public void testQnameEncoder() { @@ -39,4 +40,41 @@ public class UnsafeCharactersEncoderTest String noEncoding = "http://test.com/\uFD04"; testEncoding(noEncoding, noEncoding); } + + public void testPercentEncode() { + String beforeEncoding = "sql:select * from foo where bar like '%A'"; + String afterEncoding = "sql:select%20*%20from%20foo%20where%20bar%20like%20'%25A'"; + testEncoding(beforeEncoding, afterEncoding); + } + + public void testPercentEncodeAlready() { + String beforeEncoding = "sql:select * from foo where bar like '%25A'"; + String afterEncoding = "sql:select%20*%20from%20foo%20where%20bar%20like%20'%25A'"; + testEncoding(beforeEncoding, afterEncoding); + } + + public void testPercentEncodeDanishChar() { + String beforeEncoding = "http://localhost:{{port}}/myapp/mytest?columns=claus,s\u00F8ren&username=apiuser"; + String afterEncoding = "http://localhost:%7B%7Bport%7D%7D/myapp/mytest?columns=claus,s\u00F8ren&username=apiuser"; + testEncoding(beforeEncoding, afterEncoding); + } + + public void testPercentEncodeDanishCharEncoded() { + String beforeEncoding = "http://localhost:{{port}}/myapp/mytest?columns=claus,s%C3%B8ren&username=apiuser"; + String afterEncoding = "http://localhost:%7B%7Bport%7D%7D/myapp/mytest?columns=claus,s%C3%B8ren&username=apiuser"; + testEncoding(beforeEncoding, afterEncoding); + } + + public void testAlreadyEncoded() { + String beforeEncoding = "http://www.example.com?query=foo%20bar"; + String afterEncoding = "http://www.example.com?query=foo%20bar"; + testEncoding(beforeEncoding, afterEncoding); + } + + public void testPercentEncodedLast() { + String beforeEncoding = "http://www.example.com?like=foo%25"; + String afterEncoding = "http://www.example.com?like=foo%25"; + testEncoding(beforeEncoding, afterEncoding); + } + }