mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(tls): check SSL_is_init_finished directly for _secureEstablished (#26086)
## Summary Fixes flaky test `test/js/node/test/parallel/test-http-url.parse-https.request.js` where `request.socket._secureEstablished` sometimes returned `false` even when the TLS handshake had completed. ## Root Cause There's a race condition between when the TLS handshake completes and when the `on_handshake` callback fires. The HTTP request handler could start executing before the callback set `httpResponseData->isAuthorized = true`, causing `_secureEstablished` to return `false`. ## Previous Failed Approach (PR #25946) Attempted to trigger the handshake callback earlier in `ssl_on_data`, but this broke gRPC and HTTP/2 tests because the callback has side effects that disrupted the data processing. ## This Fix Instead of changing when the callback fires, directly query OpenSSL's `SSL_is_init_finished()` when checking `_secureEstablished`: 1. Added `us_socket_is_ssl_handshake_finished()` API that wraps `SSL_is_init_finished()` 2. Modified `JSNodeHTTPServerSocket::isAuthorized()` to use this function directly This approach is non-invasive - it doesn't change any TLS processing logic, just reads the correct state at the point where it's needed. ## Test plan - [x] Original flaky test passes under high parallelism (50/50 runs) - [x] gRPC tests pass (`test-channel-credentials.test.ts`) - [x] All `test-http-url.parse-*.js` tests pass - [x] HTTPS tests pass (`test-https-simple.js`, `test-https-agent.js`) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
@@ -315,6 +315,15 @@ int us_internal_ssl_socket_is_closed(struct us_internal_ssl_socket_t *s) {
|
||||
return us_socket_is_closed(0, &s->s);
|
||||
}
|
||||
|
||||
int us_internal_ssl_socket_is_handshake_finished(struct us_internal_ssl_socket_t *s) {
|
||||
if (!s || !s->ssl) return 0;
|
||||
return SSL_is_init_finished(s->ssl);
|
||||
}
|
||||
|
||||
int us_internal_ssl_socket_handshake_callback_has_fired(struct us_internal_ssl_socket_t *s) {
|
||||
if (!s) return 0;
|
||||
return s->handshake_state == HANDSHAKE_COMPLETED;
|
||||
}
|
||||
|
||||
void us_internal_trigger_handshake_callback_econnreset(struct us_internal_ssl_socket_t *s) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
|
||||
@@ -439,6 +439,8 @@ void *us_internal_ssl_socket_ext(us_internal_ssl_socket_r s);
|
||||
void *us_internal_connecting_ssl_socket_ext(struct us_connecting_socket_t *c);
|
||||
int us_internal_ssl_socket_is_shut_down(us_internal_ssl_socket_r s);
|
||||
int us_internal_ssl_socket_is_closed(us_internal_ssl_socket_r s);
|
||||
int us_internal_ssl_socket_is_handshake_finished(us_internal_ssl_socket_r s);
|
||||
int us_internal_ssl_socket_handshake_callback_has_fired(us_internal_ssl_socket_r s);
|
||||
void us_internal_ssl_socket_shutdown(us_internal_ssl_socket_r s);
|
||||
|
||||
struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_adopt_socket(
|
||||
|
||||
@@ -457,6 +457,12 @@ int us_socket_is_shut_down(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
/* Returns whether this socket has been closed. Only valid if memory has not yet been released. */
|
||||
int us_socket_is_closed(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Returns 1 if the TLS handshake has completed, 0 otherwise. For non-SSL sockets, always returns 1. */
|
||||
int us_socket_is_ssl_handshake_finished(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Returns 1 if the TLS handshake callback has been invoked, 0 otherwise. For non-SSL sockets, always returns 1. */
|
||||
int us_socket_ssl_handshake_callback_has_fired(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Immediately closes the socket */
|
||||
struct us_socket_t *us_socket_close(int ssl, us_socket_r s, int code, void *reason) __attribute__((nonnull(2)));
|
||||
|
||||
|
||||
@@ -128,6 +128,26 @@ int us_socket_is_closed(int ssl, struct us_socket_t *s) {
|
||||
return s->flags.is_closed;
|
||||
}
|
||||
|
||||
int us_socket_is_ssl_handshake_finished(int ssl, struct us_socket_t *s) {
|
||||
#ifndef LIBUS_NO_SSL
|
||||
if(ssl) {
|
||||
return us_internal_ssl_socket_is_handshake_finished((struct us_internal_ssl_socket_t *) s);
|
||||
}
|
||||
#endif
|
||||
// Non-SSL sockets are always "handshake finished"
|
||||
return 1;
|
||||
}
|
||||
|
||||
int us_socket_ssl_handshake_callback_has_fired(int ssl, struct us_socket_t *s) {
|
||||
#ifndef LIBUS_NO_SSL
|
||||
if(ssl) {
|
||||
return us_internal_ssl_socket_handshake_callback_has_fired((struct us_internal_ssl_socket_t *) s);
|
||||
}
|
||||
#endif
|
||||
// Non-SSL sockets are always "callback fired"
|
||||
return 1;
|
||||
}
|
||||
|
||||
int us_connecting_socket_is_closed(int ssl, struct us_connecting_socket_t *c) {
|
||||
return c->closed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user