This is an automated email from the ASF dual-hosted git repository. Croway pushed a commit to branch camel-4.22.x in repository https://gitbox.apache.org/repos/asf/camel.git
commit f08aae0758b12e79a0de3b64563b67a142fe5af9 Author: Andrea Cosentino <[email protected]> AuthorDate: Mon Aug 31 10:17:58 2026 +0200 CAMEL-24453: camel-platform-http - compare request header names case-insensitively when suppressing the echo (#25831) enhanceHeaderFilterStrategyToSkipHttpRequestHeaders() keeps common request headers - Authorization, Cookie, Proxy-Authorization and the rest of COMMON_HTTP_REQUEST_HEADERS - from being echoed back on the response. The lookup was Set.contains(headerName) against a canonically capitalised Set.of(...), while exchange headers keep the casing of the inbound request: VertxPlatformHttpConsumer populates them from the Vert.x MultiMap as received. HTTP/2 requires field names to be lower case, so on an HTTP/2 request the names are authorization, cookie and so on, none of which matched. The suppression therefore never fired for HTTP/2 traffic, nor for any client that varied the casing, and VertxPlatformHttpSupport.copyMessageHeadersToResponse wrote the headers to the response. Hold the set in a TreeSet ordered by String.CASE_INSENSITIVE_ORDER so the comparison no longer depends on how the client spelled the name. Signed-off-by: Andrea Cosentino <[email protected]> (cherry picked from commit 126c79bdf3f171184461f987c143b5a818df4d81) Co-authored-by: Claude Opus 5 (1M context) <[email protected]> --- .../platform/http/PlatformHttpEndpoint.java | 16 ++++++- .../http/PlatformHttpEndpointHeaderEchoTest.java | 53 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java index 01a57379a351..8574380b9d6e 100644 --- a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java +++ b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java @@ -16,7 +16,10 @@ */ package org.apache.camel.component.platform.http; +import java.util.Arrays; +import java.util.Collections; import java.util.Set; +import java.util.TreeSet; import org.apache.camel.AsyncEndpoint; import org.apache.camel.Category; @@ -53,7 +56,12 @@ public class PlatformHttpEndpoint extends DefaultEndpoint private static final String PROXY_PATH = "proxy"; - private static final Set<String> COMMON_HTTP_REQUEST_HEADERS = Set.of( + /** + * Request headers that must not be echoed back on the response. Compared without regard to case: exchange headers + * keep the casing of the inbound request, and HTTP/2 requires field names to be lower case, so an exact-case lookup + * against these canonical spellings never matches an HTTP/2 request. + */ + private static final Set<String> COMMON_HTTP_REQUEST_HEADERS = caseInsensitiveSet( "A-IM", "Accept", "Accept-Charset", @@ -83,6 +91,12 @@ public class PlatformHttpEndpoint extends DefaultEndpoint "TE", "User-Agent"); + private static Set<String> caseInsensitiveSet(String... names) { + Set<String> set = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + set.addAll(Arrays.asList(names)); + return Collections.unmodifiableSet(set); + } + @UriPath(description = "The path under which this endpoint serves the HTTP requests, for proxy use 'proxy'") @Metadata(required = true) private final String path; diff --git a/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpEndpointHeaderEchoTest.java b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpEndpointHeaderEchoTest.java new file mode 100644 index 000000000000..b428d6209836 --- /dev/null +++ b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpEndpointHeaderEchoTest.java @@ -0,0 +1,53 @@ +/* + * 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.platform.http; + +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.spi.HeaderFilterStrategy; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Exchange headers keep the casing of the inbound request, and HTTP/2 requires field names to be lower case. An + * exact-case lookup against canonically capitalised names therefore never suppresses anything on an HTTP/2 request, + * which is the traffic most likely to carry the credentials this is meant to keep out of the response. + */ +class PlatformHttpEndpointHeaderEchoTest { + + @Test + void requestHeadersAreSuppressedWhateverTheirCasing() throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + context.start(); + PlatformHttpComponent component = new PlatformHttpComponent(context); + PlatformHttpEndpoint endpoint + = (PlatformHttpEndpoint) component.createEndpoint("platform-http:/test"); + + HeaderFilterStrategy strategy = endpoint.getHeaderFilterStrategy(); + + // canonical, as sent over HTTP/1.1 + assertTrue(strategy.applyFilterToCamelHeaders("Authorization", "Bearer x", null)); + assertTrue(strategy.applyFilterToCamelHeaders("Cookie", "a=b", null)); + // lower case, as required by HTTP/2 + assertTrue(strategy.applyFilterToCamelHeaders("authorization", "Bearer x", null)); + assertTrue(strategy.applyFilterToCamelHeaders("cookie", "a=b", null)); + assertTrue(strategy.applyFilterToCamelHeaders("proxy-authorization", "Basic x", null)); + // and any other casing a client might send + assertTrue(strategy.applyFilterToCamelHeaders("AUTHORIZATION", "Bearer x", null)); + } + } +}
