Skip to content
Browse files

better multipart handling

  • Loading branch information...
1 parent 3690709 commit 6674f3652ed19136802a0b84f1923f0b78052442 eTM committed with chneukirchen Apr 11, 2009
Showing with 26 additions and 6 deletions.
  1. +15 −1 lib/rack/request.rb
  2. +11 −5 lib/rack/utils.rb
View
16 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)
View
16 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

1 comment on commit 6674f36

@josh
josh commented on 6674f36 Apr 11, 2009

Probably should include at least one test case for “multipart/related” uploads.

Please sign in to comment.
Something went wrong with that request. Please try again.