You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/03/04 10:42:32 UTC

[2/4] camel git commit: CAMEL-9658 - Path gets decoded when bridging HTTP endpoints

CAMEL-9658 - Path gets decoded when bridging HTTP endpoints


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/0859e250
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/0859e250
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/0859e250

Branch: refs/heads/master
Commit: 0859e2506799e7eeee087ff554d8433ae23ffb5d
Parents: 09fbc0b
Author: Tadayoshi Sato <sa...@gmail.com>
Authored: Tue Mar 1 22:04:59 2016 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Mar 4 10:15:23 2016 +0100

----------------------------------------------------------------------
 .../camel/http/common/DefaultHttpBinding.java   | 14 ++++++--
 .../jetty/CamelContinuationServlet.java         | 22 +++++++-----
 .../jetty/HttpBridgeEncodedPathTest.java        | 37 +++++++++++++++++---
 .../netty/http/DefaultNettyHttpBinding.java     |  2 +-
 .../http/NettyHttpBridgeEncodedPathTest.java    | 36 +++++++++++++++++--
 .../netty4/http/DefaultNettyHttpBinding.java    |  2 +-
 .../http/NettyHttpBridgeEncodedPathTest.java    | 36 +++++++++++++++++--
 7 files changed, 128 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
index 04f5851..ad9adfe 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
@@ -137,11 +137,12 @@ public class DefaultHttpBinding implements HttpBinding {
         }
 
         // store the method and query and other info in headers as String types
+        String rawPath = getRawPath(request);
         headers.put(Exchange.HTTP_METHOD, request.getMethod());
         headers.put(Exchange.HTTP_QUERY, request.getQueryString());
         headers.put(Exchange.HTTP_URL, request.getRequestURL().toString());
         headers.put(Exchange.HTTP_URI, request.getRequestURI());
-        headers.put(Exchange.HTTP_PATH, request.getPathInfo());
+        headers.put(Exchange.HTTP_PATH, rawPath);
         headers.put(Exchange.CONTENT_TYPE, request.getContentType());
 
         if (LOG.isTraceEnabled()) {
@@ -149,7 +150,7 @@ public class DefaultHttpBinding implements HttpBinding {
             LOG.trace("HTTP query {}", request.getQueryString());
             LOG.trace("HTTP url {}", request.getRequestURL());
             LOG.trace("HTTP uri {}", request.getRequestURI());
-            LOG.trace("HTTP path {}", request.getPathInfo());
+            LOG.trace("HTTP path {}", rawPath);
             LOG.trace("HTTP content-type {}", request.getContentType());
         }
 
@@ -224,7 +225,14 @@ public class DefaultHttpBinding implements HttpBinding {
             }
         }
     }
-    
+
+    private String getRawPath(HttpServletRequest request) {
+        String uri = request.getRequestURI();
+        String contextPath = request.getContextPath();
+        String servletPath = request.getServletPath();
+        return uri.substring(contextPath.length() + servletPath.length());
+    }
+
     protected void populateAttachments(HttpServletRequest request, HttpMessage message) {
         // check if there is multipart files, if so will put it into DataHandler
         Enumeration<?> names = request.getAttributeNames();

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
index a6a2e9c..9e77b29 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
@@ -35,6 +35,7 @@ import org.apache.camel.http.common.HttpHelper;
 import org.apache.camel.http.common.HttpMessage;
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.eclipse.jetty.continuation.Continuation;
 import org.eclipse.jetty.continuation.ContinuationSupport;
 
@@ -161,14 +162,8 @@ public class CamelContinuationServlet extends CamelServlet {
             // set context path as header
             String contextPath = consumer.getEndpoint().getPath();
             exchange.getIn().setHeader("CamelServletContextPath", contextPath);
-            
-            String httpPath = (String)exchange.getIn().getHeader(Exchange.HTTP_PATH);
-            // here we just remove the CamelServletContextPath part from the HTTP_PATH
-            if (contextPath != null
-                && httpPath.startsWith(contextPath)) {
-                exchange.getIn().setHeader(Exchange.HTTP_PATH,
-                        httpPath.substring(contextPath.length()));
-            }
+
+            updateHttpPath(exchange, contextPath);
 
             if (log.isTraceEnabled()) {
                 log.trace("Suspending continuation of exchangeId: {}", exchange.getExchangeId());
@@ -241,6 +236,17 @@ public class CamelContinuationServlet extends CamelServlet {
         }
     }
 
+    private void updateHttpPath(Exchange exchange, String contextPath) {
+        String httpPath = (String) exchange.getIn().getHeader(Exchange.HTTP_PATH);
+        // encode context path in case it contains unsafe chars, because HTTP_PATH isn't decoded at this moment
+        String encodedContextPath = UnsafeUriCharactersEncoder.encodeHttpURI(contextPath);
+
+        // here we just remove the CamelServletContextPath part from the HTTP_PATH
+        if (contextPath != null && httpPath.startsWith(encodedContextPath)) {
+            exchange.getIn().setHeader(Exchange.HTTP_PATH, httpPath.substring(encodedContextPath.length()));
+        }
+    }
+
     @Override
     public void destroy() {
         expiredExchanges.clear();

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeEncodedPathTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeEncodedPathTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeEncodedPathTest.java
index d1e3410..2ad8ca8 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeEncodedPathTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeEncodedPathTest.java
@@ -17,29 +17,55 @@
 package org.apache.camel.component.jetty;
 
 import java.io.ByteArrayInputStream;
+import java.net.URLEncoder;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
 import org.junit.Test;
 
 public class HttpBridgeEncodedPathTest extends BaseJettyTest {
 
     private int port1;
     private int port2;
+    private int port3;
+    private int port4;
 
     @Test
-    public void testHttpClient() throws Exception {
+    public void testEncodedQuery() throws Exception {
         String response = template.requestBodyAndHeader("http://localhost:" + port2 + "/test/hello?param1=%2B447777111222",
                 new ByteArrayInputStream("This is a test".getBytes()), "Content-Type", "text/plain", String.class);
         assertEquals("Get a wrong response", "param1=+447777111222", response);
     }
 
+    @Test
+    public void testEncodedPath() throws Exception {
+        String path = URLEncoder.encode(" :/?#[]@!$", "UTF-8") + "/" + URLEncoder.encode("&'()+,;=", "UTF-8");
+        MockEndpoint mock = getMockEndpoint("mock:encodedPath");
+        mock.message(0).header(Exchange.HTTP_URI).isEqualTo("/" + path);
+        mock.message(0).header(Exchange.HTTP_PATH).isEqualTo(path);
+        mock.message(0).header(Exchange.HTTP_QUERY).isNull();
+        mock.message(0).header(Exchange.HTTP_RAW_QUERY).isNull();
+
+        // cannot use template as it automatically decodes some chars in the path
+        HttpClient httpClient = new HttpClient();
+        GetMethod httpGet = new GetMethod("http://localhost:" + port4 + "/test/" + path);
+        int status = httpClient.executeMethod(httpGet);
+
+        assertEquals("Get a wrong response status", 200, status);
+        assertMockEndpointsSatisfied();
+    }
+
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
                 port1 = getPort();
-                port2 = getNextPort();
+                port2 = getPort2();
+                port3 = getNextPort();
+                port4 = getNextPort();
 
                 errorHandler(noErrorHandler());
 
@@ -56,8 +82,11 @@ public class HttpBridgeEncodedPathTest extends BaseJettyTest {
                 };
                 from("jetty:http://localhost:" + port2 + "/test/hello")
                     .to("http://localhost:" + port1 + "?throwExceptionOnFailure=false&bridgeEndpoint=true");
-                
-                from("jetty://http://localhost:" + port1 + "?matchOnUriPrefix=true").process(serviceProc);
+                from("jetty:http://localhost:" + port1 + "?matchOnUriPrefix=true").process(serviceProc);
+
+                from("jetty:http://localhost:" + port4 + "/test?matchOnUriPrefix=true")
+                    .to("http://localhost:" + port3 + "?throwExceptionOnFailure=false&bridgeEndpoint=true");
+                from("jetty:http://localhost:" + port3 + "?matchOnUriPrefix=true").to("mock:encodedPath");
             }
         };
     }    

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
index 05bd551..192d4c1 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
@@ -132,7 +132,7 @@ public class DefaultNettyHttpBinding implements NettyHttpBinding, Cloneable {
         headers.put(Exchange.HTTP_RAW_QUERY, uri.getRawQuery());
 
         // strip the starting endpoint path so the path is relative to the endpoint uri
-        String path = uri.getPath();
+        String path = uri.getRawPath();
         if (configuration.getPath() != null) {
             // need to match by lower case as we want to ignore case on context-path
             String matchPath = path.toLowerCase(Locale.US);

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBridgeEncodedPathTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBridgeEncodedPathTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBridgeEncodedPathTest.java
index 25a3bff..4c51795 100644
--- a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBridgeEncodedPathTest.java
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBridgeEncodedPathTest.java
@@ -16,28 +16,54 @@
  */
 package org.apache.camel.component.netty.http;
 
+import java.net.URLEncoder;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
 import org.junit.Test;
 
 public class NettyHttpBridgeEncodedPathTest extends BaseNettyTest {
 
     private int port1;
     private int port2;
+    private int port3;
+    private int port4;
 
     @Test
-    public void testHttpClient() throws Exception {
+    public void testEncodedQuery() throws Exception {
         String response = template.requestBody("http://localhost:" + port2 + "/nettyTestRouteA?param1=%2B447777111222", null, String.class);
         assertEquals("Get a wrong response", "param1=+447777111222", response);
     }
 
+    @Test
+    public void testEncodedPath() throws Exception {
+        String path = URLEncoder.encode(" :/?#[]@!$", "UTF-8") + "/" + URLEncoder.encode("&'()+,;=", "UTF-8");
+        MockEndpoint mock = getMockEndpoint("mock:encodedPath");
+        mock.message(0).header(Exchange.HTTP_PATH).isEqualTo("/" + path);
+        mock.message(0).header(Exchange.HTTP_QUERY).isNull();
+        mock.message(0).header(Exchange.HTTP_RAW_QUERY).isNull();
+
+        // cannot use template as it automatically decodes some chars in the path
+        HttpClient httpClient = new HttpClient();
+        GetMethod httpGet = new GetMethod("http://localhost:" + port4 + "/nettyTestRouteC/" + path);
+        int status = httpClient.executeMethod(httpGet);
+
+        assertEquals("Get a wrong response status", 200, status);
+        assertMockEndpointsSatisfied();
+    }
+
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
 
                 port1 = getPort();
                 port2 = getNextPort();
+                port3 = getNextPort();
+                port4 = getNextPort();
 
                 errorHandler(noErrorHandler());
 
@@ -55,10 +81,16 @@ public class NettyHttpBridgeEncodedPathTest extends BaseNettyTest {
                 from("netty-http:http://localhost:" + port2 + "/nettyTestRouteA?matchOnUriPrefix=true")
                         .log("Using NettyTestRouteA route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
                         .to("netty-http:http://localhost:" + port1 + "/nettyTestRouteB?throwExceptionOnFailure=false&bridgeEndpoint=true");
-
                 from("netty-http:http://localhost:" + port1 + "/nettyTestRouteB?matchOnUriPrefix=true")
                         .log("Using NettyTestRouteB route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
                         .process(serviceProc);
+
+                from("netty-http:http://localhost:" + port4 + "/nettyTestRouteC?matchOnUriPrefix=true")
+                        .log("Using NettyTestRouteC route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
+                        .to("netty-http:http://localhost:" + port3 + "/nettyTestRouteD?throwExceptionOnFailure=false&bridgeEndpoint=true");
+                from("netty-http:http://localhost:" + port3 + "/nettyTestRouteD?matchOnUriPrefix=true")
+                        .log("Using NettyTestRouteD route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
+                        .to("mock:encodedPath");
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
index 0a183a3..552f5de 100644
--- a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
@@ -134,7 +134,7 @@ public class DefaultNettyHttpBinding implements NettyHttpBinding, Cloneable {
         headers.put(Exchange.HTTP_RAW_QUERY, uri.getRawQuery());
 
         // strip the starting endpoint path so the path is relative to the endpoint uri
-        String path = uri.getPath();
+        String path = uri.getRawPath();
         if (configuration.getPath() != null) {
             // need to match by lower case as we want to ignore case on context-path
             String matchPath = path.toLowerCase(Locale.US);

http://git-wip-us.apache.org/repos/asf/camel/blob/0859e250/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpBridgeEncodedPathTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpBridgeEncodedPathTest.java b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpBridgeEncodedPathTest.java
index a2c9b3c..76d02ee 100644
--- a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpBridgeEncodedPathTest.java
+++ b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpBridgeEncodedPathTest.java
@@ -16,28 +16,54 @@
  */
 package org.apache.camel.component.netty4.http;
 
+import java.net.URLEncoder;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
 import org.junit.Test;
 
 public class NettyHttpBridgeEncodedPathTest extends BaseNettyTest {
 
     private int port1;
     private int port2;
+    private int port3;
+    private int port4;
 
     @Test
-    public void testHttpClient() throws Exception {
+    public void testEncodedQuery() throws Exception {
         String response = template.requestBody("http://localhost:" + port2 + "/nettyTestRouteA?param1=%2B447777111222", null, String.class);
         assertEquals("Get a wrong response", "param1=+447777111222", response);
     }
 
+    @Test
+    public void testEncodedPath() throws Exception {
+        String path = URLEncoder.encode(" :/?#[]@!$", "UTF-8") + "/" + URLEncoder.encode("&'()+,;=", "UTF-8");
+        MockEndpoint mock = getMockEndpoint("mock:encodedPath");
+        mock.message(0).header(Exchange.HTTP_PATH).isEqualTo("/" + path);
+        mock.message(0).header(Exchange.HTTP_QUERY).isNull();
+        mock.message(0).header(Exchange.HTTP_RAW_QUERY).isNull();
+
+        // cannot use template as it automatically decodes some chars in the path
+        HttpClient httpClient = new HttpClient();
+        GetMethod httpGet = new GetMethod("http://localhost:" + port4 + "/nettyTestRouteC/" + path);
+        int status = httpClient.executeMethod(httpGet);
+
+        assertEquals("Get a wrong response status", 200, status);
+        assertMockEndpointsSatisfied();
+    }
+
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
 
                 port1 = getPort();
                 port2 = getNextPort();
+                port3 = getNextPort();
+                port4 = getNextPort();
 
                 errorHandler(noErrorHandler());
 
@@ -55,10 +81,16 @@ public class NettyHttpBridgeEncodedPathTest extends BaseNettyTest {
                 from("netty4-http:http://localhost:" + port2 + "/nettyTestRouteA?matchOnUriPrefix=true")
                         .log("Using NettyTestRouteA route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
                         .to("netty4-http:http://localhost:" + port1 + "/nettyTestRouteB?throwExceptionOnFailure=false&bridgeEndpoint=true");
-
                 from("netty4-http:http://localhost:" + port1 + "/nettyTestRouteB?matchOnUriPrefix=true")
                         .log("Using NettyTestRouteB route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
                         .process(serviceProc);
+
+                from("netty4-http:http://localhost:" + port4 + "/nettyTestRouteC?matchOnUriPrefix=true")
+                        .log("Using NettyTestRouteC route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
+                        .to("netty4-http:http://localhost:" + port3 + "/nettyTestRouteD?throwExceptionOnFailure=false&bridgeEndpoint=true");
+                from("netty4-http:http://localhost:" + port3 + "/nettyTestRouteD?matchOnUriPrefix=true")
+                        .log("Using NettyTestRouteD route: CamelHttpPath=[${header.CamelHttpPath}], CamelHttpUri=[${header.CamelHttpUri}]")
+                        .to("mock:encodedPath");
             }
         };
     }