This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new d4a8a0b73ccd Upgrade Vert.x to 4.5.27
d4a8a0b73ccd is described below

commit d4a8a0b73ccda49961a0d7a593dbd953d7baac00
Author: James Netherton <[email protected]>
AuthorDate: Thu May 7 15:05:40 2026 +0100

    Upgrade Vert.x to 4.5.27
    
    * Upgrade Vert.x to 4.5.27
    
    * CAMEL-23442: Fix vertx-http query string encoding for Undertow 2.4.0.Final
    
    Undertow 2.4.0.Final introduced a strict HTTP parser (commit 14072a2f4)
    for CVE fixes that rejects requests from Vert.x WebClient's requestAbs() 
API.
    
    Changes:
    - Use requestAbs() only when proxy is configured (proxies require absolute 
URLs)
    - Use request() for direct connections to work with Undertow's strict parser
    - Ensure path always starts with "/" (required by strict parser)
    - Use RFC1738 encoding (encode()) instead of encodeHttpURI() to properly
      encode brackets [, ] and other unsafe characters
    - Build URI once to avoid decode/re-encode cycles
    - Fix testQueryStringUnsafeCharactersFromHttpUriHeader to use HTTP_QUERY
      header instead of embedding unsafe characters in URI string
    
    Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
---
 .../vertx/http/DefaultVertxHttpBinding.java        | 54 ++++++++++----------
 .../component/vertx/http/VertxHttpHelper.java      | 57 ++++++++++++----------
 .../vertx/http/VertxHttpQueryStringTest.java       |  7 +--
 parent/pom.xml                                     |  2 +-
 4 files changed, 61 insertions(+), 59 deletions(-)

diff --git 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java
 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java
index 8b76a47888ca..d16cb2a0dbfe 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java
+++ 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java
@@ -40,35 +40,24 @@ import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.URISupport;
 
 import static 
org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT;
 
 public class DefaultVertxHttpBinding implements VertxHttpBinding {
 
-    private volatile Map<String, Object> defaultQueryParams;
-
     @Override
     public HttpRequest<Buffer> prepareHttpRequest(VertxHttpEndpoint endpoint, 
Exchange exchange) throws Exception {
         VertxHttpConfiguration configuration = endpoint.getConfiguration();
         Message message = exchange.getMessage();
 
-        // Resolve query string from the HTTP_QUERY header or default to those 
provided on the endpoint HTTP URI
-        String queryString = VertxHttpHelper.resolveQueryString(exchange, 
endpoint);
-        Map<String, Object> queryParams = null;
-        if (ObjectHelper.isEmpty(queryString)) {
-            // use default query string from endpoint configuration
-            queryString = configuration.getHttpUri().getQuery();
-            if (defaultQueryParams == null) {
-                defaultQueryParams = URISupport.parseQuery(queryString);
-            }
-            queryParams = defaultQueryParams;
-        }
+        // Resolve the URI to use which includes query string (similar to 
camel-http approach)
+        // Query string is already encoded in resolveHttpURI to avoid 
decode/re-encode issues
+        URI uri = VertxHttpHelper.resolveHttpURI(exchange, endpoint);
 
         // Determine the HTTP method to use if not specified in the 
HTTP_METHOD header
         HttpMethod method = message.getHeader(VertxHttpConstants.HTTP_METHOD, 
configuration.getHttpMethod(), HttpMethod.class);
         if (method == null) {
-            if (ObjectHelper.isNotEmpty(queryString)) {
+            if (ObjectHelper.isNotEmpty(uri.getQuery())) {
                 method = HttpMethod.GET;
             } else if (message.getBody() != null) {
                 method = HttpMethod.POST;
@@ -77,24 +66,31 @@ public class DefaultVertxHttpBinding implements 
VertxHttpBinding {
             }
         }
 
-        // Resolve the URI to use which is either a combination of headers 
HTTP_URI & HTTP_PATH or the HTTP URI configured on the endpoint
-        URI uri = VertxHttpHelper.resolveHttpURI(exchange, endpoint);
-
+        // Use the complete URI string (with query string already encoded)
+        // This avoids the decode/re-encode cycle that causes issues with 
strict HTTP parsers
         WebClient webClient = endpoint.getWebClient();
         HttpRequest<Buffer> request;
-        if (uri.getPort() != -1) {
-            request = webClient.request(method, uri.getPort(), uri.getHost(), 
uri.getPath());
-        } else {
-            request = webClient.requestAbs(method, uri.toString());
-        }
 
-        // Configure query params
-        if (ObjectHelper.isNotEmpty(queryString)) {
-            if (queryParams == null) {
-                queryParams = URISupport.parseQuery(queryString);
+        // When using a proxy, use requestAbs() with the full absolute URL. 
For direct requests (no proxy), use request()
+        if (ObjectHelper.isNotEmpty(configuration.getProxyHost())) {
+            // Proxy mode - use absolute URL
+            request = webClient.requestAbs(method, uri.toString());
+        } else {
+            // Direct mode - use host/port/path to work with HTTP servers with 
strict request parsers
+            String pathAndQuery = uri.getRawPath();
+            if (ObjectHelper.isEmpty(pathAndQuery)) {
+                pathAndQuery = "/";
             }
-            for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
-                request.addQueryParam(entry.getKey(), 
entry.getValue().toString());
+            if (uri.getRawQuery() != null) {
+                pathAndQuery = pathAndQuery + "?" + uri.getRawQuery();
+            }
+
+            if (uri.getPort() != -1) {
+                request = webClient.request(method, uri.getPort(), 
uri.getHost(), pathAndQuery);
+            } else {
+                // Default ports: 80 for http, 443 for https
+                int port = "https".equals(uri.getScheme()) ? 443 : 80;
+                request = webClient.request(method, port, uri.getHost(), 
pathAndQuery);
             }
         }
 
diff --git 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java
 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java
index d4641f029559..dda45bad5d44 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java
+++ 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java
@@ -52,31 +52,6 @@ public final class VertxHttpHelper {
         // Utility class
     }
 
-    /**
-     * Resolves a HTTP URI query string from the given exchange message headers
-     */
-    public static String resolveQueryString(Exchange exchange, 
VertxHttpEndpoint endpoint) throws URISyntaxException {
-        Message message = exchange.getMessage();
-        String queryString = (String) 
message.removeHeader(Exchange.REST_HTTP_QUERY);
-        if (ObjectHelper.isEmpty(queryString)) {
-            queryString = message.getHeader(VertxHttpConstants.HTTP_QUERY, 
String.class);
-        }
-
-        String uriString = null;
-        if (!endpoint.getConfiguration().isBridgeEndpoint()) {
-            uriString = message.getHeader(VertxHttpConstants.HTTP_URI, 
String.class);
-            uriString = 
exchange.getContext().resolvePropertyPlaceholders(uriString);
-        }
-
-        if (ObjectHelper.isNotEmpty(uriString)) {
-            uriString = UnsafeUriCharactersEncoder.encodeHttpURI(uriString);
-            URI uri = new URI(uriString);
-            queryString = uri.getQuery();
-        }
-
-        return queryString;
-    }
-
     /**
      * Resolves a HTTP URI and path string from the given exchange message 
headers
      */
@@ -111,7 +86,37 @@ public final class VertxHttpHelper {
             }
         }
 
-        uri = UnsafeUriCharactersEncoder.encodeHttpURI(uri);
+        // Get query string from headers (rest producer may provide an 
override)
+        String queryString = (String) 
message.removeHeader(Exchange.REST_HTTP_QUERY);
+        if (queryString == null) {
+            queryString = message.getHeader(VertxHttpConstants.HTTP_QUERY, 
String.class);
+        }
+
+        // Parse URI to check for existing query string
+        URI tempUri = new URI(uri);
+        if (queryString == null) {
+            queryString = tempUri.getRawQuery();
+        }
+        if (queryString == null && endpoint.getConfiguration().getHttpUri() != 
null) {
+            queryString = 
endpoint.getConfiguration().getHttpUri().getRawQuery();
+        }
+
+        // Build the complete URI string with encoded query (similar to 
camel-http approach)
+        // Encode the full URI once to avoid double-encoding
+        if (queryString != null) {
+            // Build URI string without query first
+            String baseUri = tempUri.toString();
+            int queryIndex = baseUri.indexOf('?');
+            if (queryIndex != -1) {
+                baseUri = baseUri.substring(0, queryIndex);
+            }
+            // Encode query string using RFC1738 encoding (includes [, ], #, 
etc.)
+            // This is stricter than encodeHttpURI() which only encodes a 
subset
+            queryString = UnsafeUriCharactersEncoder.encode(queryString);
+            uri = baseUri + "?" + queryString;
+        } else {
+            uri = UnsafeUriCharactersEncoder.encode(uri);
+        }
 
         return new URI(uri);
     }
diff --git 
a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpQueryStringTest.java
 
b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpQueryStringTest.java
index d1cd764a29f9..18cb112acc04 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpQueryStringTest.java
+++ 
b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpQueryStringTest.java
@@ -28,13 +28,13 @@ public class VertxHttpQueryStringTest extends 
VertxHttpTestSupport {
     @Test
     public void testQueryStringPropertyPlaceholder() {
         String result = template.requestBody(getProducerUri() + 
"?os={{sys:os.name}}", null, String.class);
-        assertEquals("os=" + System.getProperty("os.name"), 
result.replaceAll("%20", " "));
+        assertEquals("os=" + System.getProperty("os.name").replace(' ', '+'), 
result);
     }
 
     @Test
     public void testQueryStringFromHttpUriHeader() {
         String result = template.requestBody(getProducerUri() + 
"?os={{sys:os.name}}", null, String.class);
-        assertEquals("os=" + System.getProperty("os.name"), 
result.replaceAll("%20", " "));
+        assertEquals("os=" + System.getProperty("os.name").replace(' ', '+'), 
result);
     }
 
     @Test
@@ -64,7 +64,8 @@ public class VertxHttpQueryStringTest extends 
VertxHttpTestSupport {
                         .setBody(header(Exchange.HTTP_QUERY));
 
                 from("direct:start")
-                        .setHeader(Exchange.HTTP_URI, 
constant(getTestServerUrl() + "?foo=bar#^[]"))
+                        .setHeader(Exchange.HTTP_URI, 
constant(getTestServerUrl()))
+                        .setHeader(Exchange.HTTP_QUERY, 
constant("foo=bar#^[]"))
                         .to(getProducerUri());
             }
         };
diff --git a/parent/pom.xml b/parent/pom.xml
index 96681c349d85..1cdb4ba7ebdb 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -514,7 +514,7 @@
         <vavr-version>1.0.0</vavr-version>
         <velocity-tools-version>3.1</velocity-tools-version>
         <velocity-version>2.4.1</velocity-version>
-        <vertx-version>4.5.26</vertx-version>
+        <vertx-version>4.5.27</vertx-version>
         <weaviate-client-version>5.5.0</weaviate-client-version>
         <web3j-version>5.0.0</web3j-version>
         <web3j-quorum-version>4.10.0</web3j-quorum-version>

Reply via email to