Skip to content

Fix HttpClientResponse body()/end() race (5.0 backport)#6071

Merged
vietj merged 1 commit intoeclipse-vertx:5.0from
snazy:fix-race-6038-5.0
Apr 17, 2026
Merged

Fix HttpClientResponse body()/end() race (5.0 backport)#6071
vietj merged 1 commit intoeclipse-vertx:5.0from
snazy:fix-race-6038-5.0

Conversation

@snazy
Copy link
Copy Markdown
Contributor

@snazy snazy commented Apr 16, 2026

This change fixes the race in HttpClientResponseImpl described in #6038: handleTrailers()/handleException() can run before body()/end() creates the promise. If that happens, the completion signal is dropped and the future can hang. This is observed from the call site as a HTTP request timeout.

This fix is only applied to HttpClientResponseImpl:

  • keep ended/failure state on HttpClientResponseImpl
  • in body()/end(), create the HttpEventHandler promise while holding synchronized(conn)
  • after unlock, replay completion/failure via handleEnd()/handleException() when needed

Although HttpEventHandler looks very similar (like it could be affected by the same/similar race condition), it is not affected. I intentionally did not change HttpEventHandler, because it is also used in server request processing. The only case when server request processing could be affected , is when body() is called from a different thread while end() is being processed - that is very unlikely (feels like a misuse).

Also added two new tests to Http1xTest that reliably fail without the change to HttpClientResponseImpl and reliably pass with that change. The added regression tests are testResponseBodyAfterResponseEnd and testResponseEndAfterResponseEnd.

Contributes to #6038

This change fixes the race in `HttpClientResponseImpl` described in eclipse-vertx#6038: `handleTrailers()`/`handleException()` can run before `body()`/`end()` creates the promise. If that happens, the completion signal is dropped and the future can hang. This is observed from the call site as a HTTP request timeout.

This fix is only applied to `HttpClientResponseImpl`:
- keep ended/failure state on `HttpClientResponseImpl`
- in `body()`/`end()`, create the `HttpEventHandler` promise while holding `synchronized(conn)`
- after unlock, replay completion/failure via `handleEnd()`/`handleException()` when needed

Although `HttpEventHandler` looks very similar (like it _could_ be affected by the same/similar race condition), it is not affected. I intentionally did not change `HttpEventHandler`, because it is also used in server request processing. The only case when server request processing could be affected
, is when `body()` is called from a _different_ thread while `end()` is being processed - that is very unlikely (feels like a misuse).

Also added two new tests to `Http1xTest` that reliably fail without the change to `HttpClientResponseImpl` and reliably pass with that change. The added regression tests are `testResponseBodyAfterResponseEnd` and `testResponseEndAfterResponseEnd`.

Fixes eclipse-vertx#6038
@vietj vietj self-requested a review April 16, 2026 21:42
@vietj vietj added this to the 5.0.11 milestone Apr 17, 2026
@vietj vietj merged commit 82b01d9 into eclipse-vertx:5.0 Apr 17, 2026
7 checks passed
@snazy snazy deleted the fix-race-6038-5.0 branch April 17, 2026 09:16
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