diff --git a/components/camel-undertow/pom.xml b/components/camel-undertow/pom.xml index 5ed99a6b734e0..eb7010762def7 100644 --- a/components/camel-undertow/pom.xml +++ b/components/camel-undertow/pom.xml @@ -133,6 +133,11 @@ ${awaitility-version} test + + org.assertj + assertj-core + test + org.eclipse.jetty.http2 jetty-http2-client diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java index 358c154d1f7ab..d97ae90edb266 100644 --- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java +++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java @@ -37,7 +37,6 @@ import org.apache.camel.component.undertow.UndertowConstants.EventType; import org.apache.camel.component.undertow.handlers.CamelWebSocketHandler; import org.apache.camel.component.undertow.spi.UndertowSecurityProvider; -import org.apache.camel.http.base.HttpHeaderFilterStrategy; import org.apache.camel.http.base.OAuthHttpSecuritySupport; import org.apache.camel.http.base.OAuthProfileAwareHttpEndpoint; import org.apache.camel.http.base.cookie.CookieHandler; @@ -85,7 +84,7 @@ public class UndertowEndpoint extends DefaultEndpoint @UriParam(label = "advanced") private AccessLogReceiver accessLogReceiver; @UriParam(label = "advanced") - private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy(); + private HeaderFilterStrategy headerFilterStrategy = new UndertowHeaderFilterStrategy(); @UriParam(label = "security") private SSLContextParameters sslContextParameters; @UriParam(label = "consumer") diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowEndpointTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowEndpointTest.java index 817a13a9da7fc..75a8be7ffd02e 100644 --- a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowEndpointTest.java +++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowEndpointTest.java @@ -18,9 +18,12 @@ import java.net.URI; +import org.apache.camel.http.base.HttpHeaderFilterStrategy; +import org.apache.camel.spi.HeaderFilterStrategy; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; public class UndertowEndpointTest { @@ -47,4 +50,35 @@ public void nonEmptyPathShouldBeKeptSame() { endpoint.setHttpURI(withSlash); assertEquals(withSlash, endpoint.getHttpURI()); } + + @Test + void defaultHeaderFilterStrategyIsUndertowSpecific() { + assertThat(endpoint.getHeaderFilterStrategy()).isInstanceOf(UndertowHeaderFilterStrategy.class); + } + + @Test + void defaultBindingKeepsUndertowHeaderFilterStrategy() { + // the endpoint pushes its own strategy into the lazily created binding, so the endpoint default + // decides which strategy the binding ends up running + assertThat(endpoint.getUndertowHttpBinding()).isInstanceOf(DefaultUndertowHttpBinding.class); + HeaderFilterStrategy strategy + = ((DefaultUndertowHttpBinding) endpoint.getUndertowHttpBinding()).getHeaderFilterStrategy(); + assertThat(strategy).isInstanceOf(UndertowHeaderFilterStrategy.class); + + // the undertow-specific prefixes added by CAMEL-23588 must therefore be in effect + assertThat(strategy.applyFilterToExternalHeaders(UndertowConstants.CONNECTION_KEY, "aValue", null)).isTrue(); + assertThat(strategy.applyFilterToExternalHeaders(UndertowConstants.CONNECTION_KEY_LIST, "aValue", null)).isTrue(); + assertThat(strategy.applyFilterToExternalHeaders(UndertowConstants.SEND_TO_ALL, "aValue", null)).isTrue(); + assertThat(strategy.applyFilterToCamelHeaders(UndertowConstants.CONNECTION_KEY, "aValue", null)).isTrue(); + } + + @Test + void explicitHeaderFilterStrategyIsHandedToTheBinding() { + HeaderFilterStrategy custom = new HttpHeaderFilterStrategy(); + endpoint.setHeaderFilterStrategy(custom); + + assertThat(endpoint.getUndertowHttpBinding()).isInstanceOf(DefaultUndertowHttpBinding.class); + assertThat(((DefaultUndertowHttpBinding) endpoint.getUndertowHttpBinding()).getHeaderFilterStrategy()) + .isSameAs(custom); + } } diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc index a6b8fb0663265..5bb33211e540a 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc @@ -1619,3 +1619,35 @@ only once. In a Spring Boot application, Spring AI's auto-configured `ToolCallbackResolver` is built from the `ToolCallback` and `ToolCallbackProvider` beans in the context. A bare `@Bean Function<...>` is no longer resolvable by bean name; expose such tools as `ToolCallback` or `ToolCallbackProvider` beans. + +=== camel-undertow - UndertowHeaderFilterStrategy is now the endpoint default + +`UndertowEndpoint` defaulted its `headerFilterStrategy` to the base +`HttpHeaderFilterStrategy`, and pushed that strategy into the `DefaultUndertowHttpBinding` +it creates lazily, overwriting the `UndertowHeaderFilterStrategy` that the binding installs +in its own constructor. The undertow-specific filtering was therefore not applied on +endpoint-configured routes. + +The endpoint now defaults to `UndertowHeaderFilterStrategy`, which makes two already +documented behaviours take effect: + +* The legacy `websocket.*` Exchange-header prefix, added to the in and out filters in + 4.14.8 / 4.18.3 / 4.21.0 (see the 4.18 upgrade guide), is now filtered at the undertow + transport boundary as described there. +* Header names that undertow does not accept (those for which + `io.undertow.util.HttpString.tryFromString` returns `null`) are skipped when mapping + external headers in, rather than being mapped onto the message. + +Ordinary application headers are unaffected, and Rest DSL consumers already used an +undertow-specific strategy (`UndertowRestHeaderFilterStrategy`) so their behaviour does not +change. Routes that relied on `websocket.*` headers crossing the undertow boundary in either +direction, and routes that relied on undertow-invalid header names being mapped, can restore +the previous behaviour by configuring `headerFilterStrategy` explicitly on the endpoint: + +[source,java] +---- +from("undertow:http://0.0.0.0:8080/foo?headerFilterStrategy=#myStrategy") +---- + +Routes that already supply a custom `headerFilterStrategy` or a custom `undertowHttpBinding` +are unaffected.