Skip to content

fix: prevent connection hang when Login7 response is interrupted#1736

Open
arthurschreiber wants to merge 1 commit into
masterfrom
fix-login7-response-hang
Open

fix: prevent connection hang when Login7 response is interrupted#1736
arthurschreiber wants to merge 1 commit into
masterfrom
fix-login7-response-hang

Conversation

@arthurschreiber

Copy link
Copy Markdown
Collaborator

performSentLogin7WithStandardLogin awaited the token stream parser's end event without racing it against the abort signal, unlike the NTLM, federated authentication, and initial SQL login paths. If the socket errored, half-closed, or stalled after the first packet of the login response but before the response message was complete, the parser would never emit end. The abort signal (from a socket failure or the connect timeout) had no effect at that point, so connect() would never invoke its callback and the connection would hang forever.

Race the parser's end event against the abort signal, matching the other login paths. The federated authentication flow also benefits, as it delegates to this method after sending the federated authentication token.

`performSentLogin7WithStandardLogin` awaited the token stream parser's
`end` event without racing it against the abort signal, unlike the
NTLM, federated authentication, and initial SQL login paths. If the
socket errored, half-closed, or stalled after the first packet of the
login response but before the response message was complete, the
parser would never emit `end`. The abort signal (from a socket failure
or the connect timeout) had no effect at that point, so `connect()`
would never invoke its callback and the connection would hang forever.

Race the parser's `end` event against the abort signal, matching the
other login paths. The federated authentication flow also benefits, as
it delegates to this method after sending the federated authentication
token.
@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown

Code Review

Overview

This PR fixes a genuine connection hang bug in performSentLogin7WithStandardLogin. Before the fix, if the socket stalled or errored after the first (non-EOM) Login7 response packet, await once(tokenStreamParser, 'end') would block forever — the abort signal had no effect on it. The change races the parser's end event against signalAborted, exactly as the NTLM, federated auth, and initial-SQL login paths already do. The fix is small, correct, and consistent with the established pattern.


Production Code (src/connection.ts)

The fix is correct. signalAborted is already properly set up at the top of the method (line 3420–3423) and torn down in the finally block, so adding it to the Promise.race here works without any additional plumbing. The pattern is identical to the equivalent lines in performSentLogin7WithNTLMLogin (line 3476–3477), performSentLogin7WithFederatedAuthentication (3532–3533), and performLogin7WithInitialSQLRequest (3640–3641), which is exactly what the PR description claims.

One observation out of scope for this PR but worth flagging: line 3825 has a bare await once(tokenStreamParser, 'end') in the attention-token handler path. That code lives inside a socket event callback in a different state machine context and may not need the same treatment, but it's worth a second look to confirm it can't hang under similar conditions.


Tests (test/unit/connection-failure-test.ts)

Two new tests are added, targeting exactly the right scenarios:

  1. Socket abort mid-response — sends one non-EOM packet then destroys the socket. Verifies that connect() gets a ConnectionError with the expected 'Connection lost - socket hang up' message and cause.
  2. Response stall / connect timeout — sends one non-EOM packet then goes silent. Verifies that connect() gets a timeout error with code 'ETIMEOUT'.

The test structure follows the existing conventions in the file exactly (mock server, IncomingMessageStream/OutgoingMessageStream, messageIterator, etc.). Using new Packet(0x04) directly to construct a packet without the EOM status bit is the right way to simulate an incomplete response.

Minor nits (non-blocking):

  • Both new tests (and several pre-existing ones) declare const chunks: Buffer[] = [] and push into it inside for await loops, but never actually read the accumulated data. The loop is necessary to drain the message stream so messageIterator.next() can proceed — the variable just adds visual noise. Consider for await (const _ of message) {} or a // drain comment to make the intent clearer. This is consistent with the existing file style, so it is a low-priority cleanup.
  • console.log(err) in the server-side catch blocks is a pre-existing pattern throughout the test file; it is fine for test diagnostics.
  • connectTimeout: 1000 in the stall test means it takes a full second to run. That is the minimum needed to avoid flakiness, so it is the right call.

Summary

The bug fix is correct, minimal, and well-motivated. The two new tests provide solid regression coverage for both failure modes (hard abort and soft stall). The import { Packet } addition is the only structural change needed and is scoped correctly. No issues blocking merge.

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.66%. Comparing base (2035eda) to head (a2eb626).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1736      +/-   ##
==========================================
+ Coverage   78.82%   79.66%   +0.83%     
==========================================
  Files          90       90              
  Lines        4892     4892              
  Branches      922      922              
==========================================
+ Hits         3856     3897      +41     
+ Misses        737      692      -45     
- Partials      299      303       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant