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 2021/03/26 10:55:23 UTC
[camel] branch master updated: CAMEL-15410: camel-core - URI
encoding for query parameters should use %20 for space instead of plus
sign.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push:
new f2fc19f CAMEL-15410: camel-core - URI encoding for query parameters should use %20 for space instead of plus sign.
f2fc19f is described below
commit f2fc19f1c8fc249ed2757e187deb9fe10c2ad8b9
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 26 11:30:01 2021 +0100
CAMEL-15410: camel-core - URI encoding for query parameters should use %20 for space instead of plus sign.
---
.../apache/camel/component/cron/CronComponent.java | 12 ++++++--
.../camel/component/exec/ExecEndpointTest.java | 6 ++--
.../apache/camel/component/http/HttpQueryTest.java | 2 +-
.../http/HttpSendDynamicAwareRawTest.java | 2 +-
.../camel/component/irc/IrcConfigurationTest.java | 4 +--
.../jetty/JettyHttpBridgeEncodedPathTest.java | 5 ++--
.../JettyHttpGetWithParamAsExchangeHeaderTest.java | 8 +++---
.../component/kamelet/KameletPropertiesTest.java | 5 +++-
.../component/master/EndpointUriEncodingTest.java | 2 +-
.../netty/http/NettyHttpBridgeEncodedPathTest.java | 3 +-
.../netty/http/NettyHttpCompressTest.java | 4 +--
.../NettyHttpGetWithParamAsExchangeHeaderTest.java | 12 ++++----
.../QuartzScheduledPollConsumerScheduler.java | 2 ++
.../SpringScheduledPollConsumerScheduler.java | 2 ++
.../producer/RestSwaggerGetUriParamTest.java | 2 +-
.../org/apache/camel/catalog/impl/URISupport.java | 14 +++++++--
.../catalog/CustomEndpointUriFactoryTest.java | 25 ++++++++++++++--
.../camel/component/file/FileURLDecodingTest.java | 4 +--
.../issues/EndpointWithRawUriParameterTest.java | 9 +++---
.../camel/util/UnsafeCharactersEncoderTest.java | 11 ++++++++
.../java/org/apache/camel/util/URIScanner.java | 3 ++
.../java/org/apache/camel/util/URISupport.java | 12 ++++++--
.../java/org/apache/camel/util/URISupportTest.java | 33 +++++++++++++++-------
.../ROOT/pages/camel-3x-upgrade-guide-3_10.adoc | 19 +++++++++++++
24 files changed, 152 insertions(+), 49 deletions(-)
diff --git a/components/camel-cron/src/main/java/org/apache/camel/component/cron/CronComponent.java b/components/camel-cron/src/main/java/org/apache/camel/component/cron/CronComponent.java
index ef0160f..8d66b97 100644
--- a/components/camel-cron/src/main/java/org/apache/camel/component/cron/CronComponent.java
+++ b/components/camel-cron/src/main/java/org/apache/camel/component/cron/CronComponent.java
@@ -43,12 +43,20 @@ public class CronComponent extends DefaultComponent {
}
@Override
- public Endpoint createEndpoint(String uri, String remaining, Map<String, Object> properties) throws Exception {
+ public Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
CamelCronConfiguration configuration = new CamelCronConfiguration();
configuration.setName(remaining);
+ // special for schedule where we replace + as space
+ String schedule = getAndRemoveParameter(parameters, "schedule", String.class);
+ if (schedule != null) {
+ // replace + as space
+ schedule = schedule.replace('+', ' ');
+ }
+ configuration.setSchedule(schedule);
+
CronEndpoint answer = new CronEndpoint(uri, this, configuration);
- setProperties(answer, properties);
+ setProperties(answer, parameters);
// validate configuration
validate(configuration);
diff --git a/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java b/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java
index f08bd1d..a34e801 100644
--- a/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java
+++ b/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java
@@ -108,9 +108,11 @@ public class ExecEndpointTest {
@DirtiesContext
public void testCreateEndpointWithArgs() throws Exception {
String args = "arg1 arg2 arg3";
- // Need to properly encode the URI
- ExecEndpoint e = createExecEndpoint("exec:test?args=" + args.replaceAll(" ", "+"));
+ // can use space or %20
+ ExecEndpoint e = createExecEndpoint("exec:test?args=" + args.replaceAll(" ", "%20"));
assertEquals(args, e.getArgs());
+ ExecEndpoint e2 = createExecEndpoint("exec:test?args=" + args);
+ assertEquals(args, e2.getArgs());
}
@Test
diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryTest.java
index f466870..4bad857 100644
--- a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryTest.java
+++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryTest.java
@@ -41,7 +41,7 @@ public class HttpQueryTest extends BaseHttpTest {
.setConnectionReuseStrategy(getConnectionReuseStrategy()).setResponseFactory(getHttpResponseFactory())
.setExpectationVerifier(getHttpExpectationVerifier()).setSslContext(getSSLContext())
.registerHandler("/", new BasicValidationHandler(GET.name(), "hl=en&q=camel", null, getExpectedContent()))
- .registerHandler("/test/", new BasicValidationHandler(GET.name(), "my=@+camel", null, getExpectedContent()))
+ .registerHandler("/test/", new BasicValidationHandler(GET.name(), "my=@ camel", null, getExpectedContent()))
.registerHandler("/user/pass",
new BasicValidationHandler(GET.name(), "password=baa&username=foo", null, getExpectedContent()))
.create();
diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareRawTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareRawTest.java
index 34a544e..c4ed69f 100644
--- a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareRawTest.java
+++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareRawTest.java
@@ -69,7 +69,7 @@ public class HttpSendDynamicAwareRawTest extends BaseHttpTest {
public void configure() throws Exception {
from("direct:moes")
.toD("http://localhost:" + localServer.getLocalPort()
- + "/moes?throwExceptionOnFailure=false&drink=${header.drink}&password=se+%ret");
+ + "/moes?throwExceptionOnFailure=false&drink=${header.drink}&password=RAW(se+%ret)");
from("direct:joes")
.toD("http://localhost:" + localServer.getLocalPort()
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConfigurationTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConfigurationTest.java
index 168f5ca..d8955b2 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConfigurationTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConfigurationTest.java
@@ -81,7 +81,7 @@ public class IrcConfigurationTest extends CamelTestSupport {
// irc:nick@host[:port]/#room[?options]
IrcEndpoint endpoint = (IrcEndpoint) component.createEndpoint(
- "irc://badnick@irc.freenode.net?keys=foo,&channels=#camel,#smx&realname=Camel+Bot&nickname=camelbot");
+ "irc://badnick@irc.freenode.net?keys=foo,&channels=#camel,#smx&realname=Camel Bot&nickname=camelbot");
IrcConfiguration conf = endpoint.getConfiguration();
assertEquals("camelbot", conf.getNickname());
@@ -99,7 +99,7 @@ public class IrcConfigurationTest extends CamelTestSupport {
// irc:nick@host[:port]/#room[?options]
IrcEndpoint endpoint = (IrcEndpoint) component.createEndpoint(
- "irc://badnick@irc.freenode.net?keys=foo,bar&channels=#camel,#smx&realname=Camel+Bot&nickname=camelbot");
+ "irc://badnick@irc.freenode.net?keys=foo,bar&channels=#camel,#smx&realname=Camel%20Bot&nickname=camelbot");
IrcConfiguration conf = endpoint.getConfiguration();
assertEquals("camelbot", conf.getNickname());
diff --git a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBridgeEncodedPathTest.java b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBridgeEncodedPathTest.java
index 4ef4cba..2c638ed 100644
--- a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBridgeEncodedPathTest.java
+++ b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBridgeEncodedPathTest.java
@@ -30,7 +30,7 @@ public class JettyHttpBridgeEncodedPathTest extends BaseJettyTest {
public void testJettyHttpClient() throws Exception {
String response = template.requestBody("http://localhost:" + port2 + "/jettyTestRouteA?param1=%2B447777111222", null,
String.class);
- assertEquals("param1=+447777111222", response, "Get a wrong response");
+ assertEquals("param1=%2B447777111222", response, "Get a wrong response");
}
@Override
@@ -44,7 +44,8 @@ public class JettyHttpBridgeEncodedPathTest extends BaseJettyTest {
// %2B becomes decoded to a space
Object s = exchange.getIn().getHeader("param1");
// can be either + or %2B
- assertTrue(s.equals(" 447777111222") || s.equals("+447777111222") || s.equals("%2B447777111222"));
+ assertTrue(s.equals(" 447777111222") || s.equals("%20447777111222") || s.equals("+447777111222")
+ || s.equals("%2B447777111222"));
// send back the query
exchange.getMessage().setBody(exchange.getIn().getHeader(Exchange.HTTP_QUERY));
diff --git a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpGetWithParamAsExchangeHeaderTest.java b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpGetWithParamAsExchangeHeaderTest.java
index 5a4f8c7..98e2ca3 100644
--- a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpGetWithParamAsExchangeHeaderTest.java
+++ b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpGetWithParamAsExchangeHeaderTest.java
@@ -68,27 +68,27 @@ public class JettyHttpGetWithParamAsExchangeHeaderTest extends BaseJettyTest {
}
@Test
- public void testHttpGetWithSpaceInParams() throws Exception {
+ public void testHttpGetWithSpaceEncodedInParams() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:result");
mock.expectedMessageCount(1);
mock.expectedHeaderReceived("message", " World");
mock.expectedHeaderReceived(Exchange.HTTP_METHOD, "GET");
// parameter starts with a space using %2B as decimal encoded
- template.requestBody(serverUri + "?message=%2BWorld", null, Object.class);
+ template.requestBody(serverUri + "?message=%20World", null, Object.class);
assertMockEndpointsSatisfied();
}
@Test
- public void testHttpGetWithSpaceAsPlusInParams() throws Exception {
+ public void testHttpGetWithSpaceInParams() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:result");
mock.expectedMessageCount(1);
mock.expectedHeaderReceived("message", " World");
mock.expectedHeaderReceived(Exchange.HTTP_METHOD, "GET");
// parameter starts with a space using + decoded
- template.requestBody(serverUri + "?message=+World", null, Object.class);
+ template.requestBody(serverUri + "?message= World", null, Object.class);
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
index 94e5f09..3e1ec6b 100644
--- a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
@@ -111,9 +111,12 @@ public class KameletPropertiesTest extends CamelTestSupport {
@Test
public void urlEncodingIsRespected() {
- assertThat(context.getEndpoint("kamelet:timer-source?message=Hello+Kamelets&period=1000", KameletEndpoint.class)
+ assertThat(context.getEndpoint("kamelet:timer-source?message=Hello Kamelets&period=1000", KameletEndpoint.class)
.getKameletProperties())
.containsEntry("message", "Hello Kamelets");
+ assertThat(context.getEndpoint("kamelet:timer-source?message=Hi%20Kamelets&period=1000", KameletEndpoint.class)
+ .getKameletProperties())
+ .containsEntry("message", "Hi Kamelets");
assertThat(context
.getEndpoint("kamelet:timer-source?message=messaging.knative.dev%2Fv1beta1&period=1000", KameletEndpoint.class)
.getKameletProperties())
diff --git a/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java b/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
index 9ec78a6..66b5372 100644
--- a/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
+++ b/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
@@ -49,7 +49,7 @@ public class EndpointUriEncodingTest extends CamelTestSupport {
return new RouteBuilder() {
public void configure() {
context.addComponent("dummy", new DummyComponent());
- from("master:test:dummy://path?foo=hello}+world&bar=RAW(hello}+world)")
+ from("master:test:dummy://path?foo=hello} world&bar=RAW(hello}+world)")
.to("mock:result");
}
};
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 e26bb7f..7f825b3 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
@@ -80,7 +80,8 @@ public class NettyHttpBridgeEncodedPathTest extends BaseNettyTest {
// %2B becomes decoded to a space
Object s = exchange.getIn().getHeader("param1");
// can be either + or %2B
- assertTrue(s.equals(" 447777111222") || s.equals("+447777111222") || s.equals("%2B447777111222"));
+ assertTrue(s.equals(" 447777111222") || s.equals("%20447777111222") || s.equals("+447777111222")
+ || s.equals("%2B447777111222"));
// send back the query
exchange.getMessage().setBody(exchange.getIn().getHeader(Exchange.HTTP_QUERY));
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpCompressTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpCompressTest.java
index fa70fa5..3f64007 100644
--- a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpCompressTest.java
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpCompressTest.java
@@ -27,9 +27,11 @@ import io.netty.handler.codec.http.HttpContentDecompressor;
import org.apache.camel.BindToRegistry;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Isolated;
import static org.junit.jupiter.api.Assertions.assertEquals;
+@Isolated
public class NettyHttpCompressTest extends BaseNettyTest {
// setup the decompress decoder here
@@ -42,7 +44,6 @@ public class NettyHttpCompressTest extends BaseNettyTest {
@Test
public void testContentType() throws Exception {
-
byte[] data = "Hello World".getBytes(Charset.forName("UTF-8"));
Map<String, Object> headers = new HashMap<>();
headers.put("content-type", "text/plain; charset=\"UTF-8\"");
@@ -51,7 +52,6 @@ public class NettyHttpCompressTest extends BaseNettyTest {
headers, String.class);
// The decoded out has some space to clean up.
assertEquals("Bye World", out.trim());
-
}
@Override
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpGetWithParamAsExchangeHeaderTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpGetWithParamAsExchangeHeaderTest.java
index 16b4ac9..ce1b063 100644
--- a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpGetWithParamAsExchangeHeaderTest.java
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpGetWithParamAsExchangeHeaderTest.java
@@ -65,27 +65,27 @@ public class NettyHttpGetWithParamAsExchangeHeaderTest extends BaseNettyTest {
}
@Test
- public void testHttpGetWithSpaceInParams() throws Exception {
+ public void testHttpGetWithSpaceEncodedInParams() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:result");
mock.expectedMessageCount(1);
mock.expectedHeaderReceived("message", " World");
mock.expectedHeaderReceived(Exchange.HTTP_METHOD, "GET");
- // parameter starts with a space using %2B as decimal encoded
- template.requestBody(serverUri + "&message=%2BWorld", null, Object.class);
+ // parameter starts with a space using %20 as decimal encoded
+ template.requestBody(serverUri + "&message=%20World", null, Object.class);
assertMockEndpointsSatisfied();
}
@Test
- public void testHttpGetWithSpaceAsPlusInParams() throws Exception {
+ public void testHttpGetWithSpaceInParams() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:result");
mock.expectedMessageCount(1);
mock.expectedHeaderReceived("message", " World");
mock.expectedHeaderReceived(Exchange.HTTP_METHOD, "GET");
- // parameter starts with a space using + decoded
- template.requestBody(serverUri + "&message=+World", null, Object.class);
+ // parameter starts with a space
+ template.requestBody(serverUri + "&message= World", null, Object.class);
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java b/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
index 5ad07bc..7276a93 100644
--- a/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
+++ b/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
@@ -168,6 +168,8 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
@Override
protected void doStart() throws Exception {
StringHelper.notEmpty(cron, "cron", this);
+ // special for cron where we replace + as space
+ cron = cron.replace('+', ' ');
if (quartzScheduler == null) {
// get the scheduler form the quartz component
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/pollingconsumer/SpringScheduledPollConsumerScheduler.java b/components/camel-spring/src/main/java/org/apache/camel/spring/pollingconsumer/SpringScheduledPollConsumerScheduler.java
index 454273b..a20239f 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/pollingconsumer/SpringScheduledPollConsumerScheduler.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/pollingconsumer/SpringScheduledPollConsumerScheduler.java
@@ -114,6 +114,8 @@ public class SpringScheduledPollConsumerScheduler extends ServiceSupport
@Override
protected void doStart() throws Exception {
StringHelper.notEmpty(cron, "cron", this);
+ // special for cron where we replace + as space
+ cron = cron.replace('+', ' ');
trigger = new CronTrigger(getCron(), getTimeZone());
diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/producer/RestSwaggerGetUriParamTest.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/producer/RestSwaggerGetUriParamTest.java
index beed34c..1855e47 100644
--- a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/producer/RestSwaggerGetUriParamTest.java
+++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/producer/RestSwaggerGetUriParamTest.java
@@ -29,7 +29,7 @@ public class RestSwaggerGetUriParamTest extends CamelTestSupport {
@Test
public void testSwaggerGet() throws Exception {
- getMockEndpoint("mock:result").expectedBodiesReceived("Bye Donald+Duck");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye Donald%20Duck");
template.sendBodyAndHeader("direct:start", null, "name", "Donald Duck");
diff --git a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/URISupport.java b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/URISupport.java
index 83599a1..dbc22ba 100644
--- a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/URISupport.java
+++ b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/URISupport.java
@@ -28,6 +28,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
+import org.apache.camel.util.StringHelper;
+
/**
* Copied from org.apache.camel.util.URISupport
*/
@@ -425,7 +427,11 @@ public final class URISupport {
private static void appendQueryStringParameter(String key, String value, StringBuilder rc, boolean encode)
throws UnsupportedEncodingException {
if (encode) {
- rc.append(URLEncoder.encode(key, CHARSET));
+ // the URLEncoder is for HTML forms, so it encodes spaces as + sign
+ // but we want this to be decimal encoded for URI query parameter
+ String encoded = URLEncoder.encode(key, CHARSET);
+ encoded = StringHelper.replaceAll(encoded, "+", "%20");
+ rc.append(encoded);
} else {
rc.append(key);
}
@@ -440,7 +446,11 @@ public final class URISupport {
});
if (!isRaw) {
if (encode) {
- rc.append(URLEncoder.encode(value, CHARSET));
+ // the URLEncoder is for HTML forms, so it encodes spaces as + sign
+ // but we want this to be decimal encoded for URI query parameter
+ String encoded = URLEncoder.encode(value, CHARSET);
+ encoded = StringHelper.replaceAll(encoded, "+", "%20");
+ rc.append(encoded);
} else {
rc.append(value);
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
index 97bb0c7..2d634ae 100644
--- a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
@@ -225,10 +225,10 @@ public class CustomEndpointUriFactoryTest extends ContextTestSupport {
params.put("cql", "insert into test_data(id, text) values (now(), ?)");
Assertions.assertEquals(
- "cql:localhost/test?cql=insert+into+test_data%28id%2C+text%29+values+%28now%28%29%2C+%3F%29",
+ "cql:localhost/test?cql=insert%20into%20test_data%28id%2C%20text%29%20values%20%28now%28%29%2C%20%3F%29",
assembler.buildUri("cql", new LinkedHashMap<>(params)));
Assertions.assertEquals(
- "cql:localhost/test?cql=insert+into+test_data%28id%2C+text%29+values+%28now%28%29%2C+%3F%29",
+ "cql:localhost/test?cql=insert%20into%20test_data%28id%2C%20text%29%20values%20%28now%28%29%2C%20%3F%29",
assembler.buildUri("cql", new LinkedHashMap<>(params), true));
Assertions.assertEquals(
"cql:localhost/test?cql=insert into test_data(id, text) values (now(), ?)",
@@ -236,6 +236,27 @@ public class CustomEndpointUriFactoryTest extends ContextTestSupport {
}
@Test
+ public void testCQLWithPlus() throws Exception {
+ EndpointUriFactory assembler = new MyCQLAssembler();
+ assembler.setCamelContext(context);
+
+ Map<String, Object> params = new LinkedHashMap<>();
+ params.put("host", "localhost");
+ params.put("keyspace", "test");
+ params.put("cql", "add(4 + 5)");
+
+ Assertions.assertEquals(
+ "cql:localhost/test?cql=add%284%20%2B%205%29",
+ assembler.buildUri("cql", new LinkedHashMap<>(params)));
+ Assertions.assertEquals(
+ "cql:localhost/test?cql=add%284%20%2B%205%29",
+ assembler.buildUri("cql", new LinkedHashMap<>(params), true));
+ Assertions.assertEquals(
+ "cql:localhost/test?cql=add(4 + 5)",
+ assembler.buildUri("cql", new LinkedHashMap<>(params), false));
+ }
+
+ @Test
public void testJmsSecrets() throws Exception {
EndpointUriFactory assembler = new MyJmsxAssembler();
assembler.setCamelContext(context);
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/file/FileURLDecodingTest.java b/core/camel-core/src/test/java/org/apache/camel/component/file/FileURLDecodingTest.java
index 3fe23c8..906bd3e 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/file/FileURLDecodingTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/file/FileURLDecodingTest.java
@@ -44,7 +44,7 @@ public class FileURLDecodingTest extends ContextTestSupport {
@Test
public void testFilePlus() throws Exception {
- assertTargetFile("data+.txt", "data .txt");
+ assertTargetFile("data .txt", "data .txt");
}
@Test
@@ -54,7 +54,7 @@ public class FileURLDecodingTest extends ContextTestSupport {
@Test
public void testFile2B() throws Exception {
- assertTargetFile("data%2B.txt", "data .txt");
+ assertTargetFile("data .txt", "data .txt");
}
@Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/issues/EndpointWithRawUriParameterTest.java b/core/camel-core/src/test/java/org/apache/camel/issues/EndpointWithRawUriParameterTest.java
index ac13fb5..e047546 100644
--- a/core/camel-core/src/test/java/org/apache/camel/issues/EndpointWithRawUriParameterTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/issues/EndpointWithRawUriParameterTest.java
@@ -145,15 +145,14 @@ public class EndpointWithRawUriParameterTest extends ContextTestSupport {
}
@Test
- public void testRawUriParameterFail() throws Exception {
+ public void testRawUriParameterPlusSign() throws Exception {
getMockEndpoint("mock:result").expectedMessageCount(1);
getMockEndpoint("mock:result").expectedHeaderReceived("username", "scott");
getMockEndpoint("mock:result").expectedHeaderReceived("password", "foo)+bar");
- template.sendBody("direct:fail", "Hello World");
+ template.sendBody("direct:plus", "Hello World");
- // should fail as the password has + sign which gets escaped
- getMockEndpoint("mock:result").assertIsNotSatisfied();
+ getMockEndpoint("mock:result").assertIsSatisfied();
}
@Test
@@ -191,7 +190,7 @@ public class EndpointWithRawUriParameterTest extends ContextTestSupport {
from("direct:rawlines").to("mycomponent:foo?lines=RAW(++abc++)&lines=RAW(++def++)").to("mock:result");
- from("direct:fail").to("mycomponent:foo?password=foo)+bar&username=scott").to("mock:result");
+ from("direct:plus").to("mycomponent:foo?password=foo)+bar&username=scott").to("mock:result");
from("direct:ok").to("mycomponent:foo?password=RAW(foo)+bar)&username=scott").to("mock:result");
diff --git a/core/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java b/core/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java
index d229a7f..cc87e6f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/util/UnsafeCharactersEncoderTest.java
@@ -89,6 +89,17 @@ public class UnsafeCharactersEncoderTest {
}
@Test
+ public void testPlusInQuery() {
+ String beforeEncoding = "http://www.example.com?param1=%2B447777111222";
+ String afterEncoding = "http://www.example.com?param1=%2B447777111222";
+ testEncoding(beforeEncoding, afterEncoding);
+
+ beforeEncoding = "http://www.example.com?param1=+447777111222";
+ afterEncoding = "http://www.example.com?param1=+447777111222";
+ testEncoding(beforeEncoding, afterEncoding);
+ }
+
+ @Test
public void testPasswordEncodingInRawMode() {
String password = "RAW(%j#7%c6i)";
String result = UnsafeUriCharactersEncoder.encode(password, true);
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/URIScanner.java b/core/camel-util/src/main/java/org/apache/camel/util/URIScanner.java
index e2ca9df..50508b3 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/URIScanner.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/URIScanner.java
@@ -171,7 +171,10 @@ class URIScanner {
if (isRaw) {
text = value.toString();
} else {
+ // need to replace % with %25 to avoid losing "%" when decoding
String s = StringHelper.replaceAll(value.toString(), "%", "%25");
+ // the URLDecoder is for HTML forms, so it decodes + as spaces
+ s = StringHelper.replaceAll(s, "+", "%2B");
text = URLDecoder.decode(s, CHARSET);
}
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
index 3839a86..335fedc 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
@@ -491,7 +491,11 @@ public final class URISupport {
private static void appendQueryStringParameter(String key, String value, StringBuilder rc, boolean encode)
throws UnsupportedEncodingException {
if (encode) {
- rc.append(URLEncoder.encode(key, CHARSET));
+ // the URLEncoder is for HTML forms, so it encodes spaces as + sign
+ // but we want this to be decimal encoded for URI query parameter
+ String encoded = URLEncoder.encode(key, CHARSET);
+ encoded = StringHelper.replaceAll(encoded, "+", "%20");
+ rc.append(encoded);
} else {
rc.append(key);
}
@@ -508,7 +512,11 @@ public final class URISupport {
rc.append(s);
} else {
if (encode) {
- rc.append(URLEncoder.encode(value, CHARSET));
+ // the URLEncoder is for HTML forms, so it encodes spaces as + sign
+ // but we want this to be decimal encoded for URI query parameter
+ String encoded = URLEncoder.encode(value, CHARSET);
+ encoded = StringHelper.replaceAll(encoded, "+", "%20");
+ rc.append(encoded);
} else {
rc.append(value);
}
diff --git a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
index 2fd7e46..cb7bbc2 100644
--- a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
+++ b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
@@ -134,12 +134,12 @@ public class URISupportTest {
@Test
public void testNormalizeHttpEndpointURLEncodedParameter() throws Exception {
String out = URISupport.normalizeUri("http://www.google.com?q=S%C3%B8ren%20Hansen");
- assertEquals("http://www.google.com?q=S%C3%B8ren+Hansen", out);
+ assertEquals("http://www.google.com?q=S%C3%B8ren%20Hansen", out);
}
@Test
public void testParseParametersURLEncodedValue() throws Exception {
- String out = URISupport.normalizeUri("http://www.google.com?q=S%C3%B8ren+Hansen");
+ String out = URISupport.normalizeUri("http://www.google.com?q=S%C3%B8ren%20Hansen");
URI uri = new URI(out);
Map<String, Object> parameters = URISupport.parseParameters(uri);
@@ -200,12 +200,12 @@ public class URISupportTest {
@Test
public void testParseParameters() throws Exception {
- URI u = new URI("quartz:myGroup/myTimerName?cron=0+0+*+*+*+?");
+ URI u = new URI("quartz:myGroup/myTimerName?cron=0%200%20*%20*%20*%20?");
Map<String, Object> params = URISupport.parseParameters(u);
assertEquals(1, params.size());
assertEquals("0 0 * * * ?", params.get("cron"));
- u = new URI("quartz:myGroup/myTimerName?cron=0+0+*+*+*+?&bar=123");
+ u = new URI("quartz:myGroup/myTimerName?cron=0%200%20*%20*%20*%20?&bar=123");
params = URISupport.parseParameters(u);
assertEquals(2, params.size());
assertEquals("0 0 * * * ?", params.get("cron"));
@@ -226,8 +226,8 @@ public class URISupportTest {
// create new uri with the parameters
URI out = URISupport.createRemainingURI(new URI(uri), map);
assertNotNull(out);
- assertEquals("http://localhost:23271/myapp/mytest?foo=abc+def&bar=123%2C456&name=S%C3%B8ren", out.toString());
- assertEquals("http://localhost:23271/myapp/mytest?foo=abc+def&bar=123%2C456&name=S%C3%B8ren", out.toASCIIString());
+ assertEquals("http://localhost:23271/myapp/mytest?foo=abc%20def&bar=123%2C456&name=S%C3%B8ren", out.toString());
+ assertEquals("http://localhost:23271/myapp/mytest?foo=abc%20def&bar=123%2C456&name=S%C3%B8ren", out.toASCIIString());
}
@Test
@@ -348,12 +348,12 @@ public class URISupportTest {
public void testRawParameter() throws Exception {
String out = URISupport.normalizeUri(
"xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(++?w0rd)&serviceName=some chat");
- assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(++?w0rd)&serviceName=some+chat", out);
+ assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(++?w0rd)&serviceName=some%20chat", out);
String out2 = URISupport.normalizeUri(
"xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(foo %% bar)&serviceName=some chat");
// Just make sure the RAW parameter can be resolved rightly, we need to replace the % into %25
- assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(foo %25%25 bar)&serviceName=some+chat",
+ assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW(foo %25%25 bar)&serviceName=some%20chat",
out2);
}
@@ -361,12 +361,12 @@ public class URISupportTest {
public void testRawParameterCurly() throws Exception {
String out = URISupport.normalizeUri(
"xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{++?w0rd}&serviceName=some chat");
- assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{++?w0rd}&serviceName=some+chat", out);
+ assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{++?w0rd}&serviceName=some%20chat", out);
String out2 = URISupport.normalizeUri(
"xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{foo %% bar}&serviceName=some chat");
// Just make sure the RAW parameter can be resolved rightly, we need to replace the % into %25
- assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{foo %25%25 bar}&serviceName=some+chat",
+ assertEquals("xmpp://camel-user@localhost:123/test-user@localhost?password=RAW{foo %25%25 bar}&serviceName=some%20chat",
out2);
}
@@ -577,4 +577,17 @@ public class URISupportTest {
assertEquals("recursive=true&delete=true", URISupport.extractQuery("file:foo?recursive=true&delete=true"));
}
+ @Test
+ public void testPlusInQuery() throws Exception {
+ Map<String, Object> map = new HashMap<>();
+ map.put("param1", "+447777111222");
+ String q = URISupport.createQueryString(map);
+ assertEquals("param1=%2B447777111222", q);
+
+ // will be double encoded however
+ map.put("param1", "%2B447777111222");
+ q = URISupport.createQueryString(map);
+ assertEquals("param1=%252B447777111222", q);
+ }
+
}
diff --git a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc
index cd88179..7ac110c 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc
@@ -10,6 +10,25 @@ from both 3.0 to 3.1 and 3.1 to 3.2.
The method `concurrentTasks` on `org.apache.camel.support.DefaultScheduledPollConsumerScheduler ` has been renamed to `concurrentConsumers`.
+=== Endpoint URIs with spaces
+
+The URI encoder/decode in camel-core has been improved to avoid in some use-cases to use `+` (plus sign)
+as a space in query parameters. Now spaces are encoded to decimal `%20`.
+
+The decoder will now also decode a `+` (plus sign) as plus.
+
+For example before you may call a REST endpoint with a query parameter with the value `Hello World`
+
+ to("rest:get:foo/?msg=Hello+World")
+
+Which should now be either
+
+ to("rest:get:foo/?msg=Hello World")
+
+or use decimal encoded space
+
+ to("rest:get:foo/?msg=Hello%20World")
+
=== camel-scheduler
The option `concurrentTasks` has been renamed to `poolSize` to better reflect its purpose.