diff --git a/.rubocop.yml b/.rubocop.yml index 2cab121..0c57a91 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -28,6 +28,10 @@ Metrics/BlockLength: - spec/**/* - rack-test.gemspec +# Rationale: Enforcing maximum module length makes code worse, without exception +Metrics/ModuleLength: + Enabled: false + # Rationale: allow Weirich-style blocks, but do not enforce them. Style/BlockDelimiters: Enabled: false diff --git a/lib/rack/test/uploaded_file.rb b/lib/rack/test/uploaded_file.rb index 7e9b5ca..925b7e5 100644 --- a/lib/rack/test/uploaded_file.rb +++ b/lib/rack/test/uploaded_file.rb @@ -49,6 +49,21 @@ def method_missing(method_name, *args, &block) #:nodoc: tempfile.public_send(method_name, *args, &block) end + # Append to given buffer in 64K chunks to avoid multiple large + # copies of file data in memory. Rewind tempfile before and + # after to make sure all data in tempfile is appended to the + # buffer. + def append_to(buffer) + tempfile.rewind + + buf = String.new + buffer << tempfile.readpartial(65_536, buf) until tempfile.eof? + + tempfile.rewind + + nil + end + def respond_to_missing?(method_name, include_private = false) #:nodoc: tempfile.respond_to?(method_name, include_private) || super end diff --git a/lib/rack/test/utils.rb b/lib/rack/test/utils.rb index 44d3dea..4cd48b3 100644 --- a/lib/rack/test/utils.rb +++ b/lib/rack/test/utils.rb @@ -125,14 +125,16 @@ def build_primitive_part(parameter_name, value) def build_file_part(parameter_name, uploaded_file) uploaded_file.set_encoding(Encoding::BINARY) if uploaded_file.respond_to?(:set_encoding) - <<-EOF + buffer = String.new + buffer << (<<-EOF) --#{MULTIPART_BOUNDARY}\r Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape_path(uploaded_file.original_filename)}"\r Content-Type: #{uploaded_file.content_type}\r Content-Length: #{uploaded_file.size}\r \r -#{uploaded_file.read}\r EOF + uploaded_file.append_to(buffer) + buffer << "\r\n" end module_function :build_file_part end diff --git a/spec/rack/test/utils_spec.rb b/spec/rack/test/utils_spec.rb index a841017..6429669 100644 --- a/spec/rack/test/utils_spec.rb +++ b/spec/rack/test/utils_spec.rb @@ -73,7 +73,8 @@ params = Rack::Multipart.parse_multipart(env) check expect(params['submit-name']).to eq('Larry') check expect(params['files'][:filename]).to eq('foo.txt') - expect(params['files'][:tempfile].read).to eq("bar\n") + expect(files.pos).to eq(0) + expect(params['files'][:tempfile].read).to eq(files.read) end it 'builds multipart bodies from array of files' do