Skip to content

Commit b50bc8b

Browse files
aiomasterjeremyevans
authored andcommitted
Fix multipart parser for special files #1308
1 parent f9ef9a0 commit b50bc8b

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

lib/rack/multipart/parser.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def initialize(boundary, tempfile, bufsize, query_parser)
185185
@collector = Collector.new tempfile
186186

187187
@sbuf = StringScanner.new("".dup)
188-
@body_regex = /(.*?)(#{EOL})?#{Regexp.quote(@boundary)}(#{EOL}|--)/m
188+
@body_regex = /(?:#{EOL})?#{Regexp.quote(@boundary)}(?:#{EOL}|--)/m
189189
@rx_max_size = EOL.size + @boundary.bytesize + [EOL.size, '--'.size].max
190190
@head_regex = /(.*?#{EOL})#{EOL}/m
191191
end
@@ -268,8 +268,8 @@ def handle_mime_head
268268
end
269269

270270
def handle_mime_body
271-
if @sbuf.check_until(@body_regex) # check but do not advance the pointer yet
272-
body = @sbuf[1]
271+
if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet
272+
body = body_with_boundary.sub(/#{@body_regex}\z/m, '') # remove the boundary from the string
273273
@collector.on_mime_body @mime_index, body
274274
@sbuf.pos += body.length + 2 # skip \r\n after the content
275275
@state = :CONSUME_TOKEN

test/spec_multipart.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require 'rack/multipart/parser'
77
require 'rack/utils'
88
require 'rack/mock'
9+
require 'timeout'
910

1011
describe Rack::Multipart do
1112
def multipart_fixture(name, boundary = "AaB03x")
@@ -146,6 +147,31 @@ def rd.rewind; end
146147
wr.close
147148
end
148149

150+
# see https://github.com/rack/rack/pull/1309
151+
it "parse strange multipart pdf" do
152+
boundary = '---------------------------932620571087722842402766118'
153+
154+
data = StringIO.new
155+
data.write("--#{boundary}")
156+
data.write("\r\n")
157+
data.write('Content-Disposition: form-data; name="a"; filename="a.pdf"')
158+
data.write("\r\n")
159+
data.write("Content-Type:application/pdf\r\n")
160+
data.write("\r\n")
161+
data.write("-" * (1024 * 1024))
162+
data.write("\r\n")
163+
data.write("--#{boundary}--\r\n")
164+
165+
fixture = {
166+
"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}",
167+
"CONTENT_LENGTH" => data.length.to_s,
168+
:input => data,
169+
}
170+
171+
env = Rack::MockRequest.env_for '/', fixture
172+
Timeout::timeout(10) { Rack::Multipart.parse_multipart(env) }
173+
end
174+
149175
it 'raises an EOF error on content-length mistmatch' do
150176
env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
151177
env['rack.input'] = StringIO.new

0 commit comments

Comments
 (0)