Skip to content

CAMEL-24360: camel-undertow - use UndertowHeaderFilterStrategy as the endpoint default - #25367

Merged
davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-24360
Aug 6, 2026
Merged

CAMEL-24360: camel-undertow - use UndertowHeaderFilterStrategy as the endpoint default#25367
davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-24360

Conversation

@oscerd

@oscerd oscerd commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Description

DefaultUndertowHttpBinding installs an UndertowHeaderFilterStrategy in its constructor:

public DefaultUndertowHttpBinding(boolean useStreaming) {
    this.headerFilterStrategy = new UndertowHeaderFilterStrategy();
    ...
}

but UndertowEndpoint defaulted its own field to the base HttpHeaderFilterStrategy and pushed that into the binding when creating it lazily, overwriting what the binding had just set:

private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy();   // line 88

public UndertowHttpBinding getUndertowHttpBinding() {
    if (undertowHttpBinding == null) {
        undertowHttpBinding = new DefaultUndertowHttpBinding(useStreaming);
        undertowHttpBinding.setHeaderFilterStrategy(getHeaderFilterStrategy());        // overwrites it
        ...

Unless the user supplied a custom binding or a custom headerFilterStrategy, the binding ran the base strategy and the undertow-specific filtering never executed.

Impact

Two behaviours documented as shipped were inert on endpoint-configured routes:

  • the legacy websocket.* Exchange-header prefix added to the in/out filters by CAMEL-23588 (released in 4.14.8 / 4.18.3 / 4.21.0 and described in the 4.18 upgrade guide);
  • the io.undertow.util.HttpString.tryFromString header-name validation in UndertowHeaderFilterStrategy.applyFilterToExternalHeaders, which skips header names undertow does not accept.

Documentation and runtime behaviour had therefore diverged since CAMEL-23588.

Fix

UndertowEndpoint now defaults to UndertowHeaderFilterStrategy, so both take effect.

  • Rest DSL consumers are unchanged: UndertowComponent already assigns UndertowRestHeaderFilterStrategy, which extends UndertowHeaderFilterStrategy.
  • Endpoints configuring headerFilterStrategy or undertowHttpBinding explicitly keep their behaviour.
  • Ordinary application headers are unaffected; the two added filters are narrow.

The now-unused HttpHeaderFilterStrategy import is removed. No generated metadata changes, since the catalog records only the HeaderFilterStrategy interface and not the default implementation class.

Changes

  • UndertowEndpoint - default strategy, unused import
  • UndertowEndpointTest - three cases: the endpoint default is undertow-specific; the lazily created binding keeps it and actually filters UndertowConstants.CONNECTION_KEY / CONNECTION_KEY_LIST / SEND_TO_ALL; an explicitly configured strategy still reaches the binding
  • 4.22 upgrade-guide entry, including how to restore the previous behaviour

Testing

  • camel-undertow module build green: 191 tests pass, 0 failures, 1 skipped. The websocket suites (UndertowWsConsumerRouteTest, UndertowWsTwoRoutesToSameEndpointSendToAllHeaderTest, ...) all still pass, since the producer reads those headers via in.getHeader(...), which does not go through the HeaderFilterStrategy.
  • Full reactor build from root (mvn clean install -DskipTests) green, no regenerated-artifact drift.

Backport

UndertowEndpoint line 88 and DefaultUndertowHttpBinding line 86 are identical on main, camel-4.18.x and camel-4.14.x, so this should be backported to both LTS lines (with the matching 4.18 / 4.14 upgrade-guide entries doc-synced back to main per the backport policy). Backporting matters here because CAMEL-23588 shipped on those branches and its documented effect is what this restores.

Review feedback (ff954f9)

The three new UndertowEndpointTest methods now use AssertJ (assertThat(...)) instead of JUnit assertions, per project convention. The two pre-existing methods keep their JUnit assertions, per the convention that touched code migrates without sweeping the whole file.

assertj-core was not on the camel-undertow test classpath, so it is also declared as a test dependency (version-less, supplied by the parent dependencyManagement). Flagged in the PR thread since the project standards ask that new dependencies be justified.

Note on the earlier CI failure

The earlier red on this PR was not a regression. build (17) failed in camel-cxf-spring-soap with BindException: Address already in use / Soap 1.1 endpoint already registered, and build (25) was cancelled by matrix fail-fast rather than failing. That module has no undertow: endpoint usage in its tests, so UndertowEndpoint is not on its code path (it publishes through CXF's own cxf-rt-transports-http-undertow). A re-run passed both jobs.

Claude Code on behalf of oscerd

… endpoint default

DefaultUndertowHttpBinding installs an UndertowHeaderFilterStrategy in its
constructor, but UndertowEndpoint defaulted its own headerFilterStrategy to the
base HttpHeaderFilterStrategy and pushed that into the binding when lazily
creating it, overwriting the undertow-specific strategy. Unless the user
supplied a custom binding or a custom headerFilterStrategy, the binding ran the
base strategy and the undertow-specific filtering never executed.

Two behaviours that are documented as shipped were therefore inert on
endpoint-configured routes:

  * the legacy websocket.* Exchange-header prefix added to the in and out
    filters by CAMEL-23588 (4.14.8 / 4.18.3 / 4.21.0);
  * the io.undertow.util.HttpString.tryFromString header-name validation in
    UndertowHeaderFilterStrategy.applyFilterToExternalHeaders, which skips
    header names undertow does not accept.

The endpoint now defaults to UndertowHeaderFilterStrategy, so both take effect.
Rest DSL consumers are unchanged: UndertowComponent already assigns
UndertowRestHeaderFilterStrategy, which extends UndertowHeaderFilterStrategy.
Endpoints that configure headerFilterStrategy or undertowHttpBinding explicitly
keep their existing behaviour.

Adds three UndertowEndpointTest cases covering the endpoint default, the
strategy the lazily created binding ends up running together with the websocket
prefixes actually being filtered, and an explicitly configured strategy still
reaching the binding. Adds a 4.22 upgrade-guide entry describing the change and
how to restore the previous behaviour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd
oscerd requested review from davsclaus and gnodet August 5, 2026 22:40
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-undertow
  • docs

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 39 tested, 28 compile-only — current: 38 all tested

Maveniverse Scalpel detected 67 affected modules (current approach: 38).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 39 modules (2 direct + 37 downstream), skip tests for 28 (generated code, meta-modules)

Modules Scalpel would test (39)
  • camel-a2a
  • camel-consul
  • camel-cxf-rest
  • camel-cxf-soap
  • camel-cxf-spring-rest
  • camel-cxf-spring-soap
  • camel-cxf-spring-transport
  • camel-cxf-transport
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jsonpath
  • camel-knative-http
  • camel-launcher-container
  • camel-lra
  • camel-mcp-server
  • camel-micrometer-observability
  • camel-micrometer-prometheus
  • camel-oauth
  • camel-observability-services
  • camel-openapi-validator
  • camel-opentelemetry
  • camel-opentelemetry2
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-rest-openapi
  • camel-slack
  • camel-soap
  • camel-telemetry
  • camel-telemetry-dev
  • camel-undertow
  • camel-undertow-spring-security
  • camel-vertx-http
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper
  • docs
Modules with tests skipped (28)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

Build reactor — dependencies compiled but only changed modules were tested (67 modules)
  • Camel :: AI :: A2A
  • Camel :: AI :: MCP Server
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: CXF :: REST
  • Camel :: CXF :: REST :: Spring
  • Camel :: CXF :: SOAP
  • Camel :: CXF :: SOAP :: Spring
  • Camel :: CXF :: Transport
  • Camel :: CXF :: Transport :: Spring
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Common Telemetry
  • Camel :: Component DSL
  • Camel :: Consul
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JSon Path
  • Camel :: Kamelet Main
  • Camel :: Knative HTTP
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Long-Running-Action
  • Camel :: Micrometer :: Observability 2
  • Camel :: Micrometer :: Prometheus
  • Camel :: OAuth
  • Camel :: Observability Services
  • Camel :: OpenAPI :: Validator
  • Camel :: OpenTelemetry (deprecated)
  • Camel :: Opentelemetry 2
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: REST OpenApi
  • Camel :: SOAP
  • Camel :: Slack
  • Camel :: Telemetry :: Dev
  • Camel :: Undertow
  • Camel :: Undertow Spring Security
  • Camel :: Vert.x :: HTTP
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zookeeper

⚙️ View full build and test results

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — genuine bugfix, minimal change, well-tested.

The root cause is confirmed: UndertowEndpoint line 88 defaulted to HttpHeaderFilterStrategy, and getUndertowHttpBinding() pushed that into the lazily created binding, overwriting the UndertowHeaderFilterStrategy installed by the binding's own constructor. The websocket.* prefix filtering from CAMEL-23588 was therefore never active on endpoint-configured routes.

One minor convention note (non-blocking):

  • The new test methods use JUnit assertions (assertInstanceOf, assertSame, assertTrue). Per project conventions, new test code should prefer AssertJ (assertThat(...)) for consistency.

Everything else checks out:

  • Fix is correct and minimal (one-line default change)
  • Tests cover three scenarios: default strategy, lazy binding propagation, explicit custom strategy
  • Rest DSL consumers are unaffected (UndertowRestHeaderFilterStrategy already extends UndertowHeaderFilterStrategy)
  • Upgrade guide documents the change and how to restore previous behaviour

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of davsclaus

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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: per project conventions, new test code should prefer AssertJ assertions (assertThat(...)) over JUnit assertions (assertInstanceOf, assertSame, assertTrue).

…ases

Addresses review feedback on apache#25367. The project convention is to prefer
AssertJ over JUnit assertions in new test code.

assertj-core was not on the camel-undertow test classpath, so it is declared
here as a test dependency; the version comes from the parent
dependencyManagement, matching how other modules declare it.

Only the three new test methods are converted. The two pre-existing methods
keep their JUnit assertions, per the convention that touched code migrates
without sweeping the whole file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd

oscerd commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Addressed in ff954f9 — the three new test methods now use AssertJ (assertThat(...)).

Two notes:

1. AssertJ was not on this module's classpath. The suggestion assumed it was already usable here, but mvn dependency:tree -Dincludes=org.assertj:assertj-core returns nothing for camel-undertow (and correctly resolves assertj-core:3.27.7:test for a module that does declare it, e.g. camel-langchain4j-agent-api). So this change also declares it as a test dependency, version-less since the parent dependencyManagement supplies it:

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <scope>test</scope>
</dependency>

Flagging it because the project standards ask that new dependencies be justified. Happy to revert to JUnit assertions if you would rather not add it to this component just for assertion style.

2. Only the three new methods are converted. emptyPathShouldBeReplacedWithSlash and nonEmptyPathShouldBeKeptSame predate this PR and keep their JUnit assertEquals, per the convention that touched code migrates without sweeping the whole file. The file therefore imports both, with one style per method as the convention requires. Say the word if you would prefer the whole file migrated in one go.

Module build is green: 191 tests pass, 0 failures. Full reactor build from root is clean with no regenerated-artifact drift.

Also worth noting for the record: the earlier CI red on this PR was not a regression. build (17) failed in camel-cxf-spring-soap with BindException: Address already in use / Soap 1.1 endpoint already registered, and build (25) was cancelled by matrix fail-fast rather than failing. camel-cxf-spring-soap has no undertow: endpoint usage in its tests, so UndertowEndpoint is not on that code path — it publishes through CXF's own cxf-rt-transports-http-undertow. A re-run passed both jobs.


Claude Code on behalf of oscerd

@davsclaus davsclaus added the bug Something isn't working label Aug 6, 2026
@davsclaus
davsclaus merged commit 859e93b into apache:main Aug 6, 2026
6 checks passed
davsclaus added a commit that referenced this pull request Aug 6, 2026
…derFilterStrategy as the endpoint default (#25379)

CAMEL-24360: camel-undertow - use UndertowHeaderFilterStrategy as the endpoint default

UndertowEndpoint defaulted its headerFilterStrategy to the base
HttpHeaderFilterStrategy and pushed it into the lazily created binding,
overwriting the UndertowHeaderFilterStrategy the binding's constructor had
installed. This made the undertow-specific filtering (websocket.* prefix
filtering from CAMEL-23588, HttpString header-name validation) inert on
endpoint-configured routes.

The endpoint now defaults to UndertowHeaderFilterStrategy. Rest DSL consumers
are unchanged (UndertowComponent already assigns UndertowRestHeaderFilterStrategy).
Endpoints that configure headerFilterStrategy or undertowHttpBinding explicitly
keep their existing behaviour.

Adds UndertowEndpointTest cases and a 4.22 upgrade-guide entry.

Closes #25367

Co-authored-by: Andrea Cosentino <ancosen@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
davsclaus added a commit that referenced this pull request Aug 6, 2026
…derFilterStrategy as the endpoint default (#25381)

CAMEL-24360: camel-undertow - use UndertowHeaderFilterStrategy as the endpoint default

UndertowEndpoint defaulted its headerFilterStrategy to the base
HttpHeaderFilterStrategy and pushed it into the lazily created binding,
overwriting the UndertowHeaderFilterStrategy the binding's constructor had
installed. This made the undertow-specific filtering (websocket.* prefix
filtering from CAMEL-23588, HttpString header-name validation) inert on
endpoint-configured routes.

The endpoint now defaults to UndertowHeaderFilterStrategy. Rest DSL consumers
are unchanged (UndertowComponent already assigns UndertowRestHeaderFilterStrategy).
Endpoints that configure headerFilterStrategy or undertowHttpBinding explicitly
keep their existing behaviour.

Adds UndertowEndpointTest cases and a 4.22 upgrade-guide entry.

Closes #25367

Co-authored-by: Andrea Cosentino <ancosen@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@oscerd oscerd added this to the 4.22.0 milestone Aug 6, 2026
@oscerd
oscerd deleted the fix/CAMEL-24360 branch August 6, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants