Skip to content

reverse tunnel: fix empty provider-backed formatters in handshake headers#46168

Merged
yanavlasov merged 1 commit into
envoyproxy:mainfrom
kanurag94:fix/reverse-tunnel-file-content-handshake
Jul 17, 2026
Merged

reverse tunnel: fix empty provider-backed formatters in handshake headers#46168
yanavlasov merged 1 commit into
envoyproxy:mainfrom
kanurag94:fix/reverse-tunnel-file-content-handshake

Conversation

@kanurag94

@kanurag94 kanurag94 commented Jul 16, 2026

Copy link
Copy Markdown
Member

Commit Message: reverse tunnel: fix empty provider-backed formatters in handshake headers

Additional Description:
Handshake additional_headers values that use a ThreadLocal-backed substitution formatter
(e.g. %FILE_CONTENT%, or secret/SDS-backed formatters) resolved to an empty string on the worker
thread that assembles the reverse-tunnel handshake request.

The handshake formatters were built in the bootstrap extension constructor, which runs before the
worker threads register with the ThreadLocal system. ThreadLocal::Slot::set() only propagates to
threads that are already registered and is not replayed for threads that register later, so the
formatter providers' thread-local slots were never populated on the workers, and format()
returned an empty value there.

Build the handshake formatters in onServerInitialized() instead, which runs after the workers
register, so the providers' set() reaches every worker thread. This mirrors the pattern the
extension already uses for its own thread-local slot in onWorkerThreadInitialized().

Risk Level: Low
Testing: Unit test added that evaluates the handshake header on a real worker thread (fails without
the change, passes with it); existing reverse_tunnel unit tests updated.
Docs Changes: N/A
Release Notes: Changelog entry added.
Platform Specific Features: N/A

…ders

Handshake ``additional_headers`` values that use a ThreadLocal-backed
substitution formatter (e.g. ``%FILE_CONTENT%``, or secret/SDS-backed
formatters) resolved to an empty string on the worker thread that
assembles the reverse-tunnel handshake request.

The handshake formatters were built in the bootstrap extension
constructor, which runs before the worker threads register with the
ThreadLocal system. ThreadLocal::Slot::set() only propagates to threads
that are already registered and is not replayed for threads that register
later, so the formatter providers' thread-local slots were never
populated on the workers, and format() returned an empty value there.

Build the handshake formatters in onServerInitialized() instead, which
runs after the workers register, so the providers' set() reaches every
worker thread. This mirrors the pattern the extension already uses for
its own thread-local slot in onWorkerThreadInitialized().

Adds a regression test that evaluates the handshake header value on a
real worker thread; it fails without the fix and passes with it.

Signed-off-by: Anurag Aggarwal <kanurag94@gmail.com>
@kanurag94

Copy link
Copy Markdown
Member Author

/retest

@yanavlasov
yanavlasov merged commit 5121e87 into envoyproxy:main Jul 17, 2026
28 checks passed
kanurag94 added a commit to kanurag94/envoy that referenced this pull request Jul 25, 2026
The reverse-connection listen socket snapshots the handshake formatters
when it's created, and that can happen before onServerInitialized() has
built them. The snapshot ends up null and gets reused for every re-dial,
so handshake additional_headers that use a formatter (%FILE_CONTENT%,
SDS-backed secrets, etc.) went out as the raw template string instead of
the resolved value.

Read the formatters straight from the extension when we assemble the
handshake instead of trusting that snapshot, falling back to the snapshot
only when the extension hasn't built any.

This is a follow-up to envoyproxy#46168, which fixed the same symptom in the
extension constructor but missed the socket() -> io_handle -> wrapper
snapshot path. Adds a regression test that goes through the real socket()
path so it can't regress.

Signed-off-by: Anurag Aggarwal <kanurag94@gmail.com>
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.

2 participants