-
I want to upload a file and stream the body directly to disk, without buffering the body in a I could not find anything in the documentation and not within Github discussions. My questions are the following:
My current assumption, please correct me if I am wrong: Only after Rack version 3.0, streaming a file directly to disk is possible, because it will be always written to Thank you in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
The input is not buffered on Falcon, so However, if you use multipart, this won't work as you imagine, since the multiple parts need to be buffered - this part is Rack. |
Beta Was this translation helpful? Give feedback.
-
With Apache+Passenger you can avoid this. Even with older software versions like ruby-2.5 and rack-2.0.8 on openSUSE-15.4.
Apache config: <VirtualHost *:80>
DocumentRoot /srv/www/htdocs/public
# Allow requests up to 4 GiB.
LimitRequestBody 4294967296
# "on" writes the body to: ${PassengerDataBufferDir}/buffer.XXXXXXXXXX
# On openSUSE-15.4 PassengerDataBufferDir is: /run
#
# That file will be invisible, because it's deleted and only the
# process "Passenger core" still has an open file descriptor
# for it.
# ls -lAhs /proc/$(pidof -s 'Passenger core')"/fd/
PassengerBufferUpload off
</VirtualHost>
Minimal app = Proc.new do |env|
request = Rack::Request.new(env)
# Will read all data to /tmp/PassengerTeeInput-* if
# "PassengerBufferUpload off" is set in Apache config.
# This is needed to make the data rewind'able. (method "rewind")
#
# This will NOT respect PassengerDataBufferDir. Instead it uses this:
# https://rubygems.org/gems/tmpdir
# require 'tmpdir'; Dir::tmpdir
#
# That file will be invisible, because it's deleted and only the
# process "Passenger RubyApp: /var/www/html (production)" still
# has an open file descriptor for it.
# ls -lAhs /proc/$(pidof -s 'Passenger RubyApp: /var/www/html (production)')"/fd/
#body_data = request.body
# Access underlying socket and read data directly without rewind.
body_data = request.body.instance_variable_get('@socket')
size = 0
while !body_data.eof? do
size += body_data.read(1024).size
end
[200, {'Content-Type' => 'text/plain'}, 'body size was: ' + size.to_s]
end
run(app) |
Beta Was this translation helpful? Give feedback.
The input is not buffered on Falcon, so
env['rack.input'].each{|chunk| ...}
will stream from the incoming request.However, if you use multipart, this won't work as you imagine, since the multiple parts need to be buffered - this part is Rack.