diff --git a/lib/rack/request.rb b/lib/rack/request.rb index c1e272a61..0557837bb 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -92,6 +92,14 @@ def head?; request_method == "HEAD" end 'multipart/form-data' ] + # The set of media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + # Determine whether the request body contains form-data by checking # the request media_type against registered form-data media-types: # "application/x-www-form-urlencoded" and "multipart/form-data". The @@ -101,6 +109,12 @@ def form_data? FORM_DATA_MEDIA_TYPES.include?(media_type) end + # Determine whether the request body contains data by checking + # the request media_type against registered parse-data media-types + def parseable_data? + PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) + end + # Returns the data recieved in the query string. def GET if @env["rack.request.query_string"] == query_string @@ -119,7 +133,7 @@ def GET def POST if @env["rack.request.form_input"].eql? @env["rack.input"] @env["rack.request.form_hash"] - elsif form_data? + elsif form_data? || parseable_data? @env["rack.request.form_input"] = @env["rack.input"] unless @env["rack.request.form_hash"] = Utils::Multipart.parse_multipart(env) diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 7acc10d28..01519ef43 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -293,7 +293,7 @@ module Multipart def self.parse_multipart(env) unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n nil else boundary = "--#{$1}" @@ -319,15 +319,15 @@ def self.parse_multipart(env) filename = content_type = name = nil until head && buf =~ rx - if !head && i = buf.index("\r\n\r\n") + if !head && i = buf.index(EOL+EOL) head = buf.slice!(0, i+2) # First \r\n buf.slice!(0, 2) # Second \r\n filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)\r\n/ni, 1] - name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] - if filename + if content_type || filename body = Tempfile.new("RackMultipart") body.binmode if body.respond_to?(:binmode) end @@ -369,6 +369,12 @@ def self.parse_multipart(env) data = {:filename => filename, :type => content_type, :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} else data = body end