rack 1.6.8 → 1.6.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b2092f4e0636aec14fec649deaef4dbfb68361c1
4
- data.tar.gz: b2954fc517f0c648aae2332778c34c7464ecac8d
2
+ SHA256:
3
+ metadata.gz: 1284c246863ad0e0c1472c12dc028993a5c84223a53deb943183f396c21f05ec
4
+ data.tar.gz: 6aba4634a7f953dff80b391f999eae11404516f22158d6b2931f8fc7d65aa02b
5
5
  SHA512:
6
- metadata.gz: ab7e0851574c85179644c886a1b57ca2c28c97825e41e2ffb303cb648e0d6bf93fb903002a2ff4f5585ab656c9914e9a28aefc5f4b093b248c6151ef9f0d5dbc
7
- data.tar.gz: d1532e066641f8bfa48a6f635935a00cc6fdb2e22668ee41c68bfced203a174c433f11e322b9fc19be5135832eadbba9b6a1d653debf58911c32761396198630
6
+ metadata.gz: 81f24112cf528aa9f672dede1598fe9527a7d3aa5578e11fe6d6064a96d3091f0afae7f9d4bf453f1eff8c9a3d2ce4bb57991e5a45d41abfdc1948a62c8f65e2
7
+ data.tar.gz: bfde816a21a1293b1b8be7e7f3fd583887e854c57c96afc2d9b823cf16eb40938ef563294bb323389ab241322cfd3add5503e69e3e0ce8678739988d4990e43d
@@ -26,7 +26,11 @@ module Rack
26
26
  req = Request.new(env)
27
27
  method = method_override_param(req) ||
28
28
  env[HTTP_METHOD_OVERRIDE_HEADER]
29
- method.to_s.upcase
29
+ begin
30
+ method.to_s.upcase
31
+ rescue ArgumentError
32
+ env["rack.errors"].puts "Invalid string for method"
33
+ end
30
34
  end
31
35
 
32
36
  private
@@ -38,6 +42,9 @@ module Rack
38
42
  def method_override_param(req)
39
43
  req.POST[METHOD_OVERRIDE_PARAM_KEY]
40
44
  rescue Utils::InvalidParameterError, Utils::ParameterTypeError
45
+ req.env["rack.errors"].puts "Invalid or incomplete POST params"
46
+ rescue EOFError
47
+ req.env["rack.errors"].puts "Bad request content body"
41
48
  end
42
49
  end
43
50
  end
data/lib/rack/request.rb CHANGED
@@ -13,6 +13,8 @@ module Rack
13
13
  # The environment of the request.
14
14
  attr_reader :env
15
15
 
16
+ SCHEME_WHITELIST = %w(https http).freeze
17
+
16
18
  def initialize(env)
17
19
  @env = env
18
20
  end
@@ -68,10 +70,8 @@ module Rack
68
70
  'https'
69
71
  elsif @env['HTTP_X_FORWARDED_SSL'] == 'on'
70
72
  'https'
71
- elsif @env['HTTP_X_FORWARDED_SCHEME']
72
- @env['HTTP_X_FORWARDED_SCHEME']
73
- elsif @env['HTTP_X_FORWARDED_PROTO']
74
- @env['HTTP_X_FORWARDED_PROTO'].split(',')[0]
73
+ elsif forwarded_scheme
74
+ forwarded_scheme
75
75
  else
76
76
  @env["rack.url_scheme"]
77
77
  end
@@ -394,5 +394,18 @@ module Rack
394
394
  s
395
395
  end
396
396
  end
397
+
398
+ def forwarded_scheme
399
+ scheme_headers = [
400
+ @env['HTTP_X_FORWARDED_SCHEME'],
401
+ @env['HTTP_X_FORWARDED_PROTO'].to_s.split(',')[0]
402
+ ]
403
+
404
+ scheme_headers.each do |header|
405
+ return header if SCHEME_WHITELIST.include?(header)
406
+ end
407
+
408
+ nil
409
+ end
397
410
  end
398
411
  end
@@ -9,11 +9,38 @@ begin
9
9
  rescue LoadError
10
10
  # We just won't get securerandom
11
11
  end
12
+ require "digest/sha2"
12
13
 
13
14
  module Rack
14
15
 
15
16
  module Session
16
17
 
18
+ class SessionId
19
+ ID_VERSION = 2
20
+
21
+ attr_reader :public_id
22
+
23
+ def initialize(public_id)
24
+ @public_id = public_id
25
+ end
26
+
27
+ def private_id
28
+ "#{ID_VERSION}::#{hash_sid(public_id)}"
29
+ end
30
+
31
+ alias :cookie_value :public_id
32
+ alias :to_s :public_id
33
+
34
+ def empty?; false; end
35
+ def inspect; public_id.inspect; end
36
+
37
+ private
38
+
39
+ def hash_sid(sid)
40
+ Digest::SHA256.hexdigest(sid)
41
+ end
42
+ end
43
+
17
44
  module Abstract
18
45
  ENV_SESSION_KEY = 'rack.session'.freeze
19
46
  ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
@@ -191,7 +218,7 @@ module Rack
191
218
  # Not included by default; you must require 'rack/session/abstract/id'
192
219
  # to use.
193
220
 
194
- class ID
221
+ class Persisted
195
222
  DEFAULT_OPTIONS = {
196
223
  :key => 'rack.session',
197
224
  :path => '/',
@@ -342,10 +369,10 @@ module Rack
342
369
  if not data = set_session(env, session_id, session_data, options)
343
370
  env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.")
344
371
  elsif options[:defer] and not options[:renew]
345
- env["rack.errors"].puts("Deferring cookie for #{session_id}") if $VERBOSE
372
+ env["rack.errors"].puts("Deferring cookie for #{session_id.public_id}") if $VERBOSE
346
373
  else
347
374
  cookie = Hash.new
348
- cookie[:value] = data
375
+ cookie[:value] = cookie_value(data)
349
376
  cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
350
377
  cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
351
378
  set_cookie(env, headers, cookie.merge!(options))
@@ -354,6 +381,10 @@ module Rack
354
381
  [status, headers, body]
355
382
  end
356
383
 
384
+ def cookie_value(data)
385
+ data
386
+ end
387
+
357
388
  # Sets the cookie back to the client with session id. We skip the cookie
358
389
  # setting if the value didn't change (sid is the same) or expires was given.
359
390
 
@@ -394,6 +425,51 @@ module Rack
394
425
  raise '#destroy_session not implemented'
395
426
  end
396
427
  end
428
+
429
+ class PersistedSecure < Persisted
430
+ class SecureSessionHash < SessionHash
431
+ def [](key)
432
+ if key == "session_id"
433
+ load_for_read!
434
+ id.public_id if id
435
+ else
436
+ super
437
+ end
438
+ end
439
+ end
440
+
441
+ def generate_sid(*)
442
+ public_id = super
443
+
444
+ SessionId.new(public_id)
445
+ end
446
+
447
+ def extract_session_id(*)
448
+ public_id = super
449
+ public_id && SessionId.new(public_id)
450
+ end
451
+
452
+ private
453
+
454
+ def session_class
455
+ SecureSessionHash
456
+ end
457
+
458
+ def cookie_value(data)
459
+ data.cookie_value
460
+ end
461
+ end
462
+
463
+ class ID < Persisted
464
+ def self.inherited(klass)
465
+ k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
466
+ unless k.instance_variable_defined?(:"@_rack_warned")
467
+ warn "#{klass} is inheriting from #{ID}. Inheriting from #{ID} is deprecated, please inherit from #{Persisted} instead" if $VERBOSE
468
+ k.instance_variable_set(:"@_rack_warned", true)
469
+ end
470
+ super
471
+ end
472
+ end
397
473
  end
398
474
  end
399
475
  end
@@ -44,7 +44,7 @@ module Rack
44
44
  # })
45
45
  #
46
46
 
47
- class Cookie < Abstract::ID
47
+ class Cookie < Abstract::PersistedSecure
48
48
  # Encode session cookies as Base64
49
49
  class Base64
50
50
  def encode(str)
@@ -151,6 +151,15 @@ module Rack
151
151
  data
152
152
  end
153
153
 
154
+ class SessionId < DelegateClass(Session::SessionId)
155
+ attr_reader :cookie_value
156
+
157
+ def initialize(session_id, cookie_value)
158
+ super(session_id)
159
+ @cookie_value = cookie_value
160
+ end
161
+ end
162
+
154
163
  def set_session(env, session_id, session, options)
155
164
  session = session.merge("session_id" => session_id)
156
165
  session_data = coder.encode(session)
@@ -163,7 +172,7 @@ module Rack
163
172
  env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K.")
164
173
  nil
165
174
  else
166
- session_data
175
+ SessionId.new(session_id, session_data)
167
176
  end
168
177
  end
169
178
 
@@ -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::ID
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
49
  def get_session(env, sid)
50
50
  with_lock(env) do
51
- unless sid and session = @pool.get(sid)
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
@@ -63,14 +63,15 @@ module Rack
63
63
  expiry = expiry.nil? ? 0 : expiry + 1
64
64
 
65
65
  with_lock(env) do
66
- @pool.set session_id, new_session, expiry
66
+ @pool.set session_id.private_id, new_session, expiry
67
67
  session_id
68
68
  end
69
69
  end
70
70
 
71
71
  def destroy_session(env, session_id, options)
72
72
  with_lock(env) do
73
- @pool.delete(session_id)
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
@@ -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
@@ -24,7 +24,7 @@ module Rack
24
24
  # )
25
25
  # Rack::Handler::WEBrick.run sessioned
26
26
 
27
- class Pool < Abstract::ID
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 get_session(env, sid)
45
45
  with_lock(env) do
46
- unless sid and session = @pool[sid]
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 set_session(env, session_id, new_session, options)
55
55
  with_lock(env) 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 destroy_session(env, session_id, options)
62
62
  with_lock(env) 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
@@ -47,7 +47,7 @@ module Rack
47
47
  end
48
48
 
49
49
  def prefers_plaintext?(env)
50
- !accepts_html(env)
50
+ !accepts_html?(env)
51
51
  end
52
52
 
53
53
  def accepts_html?(env)
data/lib/rack.rb CHANGED
@@ -20,7 +20,7 @@ module Rack
20
20
 
21
21
  # Return the Rack release as a dotted string.
22
22
  def self.release
23
- "1.6.8"
23
+ "1.6.13"
24
24
  end
25
25
  PATH_INFO = 'PATH_INFO'.freeze
26
26
  REQUEST_METHOD = 'REQUEST_METHOD'.freeze
data/rack.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack"
3
- s.version = "1.6.8"
3
+ s.version = "1.6.13"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.summary = "a modular Ruby webserver interface"
6
6
  s.license = "MIT"
@@ -8,7 +8,7 @@ describe Rack::MethodOverride do
8
8
  [200, {"Content-Type" => "text/plain"}, []]
9
9
  }))
10
10
  end
11
-
11
+
12
12
  should "not affect GET requests" do
13
13
  env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET")
14
14
  app.call env
@@ -23,6 +23,22 @@ describe Rack::MethodOverride do
23
23
  env["REQUEST_METHOD"].should.equal "PUT"
24
24
  end
25
25
 
26
+ if RUBY_VERSION >= "1.9"
27
+ should "set rack.errors for invalid UTF8 _method values" do
28
+ errors = StringIO.new
29
+ env = Rack::MockRequest.env_for("/",
30
+ :method => "POST",
31
+ :input => "_method=\xBF".force_encoding("ASCII-8BIT"),
32
+ "rack.errors" => errors)
33
+
34
+ app.call env
35
+
36
+ errors.rewind
37
+ errors.read.should.equal "Invalid string for method\n"
38
+ env["REQUEST_METHOD"].should.equal "POST"
39
+ end
40
+ end
41
+
26
42
  should "modify REQUEST_METHOD for POST requests when X-HTTP-Method-Override is set" do
27
43
  env = Rack::MockRequest.env_for("/",
28
44
  :method => "POST",
@@ -65,14 +81,27 @@ EOF
65
81
  "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
66
82
  "CONTENT_LENGTH" => input.size.to_s,
67
83
  :method => "POST", :input => input)
68
- begin
69
- app.call env
70
- rescue EOFError
71
- end
84
+ app.call env
72
85
 
73
86
  env["REQUEST_METHOD"].should.equal "POST"
74
87
  end
75
88
 
89
+ should "write error to RACK_ERRORS when given invalid multipart form data" do
90
+ input = <<EOF
91
+ --AaB03x\r
92
+ content-disposition: form-data; name="huge"; filename="huge"\r
93
+ EOF
94
+ env = Rack::MockRequest.env_for("/",
95
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
96
+ "CONTENT_LENGTH" => input.size.to_s,
97
+ "rack.errors" => StringIO.new,
98
+ :method => "POST", :input => input)
99
+ Rack::MethodOverride.new(proc { [200, {"Content-Type" => "text/plain"}, []] }).call env
100
+
101
+ env["rack.errors"].rewind
102
+ env["rack.errors"].read.should =~ /Bad request content body/
103
+ end
104
+
76
105
  should "not modify REQUEST_METHOD for POST requests when the params are unparseable" do
77
106
  env = Rack::MockRequest.env_for("/", :method => "POST", :input => "(%bad-params%)")
78
107
  app.call env
data/test/spec_request.rb CHANGED
@@ -425,6 +425,11 @@ describe Rack::Request do
425
425
  request.should.be.ssl?
426
426
  end
427
427
 
428
+ should "prevent scheme abuse" do
429
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'a."><script>alert(1)</script>'))
430
+ request.scheme.should.not.equal 'a."><script>alert(1)</script>'
431
+ end
432
+
428
433
  should "parse cookies" do
429
434
  req = Rack::Request.new \
430
435
  Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
@@ -47,7 +47,7 @@ describe Rack::Session::Abstract::ID do
47
47
  end
48
48
  end
49
49
  id = Rack::Session::Abstract::ID.new nil, :secure_random => secure_random.new
50
- id.send(:generate_sid).should.eql 'fake_hex'
50
+ id.send(:generate_sid).should.equal 'fake_hex'
51
51
  end
52
52
 
53
53
  end
@@ -225,15 +225,52 @@ begin
225
225
  req = Rack::MockRequest.new(pool)
226
226
 
227
227
  res0 = req.get("/")
228
- session_id = (cookie = res0["Set-Cookie"])[session_match, 1]
229
- ses0 = pool.pool.get(session_id, true)
228
+ session_id = Rack::Session::SessionId.new (cookie = res0["Set-Cookie"])[session_match, 1]
229
+ ses0 = pool.pool.get(session_id.private_id, true)
230
230
 
231
231
  req.get("/", "HTTP_COOKIE" => cookie)
232
- ses1 = pool.pool.get(session_id, true)
232
+ ses1 = pool.pool.get(session_id.private_id, true)
233
233
 
234
234
  ses1.should.not.equal ses0
235
235
  end
236
236
 
237
+ it "can read the session with the legacy id" do
238
+ pool = Rack::Session::Memcache.new(incrementor)
239
+ req = Rack::MockRequest.new(pool)
240
+
241
+ res0 = req.get("/")
242
+ cookie = res0["Set-Cookie"]
243
+ session_id = Rack::Session::SessionId.new cookie[session_match, 1]
244
+ ses0 = pool.pool.get(session_id.private_id, true)
245
+ pool.pool.set(session_id.public_id, ses0, 0, true)
246
+ pool.pool.delete(session_id.private_id)
247
+
248
+ res1 = req.get("/", "HTTP_COOKIE" => cookie)
249
+ res1["Set-Cookie"].should.be.nil
250
+ res1.body.should.equal '{"counter"=>2}'
251
+ pool.pool.get(session_id.private_id, true).should.not.be.nil
252
+ end
253
+
254
+ it "drops the session in the legacy id as well" do
255
+ pool = Rack::Session::Memcache.new(incrementor)
256
+ req = Rack::MockRequest.new(pool)
257
+ drop = Rack::Utils::Context.new(pool, drop_session)
258
+ dreq = Rack::MockRequest.new(drop)
259
+
260
+ res0 = req.get("/")
261
+ cookie = res0["Set-Cookie"]
262
+ session_id = Rack::Session::SessionId.new cookie[session_match, 1]
263
+ ses0 = pool.pool.get(session_id.private_id, true)
264
+ pool.pool.set(session_id.public_id, ses0, 0, true)
265
+ pool.pool.delete(session_id.private_id)
266
+
267
+ res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
268
+ res2["Set-Cookie"].should.be.nil
269
+ res2.body.should.equal '{"counter"=>2}'
270
+ pool.pool.get(session_id.private_id, true).should.be.nil
271
+ pool.pool.get(session_id.public_id, true).should.be.nil
272
+ end
273
+
237
274
  # anyone know how to do this better?
238
275
  it "cleanly merges sessions when multithreaded" do
239
276
  unless $DEBUG
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/global_expectations/autorun'
4
+ require 'rack/session/abstract/id'
5
+
6
+ describe Rack::Session::Abstract::PersistedSecure::SecureSessionHash do
7
+ attr_reader :hash
8
+
9
+ def setup
10
+ super
11
+ @store = Class.new do
12
+ def load_session(req)
13
+ [Rack::Session::SessionId.new("id"), { foo: :bar, baz: :qux }]
14
+ end
15
+ def session_exists?(req)
16
+ true
17
+ end
18
+ end
19
+ @hash = Rack::Session::Abstract::PersistedSecure::SecureSessionHash.new(@store.new, nil)
20
+ end
21
+
22
+ it "returns keys" do
23
+ assert_equal ["foo", "baz"], hash.keys
24
+ end
25
+
26
+ it "returns values" do
27
+ assert_equal [:bar, :qux], hash.values
28
+ end
29
+
30
+ describe "#[]" do
31
+ it "returns value for a matching key" do
32
+ assert_equal :bar, hash[:foo]
33
+ end
34
+
35
+ it "returns value for a 'session_id' key" do
36
+ assert_equal "id", hash['session_id']
37
+ end
38
+
39
+ it "returns nil value for missing 'session_id' key" do
40
+ store = @store.new
41
+ def store.load_session(req)
42
+ [nil, {}]
43
+ end
44
+ @hash = Rack::Session::Abstract::PersistedSecure::SecureSessionHash.new(store, nil)
45
+ assert_nil hash['session_id']
46
+ end
47
+ end
48
+
49
+ describe "#fetch" do
50
+ it "returns value for a matching key" do
51
+ assert_equal :bar, hash.fetch(:foo)
52
+ end
53
+
54
+ it "works with a default value" do
55
+ assert_equal :default, hash.fetch(:unknown, :default)
56
+ end
57
+
58
+ it "works with a block" do
59
+ assert_equal :default, hash.fetch(:unkown) { :default }
60
+ end
61
+
62
+ it "it raises when fetching unknown keys without defaults" do
63
+ lambda { hash.fetch(:unknown) }.must_raise KeyError
64
+ end
65
+ end
66
+
67
+ describe "#stringify_keys" do
68
+ it "returns hash or session hash with keys stringified" do
69
+ assert_equal({ "foo" => :bar, "baz" => :qux }, hash.send(:stringify_keys, hash).to_h)
70
+ end
71
+ end
72
+ end
73
+
@@ -5,7 +5,7 @@ require 'rack/session/pool'
5
5
 
6
6
  describe Rack::Session::Pool do
7
7
  session_key = Rack::Session::Pool::DEFAULT_OPTIONS[:key]
8
- session_match = /#{session_key}=[0-9a-fA-F]+;/
8
+ session_match = /#{session_key}=([0-9a-fA-F]+);/
9
9
 
10
10
  incrementor = lambda do |env|
11
11
  env["rack.session"]["counter"] ||= 0
@@ -13,7 +13,7 @@ describe Rack::Session::Pool do
13
13
  Rack::Response.new(env["rack.session"].inspect).to_a
14
14
  end
15
15
 
16
- session_id = Rack::Lint.new(lambda do |env|
16
+ get_session_id = Rack::Lint.new(lambda do |env|
17
17
  Rack::Response.new(env["rack.session"].inspect).to_a
18
18
  end)
19
19
 
@@ -142,6 +142,43 @@ describe Rack::Session::Pool do
142
142
  pool.pool.size.should.equal 1
143
143
  end
144
144
 
145
+ it "can read the session with the legacy id" do
146
+ pool = Rack::Session::Pool.new(incrementor)
147
+ req = Rack::MockRequest.new(pool)
148
+
149
+ res0 = req.get("/")
150
+ cookie = res0["Set-Cookie"]
151
+ session_id = Rack::Session::SessionId.new cookie[session_match, 1]
152
+ ses0 = pool.pool[session_id.private_id]
153
+ pool.pool[session_id.public_id] = ses0
154
+ pool.pool.delete(session_id.private_id)
155
+
156
+ res1 = req.get("/", "HTTP_COOKIE" => cookie)
157
+ res1["Set-Cookie"].should.be.nil
158
+ res1.body.should.equal '{"counter"=>2}'
159
+ pool.pool[session_id.private_id].should.not.be.nil
160
+ end
161
+
162
+ it "drops the session in the legacy id as well" do
163
+ pool = Rack::Session::Pool.new(incrementor)
164
+ req = Rack::MockRequest.new(pool)
165
+ drop = Rack::Utils::Context.new(pool, drop_session)
166
+ dreq = Rack::MockRequest.new(drop)
167
+
168
+ res0 = req.get("/")
169
+ cookie = res0["Set-Cookie"]
170
+ session_id = Rack::Session::SessionId.new cookie[session_match, 1]
171
+ ses0 = pool.pool[session_id.private_id]
172
+ pool.pool[session_id.public_id] = ses0
173
+ pool.pool.delete(session_id.private_id)
174
+
175
+ res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
176
+ res2["Set-Cookie"].should.be.nil
177
+ res2.body.should.equal '{"counter"=>2}'
178
+ pool.pool[session_id.private_id].should.be.nil
179
+ pool.pool[session_id.public_id].should.be.nil
180
+ end
181
+
145
182
  # anyone know how to do this better?
146
183
  it "should merge sessions when multithreaded" do
147
184
  unless $DEBUG
@@ -190,7 +227,7 @@ describe Rack::Session::Pool do
190
227
  end
191
228
 
192
229
  it "does not return a cookie if cookie was not written (only read)" do
193
- app = Rack::Session::Pool.new(session_id)
230
+ app = Rack::Session::Pool.new(get_session_id)
194
231
  res = Rack::MockRequest.new(app).get("/")
195
232
  res["Set-Cookie"].should.be.nil
196
233
  end
@@ -82,4 +82,17 @@ describe Rack::ShowExceptions do
82
82
  res.should =~ /ShowExceptions/
83
83
  res.should =~ /unknown location/
84
84
  end
85
+
86
+ it "knows to prefer plaintext for non-html" do
87
+ # We don't need an app for this
88
+ exc = Rack::ShowExceptions.new(nil)
89
+
90
+ [
91
+ [{ "HTTP_ACCEPT" => "text/plain" }, true],
92
+ [{ "HTTP_ACCEPT" => "text/foo" }, true],
93
+ [{ "HTTP_ACCEPT" => "text/html" }, false]
94
+ ].each do |env, expected|
95
+ expected.should.equal exc.prefers_plaintext?(env)
96
+ end
97
+ end
85
98
  end
metadata CHANGED
@@ -1,38 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.8
4
+ version: 1.6.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neukirchen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-16 00:00:00.000000000 Z
11
+ date: 2020-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: bacon
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
17
  - - ">="
17
18
  - !ruby/object:Gem::Version
18
19
  version: '0'
19
- name: bacon
20
- prerelease: false
21
20
  type: :development
21
+ prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
+ name: rake
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - ">="
31
32
  - !ruby/object:Gem::Version
32
33
  version: '0'
33
- name: rake
34
- prerelease: false
35
34
  type: :development
35
+ prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
@@ -221,6 +221,7 @@ files:
221
221
  - test/spec_session_abstract_id.rb
222
222
  - test/spec_session_cookie.rb
223
223
  - test/spec_session_memcache.rb
224
+ - test/spec_session_persisted_secure_secure_session_hash.rb
224
225
  - test/spec_session_pool.rb
225
226
  - test/spec_showexceptions.rb
226
227
  - test/spec_showstatus.rb
@@ -240,7 +241,7 @@ homepage: http://rack.github.io/
240
241
  licenses:
241
242
  - MIT
242
243
  metadata: {}
243
- post_install_message:
244
+ post_install_message:
244
245
  rdoc_options: []
245
246
  require_paths:
246
247
  - lib
@@ -255,59 +256,58 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
256
  - !ruby/object:Gem::Version
256
257
  version: '0'
257
258
  requirements: []
258
- rubyforge_project: rack
259
- rubygems_version: 2.6.8
260
- signing_key:
259
+ rubygems_version: 3.1.2
260
+ signing_key:
261
261
  specification_version: 4
262
262
  summary: a modular Ruby webserver interface
263
263
  test_files:
264
- - test/spec_auth_basic.rb
265
- - test/spec_auth_digest.rb
266
- - test/spec_body_proxy.rb
267
- - test/spec_builder.rb
268
- - test/spec_cascade.rb
269
- - test/spec_cgi.rb
270
- - test/spec_chunked.rb
271
- - test/spec_commonlogger.rb
272
- - test/spec_conditionalget.rb
273
- - test/spec_config.rb
274
- - test/spec_content_length.rb
275
- - test/spec_content_type.rb
264
+ - test/spec_multipart.rb
276
265
  - test/spec_deflater.rb
277
- - test/spec_directory.rb
266
+ - test/spec_static.rb
267
+ - test/spec_session_cookie.rb
268
+ - test/spec_commonlogger.rb
269
+ - test/spec_session_pool.rb
270
+ - test/spec_methodoverride.rb
278
271
  - test/spec_etag.rb
279
- - test/spec_fastcgi.rb
280
- - test/spec_file.rb
272
+ - test/spec_version.rb
281
273
  - test/spec_handler.rb
282
- - test/spec_head.rb
283
- - test/spec_lint.rb
284
- - test/spec_lobster.rb
285
- - test/spec_lock.rb
286
- - test/spec_logger.rb
287
- - test/spec_methodoverride.rb
274
+ - test/spec_thin.rb
275
+ - test/spec_showexceptions.rb
276
+ - test/spec_session_abstract_id.rb
288
277
  - test/spec_mime.rb
289
- - test/spec_mock.rb
290
- - test/spec_mongrel.rb
291
- - test/spec_multipart.rb
292
- - test/spec_nulllogger.rb
293
278
  - test/spec_recursive.rb
279
+ - test/spec_cgi.rb
280
+ - test/spec_content_type.rb
294
281
  - test/spec_request.rb
295
- - test/spec_response.rb
296
- - test/spec_rewindable_input.rb
282
+ - test/spec_showstatus.rb
283
+ - test/spec_chunked.rb
297
284
  - test/spec_runtime.rb
285
+ - test/spec_session_persisted_secure_secure_session_hash.rb
286
+ - test/spec_fastcgi.rb
287
+ - test/spec_builder.rb
288
+ - test/spec_config.rb
289
+ - test/spec_mongrel.rb
290
+ - test/spec_utils.rb
298
291
  - test/spec_sendfile.rb
299
- - test/spec_server.rb
300
- - test/spec_session_abstract_id.rb
301
- - test/spec_session_cookie.rb
302
- - test/spec_session_memcache.rb
303
- - test/spec_session_pool.rb
304
- - test/spec_showexceptions.rb
305
- - test/spec_showstatus.rb
306
- - test/spec_static.rb
292
+ - test/spec_lobster.rb
293
+ - test/spec_lint.rb
307
294
  - test/spec_tempfile_reaper.rb
308
- - test/spec_thin.rb
309
- - test/spec_urlmap.rb
310
- - test/spec_utils.rb
311
- - test/spec_version.rb
295
+ - test/spec_mock.rb
296
+ - test/spec_conditionalget.rb
297
+ - test/spec_server.rb
298
+ - test/spec_directory.rb
312
299
  - test/spec_webrick.rb
313
- has_rdoc:
300
+ - test/spec_response.rb
301
+ - test/spec_file.rb
302
+ - test/spec_body_proxy.rb
303
+ - test/spec_logger.rb
304
+ - test/spec_auth_digest.rb
305
+ - test/spec_urlmap.rb
306
+ - test/spec_nulllogger.rb
307
+ - test/spec_cascade.rb
308
+ - test/spec_auth_basic.rb
309
+ - test/spec_head.rb
310
+ - test/spec_lock.rb
311
+ - test/spec_rewindable_input.rb
312
+ - test/spec_session_memcache.rb
313
+ - test/spec_content_length.rb