Skip to content

SSLSocket write and non-block fixes#354

Open
kares wants to merge 7 commits intomasterfrom
gem-error-minimal
Open

SSLSocket write and non-block fixes#354
kares wants to merge 7 commits intomasterfrom
gem-error-minimal

Conversation

@kares
Copy link
Copy Markdown
Member

@kares kares commented Apr 1, 2026

another attempt at (minimal) non-blocking read/write fixes

similar to #351 but wout test madness (tests are still not ideal but we can revisit those later)

includes #347

jsvd and others added 7 commits April 1, 2026 19:40
write() unconditionally called netWriteData.clear() after a non-blocking
flushData() that may not have flushed all encrypted bytes; discarding
unflushed TLS records, corrupting the encrypted stream and causing
'Broken pipe' or 'Connection reset' errors on subsequent writes (most
commonly seen during 'gem push' over https of large artifacts)

additionally, sysread needs to also flush pending writes before
reading since after write_nonblock, encrypted bytes could remain unsent;
without flushing first the server would never receive the complete
request body (e.g. net/http POST), causing it to time out or reset
`readAndUnwrap()` called doHandshake(blocking) assuming `exception = true`

When a post-handshake TLS event (e.g. TLS 1.3 NewSessionTicket) triggered
handshake during a non-blocking read, waitSelect raised SSLErrorWaitReadable
instead of returning :wait_readable.
- writeNonblockDataIntegrity: approximates the gem push scenario (#242)
  large payload via write_nonblock loop, then read server's byte count
  response, assert data integrity (no bytes lost)
- writeNonblockNetWriteDataState: saturates TCP buffer, then accesses
  the package-private netWriteData field directly to verify buffer
  consistency after the compact() fix
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.

OpenSSL::Buffering#read_nonblock(..., exception: false) can still throw exceptions gem push fails with Broken Pipe IOError

2 participants