summary refs log tree commit
diff options
context:
space:
mode:
-rw-r--r--lib/rack/multipart/parser.rb20
-rw-r--r--test/spec_multipart.rb9
2 files changed, 21 insertions, 8 deletions
diff --git a/lib/rack/multipart/parser.rb b/lib/rack/multipart/parser.rb
index fa90ca96..faa98c7e 100644
--- a/lib/rack/multipart/parser.rb
+++ b/lib/rack/multipart/parser.rb
@@ -18,10 +18,13 @@ module Rack
         content_length = env['CONTENT_LENGTH']
         content_length = content_length.to_i if content_length
 
-        new($1, io, content_length, env)
+        tempfile = env['rack.multipart.tempfile_factory'] || lambda { |filename, content_type| Tempfile.new("RackMultipart") }
+        bufsize = env['rack.multipart.buffer_size'] || BUFSIZE
+
+        new($1, io, content_length, env, tempfile, bufsize)
       end
 
-      def initialize(boundary, io, content_length, env)
+      def initialize(boundary, io, content_length, env, tempfile, bufsize)
         @buf            = ""
 
         if @buf.respond_to? :force_encoding
@@ -34,6 +37,8 @@ module Rack
         @content_length = content_length
         @boundary_size  = Utils.bytesize(@boundary) + EOL.size
         @env = env
+        @tempfile       = tempfile
+        @bufsize        = bufsize
 
         if @content_length
           @content_length -= @boundary_size
@@ -86,7 +91,7 @@ module Rack
 
       def fast_forward_to_first_boundary
         loop do
-          content = @io.read(BUFSIZE)
+          content = @io.read(@bufsize)
           raise EOFError, "bad content body" unless content
           @buf << content
 
@@ -95,7 +100,7 @@ module Rack
             return if read_buffer == full_boundary
           end
 
-          raise EOFError, "bad content body" if Utils.bytesize(@buf) >= BUFSIZE
+          raise EOFError, "bad content body" if Utils.bytesize(@buf) >= @bufsize
         end
       end
 
@@ -125,8 +130,7 @@ module Rack
             end
 
             if filename
-              extname = ::File.extname(filename)
-              (@env['rack.tempfiles'] ||= []) << body = Tempfile.new(["RackMultipart", extname])
+              (@env['rack.tempfiles'] ||= []) << body = @tempfile.call(filename, content_type)
               body.binmode  if body.respond_to?(:binmode)
             end
 
@@ -138,7 +142,7 @@ module Rack
             body << @buf.slice!(0, @buf.size - (@boundary_size+4))
           end
 
-          content = @io.read(@content_length && BUFSIZE >= @content_length ? @content_length : BUFSIZE)
+          content = @io.read(@content_length && @bufsize >= @content_length ? @content_length : @bufsize)
           raise EOFError, "bad content body"  if content.nil? || content.empty?
 
           @buf << content
@@ -223,7 +227,7 @@ module Rack
           # filename is blank which means no file has been selected
           return
         elsif filename
-          body.rewind
+          body.rewind if body.respond_to?(:rewind)
 
           # Take the basename of the upload's original filename.
           # This handles the full Windows paths given by Internet Explorer
diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb
index ca733dae..327c6a2a 100644
--- a/test/spec_multipart.rb
+++ b/test/spec_multipart.rb
@@ -171,6 +171,15 @@ describe Rack::Multipart do
     params["file1.txt"][:tempfile].read.should.equal "contents"
   end
 
+  should "parse multipart upload file using custom tempfile class" do
+    env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
+    my_tempfile = ""
+    env['rack.multipart.tempfile_factory'] = lambda { |filename, content_type| my_tempfile }
+    params = Rack::Multipart.parse_multipart(env)
+    params["files"][:tempfile].object_id.should.equal my_tempfile.object_id
+    my_tempfile.should.equal "contents"
+  end
+
   should "parse multipart upload with nested parameters" do
     env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
     params = Rack::Multipart.parse_multipart(env)