This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch backport/29731-to-camel-4-22-x in repository https://gitbox.apache.org/repos/asf/camel.git
commit ccd9fb972c436b5bba13fe3491fba79f9b9b01d7 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Nov 12 20:44:06 2026 +0100 [camel-4.22.x] CAMEL-26485: camel-netty-http - endpoint options are no longer sent to the server as query parameters The netty-http producer no longer sends its own endpoint options (such as cookieHandler, httpMethodRestrict) to the HTTP server as query parameters. NettyHttpComponent.createEndpoint built the address URI before setProperties bound and removed the endpoint options; it is now built after. Adapted: on this branch the CAMEL-26487 backport keeps the address as the endpoint URI and the full URI as the identity, so the endpoint is created with the full URI and its endpoint URI is set to the address once the options are bound (a package-private NettyHttpEndpoint.setAddressUri). The upgrade-guide note is on main. Co-Authored-By: Claude Opus 5.5 <[email protected]> (cherry picked from commit f70ca1171086) Signed-off-by: Claus Ibsen <[email protected]> --- .../component/netty/http/NettyHttpComponent.java | 15 +-- .../component/netty/http/NettyHttpEndpoint.java | 8 ++ .../NettyHttpEndpointOptionsNotInQueryTest.java | 110 +++++++++++++++++++++ 3 files changed, 126 insertions(+), 7 deletions(-) diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java index 0e284bfddded..d067e95efb05 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java @@ -175,18 +175,19 @@ public class NettyHttpComponent extends NettyComponent // validate config config.validateConfiguration(); - // create the address uri which includes the remainder parameters (which - // is not configuration parameters for this component) - URI u = new URI(UnsafeUriCharactersEncoder.encodeHttpURI(remaining)); - - String addressUri = URISupport.createRemainingURI(u, parameters).toString(); - - NettyHttpEndpoint answer = new NettyHttpEndpoint(addressUri, this, config); + // the endpoint uri is the http address to call: it is set below, once the endpoint options are bound + NettyHttpEndpoint answer = new NettyHttpEndpoint(uri, this, config); // endpoints that differ only in their options must not be equal, so the full uri is the identity answer.setIdentityUri(uri); answer.getConfiguration().setMuteException(muteException); setProperties(answer, parameters); + // create the address uri with the remainder parameters, after the endpoint options are bound + // (and removed), so only the query parameters that are not endpoint options are sent to the server + URI u = new URI(UnsafeUriCharactersEncoder.encodeHttpURI(remaining)); + String addressUri = URISupport.createRemainingURI(u, parameters).toString(); + answer.setAddressUri(addressUri); + // must use a copy of the binding on the endpoint to avoid sharing same // instance that can cause side-effects if (answer.getNettyHttpBinding() == null) { diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java index b007ac75727b..27a65b6dd59b 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java @@ -322,6 +322,14 @@ public class NettyHttpEndpoint extends NettyEndpoint implements HeaderFilterStra this.identityUri = identityUri; } + /** + * The http address to call, which is the endpoint uri: the uri without the endpoint options, which are bound when + * the endpoint is created (CAMEL-26485). + */ + void setAddressUri(String addressUri) { + setEndpointUri(addressUri); + } + private String getIdentityUri() { return identityUri != null ? identityUri : getEndpointUri(); } diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpEndpointOptionsNotInQueryTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpEndpointOptionsNotInQueryTest.java new file mode 100644 index 000000000000..048f2a8cf483 --- /dev/null +++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpEndpointOptionsNotInQueryTest.java @@ -0,0 +1,110 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.component.netty.http; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.http.base.cookie.InstanceCookieHandler; +import org.apache.camel.support.DefaultExchange; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +public class NettyHttpEndpointOptionsNotInQueryTest extends BaseNettyTestSupport { + + @BindToRegistry("myCookieHandler") + private final InstanceCookieHandler cookieHandler = new InstanceCookieHandler(); + + @Test + public void testEndpointOptionsAreNotSentAsQueryParameters() { + String uri = "netty-http:http://localhost:{{port}}/echo?bar=1&cookieHandler=#myCookieHandler" + + "&httpMethodRestrict=GET&traceEnabled=false&exchangePattern=InOut&lazyStartProducer=true" + + "&throwExceptionOnFailure=true"; + + NettyHttpEndpoint endpoint = context.getEndpoint(uri, NettyHttpEndpoint.class); + // the options are bound to the endpoint + assertSame(cookieHandler, endpoint.getCookieHandler()); + assertEquals("GET", endpoint.getHttpMethodRestrict()); + + // and only the query parameter that is not an endpoint option is in the address + assertEquals("http://localhost:" + getPort() + "/echo?bar=1", + NettyHttpHelper.createURL(new DefaultExchange(context), endpoint)); + + String query = template.requestBody(uri, null, String.class); + assertEquals("bar=1", query); + } + + @Test + public void testOnlyEndpointOptions() { + String query = template.requestBody( + "netty-http:http://localhost:{{port}}/echo?cookieHandler=#myCookieHandler&httpMethodRestrict=GET", null, + String.class); + // no query parameters at all + assertEquals("none", query); + } + + @Test + public void testConsumersDifferingOnlyInHttpMethodRestrict() { + List<NettyHttpEndpoint> endpoints = context.getEndpoints().stream() + .filter(NettyHttpEndpoint.class::isInstance) + .map(NettyHttpEndpoint.class::cast) + .filter(e -> e.getConfiguration().getPath().equals("/orders")) + .toList(); + // the rest consumers for GET and POST on the same path differ only in httpMethodRestrict + assertEquals(2, endpoints.size()); + assertNotEquals(endpoints.get(0), endpoints.get(1)); + assertEquals(Set.of("GET", "POST"), + endpoints.stream().map(NettyHttpEndpoint::getHttpMethodRestrict).collect(Collectors.toSet())); + + String out = template.requestBodyAndHeader("netty-http:http://localhost:{{port}}/orders", null, + Exchange.HTTP_METHOD, "GET", String.class); + assertEquals("get", out); + out = template.requestBodyAndHeader("netty-http:http://localhost:{{port}}/orders", "Hello", + Exchange.HTTP_METHOD, "POST", String.class); + assertEquals("post", out); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("netty-http:http://localhost:{{port}}/echo") + .process(e -> { + String query = e.getIn().getHeader(Exchange.HTTP_QUERY, String.class); + e.getMessage().setBody(query != null ? query : "none"); + }); + + restConfiguration().component("netty-http").host("localhost").port(getPort()); + + rest("/orders") + .get().to("direct:get") + .post().to("direct:post"); + + from("direct:get").transform().constant("get"); + from("direct:post").transform().constant("post"); + } + }; + } +}
