health check: use the ALPN-negotiated protocol for HTTP health checks - #46903
Draft
zhaohuabing wants to merge 1 commit into
Draft
health check: use the ALPN-negotiated protocol for HTTP health checks#46903zhaohuabing wants to merge 1 commit into
zhaohuabing wants to merge 1 commit into
Conversation
zhaohuabing
force-pushed
the
health-check-alpn-negotiated-codec
branch
4 times, most recently
from
August 24, 2026 04:28
0fe64a9 to
3700377
Compare
HTTP health checks negotiated ALPN whenever TLS was in use and then discarded the result, always speaking whatever `codec_client_type` said. That made heterogeneous and mid-migration upstreams impossible to health check with a single configuration, and let contradictory config (`codec_client_type: HTTP2` with `tls_options.alpn_protocols: ["http/1.1"]`) load cleanly and then fail forever. Use the negotiated protocol to select the health check codec, with `codec_client_type` retained as the value used when nothing is negotiated, i.e. plaintext health checks and peers that do not do ALPN. A protocol this health checker cannot speak also falls back to `codec_client_type`, so upstreams that route health checks by a custom ALPN identifier are unaffected. The ALPN offered on health check connections is deliberately left unchanged, so no configuration that works today changes behavior on the wire. Since the codec can only be chosen once the handshake has completed, a TLS health check connection is now connected first and the codec client attached on the Connected event, mirroring what `HttpConnPoolImplMixed` already does on the data plane. Plaintext and HTTP/3 health checks keep creating the codec client up front. Guarded by `envoy.reloadable_features.health_check_use_negotiated_protocol`. Fixes envoyproxy#46848 Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
zhaohuabing
force-pushed
the
health-check-alpn-negotiated-codec
branch
from
August 24, 2026 04:36
3700377 to
614a933
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HTTP health checks negotiate ALPN whenever TLS is in use, then discard the result and speak whatever
codec_client_typesays. That means heterogeneous and mid-migration upstreams cannot be health checked with a single configuration — a pinned codec marks every host of the other protocol unhealthy, and the codec cannot vary per host — and contradictory config such ascodec_client_type: HTTP2alongsidetls_options.alpn_protocols: ["http/1.1"]loads cleanly and then fails forever with nothing in the logs pointing at ALPN.This uses the negotiated protocol to select the health check codec (
h2→ HTTP/2,http/1.1→ HTTP/1.1), and keepscodec_client_typeas the value used when nothing is negotiated, i.e. plaintext health checks and peers that do not do ALPN. A negotiated protocol this health checker cannot speak also falls back tocodec_client_type, so upstreams that route health checks by a custom ALPN identifier are unaffected.codec_client_type: HTTP3is unchanged, and gRPC health checks are unaffected since gRPC requires HTTP/2.The codec can only be chosen once the handshake has completed, so a TLS health check connection is now connected first and the codec client attached on the
Connectedevent — the same handoffHttpConnPoolImplMixedalready does on the data plane. Plaintext and HTTP/3 health checks keep creating the codec client up front, so their behavior is unchanged.I used Claude Code to help write this change and its tests. I have reviewed and understand the code and take full ownership of it.
Commit Message: health check: use the ALPN-negotiated protocol for HTTP health checks
Additional Description:
codec_client_typechanges meaning from "the codec to use" to "the codec to use when ALPN negotiates nothing". Behavior only differs for TLS health checks whose peer negotiates a protocol other than the configured one — a case that fails today — so no working configuration changes.Risk Level: Medium (changes how TLS health check connections are established; runtime guarded)
Testing: unit tests in
test/common/upstream/health_checker_impl_test.cccovering negotiated h2/http1 against the opposite configured codec, no-ALPN and unknown-ALPN fallback, plaintext, HTTP/3, both runtime guard paths, and the pending-connection close/timeout/zero-RTT/teardown paths; ALPN-over-TLS integration tests intest/integration/health_check_integration_test.cc.Docs Changes: updated the
codec_client_typeAPI comment.Release Notes: added.
Platform Specific Features: no
Optional Runtime guard:
envoy.reloadable_features.health_check_use_negotiated_protocolFixes #46848