Repository: camel Updated Branches: refs/heads/camel-2.16.x c73de90d2 -> af94e7839 refs/heads/master 0589a1490 -> 19771345d
Fixed catalog to handle uris with property placeholders and other unsafe charachters Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/ed574cbd Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/ed574cbd Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/ed574cbd Branch: refs/heads/master Commit: ed574cbd7faf246e02c775a2ff6101a775963f0f Parents: 0589a14 Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Nov 11 10:36:01 2015 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Nov 11 10:36:01 2015 +0100 ---------------------------------------------------------------------- .../camel/catalog/DefaultCamelCatalog.java | 5 +- .../org/apache/camel/catalog/URISupport.java | 11 + .../catalog/UnsafeUriCharactersEncoder.java | 206 +++++++++++++++++++ .../apache/camel/catalog/CamelCatalogTest.java | 11 + 4 files changed, 232 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/ed574cbd/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java index 2471bb7..0cf52f0 100644 --- a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java @@ -44,6 +44,7 @@ import static org.apache.camel.catalog.CatalogHelper.after; import static org.apache.camel.catalog.JSonSchemaHelper.getPropertyDefaultValue; import static org.apache.camel.catalog.JSonSchemaHelper.isPropertyRequired; import static org.apache.camel.catalog.URISupport.createQueryString; +import static org.apache.camel.catalog.URISupport.normalizeUri; import static org.apache.camel.catalog.URISupport.stripQuery; /** @@ -464,8 +465,10 @@ public class DefaultCamelCatalog implements CamelCatalog { // NOTICE: This logic is similar to org.apache.camel.util.EndpointHelper#endpointProperties // as the catalog also offers similar functionality (without having camel-core on classpath) + // need to normalize uri first + // parse the uri - URI u = new URI(uri); + URI u = normalizeUri(uri); String scheme = u.getScheme(); String json = componentJSonSchema(scheme); http://git-wip-us.apache.org/repos/asf/camel/blob/ed574cbd/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java index 3c09d41..2742d0c 100644 --- a/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java @@ -41,6 +41,17 @@ public final class URISupport { } /** + * Normalizes the URI so unsafe charachters is encoded + * + * @param uri the input uri + * @return as URI instance + * @throws URISyntaxException is thrown if syntax error in the input uri + */ + public static URI normalizeUri(String uri) throws URISyntaxException { + return new URI(UnsafeUriCharactersEncoder.encode(uri, true)); + } + + /** * Strips the query parameters from the uri * * @param uri the uri http://git-wip-us.apache.org/repos/asf/camel/blob/ed574cbd/platforms/catalog/src/main/java/org/apache/camel/catalog/UnsafeUriCharactersEncoder.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/UnsafeUriCharactersEncoder.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/UnsafeUriCharactersEncoder.java new file mode 100644 index 0000000..1d137d2 --- /dev/null +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/UnsafeUriCharactersEncoder.java @@ -0,0 +1,206 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.catalog; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 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 unsafeCharactersRfc1738; + private static BitSet unsafeCharactersHttp; + private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', + 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f'}; + + static { + unsafeCharactersRfc1738 = new BitSet(256); + unsafeCharactersRfc1738.set(' '); + unsafeCharactersRfc1738.set('"'); + unsafeCharactersRfc1738.set('<'); + unsafeCharactersRfc1738.set('>'); + unsafeCharactersRfc1738.set('#'); + unsafeCharactersRfc1738.set('%'); + unsafeCharactersRfc1738.set('{'); + unsafeCharactersRfc1738.set('}'); + unsafeCharactersRfc1738.set('|'); + unsafeCharactersRfc1738.set('\\'); + unsafeCharactersRfc1738.set('^'); + unsafeCharactersRfc1738.set('~'); + unsafeCharactersRfc1738.set('['); + unsafeCharactersRfc1738.set(']'); + unsafeCharactersRfc1738.set('`'); + } + + static { + unsafeCharactersHttp = new BitSet(256); + unsafeCharactersHttp.set(' '); + unsafeCharactersHttp.set('"'); + unsafeCharactersHttp.set('<'); + unsafeCharactersHttp.set('>'); + unsafeCharactersHttp.set('#'); + unsafeCharactersHttp.set('%'); + unsafeCharactersHttp.set('{'); + unsafeCharactersHttp.set('}'); + unsafeCharactersHttp.set('|'); + unsafeCharactersHttp.set('\\'); + unsafeCharactersHttp.set('^'); + unsafeCharactersHttp.set('~'); + unsafeCharactersHttp.set('`'); + } + + private UnsafeUriCharactersEncoder() { + // util class + } + + public static String encode(String s) { + return encode(s, unsafeCharactersRfc1738); + } + + public static String encodeHttpURI(String s) { + return encode(s, unsafeCharactersHttp); + } + + public static String encode(String s, BitSet unsafeCharacters) { + return encode(s, unsafeCharacters, false); + } + + public static String encode(String s, boolean checkRaw) { + return encode(s, unsafeCharactersRfc1738, checkRaw); + } + + public static String encodeHttpURI(String s, boolean checkRaw) { + return encode(s, unsafeCharactersHttp, checkRaw); + } + + private static List<Pair> checkRAW(String s) { + Pattern pattern = Pattern.compile("RAW\\([^\\)]+\\)"); + Matcher matcher = pattern.matcher(s); + List<Pair> answer = new ArrayList<Pair>(); + // Check all occurrences + while (matcher.find()) { + answer.add(new Pair(matcher.start(), matcher.end())); + } + return answer; + } + + private static boolean isRaw(int index, List<Pair> pairs) { + for (Pair pair : pairs) { + if (index < pair.left) { + return false; + } else { + if (index >= pair.left) { + if (index <= pair.right) { + return true; + } else { + continue; + } + } + } + } + return false; + } + + private static class Pair { + int left; + int right; + + public Pair(int left, int right) { + this.left = left; + this.right = right; + } + } + + // Just skip the encode for isRAW part + public static String encode(String s, BitSet unsafeCharacters, boolean checkRaw) { + List<Pair> rawPairs; + if (checkRaw) { + rawPairs = checkRAW(s); + } else { + rawPairs = new ArrayList<Pair>(); + } + + int n = s == null ? 0 : s.length(); + if (n == 0) { + return s; + } + + // First check whether we actually need to encode + char chars[] = s.toCharArray(); + for (int i = 0; ; ) { + // just deal with the ascii character + if (chars[i] > 0 && chars[i] < 128) { + if (unsafeCharacters.get(chars[i])) { + break; + } + } + if (++i >= chars.length) { + return s; + } + } + + // 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 (int i = 0; i < chars.length; i++) { + char ch = chars[i]; + if (ch > 0 && ch < 128 && unsafeCharacters.get(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) && !isRaw(i, rawPairs)) { + // 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) { + sb.append('%'); + sb.append(HEX_DIGITS[(b >> 4) & 0x0f]); + 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; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/ed574cbd/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java b/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java index 4bc8fee..eb7e8bf 100644 --- a/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java +++ b/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java @@ -228,6 +228,17 @@ public class CamelCatalogTest { } @Test + public void testEndpointPropertiesPlaceholders() throws Exception { + Map<String, String> map = catalog.endpointProperties("timer:foo?period={{howoften}}&repeatCount=5"); + assertNotNull(map); + assertEquals(3, map.size()); + + assertEquals("foo", map.get("timerName")); + assertEquals("{{howoften}}", map.get("period")); + assertEquals("5", map.get("repeatCount")); + } + + @Test public void testEndpointPropertiesNetty4http() throws Exception { Map<String, String> map = catalog.endpointProperties("netty4-http:http:localhost:8080/foo/bar?disconnect=true&keepAlive=false"); assertNotNull(map);