[Explanation of bug for those who are interested; I will attach a test case for QA in the next comment]
The links from the original report are broken, so I created a test extension.
To rule out any server-side influences, I also created a server that just shows the number of uploaded bytes (without parsing the form data).
I can reproduce on Firefox 65.0.2 and Firefox Nightly 68.0a1 buildID 20190321104132
The bug is more likely to occur for larger files.
I can barely reproduce the problem on localhost. Hosting the server on a different computer in my network with an upload speed capped at 80 Mbps increases the rate of reproduction (e.g. reproduced with a 100 MB file at localhost, but failed to reproduce with 4 MB at localhost after 1.8 million attempts).
The number of missing bytes depends on the size of the file.
The number of missing bytes is consistent for uploads of the same size.
The number of missing bytes seems to be around 64 (ranging from 62 to 65).
In Wireshark, I can see that the file itself has completely been uploaded, but the closing boundary of the multipart message is missing.
Example of failed request (test file created using
seq -f "%9.f" 1 1000000):
POST / HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------8612789758546048021637194161
Content-Disposition: form-data; name="file"; filename="tenfile.bin"
The size of the above request body is 10 000 171, 62 bytes are missing. Namely the following:
The chunk is supposedly generated by
FSMultipartFormData::GetSubmissionBody and appended as a separate stream to the list of upload streams.
When I add an input element,
<input name="afterfile" value="afterfile">, then I can see it in the
details.requestBody object of the
webRequest.onBeforeRequest event, which suggests that the data loss is caused by the request body extraction of the webRequest API.
And indeed, the request body parser of
WebRequestUpload.jsm passes the input stream to a
ConverterInputStream, and assumes that the input stream is not mutated except for the seek offset.
This assumption is incorrect; when a
nsConverterInputStream is destructed / garbage-collected, the input stream is cleared.
WebRequestUpload.jsm also uses
nsBinaryInputStream, but that doesn't appear to invalidate the input stream upon destruction.
I'm going to look into the best way to fix it. A possible way to fix it is to simply not call
Close() in the
nsConverterInputStream destructor; another potential fix is to stop using
nsConverterInputStream since it's deprecated anyway.