Skip to content

[ISSUE #8321] Fail fast when shenyu.httpclient.strategy holds an unsupported value - #8341

Open
konlue wants to merge 1 commit into
apache:masterfrom
konlue:fix/8321-httpclient-strategy-validation
Open

konlue wants to merge 1 commit into
apache:masterfrom
konlue:fix/8321-httpclient-strategy-validation

Conversation

@konlue

@konlue konlue commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #8321.

Problem

shenyu.httpclient.strategy accepts netty and webClient. Any other value — web-client, web_client, an empty value, or a value with surrounding whitespace — leaves the gateway in a state where it starts successfully but has no HTTP client plugin at all, and every proxied request fails without any startup hint pointing at the misconfiguration.

The two built-in HTTP plugins are selected by mutually exclusive conditional configuration classes in HttpClientPluginConfiguration:

  • NettyHttpClientConfiguration — @ConditionalOnProperty(name = "shenyu.httpclient.strategy", havingValue = "netty", matchIfMissing = true)
  • WebClientConfiguration — @ConditionalOnProperty(name = "shenyu.httpclient.strategy", havingValue = "webClient")

matchIfMissing = true only covers the case where the property is absent. When the property is present but does not match either condition, neither plugin bean is registered. The gateway then starts, the plugin chain has no http client node, divide routes never reach an upstream, and with the response plugin enabled ResponsePlugin finds no HTTP message writer and fails the request with a NullPointerException. Nothing in the startup log points at the strategy value, and HttpClientProperties.getStrategy() performed no validation either.

An empty value is the same failure: matchIfMissing does not apply to a property that is present, so an empty or valueless entry matches neither condition.

Root cause

Plugin selection was driven by property conditions while the configured value itself was never validated, so an unsupported value was silently equivalent to "no http client plugin at all". The validation also has to stay compatible with the way the conditions match: @ConditionalOnProperty compares the configured value with String#equalsIgnoreCase, so NETTY, webclient and WebClient are legal today and must keep working.

Change

  • HttpClientProperties documents the legal values on the strategy property and exposes them as the NETTY_STRATEGY and WEB_CLIENT_STRATEGY constants.
  • HttpClientProperties implements InitializingBean and validates the bound value in afterPropertiesSet(), that is once the container has bound the properties and before the gateway serves any traffic. An unsupported value fails the application context with Invalid value 'web-client' for property 'shenyu.httpclient.strategy', supported values are 'netty' and 'webClient'.
  • A property that is present but has no value is rejected as well. The binder skips such a property, so the bound value alone cannot tell an absent property from a valueless one; HttpClientProperties therefore also implements EnvironmentAware and uses Environment#containsProperty on the same key the conditions read, which distinguishes the two cases exactly.
  • The check accepts exactly what the plugin selection conditions accept: netty and webClient, matched case-insensitively, with an absent property still falling back to the netty strategy. Values are neither trimmed nor rewritten, because the conditions do not trim either.
  • RELEASE-NOTES.md documents the behavior change.

Tests

  • HttpClientPropertiesTest: unsupported values (web-client, web_client, empty, blank padded, httpclient) are rejected with a message naming the property and both legal values; netty, webClient and their case variants are accepted; an absent value is accepted; a configured but valueless property is rejected while an absent one is accepted; afterPropertiesSet() rejects an unsupported value.
  • HttpClientPluginConfigurationTest: the application context now fails to start for web-client, for an empty value and for a valueless property, while netty, webClient, NETTY, webclient and an absent property still register the corresponding plugin.

Red and green: with the new tests in place and the production change reverted, the startup tests fail because the context starts successfully instead of failing; with the production change in place the whole module is green.

Verification

  • shenyu-plugin-httpclient: 169 tests, 0 failures (163 before plus 6 new).
  • shenyu-spring-boot-starter-plugin-httpclient: 27 tests, 0 failures (21 before plus 6 new).
  • shenyu-plugin-response 17 and shenyu-spring-boot-starter-plugin-response 3 are unchanged, so the response plugin selection is not affected.
  • Full reactor build of the touched modules: BUILD SUCCESS.
  • checkstyle:check for both changed modules: 0 violations.

Scope note

ResponsePluginConfiguration selects the HTTP message writer from the same property with the same pair of conditions. This change does not touch it: the gateway starter always ships the http client starter, so an unsupported value now fails the gateway startup before the writer selection can matter. A deployment that uses the response starter without the http client starter is not covered here.

4 files changed, 235 insertions(+), 4 deletions(-)

@Aias00 Aias00 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.

Stream Agent analysis

SYNTHESIS/FINAL review of #8341 at head 50f8960 aggregating child partition reviews. Both child reviews returned INCONCLUSIVE; one due to missing CI status and unverified cross-file property name/case-sensitivity, the other due to missing implementation diff partition (part-1) and unknown CI. CI passed=false, all_parts_passed=false. No blocking HIGH/CRITICAL defects identified in supplied scopes, but completeness and cross-file correctness cannot be confirmed.

Evidence

  • Frozen attachment 5d8a43fe-f6cd-4198-ab5c-229f95d624b2: SYNTHESIS/FINAL review shows child INCONCLUSIVE, CI passed=false, all_parts_passed=false
  • Child reduce-0-0 INCONCLUSIVE due to no CI status and open cross-file verification of property name consistency and @ConditionalOnProperty case sensitivity
  • Child reduce-0-1 INCONCLUSIVE due to missing implementation diff partition (part-1) and unknown CI

Recommended next steps

  • Provide complete implementation diff partition (part-1) for full review
  • Ensure CI checks complete and pass, reporting status
  • Verify cross-file property name consistency and @ConditionalOnProperty case sensitivity

Scope: captured diff and GitHub check metadata only; no local tests were executed.

Task: 65950101-e292-4082-9322-2ce698f293e4 · Commit: 50f8960b0e1ccb87bbcfbcdfdd521ef89067c11f

Review verdict: INCONCLUSIVE

SYNTHESIS/FINAL assessment of PR #8341 at head 50f8960. Child reviews returned INCONCLUSIVE (missing CI status, missing implementation diff partition, unverified cross-file property consistency). all_parts_passed=false and CI passed=false, so FINAL PASS impossible per rules. No HIGH/CRITICAL defects invented; blocking_findings empty. Verdict INCONCLUSIVE preserves uncertainty about cross-file correctness, contract compatibility, and runtime behavior.

Publication: COMMENT (INCONCLUSIVE_REVIEW)

Review details

The review of this PR is inconclusive. The supplied child reviews indicate missing CI status and an unavailable implementation diff partition (part-1), plus open cross-file property consistency checks. Please provide the full diff, ensure CI passes, and confirm property naming/case-sensitivity before final approval.

@konlue

konlue commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@Aias00

Thanks for the review. This is the SYNTHESIS/FINAL aggregation of two child INCONCLUSIVE reviews, so there is no defect to fix in the code, but the three open items can be closed with evidence.

Cross-file property name consistency

The property name is shenyu.httpclient.strategy everywhere:

  • Bound value: HttpClientProperties is bound by @ConfigurationProperties(prefix = "shenyu.httpclient") in HttpClientPluginConfiguration#httpClientProperties() and the field is strategy, so the bound key is shenyu.httpclient.strategy. The new HttpClientProperties.STRATEGY_PROPERTY constant holds exactly that name and is used both for the lookup and in the error message.
  • Consumers: HttpClientPluginConfiguration (havingValue = "webClient" and havingValue = "netty", matchIfMissing = true") and ResponsePluginConfiguration(the same two conditions) all readname = "shenyu.httpclient.strategy"`.
  • The validation reads the same key through Environment#containsProperty("shenyu.httpclient.strategy"), that is the same environment and the same exact key name the conditions use, so the value the conditions see and the value the validation sees cannot diverge.

@ConditionalOnProperty case sensitivity

@ConditionalOnProperty matches case-insensitively: OnPropertyCondition$Spec#isMatch compares requiredValue.equalsIgnoreCase(value). So NETTY, netty, webClient, webclient and WebClient all select a plugin today.

The validation follows exactly the same rule (NETTY_STRATEGY.equalsIgnoreCase(value) and WEB_CLIENT_STRATEGY.equalsIgnoreCase(value)), so a deployment that works today is not rejected. Two tests lock this contract: testNettyStrategyIsMatchedCaseInsensitively (NETTY registers nettyHttpClientPlugin) and testWebClientStrategyIsMatchedCaseInsensitively (webclient registers webClientPlugin).

Values are neither trimmed nor rewritten, because the conditions do not trim either, so a value like " netty" is rejected instead of being silently accepted while selecting no plugin.

CI status

19 checks passed, 6 skipped and 2 still running (build, build-docker-images) at the time of this comment. The local verification for the same commit 50f8960b0: shenyu-plugin-httpclient 169/0, shenyu-spring-boot-starter-plugin-httpclient 27/0, shenyu-plugin-response 17/0 and shenyu-spring-boot-starter-plugin-response 3/0 unchanged, full reactor BUILD SUCCESS, and checkstyle:check 0 violations for both changed modules.

Implementation diff

The complete diff is one commit on fix/8321-httpclient-strategy-validation (4 files, +235/-4): HttpClientProperties (the validation), HttpClientPropertiesTest, HttpClientPluginConfigurationTest and RELEASE-NOTES.md. The starter production code is intentionally unchanged: the properties bean is created unconditionally by the auto-configuration, so the validation runs at startup regardless of which condition matches, and a configured but valueless property is distinguished from an absent one through the environment lookup.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][Bootstrap] Invalid shenyu.httpclient.strategy silently disables all HTTP proxying

2 participants