rack 2.0.9 → 2.0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/HISTORY.md +15 -0
- data/README.rdoc +17 -3
- data/SPEC +7 -8
- data/lib/rack/common_logger.rb +3 -0
- data/lib/rack/lint.rb +1 -1
- data/lib/rack/multipart/parser.rb +18 -5
- data/lib/rack/multipart.rb +3 -4
- data/lib/rack/utils.rb +23 -11
- data/lib/rack.rb +1 -1
- data/test/cgi/test.gz +0 -0
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +1 -1
- data/test/spec_common_logger.rb +12 -0
- data/test/spec_lint.rb +5 -0
- data/test/spec_multipart.rb +13 -14
- data/test/spec_request.rb +17 -1
- metadata +47 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3418ae80f8de1427728a2e17364b9c8d124f2efb3e2ce6ebd2fbf6ba08c76efa
|
4
|
+
data.tar.gz: 2ba9cd20d9b168c583813b6c1e0d39cb6b8f33d110605b2c28c97dac60718cfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff2af28dd5b0b338c61d95eb793ac577098803374db893f739402ebd41ee75a1ebab4eba32474e2e68014475f0f5e71ad8fff3b4270fe3c9f281eaf3024c4b32
|
7
|
+
data.tar.gz: 6ebf297cb644ab382bcf02d3c0a7b4376223222ccaca426e093ecba02a4a9302324199ecd43788aa5f248b060f3c37a16fe820ebb9b46570dc2831627ef486d0
|
data/HISTORY.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
Thu Mar 2 14:50:46 2023 Aaron Patterson <tenderlove@ruby-lang.org>
|
2
|
+
|
3
|
+
* [CVE-2023-27530] Introduce multipart_total_part_limit to limit total parts
|
4
|
+
|
5
|
+
Tue Jan 17 12:27:04 2023 Aaron Patterson <tenderlove@ruby-lang.org>
|
6
|
+
|
7
|
+
* [CVE-2022-44571] Fix ReDoS vulnerability in multipart parser
|
8
|
+
* [CVE-2022-44570] Fix ReDoS in Rack::Utils.get_byte_ranges
|
9
|
+
* [CVE-2022-44572] Forbid control characters in attributes (also ReDoS)
|
10
|
+
|
11
|
+
Fri May 27 08:27:04 2022 Aaron Patterson <tenderlove@ruby-lang.org>
|
12
|
+
|
13
|
+
* [CVE-2022-30123] Fix shell escaping issue in Common Logger
|
14
|
+
* [CVE-2022-30122] Restrict parsing of broken MIME attachments
|
15
|
+
|
1
16
|
Sun Dec 4 18:48:03 2015 Jeremy Daer <jeremydaer@gmail.com>
|
2
17
|
|
3
18
|
* First-party "SameSite" cookies. Browsers omit SameSite cookies
|
data/README.rdoc
CHANGED
@@ -189,16 +189,30 @@ This helps prevent a rogue client from flooding a Request.
|
|
189
189
|
|
190
190
|
Default to 65536 characters (4 kiB in worst case).
|
191
191
|
|
192
|
-
===
|
192
|
+
=== multipart_file_limit
|
193
193
|
|
194
|
-
The maximum number of parts a request can contain.
|
194
|
+
The maximum number of parts with a filename a request can contain.
|
195
195
|
Accepting too many part can lead to the server running out of file handles.
|
196
196
|
|
197
197
|
The default is 128, which means that a single request can't upload more than 128 files at once.
|
198
198
|
|
199
199
|
Set to 0 for no limit.
|
200
200
|
|
201
|
-
Can also be set via the
|
201
|
+
Can also be set via the +RACK_MULTIPART_FILE_LIMIT+ environment variable.
|
202
|
+
|
203
|
+
(This is also aliased as +multipart_part_limit+ and +RACK_MULTIPART_PART_LIMIT+ for compatibility)
|
204
|
+
|
205
|
+
=== multipart_total_part_limit
|
206
|
+
|
207
|
+
The maximum total number of parts a request can contain of any type, including
|
208
|
+
both file and non-file form fields.
|
209
|
+
|
210
|
+
The default is 4096, which means that a single request can't contain more than
|
211
|
+
4096 parts.
|
212
|
+
|
213
|
+
Set to 0 for no limit.
|
214
|
+
|
215
|
+
Can also be set via the +RACK_MULTIPART_TOTAL_PART_LIMIT+ environment variable.
|
202
216
|
|
203
217
|
== History
|
204
218
|
|
data/SPEC
CHANGED
@@ -60,8 +60,8 @@ below.
|
|
60
60
|
the presence or absence of the
|
61
61
|
appropriate HTTP header in the
|
62
62
|
request. See
|
63
|
-
|
64
|
-
RFC3875 section 4.1.18
|
63
|
+
{https://tools.ietf.org/html/rfc3875#section-4.1.18
|
64
|
+
RFC3875 section 4.1.18} for
|
65
65
|
specific behavior.
|
66
66
|
In addition to this, the Rack environment must include these
|
67
67
|
Rack-specific variables:
|
@@ -98,13 +98,12 @@ Rack-specific variables:
|
|
98
98
|
Additional environment specifications have approved to
|
99
99
|
standardized middleware APIs. None of these are required to
|
100
100
|
be implemented by the server.
|
101
|
-
<tt>rack.session</tt>:: A hash like interface for storing
|
102
|
-
request session data.
|
101
|
+
<tt>rack.session</tt>:: A hash like interface for storing request session data.
|
103
102
|
The store must implement:
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
store(key, value) (aliased as []=);
|
104
|
+
fetch(key, default = nil) (aliased as []);
|
105
|
+
delete(key);
|
106
|
+
clear;
|
108
107
|
<tt>rack.logger</tt>:: A common object interface for logging messages.
|
109
108
|
The object must implement:
|
110
109
|
info(message, &block)
|
data/lib/rack/common_logger.rb
CHANGED
@@ -54,7 +54,10 @@ module Rack
|
|
54
54
|
length,
|
55
55
|
now - began_at ]
|
56
56
|
|
57
|
+
msg.gsub!(/[^[:print:]\n]/) { |c| "\\x#{c.ord}" }
|
58
|
+
|
57
59
|
logger = @logger || env[RACK_ERRORS]
|
60
|
+
|
58
61
|
# Standard library logger doesn't support write but it supports << which actually
|
59
62
|
# calls to write on the log device without formatting
|
60
63
|
if logger.respond_to?(:write)
|
data/lib/rack/lint.rb
CHANGED
@@ -295,7 +295,7 @@ module Rack
|
|
295
295
|
check_hijack env
|
296
296
|
|
297
297
|
## * The <tt>REQUEST_METHOD</tt> must be a valid token.
|
298
|
-
assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") {
|
298
|
+
assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD].dump}") {
|
299
299
|
env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/
|
300
300
|
}
|
301
301
|
|
@@ -3,6 +3,7 @@ require 'rack/utils'
|
|
3
3
|
module Rack
|
4
4
|
module Multipart
|
5
5
|
class MultipartPartLimitError < Errno::EMFILE; end
|
6
|
+
class MultipartTotalPartLimitError < StandardError; end
|
6
7
|
|
7
8
|
class Parser
|
8
9
|
BUFSIZE = 16384
|
@@ -138,7 +139,8 @@ module Rack
|
|
138
139
|
end
|
139
140
|
|
140
141
|
@mime_parts[mime_index] = klass.new(body, head, filename, content_type, name)
|
141
|
-
|
142
|
+
|
143
|
+
check_part_limits
|
142
144
|
end
|
143
145
|
|
144
146
|
def on_mime_body mime_index, content
|
@@ -150,13 +152,23 @@ module Rack
|
|
150
152
|
|
151
153
|
private
|
152
154
|
|
153
|
-
def
|
154
|
-
|
155
|
-
|
155
|
+
def check_part_limits
|
156
|
+
file_limit = Utils.multipart_file_limit
|
157
|
+
part_limit = Utils.multipart_total_part_limit
|
158
|
+
|
159
|
+
if file_limit && file_limit > 0
|
160
|
+
if @open_files >= file_limit
|
156
161
|
@mime_parts.each(&:close)
|
157
162
|
raise MultipartPartLimitError, 'Maximum file multiparts in content reached'
|
158
163
|
end
|
159
164
|
end
|
165
|
+
|
166
|
+
if part_limit && part_limit > 0
|
167
|
+
if @mime_parts.size >= part_limit
|
168
|
+
@mime_parts.each(&:close)
|
169
|
+
raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached'
|
170
|
+
end
|
171
|
+
end
|
160
172
|
end
|
161
173
|
end
|
162
174
|
|
@@ -302,8 +314,9 @@ module Rack
|
|
302
314
|
elsif filename = params['filename*']
|
303
315
|
encoding, _, filename = filename.split("'", 3)
|
304
316
|
end
|
305
|
-
when
|
317
|
+
when BROKEN
|
306
318
|
filename = $1
|
319
|
+
filename = $1 if filename =~ /^"(.*)"$/
|
307
320
|
end
|
308
321
|
|
309
322
|
return unless filename
|
data/lib/rack/multipart.rb
CHANGED
@@ -14,13 +14,12 @@ module Rack
|
|
14
14
|
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
|
15
15
|
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
|
16
16
|
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
|
17
|
-
|
18
|
-
BROKEN_UNQUOTED = /^#{CONDISP}.*;\sfilename=(#{TOKEN})/i
|
17
|
+
BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
|
19
18
|
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
|
20
|
-
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition
|
19
|
+
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s+name=(#{VALUE})/ni
|
21
20
|
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
|
22
21
|
# Updated definitions from RFC 2231
|
23
|
-
ATTRIBUTE_CHAR = %r{[^ \
|
22
|
+
ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]}
|
24
23
|
ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
|
25
24
|
SECTION = /\*[0-9]+/
|
26
25
|
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
|
data/lib/rack/utils.rb
CHANGED
@@ -53,13 +53,24 @@ module Rack
|
|
53
53
|
module_function :unescape
|
54
54
|
|
55
55
|
class << self
|
56
|
-
attr_accessor :
|
56
|
+
attr_accessor :multipart_total_part_limit
|
57
|
+
|
58
|
+
attr_accessor :multipart_file_limit
|
59
|
+
|
60
|
+
# multipart_part_limit is the original name of multipart_file_limit, but
|
61
|
+
# the limit only counts parts with filenames.
|
62
|
+
alias multipart_part_limit multipart_file_limit
|
63
|
+
alias multipart_part_limit= multipart_file_limit=
|
57
64
|
end
|
58
65
|
|
59
|
-
# The maximum number of parts a request can contain. Accepting too
|
60
|
-
# can lead to the server running out of file handles.
|
66
|
+
# The maximum number of file parts a request can contain. Accepting too
|
67
|
+
# many parts can lead to the server running out of file handles.
|
61
68
|
# Set to `0` for no limit.
|
62
|
-
self.
|
69
|
+
self.multipart_file_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_FILE_LIMIT'] || 128).to_i
|
70
|
+
|
71
|
+
# The maximum total number of parts a request can contain. Accepting too
|
72
|
+
# many can lead to excessive memory use and parsing time.
|
73
|
+
self.multipart_total_part_limit = (ENV['RACK_MULTIPART_TOTAL_PART_LIMIT'] || 4096).to_i
|
63
74
|
|
64
75
|
def self.param_depth_limit
|
65
76
|
default_query_parser.param_depth_limit
|
@@ -129,8 +140,8 @@ module Rack
|
|
129
140
|
module_function :build_nested_query
|
130
141
|
|
131
142
|
def q_values(q_value_header)
|
132
|
-
q_value_header.to_s.split(
|
133
|
-
value, parameters = part.split(
|
143
|
+
q_value_header.to_s.split(',').map do |part|
|
144
|
+
value, parameters = part.split(';', 2).map(&:strip)
|
134
145
|
quality = 1.0
|
135
146
|
if md = /\Aq=([\d.]+)/.match(parameters)
|
136
147
|
quality = md[1].to_f
|
@@ -365,17 +376,18 @@ module Rack
|
|
365
376
|
return nil unless http_range && http_range =~ /bytes=([^;]+)/
|
366
377
|
ranges = []
|
367
378
|
$1.split(/,\s*/).each do |range_spec|
|
368
|
-
return nil
|
369
|
-
|
370
|
-
|
371
|
-
|
379
|
+
return nil unless range_spec.include?('-')
|
380
|
+
range = range_spec.split('-')
|
381
|
+
r0, r1 = range[0], range[1]
|
382
|
+
if r0.nil? || r0.empty?
|
383
|
+
return nil if r1.nil?
|
372
384
|
# suffix-byte-range-spec, represents trailing suffix of file
|
373
385
|
r0 = size - r1.to_i
|
374
386
|
r0 = 0 if r0 < 0
|
375
387
|
r1 = size - 1
|
376
388
|
else
|
377
389
|
r0 = r0.to_i
|
378
|
-
if r1.
|
390
|
+
if r1.nil?
|
379
391
|
r1 = size - 1
|
380
392
|
else
|
381
393
|
r1 = r1.to_i
|
data/lib/rack.rb
CHANGED
data/test/cgi/test.gz
CHANGED
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
--AaB03x
|
2
2
|
Content-Type: image/jpeg
|
3
|
-
Content-Disposition: attachment; name="files"; filename=""human" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
|
3
|
+
Content-Disposition: attachment; name="files"; filename="\"human\" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
|
4
4
|
Content-Description: a complete map of the human genome
|
5
5
|
|
6
6
|
contents
|
data/test/spec_common_logger.rb
CHANGED
@@ -21,6 +21,10 @@ describe Rack::CommonLogger do
|
|
21
21
|
[200,
|
22
22
|
{"Content-Type" => "text/html", "Content-Length" => "0"},
|
23
23
|
[]]}
|
24
|
+
app_without_lint = lambda { |env|
|
25
|
+
[200,
|
26
|
+
{ "content-type" => "text/html", "content-length" => length.to_s },
|
27
|
+
[obj]]}
|
24
28
|
|
25
29
|
it "log to rack.errors by default" do
|
26
30
|
res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
|
@@ -85,6 +89,14 @@ describe Rack::CommonLogger do
|
|
85
89
|
(0..1).must_include duration.to_f
|
86
90
|
end
|
87
91
|
|
92
|
+
it "escapes non printable characters except newline" do
|
93
|
+
logdev = StringIO.new
|
94
|
+
log = Logger.new(logdev)
|
95
|
+
Rack::MockRequest.new(Rack::CommonLogger.new(app_without_lint, log)).request("GET\b", "/hello")
|
96
|
+
|
97
|
+
logdev.string.must_match(/GET\\x8 \/hello/)
|
98
|
+
end
|
99
|
+
|
88
100
|
def length
|
89
101
|
123
|
90
102
|
end
|
data/test/spec_lint.rb
CHANGED
@@ -96,6 +96,11 @@ describe Rack::Lint do
|
|
96
96
|
}.must_raise(Rack::Lint::LintError).
|
97
97
|
message.must_match(/REQUEST_METHOD/)
|
98
98
|
|
99
|
+
lambda {
|
100
|
+
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "OOPS?\b!"))
|
101
|
+
}.must_raise(Rack::Lint::LintError).
|
102
|
+
message.must_match(/OOPS\?\\/)
|
103
|
+
|
99
104
|
lambda {
|
100
105
|
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
|
101
106
|
}.must_raise(Rack::Lint::LintError).
|
data/test/spec_multipart.rb
CHANGED
@@ -381,19 +381,6 @@ describe Rack::Multipart do
|
|
381
381
|
params["files"][:tempfile].read.must_equal "contents"
|
382
382
|
end
|
383
383
|
|
384
|
-
it "parse filename with unescaped quotes" do
|
385
|
-
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_quotes))
|
386
|
-
params = Rack::Multipart.parse_multipart(env)
|
387
|
-
params["files"][:type].must_equal "application/octet-stream"
|
388
|
-
params["files"][:filename].must_equal "escape \"quotes"
|
389
|
-
params["files"][:head].must_equal "Content-Disposition: form-data; " +
|
390
|
-
"name=\"files\"; " +
|
391
|
-
"filename=\"escape \"quotes\"\r\n" +
|
392
|
-
"Content-Type: application/octet-stream\r\n"
|
393
|
-
params["files"][:name].must_equal "files"
|
394
|
-
params["files"][:tempfile].read.must_equal "contents"
|
395
|
-
end
|
396
|
-
|
397
384
|
it "parse filename with escaped quotes and modification param" do
|
398
385
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param))
|
399
386
|
params = Rack::Multipart.parse_multipart(env)
|
@@ -402,7 +389,7 @@ describe Rack::Multipart do
|
|
402
389
|
params["files"][:head].must_equal "Content-Type: image/jpeg\r\n" +
|
403
390
|
"Content-Disposition: attachment; " +
|
404
391
|
"name=\"files\"; " +
|
405
|
-
"filename=\"
|
392
|
+
"filename=\"\\\"human\\\" genome.jpeg\"; " +
|
406
393
|
"modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
|
407
394
|
"Content-Description: a complete map of the human genome\r\n"
|
408
395
|
params["files"][:name].must_equal "files"
|
@@ -561,6 +548,18 @@ Content-Type: image/jpeg\r
|
|
561
548
|
end
|
562
549
|
end
|
563
550
|
|
551
|
+
it "reach a multipart total limit" do
|
552
|
+
begin
|
553
|
+
previous_limit = Rack::Utils.multipart_total_part_limit
|
554
|
+
Rack::Utils.multipart_total_part_limit = 5
|
555
|
+
|
556
|
+
env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
|
557
|
+
lambda { Rack::Multipart.parse_multipart(env) }.must_raise Rack::Multipart::MultipartTotalPartLimitError
|
558
|
+
ensure
|
559
|
+
Rack::Utils.multipart_total_part_limit = previous_limit
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
564
563
|
it "return nil if no UploadedFiles were used" do
|
565
564
|
data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
|
566
565
|
data.must_be_nil
|
data/test/spec_request.rb
CHANGED
@@ -911,7 +911,7 @@ EOF
|
|
911
911
|
f[:tempfile].size.must_equal 76
|
912
912
|
end
|
913
913
|
|
914
|
-
it "MultipartPartLimitError when request has too many multipart parts if limit set" do
|
914
|
+
it "MultipartPartLimitError when request has too many multipart file parts if limit set" do
|
915
915
|
begin
|
916
916
|
data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
917
917
|
data += "--AaB03x--\r"
|
@@ -927,6 +927,22 @@ EOF
|
|
927
927
|
end
|
928
928
|
end
|
929
929
|
|
930
|
+
it "MultipartPartLimitError when request has too many multipart total parts if limit set" do
|
931
|
+
begin
|
932
|
+
data = 10000.times.map { "--AaB03x\r\ncontent-type: text/plain\r\ncontent-disposition: attachment; name=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
933
|
+
data += "--AaB03x--\r"
|
934
|
+
|
935
|
+
options = {
|
936
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
937
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
938
|
+
:input => StringIO.new(data)
|
939
|
+
}
|
940
|
+
|
941
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
942
|
+
lambda { request.POST }.must_raise Rack::Multipart::MultipartTotalPartLimitError
|
943
|
+
end
|
944
|
+
end
|
945
|
+
|
930
946
|
it 'closes tempfiles it created in the case of too many created' do
|
931
947
|
begin
|
932
948
|
data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.9
|
4
|
+
version: 2.0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leah Neukirchen
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -260,7 +260,7 @@ homepage: https://rack.github.io/
|
|
260
260
|
licenses:
|
261
261
|
- MIT
|
262
262
|
metadata: {}
|
263
|
-
post_install_message:
|
263
|
+
post_install_message:
|
264
264
|
rdoc_options: []
|
265
265
|
require_paths:
|
266
266
|
- lib
|
@@ -275,60 +275,60 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
275
275
|
- !ruby/object:Gem::Version
|
276
276
|
version: '0'
|
277
277
|
requirements: []
|
278
|
-
rubygems_version: 3.
|
279
|
-
signing_key:
|
278
|
+
rubygems_version: 3.4.10
|
279
|
+
signing_key:
|
280
280
|
specification_version: 4
|
281
281
|
summary: a modular Ruby webserver interface
|
282
282
|
test_files:
|
283
|
-
- test/
|
283
|
+
- test/spec_auth_basic.rb
|
284
|
+
- test/spec_auth_digest.rb
|
285
|
+
- test/spec_body_proxy.rb
|
286
|
+
- test/spec_builder.rb
|
287
|
+
- test/spec_cascade.rb
|
288
|
+
- test/spec_cgi.rb
|
289
|
+
- test/spec_chunked.rb
|
290
|
+
- test/spec_common_logger.rb
|
291
|
+
- test/spec_conditional_get.rb
|
292
|
+
- test/spec_config.rb
|
293
|
+
- test/spec_content_length.rb
|
294
|
+
- test/spec_content_type.rb
|
284
295
|
- test/spec_deflater.rb
|
285
|
-
- test/
|
286
|
-
- test/spec_session_cookie.rb
|
287
|
-
- test/spec_session_pool.rb
|
296
|
+
- test/spec_directory.rb
|
288
297
|
- test/spec_etag.rb
|
289
|
-
- test/
|
298
|
+
- test/spec_events.rb
|
299
|
+
- test/spec_fastcgi.rb
|
300
|
+
- test/spec_file.rb
|
290
301
|
- test/spec_handler.rb
|
291
|
-
- test/
|
292
|
-
- test/
|
293
|
-
- test/
|
294
|
-
- test/
|
295
|
-
- test/
|
302
|
+
- test/spec_head.rb
|
303
|
+
- test/spec_lint.rb
|
304
|
+
- test/spec_lobster.rb
|
305
|
+
- test/spec_lock.rb
|
306
|
+
- test/spec_logger.rb
|
296
307
|
- test/spec_media_type.rb
|
297
|
-
- test/spec_cgi.rb
|
298
308
|
- test/spec_method_override.rb
|
299
|
-
- test/
|
300
|
-
- test/
|
309
|
+
- test/spec_mime.rb
|
310
|
+
- test/spec_mock.rb
|
311
|
+
- test/spec_multipart.rb
|
312
|
+
- test/spec_null_logger.rb
|
313
|
+
- test/spec_recursive.rb
|
301
314
|
- test/spec_request.rb
|
302
|
-
- test/
|
303
|
-
- test/
|
315
|
+
- test/spec_response.rb
|
316
|
+
- test/spec_rewindable_input.rb
|
304
317
|
- test/spec_runtime.rb
|
305
|
-
- test/spec_session_persisted_secure_secure_session_hash.rb
|
306
|
-
- test/spec_fastcgi.rb
|
307
|
-
- test/spec_common_logger.rb
|
308
|
-
- test/spec_builder.rb
|
309
|
-
- test/spec_config.rb
|
310
|
-
- test/spec_utils.rb
|
311
318
|
- test/spec_sendfile.rb
|
312
|
-
- test/spec_lobster.rb
|
313
|
-
- test/spec_lint.rb
|
314
|
-
- test/spec_conditional_get.rb
|
315
|
-
- test/spec_tempfile_reaper.rb
|
316
|
-
- test/spec_mock.rb
|
317
319
|
- test/spec_server.rb
|
318
|
-
- test/
|
319
|
-
- test/
|
320
|
-
- test/
|
321
|
-
- test/
|
320
|
+
- test/spec_session_abstract_id.rb
|
321
|
+
- test/spec_session_abstract_session_hash.rb
|
322
|
+
- test/spec_session_cookie.rb
|
323
|
+
- test/spec_session_memcache.rb
|
324
|
+
- test/spec_session_persisted_secure_secure_session_hash.rb
|
325
|
+
- test/spec_session_pool.rb
|
326
|
+
- test/spec_show_exceptions.rb
|
322
327
|
- test/spec_show_status.rb
|
323
|
-
- test/
|
324
|
-
- test/
|
325
|
-
- test/
|
328
|
+
- test/spec_static.rb
|
329
|
+
- test/spec_tempfile_reaper.rb
|
330
|
+
- test/spec_thin.rb
|
326
331
|
- test/spec_urlmap.rb
|
327
|
-
- test/
|
328
|
-
- test/
|
329
|
-
- test/
|
330
|
-
- test/spec_head.rb
|
331
|
-
- test/spec_lock.rb
|
332
|
-
- test/spec_rewindable_input.rb
|
333
|
-
- test/spec_session_memcache.rb
|
334
|
-
- test/spec_content_length.rb
|
332
|
+
- test/spec_utils.rb
|
333
|
+
- test/spec_version.rb
|
334
|
+
- test/spec_webrick.rb
|