THttpAsyncServer: fix HTTPS responses >64KB hanging on Windows IOCP+TLS#460
Conversation
|
Sounds like a clever investigation. But I don't see SSL_MODE_ENABLE_PARTIAL_WRITE and the other flag in the PR. |
|
You're right, I forgot to include it in the PR. Here is the missing change:
In TOpenSslNetTls.AfterAccept, right after fSsl := SSL_new(BoundContext.AcceptCert):
SSL_set_mode(fSsl, SSL_MODE_ENABLE_PARTIAL_WRITE or SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
Why it's needed:
Without SSL_MODE_ENABLE_PARTIAL_WRITE, when the TCP send buffer fills up, SSL_write returns -1 (WANT_WRITE) even though it has already sent some bytes (e.g. 4 TLS records = 65,536 bytes). mORMot doesn't know
how many bytes were actually written, so it copies the full buffer into fWr and retries.
On the retry (ProcessWrite), SSL_write is called with fWr.Buffer — a different pointer than the original — which violates OpenSSL's contract for retries without ACCEPT_MOVING_WRITE_BUFFER, leading to
undefined behavior and the hang.
SSL_MODE_ENABLE_PARTIAL_WRITE makes SSL_write return the actual number of bytes processed, so mORMot can advance the pointer and the next call is a clean new write. SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER covers
the residual retry case where the pointer has already changed.
All three fixes together are required to reliably send HTTPS responses larger than ~64 KB on Windows IOCP + TLS.
Best regards.
De: ab ***@***.***>
Enviado el: domingo, 12 de abril de 2026 23:40
Para: synopse/mORMot2 ***@***.***>
CC: robertomr1969 ***@***.***>; Author ***@***.***>
Asunto: Re: [synopse/mORMot2] THttpAsyncServer: fix HTTPS responses >64KB hanging on Windows IOCP+TLS (PR #460)
<https://avatars.githubusercontent.com/u/4548119?s=20&v=4> synopse left a comment (synopse/mORMot2#460) <#460 (comment)>
Sounds like a clever investigation.
But I don't see SSL_MODE_ENABLE_PARTIAL_WRITE and the other flag in the PR.
—
Reply to this email directly, view it on GitHub <#460 (comment)> , or unsubscribe <https://github.com/notifications/unsubscribe-auth/AJBSE6X3JG7QS7KM56TLUV34VQEMJAVCNFSM6AAAAACXWFGWWCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DEMZSG44TSNJQGE> .
You are receiving this because you authored the thread. <https://github.com/notifications/beacon/AJBSE6XP65YGVYO73EX5TJ34VQEMJBFCNFSM6AAAAACXWFGWWCWGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTX4JNSQ3JTSMVQXG33OUZQXK5DIN5ZA.gif> Message ID: ***@***.*** ***@***.***> >
|
|
Will this PR be merged? |
|
I am on holidays, AFK for a few days. |
|
About I am confused. It should not deadlock from the same thread, since TMultiLightLock takes the current thread ID into account, so it is reentrant. |
synopse
left a comment
There was a problem hiding this comment.
See my comment about the deadlock assumption.
|
Thanks for the review, and sorry for the delayed clarification. To answer your direct question: yes, this PR was drafted with significant AI assistance (Claude Code). I want to be upfront about that. However, the core technical claim — the OpenSSL contract violation — is independently verifiable and I believe it is real regardless of how it was found. On the SSL flags: If they are not visible in the diff, they are missing from the commit and that is a mistake in the PR. SSL_MODE_ENABLE_PARTIAL_WRITE is the most important fix. Without it, after the OS send buffer fills (~65KB on Windows), SSL_write returns WANT_WRITE and requires a retry with the exact same pointer and length. mORMot retries with fWr.Buffer which has already advanced — this violates the OpenSSL contract and causes the hang. This behavior is documented in the OpenSSL SSL_write man page. On ifSeparateWLock: I defer to your knowledge of TMultiLightLock. If it correctly handles the cross-thread read/write scenario between ProcessRead and Write(), then this change may be unnecessary. The SSL partial write fix alone may be sufficient to resolve the hang. I can strip ifSeparateWLock and ifWriteWait from the PR and submit only the SSL_MODE_ENABLE_PARTIAL_WRITE change if you prefer a minimal, reviewable fix. |
|
Yes, only the TLS part, please. |
Without SSL_MODE_ENABLE_PARTIAL_WRITE, SSL_write returns WANT_WRITE (not a partial byte count) when the OS send buffer fills (~65KB on Windows). mORMot then retries with fWr.Buffer which has already advanced, violating the OpenSSL contract that requires the same pointer/length on retry. The remaining data is never sent and the connection hangs indefinitely. SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is also set so mORMot can retry with a different buffer pointer after WANT_WRITE without triggering an error. Reproduces with HTTPS responses >64KB on Windows IOCP. Not reproduced on Linux (epoll path unaffected).
51beec8 to
d2943a4
Compare
|
PR actualized. |
Three bugs compound to prevent large TLS responses from being delivered:
Without these fixes, SSL_write sends 4 TLS records (~65KB) then returns
WANT_WRITE. mORMot retries with a different buffer pointer (fWr.Buffer),
violating OpenSSL contract. The remaining data is never delivered and
the connection hangs indefinitely.
Tested on Windows with a 103KB HTTPS JSON response. Not reproduced on
Linux (epoll path unaffected).