Skip to content

Commit

Permalink
Only handle encodings in extended parameter values
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewd committed Jul 18, 2015
1 parent 7125326 commit 384633c
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 15 deletions.
8 changes: 4 additions & 4 deletions lib/rack/multipart.rb
Expand Up @@ -19,19 +19,19 @@ module Multipart
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*\s+name="?([^\";]*)"?/ni
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
# Updated definitions from RFC 2231
ATTRIBUTE_CHAR = %r{[^ \t)(><@,;:\\"/\[\]?=]}
ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}
ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
SECTION = /\*[0-9]+/
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
EXTENDED_OTHER_PARAMETER = /#{EXTENDED_OTHER_NAME}=#{EXTENDED_OTHER_VALUE}*/
EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/
EXTENDED_INITIAL_PARAMETER = /#{EXTENDED_INITIAL_NAME}=#{EXTENDED_INITIAL_VALUE}/
EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/
EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/
DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})/
DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i

class << self
Expand Down
23 changes: 12 additions & 11 deletions lib/rack/multipart/parser.rb
Expand Up @@ -152,13 +152,16 @@ def get_current_head_and_filename_and_content_type_and_name_and_body
def get_filename(head)
filename = nil
case head
when RFC2183
params = Hash[*head.scan(DISPPARM).flat_map(&:compact)]

if filename = params['filename']
filename = $1 if filename =~ /^"(.*)"$/
elsif filename = params['filename*']
encoding, locale, filename = filename.split("'", 3)
end
when BROKEN_QUOTED, BROKEN_UNQUOTED
filename = $1
when RFC2183
params = Hash[head.scan(DISPPARM)]
filename = params['filename']
filename ||= params['filename*']
filename = $1 if filename and filename =~ /^"(.*)"$/
end

return unless filename
Expand All @@ -173,13 +176,11 @@ def get_filename(head)
filename = filename.gsub(/\\(.)/, '\1')
end

encoding, locale, name = filename.split("'",3)

if locale.nil? && name.nil?
name = encoding
else
name.force_encoding ::Encoding.find(encoding)
if encoding
filename.force_encoding ::Encoding.find(encoding)
end

filename
end

def scrub_filename(filename)
Expand Down
7 changes: 7 additions & 0 deletions test/multipart/filename_with_single_quote
@@ -0,0 +1,7 @@
--AaB03x
Content-Type: image/jpeg
Content-Disposition: attachment; name="files"; filename="bob's flowers.jpg"
Content-Description: a complete map of the human genome

contents
--AaB03x--
6 changes: 6 additions & 0 deletions test/spec_multipart.rb
Expand Up @@ -279,6 +279,12 @@ def initialize(*)
params["files"][:filename].must_equal "файл"
end

it "parse multipart form with a single quote in the filename" do
env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_single_quote)
params = Rack::Multipart.parse_multipart(env)
params["files"][:filename].must_equal "bob's flowers.jpg"
end

it "not include file params if no file was selected" do
env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
params = Rack::Multipart.parse_multipart(env)
Expand Down

0 comments on commit 384633c

Please sign in to comment.