[Bug 296316] [libfetch] Fix POST upload truncation with fetchReqHTTP()
| Newsgroups | gmane.os.freebsd.bugs |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=296316
Bug ID: 296316
Summary: [libfetch] Fix POST upload truncation with
fetchReqHTTP()
Product: Base System
Version: 15.1-RELEASE
Hardware: Any
OS: Any
Status: New
Severity: Affects Only Me
Priority: ---
Component: bin
Assignee: [email protected]
Reporter: [email protected]
Created attachment 272175
--> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=272175&action=edit
Fix for the described problem
I noticed a regression in 15.1 that causes fetchReqHTTP() to get stuck when
uploading a file via HTTPS POST request. It worked fine with FreeBSD 15.0. A
small utility that I use was able to trigger that very reliable:
https://codeberg.org/decke/mrpt-upload/src/branch/main/mrpt-upload.c
I used Claude to analyze the truss output and generate a patch that works for
me:
fetch_writev() in lib/libfetch/common.c uses a non-blocking socket with
a poll-and-write loop. The inner poll loop is gated on pfd.revents == 0,
but pfd.revents is never reset after a successful write. On subsequent
iterations the poll is skipped and SSL_write() is called immediately
without checking socket readiness. When the send buffer is full and
SSL_write() returns -1 with errno == EAGAIN, the error is not retried
— the function returns -1, silently truncating the request body.
For unencrypted connections this is less likely to trigger because
writev() operates on all iovec entries at once. For SSL, SSL_write()
operates on a single iovec per call, making short writes and a
subsequent EAGAIN much more likely with large request bodies.
The result observed with fetchReqHTTP() over HTTPS is that the server
receives a truncated POST body, returns an error response, closes its
end of the connection, and fetch_writev() then hangs polling for a
response that never arrives — until fetchTimeout fires.
Fix: In the wlen < 0 branch of fetch_writev(), handle EAGAIN by
resetting pfd.revents = 0 and continuing the loop, re-engaging the poll
before retrying SSL_write().
--
You are receiving this mail because:
You are the assignee for the bug.