rack 2.0.7 → 2.0.8
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.
- checksums.yaml +5 -5
- data/SPEC +8 -7
- data/lib/rack.rb +1 -1
- data/lib/rack/session/abstract/id.rb +66 -1
- data/lib/rack/session/cookie.rb +11 -2
- data/lib/rack/session/memcache.rb +20 -14
- data/lib/rack/session/pool.rb +13 -6
- data/test/spec_session_memcache.rb +40 -3
- data/test/spec_session_pool.rb +40 -3
- metadata +43 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e9142cfb8ba777286d8118d2b094a23c1fe4698b302c99966cb80670041c67f5
|
4
|
+
data.tar.gz: 341991ef42232bfecf702d98a17e671ffbbf6a95a8ff70bcca40f7c9aa9f5e85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 012e3ac8b25a2fa3c75e7cfbed5f5f4875010ecf96ee887aa9d4ed844badc614fa7decf04bfb889983004d0c310780763e8f9328c4dfb5243388a086f05ef059
|
7
|
+
data.tar.gz: 312252b7e153667c49c11fea9bdceaf679813d6e3176c6e8599fbe4741c326abc43510c3c0a48136a36d2027393e8286f11771a5c353c68269088a6f606b8372
|
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
|
+
<a href="https://tools.ietf.org/html/rfc3875#section-4.1.18">
|
64
|
+
RFC3875 section 4.1.18</a> for
|
65
65
|
specific behavior.
|
66
66
|
In addition to this, the Rack environment must include these
|
67
67
|
Rack-specific variables:
|
@@ -98,12 +98,13 @@ 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
|
101
|
+
<tt>rack.session</tt>:: A hash like interface for storing
|
102
|
+
request session data.
|
102
103
|
The store must implement:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
store(key, value) (aliased as []=);
|
105
|
+
fetch(key, default = nil) (aliased as []);
|
106
|
+
delete(key);
|
107
|
+
clear;
|
107
108
|
<tt>rack.logger</tt>:: A common object interface for logging messages.
|
108
109
|
The object must implement:
|
109
110
|
info(message, &block)
|
data/lib/rack.rb
CHANGED
@@ -6,11 +6,38 @@ require 'time'
|
|
6
6
|
require 'rack/request'
|
7
7
|
require 'rack/response'
|
8
8
|
require 'securerandom'
|
9
|
+
require 'digest/sha2'
|
9
10
|
|
10
11
|
module Rack
|
11
12
|
|
12
13
|
module Session
|
13
14
|
|
15
|
+
class SessionId
|
16
|
+
ID_VERSION = 2
|
17
|
+
|
18
|
+
attr_reader :public_id
|
19
|
+
|
20
|
+
def initialize(public_id)
|
21
|
+
@public_id = public_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def private_id
|
25
|
+
"#{ID_VERSION}::#{hash_sid(public_id)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :cookie_value :public_id
|
29
|
+
|
30
|
+
def empty?; false; end
|
31
|
+
def to_s; raise; end
|
32
|
+
def inspect; public_id.inspect; end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def hash_sid(sid)
|
37
|
+
Digest::SHA256.hexdigest(sid)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
14
41
|
module Abstract
|
15
42
|
# SessionHash is responsible to lazily load the session from store.
|
16
43
|
|
@@ -357,7 +384,7 @@ module Rack
|
|
357
384
|
req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE
|
358
385
|
else
|
359
386
|
cookie = Hash.new
|
360
|
-
cookie[:value] = data
|
387
|
+
cookie[:value] = cookie_value(data)
|
361
388
|
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
|
362
389
|
cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
|
363
390
|
set_cookie(req, res, cookie.merge!(options))
|
@@ -365,6 +392,10 @@ module Rack
|
|
365
392
|
end
|
366
393
|
public :commit_session
|
367
394
|
|
395
|
+
def cookie_value(data)
|
396
|
+
data
|
397
|
+
end
|
398
|
+
|
368
399
|
# Sets the cookie back to the client with session id. We skip the cookie
|
369
400
|
# setting if the value didn't change (sid is the same) or expires was given.
|
370
401
|
|
@@ -406,6 +437,40 @@ module Rack
|
|
406
437
|
end
|
407
438
|
end
|
408
439
|
|
440
|
+
class PersistedSecure < Persisted
|
441
|
+
class SecureSessionHash < SessionHash
|
442
|
+
def [](key)
|
443
|
+
if key == "session_id"
|
444
|
+
load_for_read!
|
445
|
+
id.public_id
|
446
|
+
else
|
447
|
+
super
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def generate_sid(*)
|
453
|
+
public_id = super
|
454
|
+
|
455
|
+
SessionId.new(public_id)
|
456
|
+
end
|
457
|
+
|
458
|
+
def extract_session_id(*)
|
459
|
+
public_id = super
|
460
|
+
public_id && SessionId.new(public_id)
|
461
|
+
end
|
462
|
+
|
463
|
+
private
|
464
|
+
|
465
|
+
def session_class
|
466
|
+
SecureSessionHash
|
467
|
+
end
|
468
|
+
|
469
|
+
def cookie_value(data)
|
470
|
+
data.cookie_value
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
409
474
|
class ID < Persisted
|
410
475
|
def self.inherited(klass)
|
411
476
|
k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
|
data/lib/rack/session/cookie.rb
CHANGED
@@ -45,7 +45,7 @@ module Rack
|
|
45
45
|
# })
|
46
46
|
#
|
47
47
|
|
48
|
-
class Cookie < Abstract::
|
48
|
+
class Cookie < Abstract::PersistedSecure
|
49
49
|
# Encode session cookies as Base64
|
50
50
|
class Base64
|
51
51
|
def encode(str)
|
@@ -153,6 +153,15 @@ module Rack
|
|
153
153
|
data
|
154
154
|
end
|
155
155
|
|
156
|
+
class SessionId < DelegateClass(Session::SessionId)
|
157
|
+
attr_reader :cookie_value
|
158
|
+
|
159
|
+
def initialize(session_id, cookie_value)
|
160
|
+
super(session_id)
|
161
|
+
@cookie_value = cookie_value
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
156
165
|
def write_session(req, session_id, session, options)
|
157
166
|
session = session.merge("session_id" => session_id)
|
158
167
|
session_data = coder.encode(session)
|
@@ -165,7 +174,7 @@ module Rack
|
|
165
174
|
req.get_header(RACK_ERRORS).puts("Warning! Rack::Session::Cookie data size exceeds 4K.")
|
166
175
|
nil
|
167
176
|
else
|
168
|
-
session_data
|
177
|
+
SessionId.new(session_id, session_data)
|
169
178
|
end
|
170
179
|
end
|
171
180
|
|
@@ -19,7 +19,7 @@ module Rack
|
|
19
19
|
# Note that memcache does drop data before it may be listed to expire. For
|
20
20
|
# a full description of behaviour, please see memcache's documentation.
|
21
21
|
|
22
|
-
class Memcache < Abstract::
|
22
|
+
class Memcache < Abstract::PersistedSecure
|
23
23
|
attr_reader :mutex, :pool
|
24
24
|
|
25
25
|
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \
|
@@ -42,15 +42,15 @@ module Rack
|
|
42
42
|
def generate_sid
|
43
43
|
loop do
|
44
44
|
sid = super
|
45
|
-
break sid unless @pool.get(sid, true)
|
45
|
+
break sid unless @pool.get(sid.private_id, true)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
50
|
-
with_lock(
|
51
|
-
unless sid and session =
|
49
|
+
def find_session(req, sid)
|
50
|
+
with_lock(req) do
|
51
|
+
unless sid and session = get_session_with_fallback(sid)
|
52
52
|
sid, session = generate_sid, {}
|
53
|
-
unless /^STORED/ =~ @pool.add(sid, session)
|
53
|
+
unless /^STORED/ =~ @pool.add(sid.private_id, session)
|
54
54
|
raise "Session collision on '#{sid.inspect}'"
|
55
55
|
end
|
56
56
|
end
|
@@ -58,25 +58,26 @@ module Rack
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
61
|
+
def write_session(req, session_id, new_session, options)
|
62
62
|
expiry = options[:expire_after]
|
63
63
|
expiry = expiry.nil? ? 0 : expiry + 1
|
64
64
|
|
65
|
-
with_lock(
|
66
|
-
@pool.set session_id, new_session, expiry
|
65
|
+
with_lock(req) do
|
66
|
+
@pool.set session_id.private_id, new_session, expiry
|
67
67
|
session_id
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
def
|
72
|
-
with_lock(
|
73
|
-
@pool.delete(session_id)
|
71
|
+
def delete_session(req, session_id, options)
|
72
|
+
with_lock(req) do
|
73
|
+
@pool.delete(session_id.public_id)
|
74
|
+
@pool.delete(session_id.private_id)
|
74
75
|
generate_sid unless options[:drop]
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
78
|
-
def with_lock(
|
79
|
-
@mutex.lock if
|
79
|
+
def with_lock(req)
|
80
|
+
@mutex.lock if req.multithread?
|
80
81
|
yield
|
81
82
|
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
82
83
|
if $VERBOSE
|
@@ -88,6 +89,11 @@ module Rack
|
|
88
89
|
@mutex.unlock if @mutex.locked?
|
89
90
|
end
|
90
91
|
|
92
|
+
private
|
93
|
+
|
94
|
+
def get_session_with_fallback(sid)
|
95
|
+
@pool.get(sid.private_id) || @pool.get(sid.public_id)
|
96
|
+
end
|
91
97
|
end
|
92
98
|
end
|
93
99
|
end
|
data/lib/rack/session/pool.rb
CHANGED
@@ -24,7 +24,7 @@ module Rack
|
|
24
24
|
# )
|
25
25
|
# Rack::Handler::WEBrick.run sessioned
|
26
26
|
|
27
|
-
class Pool < Abstract::
|
27
|
+
class Pool < Abstract::PersistedSecure
|
28
28
|
attr_reader :mutex, :pool
|
29
29
|
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false
|
30
30
|
|
@@ -37,15 +37,15 @@ module Rack
|
|
37
37
|
def generate_sid
|
38
38
|
loop do
|
39
39
|
sid = super
|
40
|
-
break sid unless @pool.key? sid
|
40
|
+
break sid unless @pool.key? sid.private_id
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def find_session(req, sid)
|
45
45
|
with_lock(req) do
|
46
|
-
unless sid and session =
|
46
|
+
unless sid and session = get_session_with_fallback(sid)
|
47
47
|
sid, session = generate_sid, {}
|
48
|
-
@pool.store sid, session
|
48
|
+
@pool.store sid.private_id, session
|
49
49
|
end
|
50
50
|
[sid, session]
|
51
51
|
end
|
@@ -53,14 +53,15 @@ module Rack
|
|
53
53
|
|
54
54
|
def write_session(req, session_id, new_session, options)
|
55
55
|
with_lock(req) do
|
56
|
-
@pool.store session_id, new_session
|
56
|
+
@pool.store session_id.private_id, new_session
|
57
57
|
session_id
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
def delete_session(req, session_id, options)
|
62
62
|
with_lock(req) do
|
63
|
-
@pool.delete(session_id)
|
63
|
+
@pool.delete(session_id.public_id)
|
64
|
+
@pool.delete(session_id.private_id)
|
64
65
|
generate_sid unless options[:drop]
|
65
66
|
end
|
66
67
|
end
|
@@ -71,6 +72,12 @@ module Rack
|
|
71
72
|
ensure
|
72
73
|
@mutex.unlock if @mutex.locked?
|
73
74
|
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def get_session_with_fallback(sid)
|
79
|
+
@pool[sid.private_id] || @pool[sid.public_id]
|
80
|
+
end
|
74
81
|
end
|
75
82
|
end
|
76
83
|
end
|
@@ -226,15 +226,52 @@ begin
|
|
226
226
|
req = Rack::MockRequest.new(pool)
|
227
227
|
|
228
228
|
res0 = req.get("/")
|
229
|
-
session_id = (cookie = res0["Set-Cookie"])[session_match, 1]
|
230
|
-
ses0 = pool.pool.get(session_id, true)
|
229
|
+
session_id = Rack::Session::SessionId.new (cookie = res0["Set-Cookie"])[session_match, 1]
|
230
|
+
ses0 = pool.pool.get(session_id.private_id, true)
|
231
231
|
|
232
232
|
req.get("/", "HTTP_COOKIE" => cookie)
|
233
|
-
ses1 = pool.pool.get(session_id, true)
|
233
|
+
ses1 = pool.pool.get(session_id.private_id, true)
|
234
234
|
|
235
235
|
ses1.wont_equal ses0
|
236
236
|
end
|
237
237
|
|
238
|
+
it "can read the session with the legacy id" do
|
239
|
+
pool = Rack::Session::Memcache.new(incrementor)
|
240
|
+
req = Rack::MockRequest.new(pool)
|
241
|
+
|
242
|
+
res0 = req.get("/")
|
243
|
+
cookie = res0["Set-Cookie"]
|
244
|
+
session_id = Rack::Session::SessionId.new cookie[session_match, 1]
|
245
|
+
ses0 = pool.pool.get(session_id.private_id, true)
|
246
|
+
pool.pool.set(session_id.public_id, ses0, 0, true)
|
247
|
+
pool.pool.delete(session_id.private_id)
|
248
|
+
|
249
|
+
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
250
|
+
res1["Set-Cookie"].must_be_nil
|
251
|
+
res1.body.must_equal '{"counter"=>2}'
|
252
|
+
pool.pool.get(session_id.private_id, true).wont_be_nil
|
253
|
+
end
|
254
|
+
|
255
|
+
it "drops the session in the legacy id as well" do
|
256
|
+
pool = Rack::Session::Memcache.new(incrementor)
|
257
|
+
req = Rack::MockRequest.new(pool)
|
258
|
+
drop = Rack::Utils::Context.new(pool, drop_session)
|
259
|
+
dreq = Rack::MockRequest.new(drop)
|
260
|
+
|
261
|
+
res0 = req.get("/")
|
262
|
+
cookie = res0["Set-Cookie"]
|
263
|
+
session_id = Rack::Session::SessionId.new cookie[session_match, 1]
|
264
|
+
ses0 = pool.pool.get(session_id.private_id, true)
|
265
|
+
pool.pool.set(session_id.public_id, ses0, 0, true)
|
266
|
+
pool.pool.delete(session_id.private_id)
|
267
|
+
|
268
|
+
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
269
|
+
res2["Set-Cookie"].must_be_nil
|
270
|
+
res2.body.must_equal '{"counter"=>2}'
|
271
|
+
pool.pool.get(session_id.private_id, true).must_be_nil
|
272
|
+
pool.pool.get(session_id.public_id, true).must_be_nil
|
273
|
+
end
|
274
|
+
|
238
275
|
# anyone know how to do this better?
|
239
276
|
it "cleanly merges sessions when multithreaded" do
|
240
277
|
skip unless $DEBUG
|
data/test/spec_session_pool.rb
CHANGED
@@ -6,7 +6,7 @@ require 'rack/session/pool'
|
|
6
6
|
|
7
7
|
describe Rack::Session::Pool do
|
8
8
|
session_key = Rack::Session::Pool::DEFAULT_OPTIONS[:key]
|
9
|
-
session_match = /#{session_key}=[0-9a-fA-F]
|
9
|
+
session_match = /#{session_key}=([0-9a-fA-F]+);/
|
10
10
|
|
11
11
|
incrementor = lambda do |env|
|
12
12
|
env["rack.session"]["counter"] ||= 0
|
@@ -14,7 +14,7 @@ describe Rack::Session::Pool do
|
|
14
14
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
get_session_id = Rack::Lint.new(lambda do |env|
|
18
18
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
19
19
|
end)
|
20
20
|
|
@@ -143,6 +143,43 @@ describe Rack::Session::Pool do
|
|
143
143
|
pool.pool.size.must_equal 1
|
144
144
|
end
|
145
145
|
|
146
|
+
it "can read the session with the legacy id" do
|
147
|
+
pool = Rack::Session::Pool.new(incrementor)
|
148
|
+
req = Rack::MockRequest.new(pool)
|
149
|
+
|
150
|
+
res0 = req.get("/")
|
151
|
+
cookie = res0["Set-Cookie"]
|
152
|
+
session_id = Rack::Session::SessionId.new cookie[session_match, 1]
|
153
|
+
ses0 = pool.pool[session_id.private_id]
|
154
|
+
pool.pool[session_id.public_id] = ses0
|
155
|
+
pool.pool.delete(session_id.private_id)
|
156
|
+
|
157
|
+
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
158
|
+
res1["Set-Cookie"].must_be_nil
|
159
|
+
res1.body.must_equal '{"counter"=>2}'
|
160
|
+
pool.pool[session_id.private_id].wont_be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it "drops the session in the legacy id as well" do
|
164
|
+
pool = Rack::Session::Pool.new(incrementor)
|
165
|
+
req = Rack::MockRequest.new(pool)
|
166
|
+
drop = Rack::Utils::Context.new(pool, drop_session)
|
167
|
+
dreq = Rack::MockRequest.new(drop)
|
168
|
+
|
169
|
+
res0 = req.get("/")
|
170
|
+
cookie = res0["Set-Cookie"]
|
171
|
+
session_id = Rack::Session::SessionId.new cookie[session_match, 1]
|
172
|
+
ses0 = pool.pool[session_id.private_id]
|
173
|
+
pool.pool[session_id.public_id] = ses0
|
174
|
+
pool.pool.delete(session_id.private_id)
|
175
|
+
|
176
|
+
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
177
|
+
res2["Set-Cookie"].must_be_nil
|
178
|
+
res2.body.must_equal '{"counter"=>2}'
|
179
|
+
pool.pool[session_id.private_id].must_be_nil
|
180
|
+
pool.pool[session_id.public_id].must_be_nil
|
181
|
+
end
|
182
|
+
|
146
183
|
# anyone know how to do this better?
|
147
184
|
it "should merge sessions when multithreaded" do
|
148
185
|
unless $DEBUG
|
@@ -191,7 +228,7 @@ describe Rack::Session::Pool do
|
|
191
228
|
end
|
192
229
|
|
193
230
|
it "does not return a cookie if cookie was not written (only read)" do
|
194
|
-
app = Rack::Session::Pool.new(
|
231
|
+
app = Rack::Session::Pool.new(get_session_id)
|
195
232
|
res = Rack::MockRequest.new(app).get("/")
|
196
233
|
res["Set-Cookie"].must_be_nil
|
197
234
|
end
|
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.
|
4
|
+
version: 2.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leah Neukirchen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -274,60 +274,59 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
274
274
|
- !ruby/object:Gem::Version
|
275
275
|
version: '0'
|
276
276
|
requirements: []
|
277
|
-
|
278
|
-
rubygems_version: 2.6.13
|
277
|
+
rubygems_version: 3.0.3
|
279
278
|
signing_key:
|
280
279
|
specification_version: 4
|
281
280
|
summary: a modular Ruby webserver interface
|
282
281
|
test_files:
|
283
|
-
- test/
|
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
|
282
|
+
- test/spec_multipart.rb
|
295
283
|
- test/spec_deflater.rb
|
296
|
-
- test/
|
284
|
+
- test/spec_static.rb
|
285
|
+
- test/spec_session_cookie.rb
|
286
|
+
- test/spec_session_pool.rb
|
297
287
|
- test/spec_etag.rb
|
298
|
-
- test/
|
299
|
-
- test/spec_fastcgi.rb
|
300
|
-
- test/spec_file.rb
|
288
|
+
- test/spec_version.rb
|
301
289
|
- test/spec_handler.rb
|
302
|
-
- test/
|
303
|
-
- test/
|
304
|
-
- test/spec_lobster.rb
|
305
|
-
- test/spec_lock.rb
|
306
|
-
- test/spec_logger.rb
|
307
|
-
- test/spec_media_type.rb
|
308
|
-
- test/spec_method_override.rb
|
290
|
+
- test/spec_thin.rb
|
291
|
+
- test/spec_session_abstract_id.rb
|
309
292
|
- test/spec_mime.rb
|
310
|
-
- test/spec_mock.rb
|
311
|
-
- test/spec_multipart.rb
|
312
|
-
- test/spec_null_logger.rb
|
313
293
|
- test/spec_recursive.rb
|
294
|
+
- test/spec_null_logger.rb
|
295
|
+
- test/spec_media_type.rb
|
296
|
+
- test/spec_cgi.rb
|
297
|
+
- test/spec_method_override.rb
|
298
|
+
- test/spec_content_type.rb
|
299
|
+
- test/spec_session_abstract_session_hash.rb
|
314
300
|
- test/spec_request.rb
|
315
|
-
- test/
|
316
|
-
- test/
|
301
|
+
- test/spec_chunked.rb
|
302
|
+
- test/spec_show_exceptions.rb
|
317
303
|
- test/spec_runtime.rb
|
304
|
+
- test/spec_fastcgi.rb
|
305
|
+
- test/spec_common_logger.rb
|
306
|
+
- test/spec_builder.rb
|
307
|
+
- test/spec_config.rb
|
308
|
+
- test/spec_utils.rb
|
318
309
|
- test/spec_sendfile.rb
|
310
|
+
- test/spec_lobster.rb
|
311
|
+
- test/spec_lint.rb
|
312
|
+
- test/spec_conditional_get.rb
|
313
|
+
- test/spec_tempfile_reaper.rb
|
314
|
+
- test/spec_mock.rb
|
319
315
|
- test/spec_server.rb
|
320
|
-
- test/
|
321
|
-
- test/
|
322
|
-
- test/
|
323
|
-
- test/
|
324
|
-
- test/spec_session_pool.rb
|
325
|
-
- test/spec_show_exceptions.rb
|
316
|
+
- test/spec_directory.rb
|
317
|
+
- test/spec_webrick.rb
|
318
|
+
- test/spec_response.rb
|
319
|
+
- test/spec_file.rb
|
326
320
|
- test/spec_show_status.rb
|
327
|
-
- test/
|
328
|
-
- test/
|
329
|
-
- test/
|
321
|
+
- test/spec_body_proxy.rb
|
322
|
+
- test/spec_logger.rb
|
323
|
+
- test/spec_auth_digest.rb
|
330
324
|
- test/spec_urlmap.rb
|
331
|
-
- test/
|
332
|
-
- test/
|
333
|
-
- test/
|
325
|
+
- test/spec_events.rb
|
326
|
+
- test/spec_cascade.rb
|
327
|
+
- test/spec_auth_basic.rb
|
328
|
+
- test/spec_head.rb
|
329
|
+
- test/spec_lock.rb
|
330
|
+
- test/spec_rewindable_input.rb
|
331
|
+
- test/spec_session_memcache.rb
|
332
|
+
- test/spec_content_length.rb
|