rack 1.6.13 → 2.2.3

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.

Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +694 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +6 -3
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +553 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +141 -93
  67. data/lib/rack/session/cookie.rb +35 -29
  68. data/lib/rack/session/memcache.rb +4 -93
  69. data/lib/rack/session/pool.rb +13 -11
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +12 -12
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +212 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +65 -187
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -358
  176. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  177. data/test/spec_session_pool.rb +0 -246
  178. data/test/spec_showexceptions.rb +0 -98
  179. data/test/spec_showstatus.rb +0 -103
  180. data/test/spec_static.rb +0 -145
  181. data/test/spec_tempfile_reaper.rb +0 -63
  182. data/test/spec_thin.rb +0 -91
  183. data/test/spec_urlmap.rb +0 -236
  184. data/test/spec_utils.rb +0 -647
  185. data/test/spec_version.rb +0 -17
  186. data/test/spec_webrick.rb +0 -184
  187. data/test/static/another/index.html +0 -1
  188. data/test/static/index.html +0 -1
  189. data/test/testrequest.rb +0 -78
  190. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  191. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_server.rb DELETED
@@ -1,167 +0,0 @@
1
- require 'rack'
2
- require 'rack/server'
3
- require 'tempfile'
4
- require 'socket'
5
- require 'open-uri'
6
-
7
- describe Rack::Server do
8
-
9
- def app
10
- lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
11
- end
12
-
13
- def with_stderr
14
- old, $stderr = $stderr, StringIO.new
15
- yield $stderr
16
- ensure
17
- $stderr = old
18
- end
19
-
20
- it "overrides :config if :app is passed in" do
21
- server = Rack::Server.new(:app => "FOO")
22
- server.app.should.equal "FOO"
23
- end
24
-
25
- should "prefer to use :builder when it is passed in" do
26
- server = Rack::Server.new(:builder => "run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }")
27
- server.app.class.should.equal Proc
28
- Rack::MockRequest.new(server.app).get("/").body.to_s.should.equal 'success'
29
- end
30
-
31
- should "allow subclasses to override middleware" do
32
- server = Class.new(Rack::Server).class_eval { def middleware; Hash.new [] end; self }
33
- server.middleware['deployment'].should.not.equal []
34
- server.new(:app => 'foo').middleware['deployment'].should.equal []
35
- end
36
-
37
- should "allow subclasses to override default middleware" do
38
- server = Class.new(Rack::Server).instance_eval { def default_middleware_by_environment; Hash.new [] end; self }
39
- server.middleware['deployment'].should.equal []
40
- server.new(:app => 'foo').middleware['deployment'].should.equal []
41
- end
42
-
43
- should "only provide default middleware for development and deployment environments" do
44
- Rack::Server.default_middleware_by_environment.keys.sort.should.equal %w(deployment development)
45
- end
46
-
47
- should "always return an empty array for unknown environments" do
48
- server = Rack::Server.new(:app => 'foo')
49
- server.middleware['production'].should.equal []
50
- end
51
-
52
- should "not include Rack::Lint in deployment environment" do
53
- server = Rack::Server.new(:app => 'foo')
54
- server.middleware['deployment'].flatten.should.not.include(Rack::Lint)
55
- end
56
-
57
- should "not include Rack::ShowExceptions in deployment environment" do
58
- server = Rack::Server.new(:app => 'foo')
59
- server.middleware['deployment'].flatten.should.not.include(Rack::ShowExceptions)
60
- end
61
-
62
- should "include Rack::TempfileReaper in deployment environment" do
63
- server = Rack::Server.new(:app => 'foo')
64
- server.middleware['deployment'].flatten.should.include(Rack::TempfileReaper)
65
- end
66
-
67
- should "support CGI" do
68
- begin
69
- o, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], 'foo'
70
- server = Rack::Server.new(:app => 'foo')
71
- server.server.name =~ /CGI/
72
- Rack::Server.logging_middleware.call(server).should.eql(nil)
73
- ensure
74
- ENV['REQUEST_METHOD'] = o
75
- end
76
- end
77
-
78
- should "be quiet if said so" do
79
- server = Rack::Server.new(:app => "FOO", :quiet => true)
80
- Rack::Server.logging_middleware.call(server).should.eql(nil)
81
- end
82
-
83
- should "use a full path to the pidfile" do
84
- # avoids issues with daemonize chdir
85
- opts = Rack::Server.new.send(:parse_options, %w[--pid testing.pid])
86
- opts[:pid].should.eql(::File.expand_path('testing.pid'))
87
- end
88
-
89
- should "run a server" do
90
- pidfile = Tempfile.open('pidfile') { |f| break f }.path
91
- FileUtils.rm pidfile
92
- server = Rack::Server.new(
93
- :app => app,
94
- :environment => 'none',
95
- :pid => pidfile,
96
- :Port => TCPServer.open('127.0.0.1', 0){|s| s.addr[1] },
97
- :Host => '127.0.0.1',
98
- :daemonize => false,
99
- :server => 'webrick'
100
- )
101
- t = Thread.new { server.start { |s| Thread.current[:server] = s } }
102
- t.join(0.01) until t[:server] && t[:server].status != :Stop
103
- body = open("http://127.0.0.1:#{server.options[:Port]}/") { |f| f.read }
104
- body.should.eql('success')
105
-
106
- Process.kill(:INT, $$)
107
- t.join
108
- open(pidfile) { |f| f.read.should.eql $$.to_s }
109
- end
110
-
111
- should "check pid file presence and running process" do
112
- pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
113
- server = Rack::Server.new(:pid => pidfile)
114
- server.send(:pidfile_process_status).should.eql :running
115
- end
116
-
117
- should "check pid file presence and dead process" do
118
- dead_pid = `echo $$`.to_i
119
- pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
120
- server = Rack::Server.new(:pid => pidfile)
121
- server.send(:pidfile_process_status).should.eql :dead
122
- end
123
-
124
- should "check pid file presence and exited process" do
125
- pidfile = Tempfile.open('pidfile') { |f| break f }.path
126
- ::File.delete(pidfile)
127
- server = Rack::Server.new(:pid => pidfile)
128
- server.send(:pidfile_process_status).should.eql :exited
129
- end
130
-
131
- should "check pid file presence and not owned process" do
132
- pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
133
- server = Rack::Server.new(:pid => pidfile)
134
- server.send(:pidfile_process_status).should.eql :not_owned
135
- end
136
-
137
- should "not write pid file when it is created after check" do
138
- pidfile = Tempfile.open('pidfile') { |f| break f }.path
139
- ::File.delete(pidfile)
140
- server = Rack::Server.new(:pid => pidfile)
141
- ::File.open(pidfile, 'w') { |f| f.write(1) }
142
- with_stderr do |err|
143
- should.raise(SystemExit) do
144
- server.send(:write_pid)
145
- end
146
- err.rewind
147
- output = err.read
148
- output.should.match(/already running/)
149
- output.should.include? pidfile
150
- end
151
- end
152
-
153
- should "inform the user about existing pidfiles with running processes" do
154
- pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
155
- server = Rack::Server.new(:pid => pidfile)
156
- with_stderr do |err|
157
- should.raise(SystemExit) do
158
- server.start
159
- end
160
- err.rewind
161
- output = err.read
162
- output.should.match(/already running/)
163
- output.should.include? pidfile
164
- end
165
- end
166
-
167
- end
@@ -1,53 +0,0 @@
1
- ### WARNING: there be hax in this file.
2
-
3
- require 'rack/session/abstract/id'
4
-
5
- describe Rack::Session::Abstract::ID do
6
- id = Rack::Session::Abstract::ID
7
-
8
- def silence_warning
9
- o, $VERBOSE = $VERBOSE, nil
10
- yield
11
- ensure
12
- $VERBOSE = o
13
- end
14
-
15
- def reload_id
16
- $".delete $".find { |part| part =~ %r{session/abstract/id.rb} }
17
- silence_warning { require 'rack/session/abstract/id' }
18
- end
19
-
20
- should "use securerandom when available" do
21
- begin
22
- fake = false
23
- silence_warning do
24
- ::SecureRandom = fake = true unless defined?(SecureRandom)
25
- end
26
- reload_id
27
- id::DEFAULT_OPTIONS[:secure_random].should.eql(fake || SecureRandom)
28
- ensure
29
- Object.send(:remove_const, :SecureRandom) if fake
30
- end
31
- end
32
-
33
- should "not use securerandom when unavailable" do
34
- begin
35
- sr = Object.send(:remove_const, :SecureRandom) if defined?(SecureRandom)
36
- reload_id
37
- id::DEFAULT_OPTIONS[:secure_random].should.eql false
38
- ensure
39
- ::SecureRandom = sr if defined?(sr)
40
- end
41
- end
42
-
43
- should "allow to use another securerandom provider" do
44
- secure_random = Class.new do
45
- def hex(*args)
46
- 'fake_hex'
47
- end
48
- end
49
- id = Rack::Session::Abstract::ID.new nil, :secure_random => secure_random.new
50
- id.send(:generate_sid).should.equal 'fake_hex'
51
- end
52
-
53
- end
@@ -1,410 +0,0 @@
1
- require 'rack/session/cookie'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- describe Rack::Session::Cookie do
6
- incrementor = lambda do |env|
7
- env["rack.session"]["counter"] ||= 0
8
- env["rack.session"]["counter"] += 1
9
- hash = env["rack.session"].dup
10
- hash.delete("session_id")
11
- Rack::Response.new(hash.inspect).to_a
12
- end
13
-
14
- session_id = lambda do |env|
15
- Rack::Response.new(env["rack.session"].to_hash.inspect).to_a
16
- end
17
-
18
- session_option = lambda do |opt|
19
- lambda do |env|
20
- Rack::Response.new(env["rack.session.options"][opt].inspect).to_a
21
- end
22
- end
23
-
24
- nothing = lambda do |env|
25
- Rack::Response.new("Nothing").to_a
26
- end
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
-
72
- describe 'Base64' do
73
- it 'uses base64 to encode' do
74
- coder = Rack::Session::Cookie::Base64.new
75
- str = 'fuuuuu'
76
- coder.encode(str).should.equal [str].pack('m')
77
- end
78
-
79
- it 'uses base64 to decode' do
80
- coder = Rack::Session::Cookie::Base64.new
81
- str = ['fuuuuu'].pack('m')
82
- coder.decode(str).should.equal str.unpack('m').first
83
- end
84
-
85
- describe 'Marshal' do
86
- it 'marshals and base64 encodes' do
87
- coder = Rack::Session::Cookie::Base64::Marshal.new
88
- str = 'fuuuuu'
89
- coder.encode(str).should.equal [::Marshal.dump(str)].pack('m')
90
- end
91
-
92
- it 'marshals and base64 decodes' do
93
- coder = Rack::Session::Cookie::Base64::Marshal.new
94
- str = [::Marshal.dump('fuuuuu')].pack('m')
95
- coder.decode(str).should.equal ::Marshal.load(str.unpack('m').first)
96
- end
97
-
98
- it 'rescues failures on decode' do
99
- coder = Rack::Session::Cookie::Base64::Marshal.new
100
- coder.decode('lulz').should.equal nil
101
- end
102
- end
103
-
104
- describe 'JSON' do
105
- it 'marshals and base64 encodes' do
106
- coder = Rack::Session::Cookie::Base64::JSON.new
107
- obj = %w[fuuuuu]
108
- coder.encode(obj).should.equal [::Rack::Utils::OkJson.encode(obj)].pack('m')
109
- end
110
-
111
- it 'marshals and base64 decodes' do
112
- coder = Rack::Session::Cookie::Base64::JSON.new
113
- str = [::Rack::Utils::OkJson.encode(%w[fuuuuu])].pack('m')
114
- coder.decode(str).should.equal ::Rack::Utils::OkJson.decode(str.unpack('m').first)
115
- end
116
-
117
- it 'rescues failures on decode' do
118
- coder = Rack::Session::Cookie::Base64::JSON.new
119
- coder.decode('lulz').should.equal nil
120
- end
121
- end
122
-
123
- describe 'ZipJSON' do
124
- it 'jsons, deflates, and base64 encodes' do
125
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
126
- obj = %w[fuuuuu]
127
- json = Rack::Utils::OkJson.encode(obj)
128
- coder.encode(obj).should.equal [Zlib::Deflate.deflate(json)].pack('m')
129
- end
130
-
131
- it 'base64 decodes, inflates, and decodes json' do
132
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
133
- obj = %w[fuuuuu]
134
- json = Rack::Utils::OkJson.encode(obj)
135
- b64 = [Zlib::Deflate.deflate(json)].pack('m')
136
- coder.decode(b64).should.equal obj
137
- end
138
-
139
- it 'rescues failures on decode' do
140
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
141
- coder.decode('lulz').should.equal nil
142
- end
143
- end
144
- end
145
-
146
- it "warns if no secret is given" do
147
- Rack::Session::Cookie.new(incrementor)
148
- @warnings.first.should =~ /no secret/i
149
- @warnings.clear
150
- Rack::Session::Cookie.new(incrementor, :secret => 'abc')
151
- @warnings.should.be.empty?
152
- end
153
-
154
- it 'uses a coder' do
155
- identity = Class.new {
156
- attr_reader :calls
157
-
158
- def initialize
159
- @calls = []
160
- end
161
-
162
- def encode(str); @calls << :encode; str; end
163
- def decode(str); @calls << :decode; str; end
164
- }.new
165
- response = response_for(:app => [incrementor, { :coder => identity }])
166
-
167
- response["Set-Cookie"].should.include("rack.session=")
168
- response.body.should.equal '{"counter"=>1}'
169
- identity.calls.should.equal [:decode, :encode]
170
- end
171
-
172
- it "creates a new cookie" do
173
- response = response_for(:app => incrementor)
174
- response["Set-Cookie"].should.include("rack.session=")
175
- response.body.should.equal '{"counter"=>1}'
176
- end
177
-
178
- it "loads from a cookie" do
179
- response = response_for(:app => incrementor)
180
-
181
- response = response_for(:app => incrementor, :cookie => response)
182
- response.body.should.equal '{"counter"=>2}'
183
-
184
- response = response_for(:app => incrementor, :cookie => response)
185
- response.body.should.equal '{"counter"=>3}'
186
- end
187
-
188
- it "renew session id" do
189
- response = response_for(:app => incrementor)
190
- cookie = response['Set-Cookie']
191
- response = response_for(:app => only_session_id, :cookie => cookie)
192
- cookie = response['Set-Cookie'] if response['Set-Cookie']
193
-
194
- response.body.should.not.equal ""
195
- old_session_id = response.body
196
-
197
- response = response_for(:app => renewer, :cookie => cookie)
198
- cookie = response['Set-Cookie'] if response['Set-Cookie']
199
- response = response_for(:app => only_session_id, :cookie => cookie)
200
-
201
- response.body.should.not.equal ""
202
- response.body.should.not.equal old_session_id
203
- end
204
-
205
- it "destroys session" do
206
- response = response_for(:app => incrementor)
207
- response = response_for(:app => only_session_id, :cookie => response)
208
-
209
- response.body.should.not.equal ""
210
- old_session_id = response.body
211
-
212
- response = response_for(:app => destroy_session, :cookie => response)
213
- response = response_for(:app => only_session_id, :cookie => response)
214
-
215
- response.body.should.not.equal ""
216
- response.body.should.not.equal old_session_id
217
- end
218
-
219
- it "survives broken cookies" do
220
- response = response_for(
221
- :app => incrementor,
222
- :cookie => "rack.session=blarghfasel"
223
- )
224
- response.body.should.equal '{"counter"=>1}'
225
-
226
- response = response_for(
227
- :app => [incrementor, { :secret => "test" }],
228
- :cookie => "rack.session="
229
- )
230
- response.body.should.equal '{"counter"=>1}'
231
- end
232
-
233
- it "barks on too big cookies" do
234
- lambda{
235
- response_for(:app => bigcookie, :request => { :fatal => true })
236
- }.should.raise(Rack::MockRequest::FatalWarning)
237
- end
238
-
239
- it "loads from a cookie with integrity hash" do
240
- app = [incrementor, { :secret => "test" }]
241
-
242
- response = response_for(:app => app)
243
- response = response_for(:app => app, :cookie => response)
244
- response.body.should.equal '{"counter"=>2}'
245
-
246
- response = response_for(:app => app, :cookie => response)
247
- response.body.should.equal '{"counter"=>3}'
248
-
249
- app = [incrementor, { :secret => "other" }]
250
-
251
- response = response_for(:app => app, :cookie => response)
252
- response.body.should.equal '{"counter"=>1}'
253
- end
254
-
255
- it "loads from a cookie wih accept-only integrity hash for graceful key rotation" do
256
- response = response_for(:app => [incrementor, { :secret => "test" }])
257
-
258
- app = [incrementor, { :secret => "test2", :old_secret => "test" }]
259
- response = response_for(:app => app, :cookie => response)
260
- response.body.should.equal '{"counter"=>2}'
261
-
262
- app = [incrementor, { :secret => "test3", :old_secret => "test2" }]
263
- response = response_for(:app => app, :cookie => response)
264
- response.body.should.equal '{"counter"=>3}'
265
- end
266
-
267
- it "ignores tampered with session cookies" do
268
- app = [incrementor, { :secret => "test" }]
269
- response = response_for(:app => app)
270
- response.body.should.equal '{"counter"=>1}'
271
-
272
- response = response_for(:app => app, :cookie => response)
273
- response.body.should.equal '{"counter"=>2}'
274
-
275
- _, digest = response["Set-Cookie"].split("--")
276
- tampered_with_cookie = "hackerman-was-here" + "--" + digest
277
-
278
- response = response_for(:app => app, :cookie => tampered_with_cookie)
279
- response.body.should.equal '{"counter"=>1}'
280
- end
281
-
282
- it "supports either of secret or old_secret" do
283
- app = [incrementor, { :secret => "test" }]
284
- response = response_for(:app => app)
285
- response.body.should.equal '{"counter"=>1}'
286
-
287
- response = response_for(:app => app, :cookie => response)
288
- response.body.should.equal '{"counter"=>2}'
289
-
290
- app = [incrementor, { :old_secret => "test" }]
291
- response = response_for(:app => app)
292
- response.body.should.equal '{"counter"=>1}'
293
-
294
- response = response_for(:app => app, :cookie => response)
295
- response.body.should.equal '{"counter"=>2}'
296
- end
297
-
298
- it "can handle Rack::Lint middleware" do
299
- response = response_for(:app => incrementor)
300
-
301
- lint = Rack::Lint.new(session_id)
302
- response = response_for(:app => lint, :cookie => response)
303
- response.body.should.not.be.nil
304
- end
305
-
306
- it "can handle middleware that inspects the env" do
307
- class TestEnvInspector
308
- def initialize(app)
309
- @app = app
310
- end
311
- def call(env)
312
- env.inspect
313
- @app.call(env)
314
- end
315
- end
316
-
317
- response = response_for(:app => incrementor)
318
-
319
- inspector = TestEnvInspector.new(session_id)
320
- response = response_for(:app => inspector, :cookie => response)
321
- response.body.should.not.be.nil
322
- end
323
-
324
- it "returns the session id in the session hash" do
325
- response = response_for(:app => incrementor)
326
- response.body.should.equal '{"counter"=>1}'
327
-
328
- response = response_for(:app => session_id, :cookie => response)
329
- response.body.should.match(/"session_id"=>/)
330
- response.body.should.match(/"counter"=>1/)
331
- end
332
-
333
- it "does not return a cookie if set to secure but not using ssl" do
334
- app = [incrementor, { :secure => true }]
335
-
336
- response = response_for(:app => app)
337
- response["Set-Cookie"].should.be.nil
338
-
339
- response = response_for(:app => app, :request => { "HTTPS" => "on" })
340
- response["Set-Cookie"].should.not.be.nil
341
- response["Set-Cookie"].should.match(/secure/)
342
- end
343
-
344
- it "does not return a cookie if cookie was not read/written" do
345
- response = response_for(:app => nothing)
346
- response["Set-Cookie"].should.be.nil
347
- end
348
-
349
- it "does not return a cookie if cookie was not written (only read)" do
350
- response = response_for(:app => session_id)
351
- response["Set-Cookie"].should.be.nil
352
- end
353
-
354
- it "returns even if not read/written if :expire_after is set" do
355
- app = [nothing, { :expire_after => 3600 }]
356
- request = { "rack.session" => { "not" => "empty" }}
357
- response = response_for(:app => app, :request => request)
358
- response["Set-Cookie"].should.not.be.nil
359
- end
360
-
361
- it "returns no cookie if no data was written and no session was created previously, even if :expire_after is set" do
362
- app = [nothing, { :expire_after => 3600 }]
363
- response = response_for(:app => app)
364
- response["Set-Cookie"].should.be.nil
365
- end
366
-
367
- it "exposes :secret in env['rack.session.option']" do
368
- response = response_for(:app => [session_option[:secret], { :secret => "foo" }])
369
- response.body.should == '"foo"'
370
- end
371
-
372
- it "exposes :coder in env['rack.session.option']" do
373
- response = response_for(:app => session_option[:coder])
374
- response.body.should.match(/Base64::Marshal/)
375
- end
376
-
377
- it "allows passing in a hash with session data from middleware in front" do
378
- request = { 'rack.session' => { :foo => 'bar' }}
379
- response = response_for(:app => session_id, :request => request)
380
- response.body.should.match(/foo/)
381
- end
382
-
383
- it "allows modifying session data with session data from middleware in front" do
384
- request = { 'rack.session' => { :foo => 'bar' }}
385
- response = response_for(:app => incrementor, :request => request)
386
- response.body.should.match(/counter/)
387
- response.body.should.match(/foo/)
388
- end
389
-
390
- it "allows more than one '--' in the cookie when calculating digests" do
391
- @counter = 0
392
- app = lambda do |env|
393
- env["rack.session"]["message"] ||= ""
394
- env["rack.session"]["message"] << "#{(@counter += 1).to_s}--"
395
- hash = env["rack.session"].dup
396
- hash.delete("session_id")
397
- Rack::Response.new(hash["message"]).to_a
398
- end
399
- # another example of an unsafe coder is Base64.urlsafe_encode64
400
- unsafe_coder = Class.new {
401
- def encode(hash); hash.inspect end
402
- def decode(str); eval(str) if str; end
403
- }.new
404
- _app = [ app, { :secret => "test", :coder => unsafe_coder } ]
405
- response = response_for(:app => _app)
406
- response.body.should.equal "1--"
407
- response = response_for(:app => _app, :cookie => response)
408
- response.body.should.equal "1--2--"
409
- end
410
- end