rack 1.0.1 → 2.2.21

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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +829 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +355 -0
  6. data/Rakefile +64 -98
  7. data/SPEC.rdoc +292 -0
  8. data/bin/rackup +3 -174
  9. data/contrib/rack.png +0 -0
  10. data/contrib/rack.svg +150 -0
  11. data/contrib/rack_logo.svg +164 -111
  12. data/contrib/rdoc.css +412 -0
  13. data/example/lobster.ru +2 -0
  14. data/example/protectedlobster.rb +4 -2
  15. data/example/protectedlobster.ru +3 -1
  16. data/lib/rack/auth/abstract/handler.rb +7 -5
  17. data/lib/rack/auth/abstract/request.rb +12 -2
  18. data/lib/rack/auth/basic.rb +6 -4
  19. data/lib/rack/auth/digest/md5.rb +20 -13
  20. data/lib/rack/auth/digest/nonce.rb +6 -4
  21. data/lib/rack/auth/digest/params.rb +11 -12
  22. data/lib/rack/auth/digest/request.rb +15 -12
  23. data/lib/rack/body_proxy.rb +45 -0
  24. data/lib/rack/builder.rb +213 -19
  25. data/lib/rack/cascade.rb +50 -18
  26. data/lib/rack/chunked.rb +95 -27
  27. data/lib/rack/common_logger.rb +84 -0
  28. data/lib/rack/conditional_get.rb +83 -0
  29. data/lib/rack/config.rb +22 -0
  30. data/lib/rack/content_length.rb +19 -10
  31. data/lib/rack/content_type.rb +12 -5
  32. data/lib/rack/core_ext/regexp.rb +14 -0
  33. data/lib/rack/deflater.rb +90 -42
  34. data/lib/rack/directory.rb +118 -72
  35. data/lib/rack/etag.rb +77 -0
  36. data/lib/rack/events.rb +153 -0
  37. data/lib/rack/file.rb +4 -85
  38. data/lib/rack/files.rb +218 -0
  39. data/lib/rack/handler/cgi.rb +22 -24
  40. data/lib/rack/handler/fastcgi.rb +34 -24
  41. data/lib/rack/handler/lsws.rb +16 -15
  42. data/lib/rack/handler/scgi.rb +38 -29
  43. data/lib/rack/handler/thin.rb +23 -7
  44. data/lib/rack/handler/webrick.rb +95 -37
  45. data/lib/rack/handler.rb +49 -14
  46. data/lib/rack/head.rb +19 -13
  47. data/lib/rack/lint.rb +466 -217
  48. data/lib/rack/lobster.rb +19 -14
  49. data/lib/rack/lock.rb +24 -8
  50. data/lib/rack/logger.rb +20 -0
  51. data/lib/rack/media_type.rb +53 -0
  52. data/lib/rack/method_override.rb +52 -0
  53. data/lib/rack/mime.rb +652 -171
  54. data/lib/rack/mock.rb +203 -64
  55. data/lib/rack/multipart/generator.rb +97 -0
  56. data/lib/rack/multipart/parser.rb +440 -0
  57. data/lib/rack/multipart/uploaded_file.rb +41 -0
  58. data/lib/rack/multipart.rb +64 -0
  59. data/lib/rack/null_logger.rb +39 -0
  60. data/lib/rack/query_parser.rb +266 -0
  61. data/lib/rack/recursive.rb +18 -11
  62. data/lib/rack/reloader.rb +13 -5
  63. data/lib/rack/request.rb +607 -191
  64. data/lib/rack/response.rb +245 -110
  65. data/lib/rack/rewindable_input.rb +15 -21
  66. data/lib/rack/runtime.rb +34 -0
  67. data/lib/rack/sendfile.rb +192 -0
  68. data/lib/rack/server.rb +466 -0
  69. data/lib/rack/session/abstract/id.rb +449 -68
  70. data/lib/rack/session/cookie.rb +159 -47
  71. data/lib/rack/session/memcache.rb +4 -103
  72. data/lib/rack/session/pool.rb +39 -49
  73. data/lib/rack/show_exceptions.rb +390 -0
  74. data/lib/rack/{showstatus.rb → show_status.rb} +21 -14
  75. data/lib/rack/static.rb +164 -14
  76. data/lib/rack/tempfile_reaper.rb +22 -0
  77. data/lib/rack/urlmap.rb +60 -18
  78. data/lib/rack/utils.rb +508 -277
  79. data/lib/rack/version.rb +29 -0
  80. data/lib/rack.rb +85 -34
  81. data/rack.gemspec +43 -51
  82. metadata +119 -207
  83. data/KNOWN-ISSUES +0 -18
  84. data/RDOX +0 -428
  85. data/README +0 -364
  86. data/SPEC +0 -164
  87. data/lib/rack/adapter/camping.rb +0 -22
  88. data/lib/rack/auth/openid.rb +0 -480
  89. data/lib/rack/commonlogger.rb +0 -61
  90. data/lib/rack/conditionalget.rb +0 -47
  91. data/lib/rack/handler/evented_mongrel.rb +0 -8
  92. data/lib/rack/handler/mongrel.rb +0 -87
  93. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  94. data/lib/rack/methodoverride.rb +0 -27
  95. data/lib/rack/showexceptions.rb +0 -349
  96. data/test/cgi/lighttpd.conf +0 -20
  97. data/test/cgi/test +0 -9
  98. data/test/cgi/test.fcgi +0 -8
  99. data/test/cgi/test.ru +0 -7
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/empty +0 -10
  102. data/test/multipart/ie +0 -6
  103. data/test/multipart/nested +0 -10
  104. data/test/multipart/none +0 -9
  105. data/test/multipart/semicolon +0 -6
  106. data/test/multipart/text +0 -10
  107. data/test/spec_rack_auth_basic.rb +0 -73
  108. data/test/spec_rack_auth_digest.rb +0 -226
  109. data/test/spec_rack_auth_openid.rb +0 -84
  110. data/test/spec_rack_builder.rb +0 -84
  111. data/test/spec_rack_camping.rb +0 -51
  112. data/test/spec_rack_cascade.rb +0 -50
  113. data/test/spec_rack_cgi.rb +0 -89
  114. data/test/spec_rack_chunked.rb +0 -62
  115. data/test/spec_rack_commonlogger.rb +0 -32
  116. data/test/spec_rack_conditionalget.rb +0 -41
  117. data/test/spec_rack_content_length.rb +0 -43
  118. data/test/spec_rack_content_type.rb +0 -30
  119. data/test/spec_rack_deflater.rb +0 -127
  120. data/test/spec_rack_directory.rb +0 -61
  121. data/test/spec_rack_fastcgi.rb +0 -89
  122. data/test/spec_rack_file.rb +0 -75
  123. data/test/spec_rack_handler.rb +0 -43
  124. data/test/spec_rack_head.rb +0 -30
  125. data/test/spec_rack_lint.rb +0 -521
  126. data/test/spec_rack_lobster.rb +0 -45
  127. data/test/spec_rack_lock.rb +0 -38
  128. data/test/spec_rack_methodoverride.rb +0 -60
  129. data/test/spec_rack_mock.rb +0 -157
  130. data/test/spec_rack_mongrel.rb +0 -189
  131. data/test/spec_rack_recursive.rb +0 -77
  132. data/test/spec_rack_request.rb +0 -504
  133. data/test/spec_rack_response.rb +0 -218
  134. data/test/spec_rack_rewindable_input.rb +0 -118
  135. data/test/spec_rack_session_cookie.rb +0 -82
  136. data/test/spec_rack_session_memcache.rb +0 -240
  137. data/test/spec_rack_session_pool.rb +0 -172
  138. data/test/spec_rack_showexceptions.rb +0 -21
  139. data/test/spec_rack_showstatus.rb +0 -72
  140. data/test/spec_rack_static.rb +0 -37
  141. data/test/spec_rack_thin.rb +0 -91
  142. data/test/spec_rack_urlmap.rb +0 -185
  143. data/test/spec_rack_utils.rb +0 -387
  144. data/test/spec_rack_webrick.rb +0 -130
  145. data/test/testrequest.rb +0 -57
  146. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  147. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,218 +0,0 @@
1
- require 'test/spec'
2
- require 'set'
3
-
4
- require 'rack/response'
5
-
6
- context "Rack::Response" do
7
- specify "has sensible default values" do
8
- response = Rack::Response.new
9
- status, header, body = response.finish
10
- status.should.equal 200
11
- header.should.equal "Content-Type" => "text/html"
12
- body.each { |part|
13
- part.should.equal ""
14
- }
15
-
16
- response = Rack::Response.new
17
- status, header, body = *response
18
- status.should.equal 200
19
- header.should.equal "Content-Type" => "text/html"
20
- body.each { |part|
21
- part.should.equal ""
22
- }
23
- end
24
-
25
- specify "can be written to" do
26
- response = Rack::Response.new
27
-
28
- status, header, body = response.finish do
29
- response.write "foo"
30
- response.write "bar"
31
- response.write "baz"
32
- end
33
-
34
- parts = []
35
- body.each { |part| parts << part }
36
-
37
- parts.should.equal ["foo", "bar", "baz"]
38
- end
39
-
40
- specify "can set and read headers" do
41
- response = Rack::Response.new
42
- response["Content-Type"].should.equal "text/html"
43
- response["Content-Type"] = "text/plain"
44
- response["Content-Type"].should.equal "text/plain"
45
- end
46
-
47
- specify "can set cookies" do
48
- response = Rack::Response.new
49
-
50
- response.set_cookie "foo", "bar"
51
- response["Set-Cookie"].should.equal "foo=bar"
52
- response.set_cookie "foo2", "bar2"
53
- response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"]
54
- response.set_cookie "foo3", "bar3"
55
- response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"]
56
- end
57
-
58
- specify "formats the Cookie expiration date accordingly to RFC 2109" do
59
- response = Rack::Response.new
60
-
61
- response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
62
- response["Set-Cookie"].should.match(
63
- /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
64
- end
65
-
66
- specify "can set secure cookies" do
67
- response = Rack::Response.new
68
- response.set_cookie "foo", {:value => "bar", :secure => true}
69
- response["Set-Cookie"].should.equal "foo=bar; secure"
70
- end
71
-
72
- specify "can set http only cookies" do
73
- response = Rack::Response.new
74
- response.set_cookie "foo", {:value => "bar", :httponly => true}
75
- response["Set-Cookie"].should.equal "foo=bar; HttpOnly"
76
- end
77
-
78
- specify "can delete cookies" do
79
- response = Rack::Response.new
80
- response.set_cookie "foo", "bar"
81
- response.set_cookie "foo2", "bar2"
82
- response.delete_cookie "foo"
83
- response["Set-Cookie"].should.equal ["foo2=bar2",
84
- "foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"]
85
- end
86
-
87
- specify "can do redirects" do
88
- response = Rack::Response.new
89
- response.redirect "/foo"
90
- status, header, body = response.finish
91
-
92
- status.should.equal 302
93
- header["Location"].should.equal "/foo"
94
-
95
- response = Rack::Response.new
96
- response.redirect "/foo", 307
97
- status, header, body = response.finish
98
-
99
- status.should.equal 307
100
- end
101
-
102
- specify "has a useful constructor" do
103
- r = Rack::Response.new("foo")
104
- status, header, body = r.finish
105
- str = ""; body.each { |part| str << part }
106
- str.should.equal "foo"
107
-
108
- r = Rack::Response.new(["foo", "bar"])
109
- status, header, body = r.finish
110
- str = ""; body.each { |part| str << part }
111
- str.should.equal "foobar"
112
-
113
- r = Rack::Response.new(["foo", "bar"].to_set)
114
- r.write "foo"
115
- status, header, body = r.finish
116
- str = ""; body.each { |part| str << part }
117
- str.should.equal "foobarfoo"
118
-
119
- r = Rack::Response.new([], 500)
120
- r.status.should.equal 500
121
- end
122
-
123
- specify "has a constructor that can take a block" do
124
- r = Rack::Response.new { |res|
125
- res.status = 404
126
- res.write "foo"
127
- }
128
- status, header, body = r.finish
129
- str = ""; body.each { |part| str << part }
130
- str.should.equal "foo"
131
- status.should.equal 404
132
- end
133
-
134
- specify "doesn't return invalid responses" do
135
- r = Rack::Response.new(["foo", "bar"], 204)
136
- status, header, body = r.finish
137
- str = ""; body.each { |part| str << part }
138
- str.should.be.empty
139
- header["Content-Type"].should.equal nil
140
-
141
- lambda {
142
- Rack::Response.new(Object.new)
143
- }.should.raise(TypeError).
144
- message.should =~ /stringable or iterable required/
145
- end
146
-
147
- specify "knows if it's empty" do
148
- r = Rack::Response.new
149
- r.should.be.empty
150
- r.write "foo"
151
- r.should.not.be.empty
152
-
153
- r = Rack::Response.new
154
- r.should.be.empty
155
- r.finish
156
- r.should.be.empty
157
-
158
- r = Rack::Response.new
159
- r.should.be.empty
160
- r.finish { }
161
- r.should.not.be.empty
162
- end
163
-
164
- specify "should provide access to the HTTP status" do
165
- res = Rack::Response.new
166
- res.status = 200
167
- res.should.be.successful
168
- res.should.be.ok
169
-
170
- res.status = 404
171
- res.should.not.be.successful
172
- res.should.be.client_error
173
- res.should.be.not_found
174
-
175
- res.status = 501
176
- res.should.not.be.successful
177
- res.should.be.server_error
178
-
179
- res.status = 307
180
- res.should.be.redirect
181
- end
182
-
183
- specify "should provide access to the HTTP headers" do
184
- res = Rack::Response.new
185
- res["Content-Type"] = "text/yaml"
186
-
187
- res.should.include "Content-Type"
188
- res.headers["Content-Type"].should.equal "text/yaml"
189
- res["Content-Type"].should.equal "text/yaml"
190
- res.content_type.should.equal "text/yaml"
191
- res.content_length.should.be.nil
192
- res.location.should.be.nil
193
- end
194
-
195
- specify "does not add or change Content-Length when #finish()ing" do
196
- res = Rack::Response.new
197
- res.status = 200
198
- res.finish
199
- res.headers["Content-Length"].should.be.nil
200
-
201
- res = Rack::Response.new
202
- res.status = 200
203
- res.headers["Content-Length"] = "10"
204
- res.finish
205
- res.headers["Content-Length"].should.equal "10"
206
- end
207
-
208
- specify "updates Content-Length when body appended to using #write" do
209
- res = Rack::Response.new
210
- res.status = 200
211
- res.headers["Content-Length"].should.be.nil
212
- res.write "Hi"
213
- res.headers["Content-Length"].should.equal "2"
214
- res.write " there"
215
- res.headers["Content-Length"].should.equal "8"
216
- end
217
-
218
- end
@@ -1,118 +0,0 @@
1
- require 'test/spec'
2
- require 'stringio'
3
- require 'rack/rewindable_input'
4
-
5
- shared_context "a rewindable IO object" do
6
- setup do
7
- @rio = Rack::RewindableInput.new(@io)
8
- end
9
-
10
- teardown do
11
- @rio.close
12
- end
13
-
14
- specify "should be able to handle to read()" do
15
- @rio.read.should.equal "hello world"
16
- end
17
-
18
- specify "should be able to handle to read(nil)" do
19
- @rio.read(nil).should.equal "hello world"
20
- end
21
-
22
- specify "should be able to handle to read(length)" do
23
- @rio.read(1).should.equal "h"
24
- end
25
-
26
- specify "should be able to handle to read(length, buffer)" do
27
- buffer = ""
28
- result = @rio.read(1, buffer)
29
- result.should.equal "h"
30
- result.object_id.should.equal buffer.object_id
31
- end
32
-
33
- specify "should be able to handle to read(nil, buffer)" do
34
- buffer = ""
35
- result = @rio.read(nil, buffer)
36
- result.should.equal "hello world"
37
- result.object_id.should.equal buffer.object_id
38
- end
39
-
40
- specify "should rewind to the beginning when #rewind is called" do
41
- @rio.read(1)
42
- @rio.rewind
43
- @rio.read.should.equal "hello world"
44
- end
45
-
46
- specify "should be able to handle gets" do
47
- @rio.gets.should == "hello world"
48
- end
49
-
50
- specify "should be able to handle each" do
51
- array = []
52
- @rio.each do |data|
53
- array << data
54
- end
55
- array.should.equal(["hello world"])
56
- end
57
-
58
- specify "should not buffer into a Tempfile if no data has been read yet" do
59
- @rio.instance_variable_get(:@rewindable_io).should.be.nil
60
- end
61
-
62
- specify "should buffer into a Tempfile when data has been consumed for the first time" do
63
- @rio.read(1)
64
- tempfile = @rio.instance_variable_get(:@rewindable_io)
65
- tempfile.should.not.be.nil
66
- @rio.read(1)
67
- tempfile2 = @rio.instance_variable_get(:@rewindable_io)
68
- tempfile2.should.equal tempfile
69
- end
70
-
71
- specify "should close the underlying tempfile upon calling #close" do
72
- @rio.read(1)
73
- tempfile = @rio.instance_variable_get(:@rewindable_io)
74
- @rio.close
75
- tempfile.should.be.closed
76
- end
77
-
78
- specify "should be possibel to call #close when no data has been buffered yet" do
79
- @rio.close
80
- end
81
-
82
- specify "should be possible to call #close multiple times" do
83
- @rio.close
84
- @rio.close
85
- end
86
- end
87
-
88
- context "Rack::RewindableInput" do
89
- context "given an IO object that is already rewindable" do
90
- setup do
91
- @io = StringIO.new("hello world")
92
- end
93
-
94
- it_should_behave_like "a rewindable IO object"
95
- end
96
-
97
- context "given an IO object that is not rewindable" do
98
- setup do
99
- @io = StringIO.new("hello world")
100
- @io.instance_eval do
101
- undef :rewind
102
- end
103
- end
104
-
105
- it_should_behave_like "a rewindable IO object"
106
- end
107
-
108
- context "given an IO object whose rewind method raises Errno::ESPIPE" do
109
- setup do
110
- @io = StringIO.new("hello world")
111
- def @io.rewind
112
- raise Errno::ESPIPE, "You can't rewind this!"
113
- end
114
- end
115
-
116
- it_should_behave_like "a rewindable IO object"
117
- end
118
- end
@@ -1,82 +0,0 @@
1
- require 'test/spec'
2
-
3
- require 'rack/session/cookie'
4
- require 'rack/mock'
5
- require 'rack/response'
6
-
7
- context "Rack::Session::Cookie" do
8
- incrementor = lambda { |env|
9
- env["rack.session"]["counter"] ||= 0
10
- env["rack.session"]["counter"] += 1
11
- Rack::Response.new(env["rack.session"].inspect).to_a
12
- }
13
-
14
- specify "creates a new cookie" do
15
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
16
- res["Set-Cookie"].should.match("rack.session=")
17
- res.body.should.equal '{"counter"=>1}'
18
- end
19
-
20
- specify "loads from a cookie" do
21
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
22
- cookie = res["Set-Cookie"]
23
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
24
- get("/", "HTTP_COOKIE" => cookie)
25
- res.body.should.equal '{"counter"=>2}'
26
- cookie = res["Set-Cookie"]
27
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
28
- get("/", "HTTP_COOKIE" => cookie)
29
- res.body.should.equal '{"counter"=>3}'
30
- end
31
-
32
- specify "survives broken cookies" do
33
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
34
- get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
35
- res.body.should.equal '{"counter"=>1}'
36
- end
37
-
38
- bigcookie = lambda { |env|
39
- env["rack.session"]["cookie"] = "big" * 3000
40
- Rack::Response.new(env["rack.session"].inspect).to_a
41
- }
42
-
43
- specify "barks on too big cookies" do
44
- lambda {
45
- Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)).
46
- get("/", :fatal => true)
47
- }.should.raise(Rack::MockRequest::FatalWarning)
48
- end
49
-
50
- specify "creates a new cookie with integrity hash" do
51
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
52
- if RUBY_VERSION < "1.9"
53
- res["Set-Cookie"].should.match("rack.session=BAh7BiIMY291bnRlcmkG%0A--1439b4d37b9d4b04c603848382f712d6fcd31088")
54
- else
55
- res["Set-Cookie"].should.match("rack.session=BAh7BkkiDGNvdW50ZXIGOg1lbmNvZGluZyINVVMtQVNDSUlpBg%3D%3D%0A--d7a6637b94d2728194a96c18484e1f7ed9074a83")
56
- end
57
- end
58
-
59
- specify "loads from a cookie wih integrity hash" do
60
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
61
- cookie = res["Set-Cookie"]
62
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
63
- get("/", "HTTP_COOKIE" => cookie)
64
- res.body.should.equal '{"counter"=>2}'
65
- cookie = res["Set-Cookie"]
66
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
67
- get("/", "HTTP_COOKIE" => cookie)
68
- res.body.should.equal '{"counter"=>3}'
69
- end
70
-
71
- specify "ignores tampered with session cookies" do
72
- app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
73
- response1 = Rack::MockRequest.new(app).get("/")
74
- _, digest = response1["Set-Cookie"].split("--")
75
- tampered_with_cookie = "hackerman-was-here" + "--" + digest
76
- response2 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" =>
77
- tampered_with_cookie)
78
-
79
- # The tampered-with cookie is ignored, so we get back an identical Set-Cookie
80
- response2["Set-Cookie"].should.equal(response1["Set-Cookie"])
81
- end
82
- end
@@ -1,240 +0,0 @@
1
- require 'test/spec'
2
-
3
- begin
4
- require 'rack/session/memcache'
5
- require 'rack/mock'
6
- require 'rack/response'
7
- require 'thread'
8
-
9
- context "Rack::Session::Memcache" do
10
- session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key]
11
- session_match = /#{session_key}=[0-9a-fA-F]+;/
12
- incrementor = lambda do |env|
13
- env["rack.session"]["counter"] ||= 0
14
- env["rack.session"]["counter"] += 1
15
- Rack::Response.new(env["rack.session"].inspect).to_a
16
- end
17
- drop_session = proc do |env|
18
- env['rack.session.options'][:drop] = true
19
- incrementor.call(env)
20
- end
21
- renew_session = proc do |env|
22
- env['rack.session.options'][:renew] = true
23
- incrementor.call(env)
24
- end
25
- defer_session = proc do |env|
26
- env['rack.session.options'][:defer] = true
27
- incrementor.call(env)
28
- end
29
-
30
- specify "MemCache can connect to existing server" do
31
- test_pool = MemCache.new :namespace => 'test:rack:session'
32
- end
33
-
34
- specify "faults on no connection" do
35
- lambda do
36
- Rack::Session::Memcache.new(incrementor, :memcache_server => '')
37
- end.should.raise
38
- end
39
-
40
- specify "creates a new cookie" do
41
- pool = Rack::Session::Memcache.new(incrementor)
42
- res = Rack::MockRequest.new(pool).get("/")
43
- res["Set-Cookie"].should.match("#{session_key}=")
44
- res.body.should.equal '{"counter"=>1}'
45
- end
46
-
47
- specify "determines session from a cookie" do
48
- pool = Rack::Session::Memcache.new(incrementor)
49
- req = Rack::MockRequest.new(pool)
50
- res = req.get("/")
51
- cookie = res["Set-Cookie"]
52
- req.get("/", "HTTP_COOKIE" => cookie).
53
- body.should.equal '{"counter"=>2}'
54
- req.get("/", "HTTP_COOKIE" => cookie).
55
- body.should.equal '{"counter"=>3}'
56
- end
57
-
58
- specify "survives nonexistant cookies" do
59
- bad_cookie = "rack.session=blarghfasel"
60
- pool = Rack::Session::Memcache.new(incrementor)
61
- res = Rack::MockRequest.new(pool).
62
- get("/", "HTTP_COOKIE" => bad_cookie)
63
- res.body.should.equal '{"counter"=>1}'
64
- cookie = res["Set-Cookie"][session_match]
65
- cookie.should.not.match(/#{bad_cookie}/)
66
- end
67
-
68
- specify "maintains freshness" do
69
- pool = Rack::Session::Memcache.new(incrementor, :expire_after => 3)
70
- res = Rack::MockRequest.new(pool).get('/')
71
- res.body.should.include '"counter"=>1'
72
- cookie = res["Set-Cookie"]
73
- res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
74
- res["Set-Cookie"].should.equal cookie
75
- res.body.should.include '"counter"=>2'
76
- puts 'Sleeping to expire session' if $DEBUG
77
- sleep 4
78
- res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
79
- res["Set-Cookie"].should.not.equal cookie
80
- res.body.should.include '"counter"=>1'
81
- end
82
-
83
- specify "deletes cookies with :drop option" do
84
- pool = Rack::Session::Memcache.new(incrementor)
85
- req = Rack::MockRequest.new(pool)
86
- drop = Rack::Utils::Context.new(pool, drop_session)
87
- dreq = Rack::MockRequest.new(drop)
88
-
89
- res0 = req.get("/")
90
- session = (cookie = res0["Set-Cookie"])[session_match]
91
- res0.body.should.equal '{"counter"=>1}'
92
-
93
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
94
- res1["Set-Cookie"][session_match].should.equal session
95
- res1.body.should.equal '{"counter"=>2}'
96
-
97
- res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
98
- res2["Set-Cookie"].should.equal nil
99
- res2.body.should.equal '{"counter"=>3}'
100
-
101
- res3 = req.get("/", "HTTP_COOKIE" => cookie)
102
- res3["Set-Cookie"][session_match].should.not.equal session
103
- res3.body.should.equal '{"counter"=>1}'
104
- end
105
-
106
- specify "provides new session id with :renew option" do
107
- pool = Rack::Session::Memcache.new(incrementor)
108
- req = Rack::MockRequest.new(pool)
109
- renew = Rack::Utils::Context.new(pool, renew_session)
110
- rreq = Rack::MockRequest.new(renew)
111
-
112
- res0 = req.get("/")
113
- session = (cookie = res0["Set-Cookie"])[session_match]
114
- res0.body.should.equal '{"counter"=>1}'
115
-
116
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
117
- res1["Set-Cookie"][session_match].should.equal session
118
- res1.body.should.equal '{"counter"=>2}'
119
-
120
- res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
121
- new_cookie = res2["Set-Cookie"]
122
- new_session = new_cookie[session_match]
123
- new_session.should.not.equal session
124
- res2.body.should.equal '{"counter"=>3}'
125
-
126
- res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
127
- res3["Set-Cookie"][session_match].should.equal new_session
128
- res3.body.should.equal '{"counter"=>4}'
129
- end
130
-
131
- specify "omits cookie with :defer option" do
132
- pool = Rack::Session::Memcache.new(incrementor)
133
- req = Rack::MockRequest.new(pool)
134
- defer = Rack::Utils::Context.new(pool, defer_session)
135
- dreq = Rack::MockRequest.new(defer)
136
-
137
- res0 = req.get("/")
138
- session = (cookie = res0["Set-Cookie"])[session_match]
139
- res0.body.should.equal '{"counter"=>1}'
140
-
141
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
142
- res1["Set-Cookie"][session_match].should.equal session
143
- res1.body.should.equal '{"counter"=>2}'
144
-
145
- res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
146
- res2["Set-Cookie"].should.equal nil
147
- res2.body.should.equal '{"counter"=>3}'
148
-
149
- res3 = req.get("/", "HTTP_COOKIE" => cookie)
150
- res3["Set-Cookie"][session_match].should.equal session
151
- res3.body.should.equal '{"counter"=>4}'
152
- end
153
-
154
- # anyone know how to do this better?
155
- specify "multithread: should cleanly merge sessions" do
156
- next unless $DEBUG
157
- warn 'Running multithread test for Session::Memcache'
158
- pool = Rack::Session::Memcache.new(incrementor)
159
- req = Rack::MockRequest.new(pool)
160
-
161
- res = req.get('/')
162
- res.body.should.equal '{"counter"=>1}'
163
- cookie = res["Set-Cookie"]
164
- sess_id = cookie[/#{pool.key}=([^,;]+)/,1]
165
-
166
- delta_incrementor = lambda do |env|
167
- # emulate disconjoinment of threading
168
- env['rack.session'] = env['rack.session'].dup
169
- Thread.stop
170
- env['rack.session'][(Time.now.usec*rand).to_i] = true
171
- incrementor.call(env)
172
- end
173
- tses = Rack::Utils::Context.new pool, delta_incrementor
174
- treq = Rack::MockRequest.new(tses)
175
- tnum = rand(7).to_i+5
176
- r = Array.new(tnum) do
177
- Thread.new(treq) do |run|
178
- run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
179
- end
180
- end.reverse.map{|t| t.run.join.value }
181
- r.each do |res|
182
- res['Set-Cookie'].should.equal cookie
183
- res.body.should.include '"counter"=>2'
184
- end
185
-
186
- session = pool.pool.get(sess_id)
187
- session.size.should.be tnum+1 # counter
188
- session['counter'].should.be 2 # meeeh
189
-
190
- tnum = rand(7).to_i+5
191
- r = Array.new(tnum) do |i|
192
- delta_time = proc do |env|
193
- env['rack.session'][i] = Time.now
194
- Thread.stop
195
- env['rack.session'] = env['rack.session'].dup
196
- env['rack.session'][i] -= Time.now
197
- incrementor.call(env)
198
- end
199
- app = Rack::Utils::Context.new pool, time_delta
200
- req = Rack::MockRequest.new app
201
- Thread.new(req) do |run|
202
- run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
203
- end
204
- end.reverse.map{|t| t.run.join.value }
205
- r.each do |res|
206
- res['Set-Cookie'].should.equal cookie
207
- res.body.should.include '"counter"=>3'
208
- end
209
-
210
- session = pool.pool.get(sess_id)
211
- session.size.should.be tnum+1
212
- session['counter'].should.be 3
213
-
214
- drop_counter = proc do |env|
215
- env['rack.session'].delete 'counter'
216
- env['rack.session']['foo'] = 'bar'
217
- [200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
218
- end
219
- tses = Rack::Utils::Context.new pool, drop_counter
220
- treq = Rack::MockRequest.new(tses)
221
- tnum = rand(7).to_i+5
222
- r = Array.new(tnum) do
223
- Thread.new(treq) do |run|
224
- run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
225
- end
226
- end.reverse.map{|t| t.run.join.value }
227
- r.each do |res|
228
- res['Set-Cookie'].should.equal cookie
229
- res.body.should.include '"foo"=>"bar"'
230
- end
231
-
232
- session = pool.pool.get(sess_id)
233
- session.size.should.be r.size+1
234
- session['counter'].should.be.nil?
235
- session['foo'].should.equal 'bar'
236
- end
237
- end
238
- rescue LoadError
239
- $stderr.puts "Skipping Rack::Session::Memcache tests (Memcache is required). `gem install memcache-client` and try again."
240
- end