rack 1.4.1 → 1.4.5

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.
Files changed (84) hide show
  1. data/COPYING +1 -1
  2. data/KNOWN-ISSUES +9 -0
  3. data/README.rdoc +105 -7
  4. data/Rakefile +18 -11
  5. data/SPEC +3 -1
  6. data/contrib/rack.png +0 -0
  7. data/contrib/rack.svg +150 -0
  8. data/contrib/rdoc.css +412 -0
  9. data/lib/rack/auth/abstract/request.rb +5 -1
  10. data/lib/rack/auth/basic.rb +1 -1
  11. data/lib/rack/auth/digest/nonce.rb +1 -1
  12. data/lib/rack/backports/uri/common_18.rb +14 -28
  13. data/lib/rack/backports/uri/common_192.rb +14 -17
  14. data/lib/rack/backports/uri/common_193.rb +29 -0
  15. data/lib/rack/body_proxy.rb +10 -0
  16. data/lib/rack/builder.rb +1 -1
  17. data/lib/rack/cascade.rb +11 -0
  18. data/lib/rack/commonlogger.rb +18 -5
  19. data/lib/rack/deflater.rb +5 -1
  20. data/lib/rack/directory.rb +1 -1
  21. data/lib/rack/etag.rb +6 -3
  22. data/lib/rack/file.rb +19 -15
  23. data/lib/rack/head.rb +1 -0
  24. data/lib/rack/lint.rb +3 -1
  25. data/lib/rack/lock.rb +3 -4
  26. data/lib/rack/mime.rb +1 -1
  27. data/lib/rack/mock.rb +3 -2
  28. data/lib/rack/multipart/parser.rb +16 -7
  29. data/lib/rack/multipart.rb +2 -2
  30. data/lib/rack/reloader.rb +1 -1
  31. data/lib/rack/request.rb +2 -4
  32. data/lib/rack/response.rb +2 -1
  33. data/lib/rack/server.rb +28 -2
  34. data/lib/rack/session/abstract/id.rb +5 -0
  35. data/lib/rack/session/cookie.rb +10 -1
  36. data/lib/rack/static.rb +90 -8
  37. data/lib/rack/utils.rb +28 -10
  38. data/lib/rack.rb +12 -0
  39. data/rack.gemspec +3 -3
  40. data/test/builder/line.ru +1 -0
  41. data/test/cgi/assets/folder/test.js +1 -0
  42. data/test/cgi/assets/fonts/font.eot +1 -0
  43. data/test/cgi/assets/images/image.png +1 -0
  44. data/test/cgi/assets/index.html +1 -0
  45. data/test/cgi/assets/javascripts/app.js +1 -0
  46. data/test/cgi/assets/stylesheets/app.css +1 -0
  47. data/test/spec_auth.rb +57 -0
  48. data/test/spec_auth_basic.rb +8 -0
  49. data/test/spec_auth_digest.rb +14 -0
  50. data/test/spec_body_proxy.rb +4 -0
  51. data/test/spec_builder.rb +7 -1
  52. data/test/spec_cascade.rb +8 -0
  53. data/test/spec_chunked.rb +6 -6
  54. data/test/spec_config.rb +0 -1
  55. data/test/spec_content_length.rb +26 -13
  56. data/test/spec_content_type.rb +15 -5
  57. data/test/spec_deflater.rb +35 -17
  58. data/test/spec_directory.rb +20 -1
  59. data/test/spec_etag.rb +29 -13
  60. data/test/spec_file.rb +42 -25
  61. data/test/spec_head.rb +25 -7
  62. data/test/spec_lobster.rb +20 -5
  63. data/test/spec_lock.rb +46 -21
  64. data/test/spec_logger.rb +2 -7
  65. data/test/spec_methodoverride.rb +21 -22
  66. data/test/spec_mock.rb +12 -7
  67. data/test/spec_multipart.rb +82 -0
  68. data/test/spec_nulllogger.rb +13 -2
  69. data/test/spec_recursive.rb +12 -9
  70. data/test/spec_request.rb +2 -2
  71. data/test/spec_response.rb +30 -0
  72. data/test/spec_runtime.rb +15 -5
  73. data/test/spec_sendfile.rb +13 -9
  74. data/test/spec_server.rb +47 -0
  75. data/test/spec_session_cookie.rb +68 -1
  76. data/test/spec_session_memcache.rb +10 -8
  77. data/test/spec_session_pool.rb +13 -10
  78. data/test/spec_showexceptions.rb +9 -4
  79. data/test/spec_showstatus.rb +10 -5
  80. data/test/spec_static.rb +85 -9
  81. data/test/spec_urlmap.rb +10 -10
  82. data/test/spec_utils.rb +19 -1
  83. data/test/static/another/index.html +1 -0
  84. metadata +23 -8
@@ -48,6 +48,59 @@ describe Rack::Multipart do
48
48
  params['profile']['bio'].should.include 'hello'
49
49
  end
50
50
 
51
+ should "reject insanely long boundaries" do
52
+ # using a pipe since a tempfile can use up too much space
53
+ rd, wr = IO.pipe
54
+
55
+ # we only call rewind once at start, so make sure it succeeds
56
+ # and doesn't hit ESPIPE
57
+ def rd.rewind; end
58
+ wr.sync = true
59
+
60
+ # mock out length to make this pipe look like a Tempfile
61
+ def rd.length
62
+ 1024 * 1024 * 8
63
+ end
64
+
65
+ # write to a pipe in a background thread, this will write a lot
66
+ # unless Rack (properly) shuts down the read end
67
+ thr = Thread.new do
68
+ begin
69
+ wr.write("--AaB03x")
70
+
71
+ # make the initial boundary a few gigs long
72
+ longer = "0123456789" * 1024 * 1024
73
+ (1024 * 1024).times { wr.write(longer) }
74
+
75
+ wr.write("\r\n")
76
+ wr.write('Content-Disposition: form-data; name="a"; filename="a.txt"')
77
+ wr.write("\r\n")
78
+ wr.write("Content-Type: text/plain\r\n")
79
+ wr.write("\r\na")
80
+ wr.write("--AaB03x--\r\n")
81
+ wr.close
82
+ rescue => err # this is EPIPE if Rack shuts us down
83
+ err
84
+ end
85
+ end
86
+
87
+ fixture = {
88
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
89
+ "CONTENT_LENGTH" => rd.length.to_s,
90
+ :input => rd,
91
+ }
92
+
93
+ env = Rack::MockRequest.env_for '/', fixture
94
+ lambda {
95
+ Rack::Multipart.parse_multipart(env)
96
+ }.should.raise(EOFError)
97
+ rd.close
98
+
99
+ err = thr.value
100
+ err.should.be.instance_of Errno::EPIPE
101
+ wr.close
102
+ end
103
+
51
104
  should "parse multipart upload with text file" do
52
105
  env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
53
106
  params = Rack::Multipart.parse_multipart(env)
@@ -360,4 +413,33 @@ EOF
360
413
  params.should.equal({"description"=>"Very very blue"})
361
414
  end
362
415
 
416
+ should "parse multipart upload with no content-length header" do
417
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
418
+ env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
419
+ env.delete 'CONTENT_LENGTH'
420
+ params = Rack::Multipart.parse_multipart(env)
421
+ params['profile']['bio'].should.include 'hello'
422
+ end
423
+
424
+ should "parse very long unquoted multipart file names" do
425
+ data = <<-EOF
426
+ --AaB03x\r
427
+ Content-Type: text/plain\r
428
+ Content-Disposition: attachment; name=file; filename=#{'long' * 100}\r
429
+ \r
430
+ contents\r
431
+ --AaB03x--\r
432
+ EOF
433
+
434
+ options = {
435
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
436
+ "CONTENT_LENGTH" => data.length.to_s,
437
+ :input => StringIO.new(data)
438
+ }
439
+ env = Rack::MockRequest.env_for("/", options)
440
+ params = Rack::Utils::Multipart.parse_multipart(env)
441
+
442
+ params["file"][:filename].should.equal('long' * 100)
443
+ end
444
+
363
445
  end
@@ -1,12 +1,23 @@
1
+ require 'enumerator'
2
+ require 'rack/lint'
3
+ require 'rack/mock'
1
4
  require 'rack/nulllogger'
2
5
 
3
6
  describe Rack::NullLogger do
7
+ ::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
8
+
4
9
  should "act as a noop logger" do
5
10
  app = lambda { |env|
6
11
  env['rack.logger'].warn "b00m"
7
12
  [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
8
13
  }
9
- logger = Rack::NullLogger.new(app)
10
- lambda{ logger.call({}) }.should.not.raise
14
+
15
+ logger = Rack::Lint.new(Rack::NullLogger.new(app))
16
+
17
+ res = logger.call(Rack::MockRequest.env_for)
18
+ res[0..1].should.equal [
19
+ 200, {'Content-Type' => 'text/plain'}
20
+ ]
21
+ Enumerator.new(res[2]).to_a.should.equal ["Hello, World!"]
11
22
  end
12
23
  end
@@ -1,3 +1,4 @@
1
+ require 'rack/lint'
1
2
  require 'rack/recursive'
2
3
  require 'rack/mock'
3
4
 
@@ -28,11 +29,14 @@ describe Rack::Recursive do
28
29
  @app4 = lambda { |env|
29
30
  raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
30
31
  }
32
+
33
+ def recursive(map)
34
+ Rack::Lint.new Rack::Recursive.new(Rack::URLMap.new(map))
35
+ end
31
36
 
32
37
  should "allow for subrequests" do
33
- res = Rack::MockRequest.new(Rack::Recursive.new(
34
- Rack::URLMap.new("/app1" => @app1,
35
- "/app2" => @app2))).
38
+ res = Rack::MockRequest.new(recursive("/app1" => @app1,
39
+ "/app2" => @app2)).
36
40
  get("/app2")
37
41
 
38
42
  res.should.be.ok
@@ -41,9 +45,8 @@ describe Rack::Recursive do
41
45
 
42
46
  should "raise error on requests not below the app" do
43
47
  app = Rack::URLMap.new("/app1" => @app1,
44
- "/app" => Rack::Recursive.new(
45
- Rack::URLMap.new("/1" => @app1,
46
- "/2" => @app2)))
48
+ "/app" => recursive("/1" => @app1,
49
+ "/2" => @app2))
47
50
 
48
51
  lambda {
49
52
  Rack::MockRequest.new(app).get("/app/2")
@@ -52,9 +55,9 @@ describe Rack::Recursive do
52
55
  end
53
56
 
54
57
  should "support forwarding" do
55
- app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
56
- "/app3" => @app3,
57
- "/app4" => @app4))
58
+ app = recursive("/app1" => @app1,
59
+ "/app3" => @app3,
60
+ "/app4" => @app4)
58
61
 
59
62
  res = Rack::MockRequest.new(app).get("/app3")
60
63
  res.should.be.ok
data/test/spec_request.rb CHANGED
@@ -411,9 +411,9 @@ describe Rack::Request do
411
411
  req.cookies.should.equal 'foo' => 'bar'
412
412
  end
413
413
 
414
- should "raise any errors on every request" do
414
+ should "pass through non-uri escaped cookies as-is" do
415
415
  req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
416
- 2.times { proc { req.cookies }.should.raise(ArgumentError) }
416
+ req.cookies["foo"].should == "%"
417
417
  end
418
418
 
419
419
  should "parse cookies according to RFC 2109" do
@@ -280,4 +280,34 @@ describe Rack::Response do
280
280
  res.close
281
281
  res.body.should.be.closed
282
282
  end
283
+
284
+ it "calls close on #body when 204, 205, or 304" do
285
+ res = Rack::Response.new
286
+ res.body = StringIO.new
287
+ res.finish
288
+ res.body.should.not.be.closed
289
+
290
+ res.status = 204
291
+ _, _, b = res.finish
292
+ res.body.should.be.closed
293
+ b.should.not == res.body
294
+
295
+ res.body = StringIO.new
296
+ res.status = 205
297
+ _, _, b = res.finish
298
+ res.body.should.be.closed
299
+ b.should.not == res.body
300
+
301
+ res.body = StringIO.new
302
+ res.status = 304
303
+ _, _, b = res.finish
304
+ res.body.should.be.closed
305
+ b.should.not == res.body
306
+ end
307
+
308
+ it "wraps the body from #to_ary to prevent infinite loops" do
309
+ res = Rack::Response.new
310
+ res.finish.last.should.not.respond_to?(:to_ary)
311
+ lambda { res.finish.last.to_ary }.should.raise(NoMethodError)
312
+ end
283
313
  end
data/test/spec_runtime.rb CHANGED
@@ -1,27 +1,37 @@
1
+ require 'rack/lint'
2
+ require 'rack/mock'
1
3
  require 'rack/runtime'
2
4
 
3
5
  describe Rack::Runtime do
6
+ def runtime_app(app, *args)
7
+ Rack::Lint.new Rack::Runtime.new(app, *args)
8
+ end
9
+
10
+ def request
11
+ Rack::MockRequest.env_for
12
+ end
13
+
4
14
  it "sets X-Runtime is none is set" do
5
15
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
6
- response = Rack::Runtime.new(app).call({})
16
+ response = runtime_app(app).call(request)
7
17
  response[1]['X-Runtime'].should =~ /[\d\.]+/
8
18
  end
9
19
 
10
20
  it "doesn't set the X-Runtime if it is already set" do
11
21
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
12
- response = Rack::Runtime.new(app).call({})
22
+ response = runtime_app(app).call(request)
13
23
  response[1]['X-Runtime'].should == "foobar"
14
24
  end
15
25
 
16
26
  should "allow a suffix to be set" do
17
27
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
18
- response = Rack::Runtime.new(app, "Test").call({})
28
+ response = runtime_app(app, "Test").call(request)
19
29
  response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
20
30
  end
21
31
 
22
32
  should "allow multiple timers to be set" do
23
33
  app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
24
- runtime = Rack::Runtime.new(app, "App")
34
+ runtime = runtime_app(app, "App")
25
35
 
26
36
  # wrap many times to guarantee a measurable difference
27
37
  100.times do |i|
@@ -29,7 +39,7 @@ describe Rack::Runtime do
29
39
  end
30
40
  runtime = Rack::Runtime.new(runtime, "All")
31
41
 
32
- response = runtime.call({})
42
+ response = runtime.call(request)
33
43
 
34
44
  response[1]['X-Runtime-App'].should =~ /[\d\.]+/
35
45
  response[1]['X-Runtime-All'].should =~ /[\d\.]+/
@@ -1,5 +1,8 @@
1
+ require 'fileutils'
2
+ require 'rack/lint'
1
3
  require 'rack/sendfile'
2
4
  require 'rack/mock'
5
+ require 'tmpdir'
3
6
 
4
7
  describe Rack::File do
5
8
  should "respond to #to_path" do
@@ -9,8 +12,9 @@ end
9
12
 
10
13
  describe Rack::Sendfile do
11
14
  def sendfile_body
15
+ FileUtils.touch File.join(Dir.tmpdir, "rack_sendfile")
12
16
  res = ['Hello World']
13
- def res.to_path ; "/tmp/hello.txt" ; end
17
+ def res.to_path ; File.join(Dir.tmpdir, "rack_sendfile") ; end
14
18
  res
15
19
  end
16
20
 
@@ -19,7 +23,7 @@ describe Rack::Sendfile do
19
23
  end
20
24
 
21
25
  def sendfile_app(body=sendfile_body)
22
- Rack::Sendfile.new(simple_app(body))
26
+ Rack::Lint.new Rack::Sendfile.new(simple_app(body))
23
27
  end
24
28
 
25
29
  @request = Rack::MockRequest.new(sendfile_app)
@@ -40,8 +44,8 @@ describe Rack::Sendfile do
40
44
  request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
41
45
  response.should.be.ok
42
46
  response.body.should.be.empty
43
- response.headers['Content-Length'].should == '0'
44
- response.headers['X-Sendfile'].should.equal '/tmp/hello.txt'
47
+ response.headers['Content-Length'].should.equal '0'
48
+ response.headers['X-Sendfile'].should.equal File.join(Dir.tmpdir, "rack_sendfile")
45
49
  end
46
50
  end
47
51
 
@@ -49,21 +53,21 @@ describe Rack::Sendfile do
49
53
  request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
50
54
  response.should.be.ok
51
55
  response.body.should.be.empty
52
- response.headers['Content-Length'].should == '0'
53
- response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt'
56
+ response.headers['Content-Length'].should.equal '0'
57
+ response.headers['X-Lighttpd-Send-File'].should.equal File.join(Dir.tmpdir, "rack_sendfile")
54
58
  end
55
59
  end
56
60
 
57
61
  it "sets X-Accel-Redirect response header and discards body" do
58
62
  headers = {
59
63
  'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
60
- 'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
64
+ 'HTTP_X_ACCEL_MAPPING' => "#{Dir.tmpdir}/=/foo/bar/"
61
65
  }
62
66
  request headers do |response|
63
67
  response.should.be.ok
64
68
  response.body.should.be.empty
65
- response.headers['Content-Length'].should == '0'
66
- response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt'
69
+ response.headers['Content-Length'].should.equal '0'
70
+ response.headers['X-Accel-Redirect'].should.equal '/foo/bar/rack_sendfile'
67
71
  end
68
72
  end
69
73
 
data/test/spec_server.rb CHANGED
@@ -10,6 +10,13 @@ describe Rack::Server do
10
10
  lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
11
11
  end
12
12
 
13
+ def with_stderr
14
+ old, $stderr = $stderr, StringIO.new
15
+ yield $stderr
16
+ ensure
17
+ $stderr = old
18
+ end
19
+
13
20
  it "overrides :config if :app is passed in" do
14
21
  server = Rack::Server.new(:app => "FOO")
15
22
  server.app.should == "FOO"
@@ -71,4 +78,44 @@ describe Rack::Server do
71
78
  open(pidfile) { |f| f.read.should.eql $$.to_s }
72
79
  end
73
80
 
81
+ should "check pid file presence and running process" do
82
+ pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
83
+ server = Rack::Server.new(:pid => pidfile)
84
+ server.send(:pidfile_process_status).should.eql :running
85
+ end
86
+
87
+ should "check pid file presence and dead process" do
88
+ dead_pid = `echo $$`.to_i
89
+ pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
90
+ server = Rack::Server.new(:pid => pidfile)
91
+ server.send(:pidfile_process_status).should.eql :dead
92
+ end
93
+
94
+ should "check pid file presence and exited process" do
95
+ pidfile = Tempfile.open('pidfile') { |f| break f }.path
96
+ ::File.delete(pidfile)
97
+ server = Rack::Server.new(:pid => pidfile)
98
+ server.send(:pidfile_process_status).should.eql :exited
99
+ end
100
+
101
+ should "check pid file presence and not owned process" do
102
+ pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
103
+ server = Rack::Server.new(:pid => pidfile)
104
+ server.send(:pidfile_process_status).should.eql :not_owned
105
+ end
106
+
107
+ should "inform the user about existing pidfiles with running processes" do
108
+ pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
109
+ server = Rack::Server.new(:pid => pidfile)
110
+ with_stderr do |err|
111
+ should.raise(SystemExit) do
112
+ server.start
113
+ end
114
+ err.rewind
115
+ output = err.read
116
+ output.should.match(/already running/)
117
+ output.should.include? pidfile
118
+ end
119
+ end
120
+
74
121
  end
@@ -1,4 +1,5 @@
1
1
  require 'rack/session/cookie'
2
+ require 'rack/lint'
2
3
  require 'rack/mock'
3
4
 
4
5
  describe Rack::Session::Cookie do
@@ -9,7 +10,7 @@ describe Rack::Session::Cookie do
9
10
  hash.delete("session_id")
10
11
  Rack::Response.new(hash.inspect).to_a
11
12
  end
12
-
13
+
13
14
  session_id = lambda do |env|
14
15
  Rack::Response.new(env["rack.session"].to_hash.inspect).to_a
15
16
  end
@@ -24,6 +25,50 @@ describe Rack::Session::Cookie do
24
25
  Rack::Response.new("Nothing").to_a
25
26
  end
26
27
 
28
+ renewer = lambda do |env|
29
+ env["rack.session.options"][:renew] = true
30
+ Rack::Response.new("Nothing").to_a
31
+ end
32
+
33
+ only_session_id = lambda do |env|
34
+ Rack::Response.new(env["rack.session"]["session_id"].to_s).to_a
35
+ end
36
+
37
+ bigcookie = lambda do |env|
38
+ env["rack.session"]["cookie"] = "big" * 3000
39
+ Rack::Response.new(env["rack.session"].inspect).to_a
40
+ end
41
+
42
+ destroy_session = lambda do |env|
43
+ env["rack.session"].destroy
44
+ Rack::Response.new("Nothing").to_a
45
+ end
46
+
47
+ def response_for(options={})
48
+ request_options = options.fetch(:request, {})
49
+ cookie = if options[:cookie].is_a?(Rack::Response)
50
+ options[:cookie]["Set-Cookie"]
51
+ else
52
+ options[:cookie]
53
+ end
54
+ request_options["HTTP_COOKIE"] = cookie || ""
55
+
56
+ app_with_cookie = Rack::Session::Cookie.new(*options[:app])
57
+ app_with_cookie = Rack::Lint.new(app_with_cookie)
58
+ Rack::MockRequest.new(app_with_cookie).get("/", request_options)
59
+ end
60
+
61
+ before do
62
+ @warnings = warnings = []
63
+ Rack::Session::Cookie.class_eval do
64
+ define_method(:warn) { |m| warnings << m }
65
+ end
66
+ end
67
+
68
+ after do
69
+ Rack::Session::Cookie.class_eval { remove_method :warn }
70
+ end
71
+
27
72
  describe 'Base64' do
28
73
  it 'uses base64 to encode' do
29
74
  coder = Rack::Session::Cookie::Base64.new
@@ -57,6 +102,14 @@ describe Rack::Session::Cookie do
57
102
  end
58
103
  end
59
104
 
105
+ it "warns if no secret is given" do
106
+ cookie = Rack::Session::Cookie.new(incrementor)
107
+ @warnings.first.should =~ /no secret/i
108
+ @warnings.clear
109
+ cookie = Rack::Session::Cookie.new(incrementor, :secret => 'abc')
110
+ @warnings.should.be.empty?
111
+ end
112
+
60
113
  it 'uses a coder' do
61
114
  identity = Class.new {
62
115
  attr_reader :calls
@@ -291,4 +344,18 @@ describe Rack::Session::Cookie do
291
344
  res = Rack::MockRequest.new(app).get("/", 'rack.session' => {:foo => 'bar'})
292
345
  res.body.should.match(/foo/)
293
346
  end
347
+
348
+ it "allows modifying session data with session data from middleware in front" do
349
+ request = { 'rack.session' => { :foo => 'bar' }}
350
+ response = response_for(:app => incrementor, :request => request)
351
+ response.body.should.match(/counter/)
352
+ response.body.should.match(/foo/)
353
+ end
354
+
355
+ it "allows modifying session data with session data from middleware in front" do
356
+ request = { 'rack.session' => { :foo => 'bar' }}
357
+ response = response_for(:app => incrementor, :request => request)
358
+ response.body.should.match(/counter/)
359
+ response.body.should.match(/foo/)
360
+ end
294
361
  end
@@ -1,5 +1,6 @@
1
1
  begin
2
2
  require 'rack/session/memcache'
3
+ require 'rack/lint'
3
4
  require 'rack/mock'
4
5
  require 'thread'
5
6
 
@@ -11,22 +12,23 @@ begin
11
12
  env["rack.session"]["counter"] += 1
12
13
  Rack::Response.new(env["rack.session"].inspect).to_a
13
14
  end
14
- drop_session = proc do |env|
15
+ drop_session = Rack::Lint.new(proc do |env|
15
16
  env['rack.session.options'][:drop] = true
16
17
  incrementor.call(env)
17
- end
18
- renew_session = proc do |env|
18
+ end)
19
+ renew_session = Rack::Lint.new(proc do |env|
19
20
  env['rack.session.options'][:renew] = true
20
21
  incrementor.call(env)
21
- end
22
- defer_session = proc do |env|
22
+ end)
23
+ defer_session = Rack::Lint.new(proc do |env|
23
24
  env['rack.session.options'][:defer] = true
24
25
  incrementor.call(env)
25
- end
26
- skip_session = proc do |env|
26
+ end)
27
+ skip_session = Rack::Lint.new(proc do |env|
27
28
  env['rack.session.options'][:skip] = true
28
29
  incrementor.call(env)
29
- end
30
+ end)
31
+ incrementor = Rack::Lint.new(incrementor)
30
32
 
31
33
  # test memcache connection
32
34
  Rack::Session::Memcache.new(incrementor)
@@ -1,4 +1,5 @@
1
1
  require 'thread'
2
+ require 'rack/lint'
2
3
  require 'rack/mock'
3
4
  require 'rack/session/pool'
4
5
 
@@ -12,28 +13,30 @@ describe Rack::Session::Pool do
12
13
  Rack::Response.new(env["rack.session"].inspect).to_a
13
14
  end
14
15
 
15
- session_id = lambda do |env|
16
+ session_id = Rack::Lint.new(lambda do |env|
16
17
  Rack::Response.new(env["rack.session"].inspect).to_a
17
- end
18
+ end)
18
19
 
19
- nothing = lambda do |env|
20
+ nothing = Rack::Lint.new(lambda do |env|
20
21
  Rack::Response.new("Nothing").to_a
21
- end
22
+ end)
22
23
 
23
- drop_session = lambda do |env|
24
+ drop_session = Rack::Lint.new(lambda do |env|
24
25
  env['rack.session.options'][:drop] = true
25
26
  incrementor.call(env)
26
- end
27
+ end)
27
28
 
28
- renew_session = lambda do |env|
29
+ renew_session = Rack::Lint.new(lambda do |env|
29
30
  env['rack.session.options'][:renew] = true
30
31
  incrementor.call(env)
31
- end
32
+ end)
32
33
 
33
- defer_session = lambda do |env|
34
+ defer_session = Rack::Lint.new(lambda do |env|
34
35
  env['rack.session.options'][:defer] = true
35
36
  incrementor.call(env)
36
- end
37
+ end)
38
+
39
+ incrementor = Rack::Lint.new(incrementor)
37
40
 
38
41
  it "creates a new cookie" do
39
42
  pool = Rack::Session::Pool.new(incrementor)
@@ -1,12 +1,17 @@
1
1
  require 'rack/showexceptions'
2
+ require 'rack/lint'
2
3
  require 'rack/mock'
3
4
 
4
5
  describe Rack::ShowExceptions do
6
+ def show_exceptions(app)
7
+ Rack::Lint.new Rack::ShowExceptions.new(app)
8
+ end
9
+
5
10
  it "catches exceptions" do
6
11
  res = nil
7
12
 
8
13
  req = Rack::MockRequest.new(
9
- Rack::ShowExceptions.new(
14
+ show_exceptions(
10
15
  lambda{|env| raise RuntimeError }
11
16
  ))
12
17
 
@@ -25,7 +30,7 @@ describe Rack::ShowExceptions do
25
30
  res = nil
26
31
 
27
32
  req = Rack::MockRequest.new(
28
- Rack::ShowExceptions.new(
33
+ show_exceptions(
29
34
  lambda{|env| raise RuntimeError, "It was never supposed to work" }
30
35
  ))
31
36
 
@@ -46,7 +51,7 @@ describe Rack::ShowExceptions do
46
51
  res = nil
47
52
 
48
53
  req = Rack::MockRequest.new(
49
- Rack::ShowExceptions.new(
54
+ show_exceptions(
50
55
  lambda{|env| raise RuntimeError, "It was never supposed to work" }
51
56
  ))
52
57
 
@@ -68,7 +73,7 @@ describe Rack::ShowExceptions do
68
73
  res = nil
69
74
 
70
75
  req = Rack::MockRequest.new(
71
- Rack::ShowExceptions.new(
76
+ show_exceptions(
72
77
  lambda{|env| raise RuntimeError, "", [] }
73
78
  )
74
79
  )
@@ -1,10 +1,15 @@
1
1
  require 'rack/showstatus'
2
+ require 'rack/lint'
2
3
  require 'rack/mock'
3
4
 
4
5
  describe Rack::ShowStatus do
6
+ def show_status(app)
7
+ Rack::Lint.new Rack::ShowStatus.new(app)
8
+ end
9
+
5
10
  should "provide a default status message" do
6
11
  req = Rack::MockRequest.new(
7
- Rack::ShowStatus.new(lambda{|env|
12
+ show_status(lambda{|env|
8
13
  [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
9
14
  }))
10
15
 
@@ -19,7 +24,7 @@ describe Rack::ShowStatus do
19
24
 
20
25
  should "let the app provide additional information" do
21
26
  req = Rack::MockRequest.new(
22
- Rack::ShowStatus.new(
27
+ show_status(
23
28
  lambda{|env|
24
29
  env["rack.showstatus.detail"] = "gone too meta."
25
30
  [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
@@ -37,7 +42,7 @@ describe Rack::ShowStatus do
37
42
 
38
43
  should "not replace existing messages" do
39
44
  req = Rack::MockRequest.new(
40
- Rack::ShowStatus.new(
45
+ show_status(
41
46
  lambda{|env|
42
47
  [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
43
48
  }))
@@ -52,7 +57,7 @@ describe Rack::ShowStatus do
52
57
  headers = {"WWW-Authenticate" => "Basic blah"}
53
58
 
54
59
  req = Rack::MockRequest.new(
55
- Rack::ShowStatus.new(lambda{|env| [401, headers, []] }))
60
+ show_status(lambda{|env| [401, headers, []] }))
56
61
  res = req.get("/", :lint => true)
57
62
 
58
63
  res["WWW-Authenticate"].should.equal("Basic blah")
@@ -60,7 +65,7 @@ describe Rack::ShowStatus do
60
65
 
61
66
  should "replace existing messages if there is detail" do
62
67
  req = Rack::MockRequest.new(
63
- Rack::ShowStatus.new(
68
+ show_status(
64
69
  lambda{|env|
65
70
  env["rack.showstatus.detail"] = "gone too meta."
66
71
  [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]