rack 1.1.6 → 1.6.9

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 (212) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +1 -1
  3. data/HISTORY.md +375 -0
  4. data/KNOWN-ISSUES +23 -0
  5. data/README.rdoc +312 -0
  6. data/Rakefile +124 -0
  7. data/SPEC +125 -32
  8. data/contrib/rack.png +0 -0
  9. data/contrib/rack.svg +150 -0
  10. data/contrib/rack_logo.svg +1 -1
  11. data/contrib/rdoc.css +412 -0
  12. data/example/protectedlobster.rb +1 -1
  13. data/lib/rack/auth/abstract/handler.rb +4 -4
  14. data/lib/rack/auth/abstract/request.rb +7 -5
  15. data/lib/rack/auth/basic.rb +1 -1
  16. data/lib/rack/auth/digest/md5.rb +7 -3
  17. data/lib/rack/auth/digest/nonce.rb +1 -1
  18. data/lib/rack/auth/digest/params.rb +7 -9
  19. data/lib/rack/auth/digest/request.rb +10 -9
  20. data/lib/rack/backports/uri/common_18.rb +56 -0
  21. data/lib/rack/backports/uri/common_192.rb +52 -0
  22. data/lib/rack/backports/uri/common_193.rb +29 -0
  23. data/lib/rack/body_proxy.rb +39 -0
  24. data/lib/rack/builder.rb +106 -22
  25. data/lib/rack/cascade.rb +17 -6
  26. data/lib/rack/chunked.rb +44 -24
  27. data/lib/rack/commonlogger.rb +36 -13
  28. data/lib/rack/conditionalget.rb +49 -17
  29. data/lib/rack/config.rb +5 -0
  30. data/lib/rack/content_length.rb +14 -6
  31. data/lib/rack/content_type.rb +7 -1
  32. data/lib/rack/deflater.rb +73 -15
  33. data/lib/rack/directory.rb +18 -8
  34. data/lib/rack/etag.rb +59 -9
  35. data/lib/rack/file.rb +106 -44
  36. data/lib/rack/handler/cgi.rb +11 -11
  37. data/lib/rack/handler/fastcgi.rb +18 -6
  38. data/lib/rack/handler/lsws.rb +2 -4
  39. data/lib/rack/handler/mongrel.rb +22 -6
  40. data/lib/rack/handler/scgi.rb +16 -8
  41. data/lib/rack/handler/thin.rb +19 -4
  42. data/lib/rack/handler/webrick.rb +72 -19
  43. data/lib/rack/handler.rb +47 -14
  44. data/lib/rack/head.rb +10 -2
  45. data/lib/rack/lint.rb +260 -75
  46. data/lib/rack/lobster.rb +13 -8
  47. data/lib/rack/lock.rb +13 -3
  48. data/lib/rack/logger.rb +0 -2
  49. data/lib/rack/methodoverride.rb +27 -8
  50. data/lib/rack/mime.rb +625 -167
  51. data/lib/rack/mock.rb +78 -53
  52. data/lib/rack/multipart/generator.rb +93 -0
  53. data/lib/rack/multipart/parser.rb +253 -0
  54. data/lib/rack/multipart/uploaded_file.rb +34 -0
  55. data/lib/rack/multipart.rb +34 -0
  56. data/lib/rack/nulllogger.rb +21 -2
  57. data/lib/rack/recursive.rb +10 -5
  58. data/lib/rack/reloader.rb +3 -2
  59. data/lib/rack/request.rb +201 -74
  60. data/lib/rack/response.rb +41 -28
  61. data/lib/rack/rewindable_input.rb +15 -11
  62. data/lib/rack/runtime.rb +16 -3
  63. data/lib/rack/sendfile.rb +47 -29
  64. data/lib/rack/server.rb +223 -47
  65. data/lib/rack/session/abstract/id.rb +289 -30
  66. data/lib/rack/session/cookie.rb +133 -44
  67. data/lib/rack/session/memcache.rb +30 -56
  68. data/lib/rack/session/pool.rb +19 -43
  69. data/lib/rack/showexceptions.rb +53 -15
  70. data/lib/rack/showstatus.rb +14 -7
  71. data/lib/rack/static.rb +124 -12
  72. data/lib/rack/tempfile_reaper.rb +22 -0
  73. data/lib/rack/urlmap.rb +49 -15
  74. data/lib/rack/utils/okjson.rb +600 -0
  75. data/lib/rack/utils.rb +363 -361
  76. data/lib/rack.rb +17 -23
  77. data/rack.gemspec +11 -20
  78. data/test/builder/anything.rb +5 -0
  79. data/test/builder/comment.ru +4 -0
  80. data/test/builder/end.ru +5 -0
  81. data/test/builder/line.ru +1 -0
  82. data/test/builder/options.ru +2 -0
  83. data/test/cgi/assets/folder/test.js +1 -0
  84. data/test/cgi/assets/fonts/font.eot +1 -0
  85. data/test/cgi/assets/images/image.png +1 -0
  86. data/test/cgi/assets/index.html +1 -0
  87. data/test/cgi/assets/javascripts/app.js +1 -0
  88. data/test/cgi/assets/stylesheets/app.css +1 -0
  89. data/test/cgi/lighttpd.conf +26 -0
  90. data/test/cgi/rackup_stub.rb +6 -0
  91. data/test/cgi/sample_rackup.ru +5 -0
  92. data/test/cgi/test +9 -0
  93. data/test/cgi/test+directory/test+file +1 -0
  94. data/test/cgi/test.fcgi +8 -0
  95. data/test/cgi/test.ru +5 -0
  96. data/test/gemloader.rb +10 -0
  97. data/test/multipart/bad_robots +259 -0
  98. data/test/multipart/binary +0 -0
  99. data/test/multipart/content_type_and_no_filename +6 -0
  100. data/test/multipart/empty +10 -0
  101. data/test/multipart/fail_16384_nofile +814 -0
  102. data/test/multipart/file1.txt +1 -0
  103. data/test/multipart/filename_and_modification_param +7 -0
  104. data/test/multipart/filename_and_no_name +6 -0
  105. data/test/multipart/filename_with_escaped_quotes +6 -0
  106. data/test/multipart/filename_with_escaped_quotes_and_modification_param +7 -0
  107. data/test/multipart/filename_with_null_byte +7 -0
  108. data/test/multipart/filename_with_percent_escaped_quotes +6 -0
  109. data/test/multipart/filename_with_unescaped_percentages +6 -0
  110. data/test/multipart/filename_with_unescaped_percentages2 +6 -0
  111. data/test/multipart/filename_with_unescaped_percentages3 +6 -0
  112. data/test/multipart/filename_with_unescaped_quotes +6 -0
  113. data/test/multipart/ie +6 -0
  114. data/test/multipart/invalid_character +6 -0
  115. data/test/multipart/mixed_files +21 -0
  116. data/test/multipart/nested +10 -0
  117. data/test/multipart/none +9 -0
  118. data/test/multipart/semicolon +6 -0
  119. data/test/multipart/text +15 -0
  120. data/test/multipart/three_files_three_fields +31 -0
  121. data/test/multipart/webkit +32 -0
  122. data/test/rackup/config.ru +31 -0
  123. data/test/registering_handler/rack/handler/registering_myself.rb +8 -0
  124. data/test/{spec_rack_auth_basic.rb → spec_auth_basic.rb} +23 -15
  125. data/test/{spec_rack_auth_digest.rb → spec_auth_digest.rb} +56 -29
  126. data/test/spec_body_proxy.rb +85 -0
  127. data/test/spec_builder.rb +223 -0
  128. data/test/{spec_rack_cascade.rb → spec_cascade.rb} +28 -15
  129. data/test/{spec_rack_cgi.rb → spec_cgi.rb} +44 -31
  130. data/test/spec_chunked.rb +101 -0
  131. data/test/spec_commonlogger.rb +93 -0
  132. data/test/spec_conditionalget.rb +102 -0
  133. data/test/{spec_rack_config.rb → spec_config.rb} +6 -8
  134. data/test/spec_content_length.rb +85 -0
  135. data/test/spec_content_type.rb +45 -0
  136. data/test/spec_deflater.rb +339 -0
  137. data/test/{spec_rack_directory.rb → spec_directory.rb} +37 -10
  138. data/test/spec_etag.rb +107 -0
  139. data/test/{spec_rack_fastcgi.rb → spec_fastcgi.rb} +47 -29
  140. data/test/spec_file.rb +221 -0
  141. data/test/spec_handler.rb +72 -0
  142. data/test/spec_head.rb +45 -0
  143. data/test/{spec_rack_lint.rb → spec_lint.rb} +82 -60
  144. data/test/spec_lobster.rb +58 -0
  145. data/test/spec_lock.rb +164 -0
  146. data/test/spec_logger.rb +23 -0
  147. data/test/spec_methodoverride.rb +95 -0
  148. data/test/spec_mime.rb +51 -0
  149. data/test/{spec_rack_mock.rb → spec_mock.rb} +92 -38
  150. data/test/{spec_rack_mongrel.rb → spec_mongrel.rb} +46 -53
  151. data/test/spec_multipart.rb +600 -0
  152. data/test/spec_nulllogger.rb +20 -0
  153. data/test/spec_recursive.rb +72 -0
  154. data/test/spec_request.rb +1227 -0
  155. data/test/spec_response.rb +407 -0
  156. data/test/spec_rewindable_input.rb +118 -0
  157. data/test/spec_runtime.rb +49 -0
  158. data/test/spec_sendfile.rb +130 -0
  159. data/test/spec_server.rb +167 -0
  160. data/test/spec_session_abstract_id.rb +53 -0
  161. data/test/spec_session_cookie.rb +410 -0
  162. data/test/{spec_rack_session_memcache.rb → spec_session_memcache.rb} +119 -71
  163. data/test/{spec_rack_session_pool.rb → spec_session_pool.rb} +106 -69
  164. data/test/spec_showexceptions.rb +85 -0
  165. data/test/spec_showstatus.rb +103 -0
  166. data/test/spec_static.rb +145 -0
  167. data/test/spec_tempfile_reaper.rb +63 -0
  168. data/test/{spec_rack_thin.rb → spec_thin.rb} +35 -35
  169. data/test/{spec_rack_urlmap.rb → spec_urlmap.rb} +40 -19
  170. data/test/spec_utils.rb +647 -0
  171. data/test/spec_version.rb +17 -0
  172. data/test/spec_webrick.rb +184 -0
  173. data/test/static/another/index.html +1 -0
  174. data/test/static/index.html +1 -0
  175. data/test/testrequest.rb +78 -0
  176. data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
  177. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
  178. metadata +220 -239
  179. data/RDOX +0 -0
  180. data/README +0 -592
  181. data/lib/rack/adapter/camping.rb +0 -22
  182. data/test/spec_auth.rb +0 -57
  183. data/test/spec_rack_builder.rb +0 -84
  184. data/test/spec_rack_camping.rb +0 -55
  185. data/test/spec_rack_chunked.rb +0 -62
  186. data/test/spec_rack_commonlogger.rb +0 -61
  187. data/test/spec_rack_conditionalget.rb +0 -41
  188. data/test/spec_rack_content_length.rb +0 -43
  189. data/test/spec_rack_content_type.rb +0 -30
  190. data/test/spec_rack_deflater.rb +0 -127
  191. data/test/spec_rack_etag.rb +0 -17
  192. data/test/spec_rack_file.rb +0 -75
  193. data/test/spec_rack_handler.rb +0 -43
  194. data/test/spec_rack_head.rb +0 -30
  195. data/test/spec_rack_lobster.rb +0 -45
  196. data/test/spec_rack_lock.rb +0 -38
  197. data/test/spec_rack_logger.rb +0 -21
  198. data/test/spec_rack_methodoverride.rb +0 -60
  199. data/test/spec_rack_nulllogger.rb +0 -13
  200. data/test/spec_rack_recursive.rb +0 -77
  201. data/test/spec_rack_request.rb +0 -594
  202. data/test/spec_rack_response.rb +0 -221
  203. data/test/spec_rack_rewindable_input.rb +0 -118
  204. data/test/spec_rack_runtime.rb +0 -35
  205. data/test/spec_rack_sendfile.rb +0 -86
  206. data/test/spec_rack_session_cookie.rb +0 -92
  207. data/test/spec_rack_showexceptions.rb +0 -21
  208. data/test/spec_rack_showstatus.rb +0 -72
  209. data/test/spec_rack_static.rb +0 -37
  210. data/test/spec_rack_utils.rb +0 -557
  211. data/test/spec_rack_webrick.rb +0 -130
  212. data/test/spec_rackup.rb +0 -164
@@ -0,0 +1 @@
1
+ contents
@@ -0,0 +1,7 @@
1
+ --AaB03x
2
+ Content-Type: image/jpeg
3
+ Content-Disposition: attachment; name="files"; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
4
+ Content-Description: a complete map of the human genome
5
+
6
+ contents
7
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; filename="file1.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="escape \"quotes"
3
+ Content-Type: application/octet-stream
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,7 @@
1
+ --AaB03x
2
+ Content-Type: image/jpeg
3
+ Content-Disposition: attachment; name="files"; filename=""human" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
4
+ Content-Description: a complete map of the human genome
5
+
6
+ contents
7
+ --AaB03x--
@@ -0,0 +1,7 @@
1
+ --AaB03x
2
+ Content-Type: image/jpeg
3
+ Content-Disposition: attachment; name="files"; filename="flowers.exe%00.jpg"
4
+ Content-Description: a complete map of the human genome
5
+
6
+ contents
7
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="escape %22quotes"
3
+ Content-Type: application/octet-stream
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al
2
+ Content-Disposition: form-data; name="document[attachment]"; filename="100% of a photo.jpeg"
3
+ Content-Type: image/jpeg
4
+
5
+ contents
6
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al--
@@ -0,0 +1,6 @@
1
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al
2
+ Content-Disposition: form-data; name="document[attachment]"; filename="100%a"
3
+ Content-Type: image/jpeg
4
+
5
+ contents
6
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al--
@@ -0,0 +1,6 @@
1
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al
2
+ Content-Disposition: form-data; name="document[attachment]"; filename="100%"
3
+ Content-Type: image/jpeg
4
+
5
+ contents
6
+ ------WebKitFormBoundary2NHc7OhsgU68l3Al--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="escape "quotes"
3
+ Content-Type: application/octet-stream
4
+
5
+ contents
6
+ --AaB03x--
data/test/multipart/ie ADDED
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="invalid�.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,21 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="foo"
3
+
4
+ bar
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="files"
7
+ Content-Type: multipart/mixed, boundary=BbC04y
8
+
9
+ --BbC04y
10
+ Content-Disposition: attachment; filename="file.txt"
11
+ Content-Type: text/plain
12
+
13
+ contents
14
+ --BbC04y
15
+ Content-Disposition: attachment; filename="flowers.jpg"
16
+ Content-Type: image/jpeg
17
+ Content-Transfer-Encoding: binary
18
+
19
+ contents
20
+ --BbC04y--
21
+ --AaB03x--
@@ -0,0 +1,10 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="foo[submit-name]"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="foo[files]"; filename="file1.txt"
7
+ Content-Type: text/plain
8
+
9
+ contents
10
+ --AaB03x--
@@ -0,0 +1,9 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="submit-name"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="files"; filename=""
7
+
8
+
9
+ --AaB03x--
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="fi;le1.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -0,0 +1,15 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="submit-name"
3
+
4
+ Larry
5
+ --AaB03x
6
+ Content-Disposition: form-data; name="submit-name-with-content"
7
+ Content-Type: text/plain
8
+
9
+ Berry
10
+ --AaB03x
11
+ Content-Disposition: form-data; name="files"; filename="file1.txt"
12
+ Content-Type: text/plain
13
+
14
+ contents
15
+ --AaB03x--
@@ -0,0 +1,31 @@
1
+ --AaB03x
2
+ content-disposition: form-data; name="reply"
3
+
4
+ yes
5
+ --AaB03x
6
+ content-disposition: form-data; name="to"
7
+
8
+ people
9
+ --AaB03x
10
+ content-disposition: form-data; name="from"
11
+
12
+ others
13
+ --AaB03x
14
+ content-disposition: form-data; name="fileupload1"; filename="file1.jpg"
15
+ Content-Type: image/jpeg
16
+ Content-Transfer-Encoding: base64
17
+
18
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
19
+ --AaB03x
20
+ content-disposition: form-data; name="fileupload2"; filename="file2.jpg"
21
+ Content-Type: image/jpeg
22
+ Content-Transfer-Encoding: base64
23
+
24
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
25
+ --AaB03x
26
+ content-disposition: form-data; name="fileupload3"; filename="file3.jpg"
27
+ Content-Type: image/jpeg
28
+ Content-Transfer-Encoding: base64
29
+
30
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
31
+ --AaB03x--
@@ -0,0 +1,32 @@
1
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
2
+ Content-Disposition: form-data; name="_method"
3
+
4
+ put
5
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
6
+ Content-Disposition: form-data; name="profile[blog]"
7
+
8
+
9
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
10
+ Content-Disposition: form-data; name="profile[public_email]"
11
+
12
+
13
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
14
+ Content-Disposition: form-data; name="profile[interests]"
15
+
16
+
17
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
18
+ Content-Disposition: form-data; name="profile[bio]"
19
+
20
+ hello
21
+
22
+ "quote"
23
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
24
+ Content-Disposition: form-data; name="media"; filename=""
25
+ Content-Type: application/octet-stream
26
+
27
+
28
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR
29
+ Content-Disposition: form-data; name="commit"
30
+
31
+ Save
32
+ ------WebKitFormBoundaryWLHCs9qmcJJoyjKR--
@@ -0,0 +1,31 @@
1
+ require "#{File.dirname(__FILE__)}/../testrequest"
2
+
3
+ $stderr = File.open("#{File.dirname(__FILE__)}/log_output", "w")
4
+
5
+ class EnvMiddleware
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ # provides a way to test that lint is present
12
+ if env["PATH_INFO"] == "/broken_lint"
13
+ return [200, {}, ["Broken Lint"]]
14
+ # provides a way to kill the process without knowing the pid
15
+ elsif env["PATH_INFO"] == "/die"
16
+ exit!
17
+ end
18
+
19
+ env["test.$DEBUG"] = $DEBUG
20
+ env["test.$EVAL"] = BUKKIT if defined?(BUKKIT)
21
+ env["test.$VERBOSE"] = $VERBOSE
22
+ env["test.$LOAD_PATH"] = $LOAD_PATH
23
+ env["test.stderr"] = File.expand_path($stderr.path)
24
+ env["test.Ping"] = defined?(Ping)
25
+ env["test.pid"] = Process.pid
26
+ @app.call(env)
27
+ end
28
+ end
29
+
30
+ use EnvMiddleware
31
+ run TestRequest.new
@@ -0,0 +1,8 @@
1
+ module Rack
2
+ module Handler
3
+ class RegisteringMyself
4
+ end
5
+
6
+ register :registering_myself, RegisteringMyself
7
+ end
8
+ end
@@ -1,25 +1,25 @@
1
- require 'test/spec'
2
-
3
1
  require 'rack/auth/basic'
2
+ require 'rack/lint'
4
3
  require 'rack/mock'
5
4
 
6
- context 'Rack::Auth::Basic' do
7
-
5
+ describe Rack::Auth::Basic do
8
6
  def realm
9
7
  'WallysWorld'
10
8
  end
11
-
9
+
12
10
  def unprotected_app
13
- lambda { |env| [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ] }
11
+ Rack::Lint.new lambda { |env|
12
+ [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ]
13
+ }
14
14
  end
15
-
15
+
16
16
  def protected_app
17
17
  app = Rack::Auth::Basic.new(unprotected_app) { |username, password| 'Boss' == username }
18
18
  app.realm = realm
19
19
  app
20
20
  end
21
21
 
22
- setup do
22
+ before do
23
23
  @request = Rack::MockRequest.new(protected_app)
24
24
  end
25
25
 
@@ -39,26 +39,26 @@ context 'Rack::Auth::Basic' do
39
39
  response.body.should.be.empty
40
40
  end
41
41
 
42
- specify 'should challenge correctly when no credentials are specified' do
42
+ should 'challenge correctly when no credentials are specified' do
43
43
  request do |response|
44
44
  assert_basic_auth_challenge response
45
45
  end
46
46
  end
47
47
 
48
- specify 'should rechallenge if incorrect credentials are specified' do
48
+ should 'rechallenge if incorrect credentials are specified' do
49
49
  request_with_basic_auth 'joe', 'password' do |response|
50
50
  assert_basic_auth_challenge response
51
51
  end
52
52
  end
53
53
 
54
- specify 'should return application output if correct credentials are specified' do
54
+ should 'return application output if correct credentials are specified' do
55
55
  request_with_basic_auth 'Boss', 'password' do |response|
56
56
  response.status.should.equal 200
57
57
  response.body.to_s.should.equal 'Hi Boss'
58
58
  end
59
59
  end
60
-
61
- specify 'should return 400 Bad Request if different auth scheme used' do
60
+
61
+ should 'return 400 Bad Request if different auth scheme used' do
62
62
  request 'HTTP_AUTHORIZATION' => 'Digest params' do |response|
63
63
  response.should.be.a.client_error
64
64
  response.status.should.equal 400
@@ -66,8 +66,16 @@ context 'Rack::Auth::Basic' do
66
66
  end
67
67
  end
68
68
 
69
- specify 'realm as optional constructor arg' do
69
+ should 'return 400 Bad Request for a malformed authorization header' do
70
+ request 'HTTP_AUTHORIZATION' => '' do |response|
71
+ response.should.be.a.client_error
72
+ response.status.should.equal 400
73
+ response.should.not.include 'WWW-Authenticate'
74
+ end
75
+ end
76
+
77
+ it 'takes realm as optional constructor arg' do
70
78
  app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
71
- assert_equal realm, app.realm
79
+ realm.should == app.realm
72
80
  end
73
81
  end
@@ -1,27 +1,23 @@
1
- require 'test/spec'
2
-
3
1
  require 'rack/auth/digest/md5'
2
+ require 'rack/lint'
4
3
  require 'rack/mock'
5
4
 
6
- context 'Rack::Auth::Digest::MD5' do
7
-
5
+ describe Rack::Auth::Digest::MD5 do
8
6
  def realm
9
7
  'WallysWorld'
10
8
  end
11
9
 
12
10
  def unprotected_app
13
- lambda do |env|
14
- [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ]
15
- end
11
+ Rack::Lint.new lambda { |env|
12
+ friend = Rack::Utils.parse_query(env["QUERY_STRING"])["friend"]
13
+ [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}#{friend ? " and #{friend}" : ''}"] ]
14
+ }
16
15
  end
17
16
 
18
17
  def protected_app
19
- app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
18
+ Rack::Auth::Digest::MD5.new(unprotected_app, :realm => realm, :opaque => 'this-should-be-secret') do |username|
20
19
  { 'Alice' => 'correct-password' }[username]
21
20
  end
22
- app.realm = realm
23
- app.opaque = 'this-should-be-secret'
24
- app
25
21
  end
26
22
 
27
23
  def protected_app_with_hashed_passwords
@@ -45,7 +41,7 @@ context 'Rack::Auth::Digest::MD5' do
45
41
  Rack::MethodOverride.new(protected_app)
46
42
  end
47
43
 
48
- setup do
44
+ before do
49
45
  @request = Rack::MockRequest.new(protected_app)
50
46
  end
51
47
 
@@ -117,20 +113,20 @@ context 'Rack::Auth::Digest::MD5' do
117
113
  response.should.not.include 'WWW-Authenticate'
118
114
  end
119
115
 
120
- specify 'should challenge when no credentials are specified' do
116
+ should 'challenge when no credentials are specified' do
121
117
  request 'GET', '/' do |response|
122
118
  assert_digest_auth_challenge response
123
119
  end
124
120
  end
125
121
 
126
- specify 'should return application output if correct credentials given' do
122
+ should 'return application output if correct credentials given' do
127
123
  request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
128
124
  response.status.should.equal 200
129
125
  response.body.to_s.should.equal 'Hi Alice'
130
126
  end
131
127
  end
132
128
 
133
- specify 'should return application output if correct credentials given (hashed passwords)' do
129
+ should 'return application output if correct credentials given (hashed passwords)' do
134
130
  @request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
135
131
 
136
132
  request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
@@ -139,25 +135,39 @@ context 'Rack::Auth::Digest::MD5' do
139
135
  end
140
136
  end
141
137
 
142
- specify 'should rechallenge if incorrect username given' do
138
+ should 'rechallenge if incorrect username given' do
143
139
  request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response|
144
140
  assert_digest_auth_challenge response
145
141
  end
146
142
  end
147
143
 
148
- specify 'should rechallenge if incorrect password given' do
144
+ should 'rechallenge if incorrect password given' do
149
145
  request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response|
150
146
  assert_digest_auth_challenge response
151
147
  end
152
148
  end
153
149
 
154
- specify 'rechallenge if incorrect user and blank password given' do
150
+ should 'rechallenge if incorrect user and blank password given' do
155
151
  request_with_digest_auth 'GET', '/', 'Bob', '' do |response|
156
152
  assert_digest_auth_challenge response
157
153
  end
158
154
  end
159
155
 
160
- specify 'should rechallenge with stale parameter if nonce is stale' do
156
+ should 'not rechallenge if nonce is not stale' do
157
+ begin
158
+ Rack::Auth::Digest::Nonce.time_limit = 10
159
+
160
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 1 do |response|
161
+ response.status.should.equal 200
162
+ response.body.to_s.should.equal 'Hi Alice'
163
+ response.headers['WWW-Authenticate'].should.not =~ /\bstale=true\b/
164
+ end
165
+ ensure
166
+ Rack::Auth::Digest::Nonce.time_limit = nil
167
+ end
168
+ end
169
+
170
+ should 'rechallenge with stale parameter if nonce is stale' do
161
171
  begin
162
172
  Rack::Auth::Digest::Nonce.time_limit = 1
163
173
 
@@ -170,39 +180,39 @@ context 'Rack::Auth::Digest::MD5' do
170
180
  end
171
181
  end
172
182
 
173
- specify 'should return 400 Bad Request if incorrect qop given' do
183
+ should 'return 400 Bad Request if incorrect qop given' do
174
184
  request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
175
185
  assert_bad_request response
176
186
  end
177
187
  end
178
188
 
179
- specify 'should return 400 Bad Request if incorrect uri given' do
189
+ should 'return 400 Bad Request if incorrect uri given' do
180
190
  request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
181
191
  assert_bad_request response
182
192
  end
183
193
  end
184
194
 
185
- specify 'should return 400 Bad Request if different auth scheme used' do
195
+ should 'return 400 Bad Request if different auth scheme used' do
186
196
  request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
187
197
  assert_bad_request response
188
198
  end
189
199
  end
190
200
 
191
- specify 'should not require credentials for unprotected path' do
201
+ should 'not require credentials for unprotected path' do
192
202
  @request = Rack::MockRequest.new(partially_protected_app)
193
203
  request 'GET', '/' do |response|
194
204
  response.should.be.ok
195
205
  end
196
206
  end
197
207
 
198
- specify 'should challenge when no credentials are specified for protected path' do
208
+ should 'challenge when no credentials are specified for protected path' do
199
209
  @request = Rack::MockRequest.new(partially_protected_app)
200
210
  request 'GET', '/protected' do |response|
201
211
  assert_digest_auth_challenge response
202
212
  end
203
213
  end
204
214
 
205
- specify 'should return application output if correct credentials given for protected path' do
215
+ should 'return application output if correct credentials given for protected path' do
206
216
  @request = Rack::MockRequest.new(partially_protected_app)
207
217
  request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response|
208
218
  response.status.should.equal 200
@@ -210,14 +220,31 @@ context 'Rack::Auth::Digest::MD5' do
210
220
  end
211
221
  end
212
222
 
213
- specify 'should return application output if correct credentials given for POST' do
223
+ should 'return application output when used with a query string and path as uri' do
224
+ @request = Rack::MockRequest.new(partially_protected_app)
225
+ request_with_digest_auth 'GET', '/protected?friend=Mike', 'Alice', 'correct-password' do |response|
226
+ response.status.should.equal 200
227
+ response.body.to_s.should.equal 'Hi Alice and Mike'
228
+ end
229
+ end
230
+
231
+ should 'return application output when used with a query string and fullpath as uri' do
232
+ @request = Rack::MockRequest.new(partially_protected_app)
233
+ qs_uri = '/protected?friend=Mike'
234
+ request_with_digest_auth 'GET', qs_uri, 'Alice', 'correct-password', 'uri' => qs_uri do |response|
235
+ response.status.should.equal 200
236
+ response.body.to_s.should.equal 'Hi Alice and Mike'
237
+ end
238
+ end
239
+
240
+ should 'return application output if correct credentials given for POST' do
214
241
  request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response|
215
242
  response.status.should.equal 200
216
243
  response.body.to_s.should.equal 'Hi Alice'
217
244
  end
218
245
  end
219
246
 
220
- specify 'should return application output if correct credentials given for PUT (using method override of POST)' do
247
+ should 'return application output if correct credentials given for PUT (using method override of POST)' do
221
248
  @request = Rack::MockRequest.new(protected_app_with_method_override)
222
249
  request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response|
223
250
  response.status.should.equal 200
@@ -225,8 +252,8 @@ context 'Rack::Auth::Digest::MD5' do
225
252
  end
226
253
  end
227
254
 
228
- specify 'realm as optional constructor arg' do
255
+ it 'takes realm as optional constructor arg' do
229
256
  app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
230
- assert_equal realm, app.realm
257
+ realm.should == app.realm
231
258
  end
232
259
  end
@@ -0,0 +1,85 @@
1
+ require 'rack/body_proxy'
2
+ require 'stringio'
3
+ require 'ostruct'
4
+
5
+ describe Rack::BodyProxy do
6
+ should 'call each on the wrapped body' do
7
+ called = false
8
+ proxy = Rack::BodyProxy.new(['foo']) { }
9
+ proxy.each do |str|
10
+ called = true
11
+ str.should.equal 'foo'
12
+ end
13
+ called.should.equal true
14
+ end
15
+
16
+ should 'call close on the wrapped body' do
17
+ body = StringIO.new
18
+ proxy = Rack::BodyProxy.new(body) { }
19
+ proxy.close
20
+ body.should.be.closed
21
+ end
22
+
23
+ should 'only call close on the wrapped body if it responds to close' do
24
+ body = []
25
+ proxy = Rack::BodyProxy.new(body) { }
26
+ proc { proxy.close }.should.not.raise
27
+ end
28
+
29
+ should 'call the passed block on close' do
30
+ called = false
31
+ proxy = Rack::BodyProxy.new([]) { called = true }
32
+ called.should.equal false
33
+ proxy.close
34
+ called.should.equal true
35
+ end
36
+
37
+ should 'call the passed block on close even if there is an exception' do
38
+ object = Object.new
39
+ def object.close() raise "No!" end
40
+ called = false
41
+
42
+ begin
43
+ proxy = Rack::BodyProxy.new(object) { called = true }
44
+ called.should.equal false
45
+ proxy.close
46
+ rescue RuntimeError => e
47
+ end
48
+
49
+ raise "Expected exception to have been raised" unless e
50
+ called.should.equal true
51
+ end
52
+
53
+ should 'allow multiple arguments in respond_to?' do
54
+ body = []
55
+ proxy = Rack::BodyProxy.new(body) { }
56
+ proc { proxy.respond_to?(:foo, false) }.should.not.raise
57
+ end
58
+
59
+ should 'not respond to :to_ary' do
60
+ body = OpenStruct.new(:to_ary => true)
61
+ body.respond_to?(:to_ary).should.equal true
62
+
63
+ proxy = Rack::BodyProxy.new(body) { }
64
+ proxy.respond_to?(:to_ary).should.equal false
65
+ proxy.respond_to?("to_ary").should.equal false
66
+ end
67
+
68
+ should 'not close more than one time' do
69
+ count = 0
70
+ proxy = Rack::BodyProxy.new([]) { count += 1; raise "Block invoked more than 1 time!" if count > 1 }
71
+ 2.times { proxy.close }
72
+ count.should.equal 1
73
+ end
74
+
75
+ should 'be closed when the callback is triggered' do
76
+ closed = false
77
+ proxy = Rack::BodyProxy.new([]) { closed = proxy.closed? }
78
+ proxy.close
79
+ closed.should.equal true
80
+ end
81
+
82
+ should 'provide an #each method' do
83
+ Rack::BodyProxy.method_defined?(:each).should.equal true
84
+ end
85
+ end