rack 1.4.1 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/COPYING +1 -1
- data/KNOWN-ISSUES +9 -0
- data/README.rdoc +72 -7
- data/Rakefile +18 -11
- data/SPEC +3 -1
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +150 -0
- data/contrib/rdoc.css +412 -0
- data/lib/rack/auth/basic.rb +1 -1
- data/lib/rack/auth/digest/nonce.rb +1 -1
- data/lib/rack/backports/uri/common_18.rb +14 -28
- data/lib/rack/backports/uri/common_192.rb +14 -17
- data/lib/rack/backports/uri/common_193.rb +29 -0
- data/lib/rack/body_proxy.rb +10 -0
- data/lib/rack/builder.rb +1 -1
- data/lib/rack/cascade.rb +11 -0
- data/lib/rack/commonlogger.rb +18 -5
- data/lib/rack/deflater.rb +5 -1
- data/lib/rack/directory.rb +1 -1
- data/lib/rack/etag.rb +6 -3
- data/lib/rack/file.rb +13 -4
- data/lib/rack/head.rb +1 -0
- data/lib/rack/lint.rb +3 -1
- data/lib/rack/lock.rb +3 -4
- data/lib/rack/mime.rb +1 -1
- data/lib/rack/mock.rb +3 -2
- data/lib/rack/multipart.rb +2 -2
- data/lib/rack/multipart/parser.rb +6 -4
- data/lib/rack/reloader.rb +1 -1
- data/lib/rack/request.rb +2 -4
- data/lib/rack/response.rb +2 -1
- data/lib/rack/server.rb +28 -2
- data/lib/rack/session/abstract/id.rb +5 -0
- data/lib/rack/session/cookie.rb +9 -0
- data/lib/rack/static.rb +90 -8
- data/lib/rack/utils.rb +17 -10
- data/rack.gemspec +3 -3
- data/test/builder/line.ru +1 -0
- data/test/cgi/assets/folder/test.js +1 -0
- data/test/cgi/assets/fonts/font.eot +1 -0
- data/test/cgi/assets/images/image.png +1 -0
- data/test/cgi/assets/index.html +1 -0
- data/test/cgi/assets/javascripts/app.js +1 -0
- data/test/cgi/assets/stylesheets/app.css +1 -0
- data/test/spec_auth_basic.rb +8 -0
- data/test/spec_auth_digest.rb +14 -0
- data/test/spec_body_proxy.rb +4 -0
- data/test/spec_builder.rb +7 -1
- data/test/spec_cascade.rb +8 -0
- data/test/spec_chunked.rb +6 -6
- data/test/spec_config.rb +0 -1
- data/test/spec_content_length.rb +26 -13
- data/test/spec_content_type.rb +15 -5
- data/test/spec_deflater.rb +35 -17
- data/test/spec_directory.rb +20 -1
- data/test/spec_etag.rb +29 -13
- data/test/spec_file.rb +42 -25
- data/test/spec_head.rb +25 -7
- data/test/spec_lobster.rb +20 -5
- data/test/spec_lock.rb +46 -21
- data/test/spec_logger.rb +2 -7
- data/test/spec_methodoverride.rb +21 -22
- data/test/spec_mock.rb +12 -7
- data/test/spec_multipart.rb +29 -0
- data/test/spec_nulllogger.rb +13 -2
- data/test/spec_recursive.rb +12 -9
- data/test/spec_request.rb +2 -2
- data/test/spec_response.rb +30 -0
- data/test/spec_runtime.rb +15 -5
- data/test/spec_sendfile.rb +11 -8
- data/test/spec_server.rb +47 -0
- data/test/spec_session_cookie.rb +68 -1
- data/test/spec_session_memcache.rb +10 -8
- data/test/spec_session_pool.rb +13 -10
- data/test/spec_showexceptions.rb +9 -4
- data/test/spec_showstatus.rb +10 -5
- data/test/spec_static.rb +85 -9
- data/test/spec_urlmap.rb +10 -10
- data/test/spec_utils.rb +14 -1
- data/test/static/another/index.html +1 -0
- metadata +21 -8
data/lib/rack/auth/basic.rb
CHANGED
@@ -8,7 +8,21 @@
|
|
8
8
|
|
9
9
|
module URI
|
10
10
|
TBLENCWWWCOMP_ = {} # :nodoc:
|
11
|
+
256.times do |i|
|
12
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
13
|
+
end
|
14
|
+
TBLENCWWWCOMP_[' '] = '+'
|
15
|
+
TBLENCWWWCOMP_.freeze
|
11
16
|
TBLDECWWWCOMP_ = {} # :nodoc:
|
17
|
+
256.times do |i|
|
18
|
+
h, l = i>>4, i&15
|
19
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
20
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
21
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
22
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
23
|
+
end
|
24
|
+
TBLDECWWWCOMP_['+'] = ' '
|
25
|
+
TBLDECWWWCOMP_.freeze
|
12
26
|
|
13
27
|
# Encode given +s+ to URL-encoded form data.
|
14
28
|
#
|
@@ -26,18 +40,6 @@ module URI
|
|
26
40
|
'%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
|
27
41
|
end.tr(' ', '+')
|
28
42
|
else
|
29
|
-
if TBLENCWWWCOMP_.empty?
|
30
|
-
tbl = {}
|
31
|
-
256.times do |i|
|
32
|
-
tbl[i.chr] = '%%%02X' % i
|
33
|
-
end
|
34
|
-
tbl[' '] = '+'
|
35
|
-
begin
|
36
|
-
TBLENCWWWCOMP_.replace(tbl)
|
37
|
-
TBLENCWWWCOMP_.freeze
|
38
|
-
rescue
|
39
|
-
end
|
40
|
-
end
|
41
43
|
str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
|
42
44
|
end
|
43
45
|
end
|
@@ -48,22 +50,6 @@ module URI
|
|
48
50
|
#
|
49
51
|
# See URI.encode_www_form_component, URI.decode_www_form
|
50
52
|
def self.decode_www_form_component(str, enc=nil)
|
51
|
-
if TBLDECWWWCOMP_.empty?
|
52
|
-
tbl = {}
|
53
|
-
256.times do |i|
|
54
|
-
h, l = i>>4, i&15
|
55
|
-
tbl['%%%X%X' % [h, l]] = i.chr
|
56
|
-
tbl['%%%x%X' % [h, l]] = i.chr
|
57
|
-
tbl['%%%X%x' % [h, l]] = i.chr
|
58
|
-
tbl['%%%x%x' % [h, l]] = i.chr
|
59
|
-
end
|
60
|
-
tbl['+'] = ' '
|
61
|
-
begin
|
62
|
-
TBLDECWWWCOMP_.replace(tbl)
|
63
|
-
TBLDECWWWCOMP_.freeze
|
64
|
-
rescue
|
65
|
-
end
|
66
|
-
end
|
67
53
|
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%[0-9a-fA-F]{2}|[^%])*\z/ =~ str
|
68
54
|
str.gsub(/\+|%[0-9a-fA-F]{2}/) {|m| TBLDECWWWCOMP_[m]}
|
69
55
|
end
|
@@ -17,6 +17,19 @@
|
|
17
17
|
require 'uri/common'
|
18
18
|
|
19
19
|
module URI
|
20
|
+
TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
|
21
|
+
if TBLDECWWWCOMP_.empty?
|
22
|
+
256.times do |i|
|
23
|
+
h, l = i>>4, i&15
|
24
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
25
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
26
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
27
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
28
|
+
end
|
29
|
+
TBLDECWWWCOMP_['+'] = ' '
|
30
|
+
TBLDECWWWCOMP_.freeze
|
31
|
+
end
|
32
|
+
|
20
33
|
def self.decode_www_form(str, enc=Encoding::UTF_8)
|
21
34
|
return [] if str.empty?
|
22
35
|
unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
|
@@ -30,26 +43,10 @@ module URI
|
|
30
43
|
end
|
31
44
|
|
32
45
|
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
|
33
|
-
if TBLDECWWWCOMP_.empty?
|
34
|
-
tbl = {}
|
35
|
-
256.times do |i|
|
36
|
-
h, l = i>>4, i&15
|
37
|
-
tbl['%%%X%X' % [h, l]] = i.chr
|
38
|
-
tbl['%%%x%X' % [h, l]] = i.chr
|
39
|
-
tbl['%%%X%x' % [h, l]] = i.chr
|
40
|
-
tbl['%%%x%x' % [h, l]] = i.chr
|
41
|
-
end
|
42
|
-
tbl['+'] = ' '
|
43
|
-
begin
|
44
|
-
TBLDECWWWCOMP_.replace(tbl)
|
45
|
-
TBLDECWWWCOMP_.freeze
|
46
|
-
rescue
|
47
|
-
end
|
48
|
-
end
|
49
46
|
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
|
50
47
|
str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
|
51
48
|
end
|
52
49
|
|
53
|
-
remove_const :WFKV_
|
50
|
+
remove_const :WFKV_ if const_defined?(:WFKV_)
|
54
51
|
WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
|
55
52
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
|
3
|
+
require 'uri/common'
|
4
|
+
|
5
|
+
# Issue:
|
6
|
+
# http://bugs.ruby-lang.org/issues/5925
|
7
|
+
#
|
8
|
+
# Relevant commit:
|
9
|
+
# https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
|
10
|
+
|
11
|
+
module URI
|
12
|
+
256.times do |i|
|
13
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
14
|
+
end
|
15
|
+
TBLENCWWWCOMP_[' '] = '+'
|
16
|
+
TBLENCWWWCOMP_.freeze
|
17
|
+
|
18
|
+
256.times do |i|
|
19
|
+
h, l = i>>4, i&15
|
20
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
21
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
22
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
23
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
24
|
+
end
|
25
|
+
TBLDECWWWCOMP_['+'] = ' '
|
26
|
+
TBLDECWWWCOMP_.freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
# :startdoc:
|
data/lib/rack/body_proxy.rb
CHANGED
@@ -5,6 +5,7 @@ module Rack
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def respond_to?(*args)
|
8
|
+
return false if args.first.to_s =~ /^to_ary$/
|
8
9
|
super or @body.respond_to?(*args)
|
9
10
|
end
|
10
11
|
|
@@ -22,7 +23,16 @@ module Rack
|
|
22
23
|
@closed
|
23
24
|
end
|
24
25
|
|
26
|
+
# N.B. This method is a special case to address the bug described by #434.
|
27
|
+
# We are applying this special case for #each only. Future bugs of this
|
28
|
+
# class will be handled by requesting users to patch their ruby
|
29
|
+
# implementation, to save adding too many methods in this class.
|
30
|
+
def each(*args, &block)
|
31
|
+
@body.each(*args, &block)
|
32
|
+
end
|
33
|
+
|
25
34
|
def method_missing(*args, &block)
|
35
|
+
super if args.first.to_s =~ /^to_ary$/
|
26
36
|
@body.__send__(*args, &block)
|
27
37
|
end
|
28
38
|
end
|
data/lib/rack/builder.rb
CHANGED
@@ -38,7 +38,7 @@ module Rack
|
|
38
38
|
end
|
39
39
|
cfgfile.sub!(/^__END__\n.*\Z/m, '')
|
40
40
|
app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
|
41
|
-
TOPLEVEL_BINDING, config
|
41
|
+
TOPLEVEL_BINDING, config, 0
|
42
42
|
else
|
43
43
|
require config
|
44
44
|
app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
data/lib/rack/cascade.rb
CHANGED
@@ -19,8 +19,19 @@ module Rack
|
|
19
19
|
def call(env)
|
20
20
|
result = NotFound
|
21
21
|
|
22
|
+
last_body = nil
|
23
|
+
|
22
24
|
@apps.each do |app|
|
25
|
+
# The SPEC says that the body must be closed after it has been iterated
|
26
|
+
# by the server, or if it is replaced by a middleware action. Cascade
|
27
|
+
# replaces the body each time a cascade happens. It is assumed that nil
|
28
|
+
# does not respond to close, otherwise the previous application body
|
29
|
+
# will be closed. The final application body will not be closed, as it
|
30
|
+
# will be passed to the server as a result.
|
31
|
+
last_body.close if last_body.respond_to? :close
|
32
|
+
|
23
33
|
result = app.call(env)
|
34
|
+
last_body = result[2]
|
24
35
|
break unless @catch.include?(result[0].to_i)
|
25
36
|
end
|
26
37
|
|
data/lib/rack/commonlogger.rb
CHANGED
@@ -1,13 +1,26 @@
|
|
1
1
|
require 'rack/body_proxy'
|
2
2
|
|
3
3
|
module Rack
|
4
|
-
# Rack::CommonLogger forwards every request to
|
5
|
-
# logs a line in the
|
6
|
-
#
|
4
|
+
# Rack::CommonLogger forwards every request to the given +app+, and
|
5
|
+
# logs a line in the
|
6
|
+
# {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
|
7
|
+
# to the +logger+.
|
8
|
+
#
|
9
|
+
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
10
|
+
# an instance of Rack::NullLogger.
|
11
|
+
#
|
12
|
+
# +logger+ can be any class, including the standard library Logger, and is
|
13
|
+
# expected to have a +write+ method, which accepts the CommonLogger::FORMAT.
|
14
|
+
# According to the SPEC, the error stream must also respond to +puts+
|
15
|
+
# (which takes a single argument that responds to +to_s+), and +flush+
|
16
|
+
# (which is called without arguments in order to make the error appear for
|
17
|
+
# sure)
|
7
18
|
class CommonLogger
|
8
19
|
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
9
|
-
#
|
10
|
-
#
|
20
|
+
#
|
21
|
+
# lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
|
22
|
+
#
|
23
|
+
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
11
24
|
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
12
25
|
|
13
26
|
def initialize(app, logger=nil)
|
data/lib/rack/deflater.rb
CHANGED
@@ -45,6 +45,7 @@ module Rack
|
|
45
45
|
when "identity"
|
46
46
|
[status, headers, body]
|
47
47
|
when nil
|
48
|
+
body.close if body.respond_to?(:close)
|
48
49
|
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
49
50
|
[406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]]
|
50
51
|
end
|
@@ -64,6 +65,7 @@ module Rack
|
|
64
65
|
gzip.write(part)
|
65
66
|
gzip.flush
|
66
67
|
}
|
68
|
+
ensure
|
67
69
|
@body.close if @body.respond_to?(:close)
|
68
70
|
gzip.close
|
69
71
|
@writer = nil
|
@@ -90,9 +92,11 @@ module Rack
|
|
90
92
|
def each
|
91
93
|
deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS)
|
92
94
|
@body.each { |part| yield deflater.deflate(part, Zlib::SYNC_FLUSH) }
|
93
|
-
@body.close if @body.respond_to?(:close)
|
94
95
|
yield deflater.finish
|
95
96
|
nil
|
97
|
+
ensure
|
98
|
+
@body.close if @body.respond_to?(:close)
|
99
|
+
deflater.close
|
96
100
|
end
|
97
101
|
end
|
98
102
|
end
|
data/lib/rack/directory.rb
CHANGED
@@ -80,7 +80,7 @@ table { width:100%%; }
|
|
80
80
|
@files = [['../','Parent Directory','','','']]
|
81
81
|
glob = F.join(@path, '*')
|
82
82
|
|
83
|
-
url_head = (
|
83
|
+
url_head = (@script_name.split('/') + @path_info.split('/')).map do |part|
|
84
84
|
Rack::Utils.escape part
|
85
85
|
end
|
86
86
|
|
data/lib/rack/etag.rb
CHANGED
@@ -28,8 +28,11 @@ module Rack
|
|
28
28
|
end
|
29
29
|
|
30
30
|
unless headers['Cache-Control']
|
31
|
-
|
32
|
-
|
31
|
+
if digest
|
32
|
+
headers['Cache-Control'] = @cache_control if @cache_control
|
33
|
+
else
|
34
|
+
headers['Cache-Control'] = @no_cache_control if @no_cache_control
|
35
|
+
end
|
33
36
|
end
|
34
37
|
|
35
38
|
[status, headers, body]
|
@@ -46,7 +49,7 @@ module Rack
|
|
46
49
|
end
|
47
50
|
|
48
51
|
def skip_caching?(headers)
|
49
|
-
headers['Cache-Control']
|
52
|
+
(headers['Cache-Control'] && headers['Cache-Control'].include?('no-cache')) ||
|
50
53
|
headers.key?('ETag') || headers.key?('Last-Modified')
|
51
54
|
end
|
52
55
|
|
data/lib/rack/file.rb
CHANGED
@@ -21,9 +21,16 @@ module Rack
|
|
21
21
|
|
22
22
|
alias :to_path :path
|
23
23
|
|
24
|
-
def initialize(root,
|
24
|
+
def initialize(root, headers={})
|
25
25
|
@root = root
|
26
|
-
|
26
|
+
# Allow a cache_control string for backwards compatibility
|
27
|
+
if headers.instance_of? String
|
28
|
+
warn \
|
29
|
+
"Rack::File headers parameter replaces cache_control after Rack 1.5."
|
30
|
+
@headers = { 'Cache-Control' => headers }
|
31
|
+
else
|
32
|
+
@headers = headers
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
def call(env)
|
@@ -78,7 +85,9 @@ module Rack
|
|
78
85
|
},
|
79
86
|
env["REQUEST_METHOD"] == "HEAD" ? [] : self
|
80
87
|
]
|
81
|
-
|
88
|
+
|
89
|
+
# Set custom headers
|
90
|
+
@headers.each { |field, content| response[1][field] = content } if @headers
|
82
91
|
|
83
92
|
# NOTE:
|
84
93
|
# We check via File::size? whether this file provides size info
|
@@ -101,7 +110,7 @@ module Rack
|
|
101
110
|
# Partial content:
|
102
111
|
@range = ranges[0]
|
103
112
|
response[0] = 206
|
104
|
-
response[1]["Content-Range"]
|
113
|
+
response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
|
105
114
|
size = @range.end - @range.begin + 1
|
106
115
|
end
|
107
116
|
|
data/lib/rack/head.rb
CHANGED
data/lib/rack/lint.rb
CHANGED
@@ -528,7 +528,9 @@ module Rack
|
|
528
528
|
## The Body itself should not be an instance of String, as this will
|
529
529
|
## break in Ruby 1.9.
|
530
530
|
##
|
531
|
-
## If the Body responds to +close+, it will be called after iteration.
|
531
|
+
## If the Body responds to +close+, it will be called after iteration. If
|
532
|
+
## the body is replaced by a middleware after action, the original body
|
533
|
+
## must be closed first, if it repsonds to close.
|
532
534
|
# XXX howto: assert("Body has not been closed") { @closed }
|
533
535
|
|
534
536
|
|
data/lib/rack/lock.rb
CHANGED
@@ -13,12 +13,11 @@ module Rack
|
|
13
13
|
old, env[FLAG] = env[FLAG], false
|
14
14
|
@mutex.lock
|
15
15
|
response = @app.call(env)
|
16
|
-
|
16
|
+
body = BodyProxy.new(response[2]) { @mutex.unlock }
|
17
|
+
response[2] = body
|
17
18
|
response
|
18
|
-
rescue Exception
|
19
|
-
@mutex.unlock
|
20
|
-
raise
|
21
19
|
ensure
|
20
|
+
@mutex.unlock unless body
|
22
21
|
env[FLAG] = old
|
23
22
|
end
|
24
23
|
end
|
data/lib/rack/mime.rb
CHANGED
@@ -598,7 +598,7 @@ module Rack
|
|
598
598
|
".wmv" => "video/x-ms-wmv",
|
599
599
|
".wmx" => "video/x-ms-wmx",
|
600
600
|
".wmz" => "application/x-ms-wmz",
|
601
|
-
".woff" => "application/
|
601
|
+
".woff" => "application/font-woff",
|
602
602
|
".wpd" => "application/vnd.wordperfect",
|
603
603
|
".wpl" => "application/vnd.ms-wpl",
|
604
604
|
".wps" => "application/vnd.ms-works",
|
data/lib/rack/mock.rb
CHANGED
@@ -9,12 +9,12 @@ module Rack
|
|
9
9
|
# Rack::MockRequest helps testing your Rack application without
|
10
10
|
# actually using HTTP.
|
11
11
|
#
|
12
|
-
# After performing a request on a URL with get/post/put/delete, it
|
12
|
+
# After performing a request on a URL with get/post/put/patch/delete, it
|
13
13
|
# returns a MockResponse with useful helper methods for effective
|
14
14
|
# testing.
|
15
15
|
#
|
16
16
|
# You can pass a hash with additional configuration to the
|
17
|
-
# get/post/put/delete.
|
17
|
+
# get/post/put/patch/delete.
|
18
18
|
# <tt>:input</tt>:: A String or IO-like to be used as rack.input.
|
19
19
|
# <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
|
20
20
|
# <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
|
@@ -56,6 +56,7 @@ module Rack
|
|
56
56
|
def get(uri, opts={}) request("GET", uri, opts) end
|
57
57
|
def post(uri, opts={}) request("POST", uri, opts) end
|
58
58
|
def put(uri, opts={}) request("PUT", uri, opts) end
|
59
|
+
def patch(uri, opts={}) request("PATCH", uri, opts) end
|
59
60
|
def delete(uri, opts={}) request("DELETE", uri, opts) end
|
60
61
|
def head(uri, opts={}) request("HEAD", uri, opts) end
|
61
62
|
|
data/lib/rack/multipart.rb
CHANGED
@@ -12,7 +12,7 @@ module Rack
|
|
12
12
|
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
|
13
13
|
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
|
14
14
|
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
|
15
|
-
DISPPARM = /;\s*(#{TOKEN})=("(?:\\"|[^"])*"|#{TOKEN})
|
15
|
+
DISPPARM = /;\s*(#{TOKEN})=("(?:\\"|[^"])*"|#{TOKEN})/
|
16
16
|
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
|
17
17
|
BROKEN_QUOTED = /^#{CONDISP}.*;\sfilename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i
|
18
18
|
BROKEN_UNQUOTED = /^#{CONDISP}.*;\sfilename=(#{TOKEN})/i
|
@@ -31,4 +31,4 @@ module Rack
|
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
@@ -48,13 +48,15 @@ module Rack
|
|
48
48
|
@buf = ""
|
49
49
|
@params = Utils::KeySpaceConstrainedParams.new
|
50
50
|
|
51
|
-
@content_length = @env['CONTENT_LENGTH'].to_i
|
52
51
|
@io = @env['rack.input']
|
53
52
|
@io.rewind
|
54
53
|
|
55
54
|
@boundary_size = Utils.bytesize(@boundary) + EOL.size
|
56
55
|
|
57
|
-
@content_length
|
56
|
+
if @content_length = @env['CONTENT_LENGTH']
|
57
|
+
@content_length = @content_length.to_i
|
58
|
+
@content_length -= @boundary_size
|
59
|
+
end
|
58
60
|
true
|
59
61
|
end
|
60
62
|
|
@@ -104,11 +106,11 @@ module Rack
|
|
104
106
|
body << @buf.slice!(0, @buf.size - (@boundary_size+4))
|
105
107
|
end
|
106
108
|
|
107
|
-
content = @io.read(BUFSIZE
|
109
|
+
content = @io.read(@content_length && BUFSIZE >= @content_length ? @content_length : BUFSIZE)
|
108
110
|
raise EOFError, "bad content body" if content.nil? || content.empty?
|
109
111
|
|
110
112
|
@buf << content
|
111
|
-
@content_length -= content.size
|
113
|
+
@content_length -= content.size if @content_length
|
112
114
|
end
|
113
115
|
|
114
116
|
[head, filename, content_type, name, body]
|