Patch #33752
Uploading big files
Status: | New | Start date: | ||
---|---|---|---|---|
Priority: | Normal | Due date: | ||
Assignee: | - | % Done: | 0% | |
Category: | Attachments | |||
Target version: | Candidate for next minor release |
Description
Uploading of a file bigger than available RAM fails with no memory error. I've found the reason in request.raw_post which is String and doesn't respond to :read. Consequently, the whole file is read into memory. The attached patch simply replaces raw_post with body which is type of StringIO that provides read method.
History
#2
Updated by Pavel Rosický 6 months ago
- File attachments_test.rb.patch
added
Hi @Go MAEDA,
in my opinion, the fix in #10832 is wrong. It breaks the concept of streaming file uploads https://github.com/redmine/redmine/blob/master/app/models/attachment.rb#L126
however, the proposed patch breaks FCGI. I've attached a test case.
unlike other request handlers, CGI uses a rewindable input, that doesn't support the #size method. In theory, the only way how to determine the file size is to read the content first. The content should be streamed into a tempfile not into a memory.
https://github.com/rack/rack/blob/master/lib/rack/rewindable_input.rb
the second option is to rely on the CONTENT-LENGTH header, but it might not be accurate or it could be faked.
after some investigation, I found that Rails actually relies on the header
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb#L327
this means that FCGI is currently broken if an invalid CONTENT-LENGTH is provided. Note that most web-browsers and curl do send this header by default.
I'm wondering why anyone wants to use FCGI these days, they're definitely better options. We should try to fix it if possible, but the original patch #10832 broke other webservers that behave correctly.
#3
Updated by Karel Pičman 6 months ago
- File file_size.diff
added
I think that the problem with the size can be solved as suggested by Pavel by getting the size after data are stored into the filesystem. See the patch.
#5
Updated by Go MAEDA 5 months ago
A test is broken after applying big_files_upload.diff and file_size.diff.
Failure: Redmine::ApiTest::AttachmentsTest#test_POST_/uploads.xml_should_return_errors_if_file_is_too_big [test/integration/api_test/attachments_test.rb:207]: Expected response to be a <422: Unprocessable Entity>, but was a <201: Created> Response body: <?xml version="1.0" encoding="UTF-8"?><upload><id>24</id><token>24.1d1801f753ccd9fa57966c46f360585caf83337a394a5f238d4e4e7d6005788d</token></upload>. Expected: 422 Actual: 201 bin/rails test test/integration/api_test/attachments_test.rb:204
#6
Updated by Pavel Rosický 5 months ago
- File 10-patches.rb.patch
added
there're validations for size before the file is actually uploaded.
let's choose a simpler approach. These patches should be commited:
big_files_upload.diff
10-patches.rb.patch
attachments_test.rb.patch
it passes all tests.