rack 2.0.4 → 2.1.0

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY.md → CHANGELOG.md} +220 -155
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +77 -119
  5. data/Rakefile +25 -18
  6. data/SPEC +3 -4
  7. data/bin/rackup +1 -0
  8. data/example/lobster.ru +2 -0
  9. data/example/protectedlobster.rb +3 -1
  10. data/example/protectedlobster.ru +2 -0
  11. data/lib/rack.rb +63 -60
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +2 -0
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +4 -2
  18. data/lib/rack/auth/digest/request.rb +2 -0
  19. data/lib/rack/body_proxy.rb +3 -6
  20. data/lib/rack/builder.rb +38 -15
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +29 -6
  23. data/lib/rack/common_logger.rb +9 -8
  24. data/lib/rack/conditional_get.rb +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +3 -1
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +28 -17
  30. data/lib/rack/directory.rb +17 -14
  31. data/lib/rack/etag.rb +3 -1
  32. data/lib/rack/events.rb +5 -3
  33. data/lib/rack/file.rb +5 -173
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler.rb +7 -2
  36. data/lib/rack/handler/cgi.rb +3 -1
  37. data/lib/rack/handler/fastcgi.rb +4 -2
  38. data/lib/rack/handler/lsws.rb +3 -1
  39. data/lib/rack/handler/scgi.rb +9 -6
  40. data/lib/rack/handler/thin.rb +3 -1
  41. data/lib/rack/handler/webrick.rb +4 -2
  42. data/lib/rack/head.rb +2 -0
  43. data/lib/rack/lint.rb +14 -11
  44. data/lib/rack/lobster.rb +7 -5
  45. data/lib/rack/lock.rb +2 -0
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +9 -3
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +74 -15
  51. data/lib/rack/multipart.rb +5 -3
  52. data/lib/rack/multipart/generator.rb +6 -7
  53. data/lib/rack/multipart/parser.rb +54 -51
  54. data/lib/rack/multipart/uploaded_file.rb +2 -0
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +51 -25
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +89 -23
  60. data/lib/rack/response.rb +71 -31
  61. data/lib/rack/rewindable_input.rb +4 -2
  62. data/lib/rack/runtime.rb +4 -2
  63. data/lib/rack/sendfile.rb +15 -8
  64. data/lib/rack/server.rb +88 -16
  65. data/lib/rack/session/abstract/id.rb +104 -21
  66. data/lib/rack/session/cookie.rb +21 -11
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +17 -8
  69. data/lib/rack/show_exceptions.rb +16 -10
  70. data/lib/rack/show_status.rb +4 -2
  71. data/lib/rack/static.rb +15 -10
  72. data/lib/rack/tempfile_reaper.rb +2 -0
  73. data/lib/rack/urlmap.rb +11 -2
  74. data/lib/rack/utils.rb +55 -70
  75. data/rack.gemspec +19 -9
  76. metadata +32 -173
  77. data/test/builder/an_underscore_app.rb +0 -5
  78. data/test/builder/anything.rb +0 -5
  79. data/test/builder/comment.ru +0 -4
  80. data/test/builder/end.ru +0 -5
  81. data/test/builder/line.ru +0 -1
  82. data/test/builder/options.ru +0 -2
  83. data/test/cgi/assets/folder/test.js +0 -1
  84. data/test/cgi/assets/fonts/font.eot +0 -1
  85. data/test/cgi/assets/images/image.png +0 -1
  86. data/test/cgi/assets/index.html +0 -1
  87. data/test/cgi/assets/javascripts/app.js +0 -1
  88. data/test/cgi/assets/stylesheets/app.css +0 -1
  89. data/test/cgi/lighttpd.conf +0 -26
  90. data/test/cgi/rackup_stub.rb +0 -6
  91. data/test/cgi/sample_rackup.ru +0 -5
  92. data/test/cgi/test +0 -9
  93. data/test/cgi/test+directory/test+file +0 -1
  94. data/test/cgi/test.fcgi +0 -9
  95. data/test/cgi/test.gz +0 -0
  96. data/test/cgi/test.ru +0 -5
  97. data/test/gemloader.rb +0 -10
  98. data/test/helper.rb +0 -34
  99. data/test/multipart/bad_robots +0 -259
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/content_type_and_no_filename +0 -6
  102. data/test/multipart/empty +0 -10
  103. data/test/multipart/fail_16384_nofile +0 -814
  104. data/test/multipart/file1.txt +0 -1
  105. data/test/multipart/filename_and_modification_param +0 -7
  106. data/test/multipart/filename_and_no_name +0 -6
  107. data/test/multipart/filename_with_encoded_words +0 -7
  108. data/test/multipart/filename_with_escaped_quotes +0 -6
  109. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  110. data/test/multipart/filename_with_null_byte +0 -7
  111. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_single_quote +0 -7
  113. data/test/multipart/filename_with_unescaped_percentages +0 -6
  114. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  115. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  116. data/test/multipart/filename_with_unescaped_quotes +0 -6
  117. data/test/multipart/ie +0 -6
  118. data/test/multipart/invalid_character +0 -6
  119. data/test/multipart/mixed_files +0 -21
  120. data/test/multipart/nested +0 -10
  121. data/test/multipart/none +0 -9
  122. data/test/multipart/quoted +0 -15
  123. data/test/multipart/rack-logo.png +0 -0
  124. data/test/multipart/semicolon +0 -6
  125. data/test/multipart/text +0 -15
  126. data/test/multipart/three_files_three_fields +0 -31
  127. data/test/multipart/unity3d_wwwform +0 -11
  128. data/test/multipart/webkit +0 -32
  129. data/test/rackup/config.ru +0 -31
  130. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  131. data/test/spec_auth_basic.rb +0 -89
  132. data/test/spec_auth_digest.rb +0 -260
  133. data/test/spec_body_proxy.rb +0 -85
  134. data/test/spec_builder.rb +0 -233
  135. data/test/spec_cascade.rb +0 -63
  136. data/test/spec_cgi.rb +0 -84
  137. data/test/spec_chunked.rb +0 -103
  138. data/test/spec_common_logger.rb +0 -95
  139. data/test/spec_conditional_get.rb +0 -103
  140. data/test/spec_config.rb +0 -23
  141. data/test/spec_content_length.rb +0 -86
  142. data/test/spec_content_type.rb +0 -46
  143. data/test/spec_deflater.rb +0 -375
  144. data/test/spec_directory.rb +0 -148
  145. data/test/spec_etag.rb +0 -108
  146. data/test/spec_events.rb +0 -133
  147. data/test/spec_fastcgi.rb +0 -85
  148. data/test/spec_file.rb +0 -264
  149. data/test/spec_handler.rb +0 -57
  150. data/test/spec_head.rb +0 -46
  151. data/test/spec_lint.rb +0 -515
  152. data/test/spec_lobster.rb +0 -59
  153. data/test/spec_lock.rb +0 -204
  154. data/test/spec_logger.rb +0 -24
  155. data/test/spec_media_type.rb +0 -42
  156. data/test/spec_method_override.rb +0 -96
  157. data/test/spec_mime.rb +0 -51
  158. data/test/spec_mock.rb +0 -359
  159. data/test/spec_multipart.rb +0 -722
  160. data/test/spec_null_logger.rb +0 -21
  161. data/test/spec_recursive.rb +0 -75
  162. data/test/spec_request.rb +0 -1393
  163. data/test/spec_response.rb +0 -510
  164. data/test/spec_rewindable_input.rb +0 -128
  165. data/test/spec_runtime.rb +0 -50
  166. data/test/spec_sendfile.rb +0 -125
  167. data/test/spec_server.rb +0 -193
  168. data/test/spec_session_abstract_id.rb +0 -31
  169. data/test/spec_session_abstract_session_hash.rb +0 -45
  170. data/test/spec_session_cookie.rb +0 -442
  171. data/test/spec_session_memcache.rb +0 -320
  172. data/test/spec_session_pool.rb +0 -210
  173. data/test/spec_show_exceptions.rb +0 -80
  174. data/test/spec_show_status.rb +0 -104
  175. data/test/spec_static.rb +0 -184
  176. data/test/spec_tempfile_reaper.rb +0 -64
  177. data/test/spec_thin.rb +0 -96
  178. data/test/spec_urlmap.rb +0 -237
  179. data/test/spec_utils.rb +0 -742
  180. data/test/spec_version.rb +0 -11
  181. data/test/spec_webrick.rb +0 -206
  182. data/test/static/another/index.html +0 -1
  183. data/test/static/foo.html +0 -1
  184. data/test/static/index.html +0 -1
  185. data/test/testrequest.rb +0 -78
  186. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  187. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,108 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/etag'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
- require 'time'
6
-
7
- describe Rack::ETag do
8
- def etag(app, *args)
9
- Rack::Lint.new Rack::ETag.new(app, *args)
10
- end
11
-
12
- def request
13
- Rack::MockRequest.env_for
14
- end
15
-
16
- def sendfile_body
17
- res = ['Hello World']
18
- def res.to_path ; "/tmp/hello.txt" ; end
19
- res
20
- end
21
-
22
- it "set ETag if none is set if status is 200" do
23
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
24
- response = etag(app).call(request)
25
- response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
26
- end
27
-
28
- it "set ETag if none is set if status is 201" do
29
- app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
30
- response = etag(app).call(request)
31
- response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
32
- end
33
-
34
- it "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
35
- app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
36
- response = etag(app).call(request)
37
- response[1]['Cache-Control'].must_equal 'max-age=0, private, must-revalidate'
38
- end
39
-
40
- it "set Cache-Control to chosen one if none is set" do
41
- app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
42
- response = etag(app, nil, 'public').call(request)
43
- response[1]['Cache-Control'].must_equal 'public'
44
- end
45
-
46
- it "set a given Cache-Control even if digest could not be calculated" do
47
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, []] }
48
- response = etag(app, 'no-cache').call(request)
49
- response[1]['Cache-Control'].must_equal 'no-cache'
50
- end
51
-
52
- it "not set Cache-Control if it is already set" do
53
- app = lambda { |env| [201, {'Content-Type' => 'text/plain', 'Cache-Control' => 'public'}, ["Hello, World!"]] }
54
- response = etag(app).call(request)
55
- response[1]['Cache-Control'].must_equal 'public'
56
- end
57
-
58
- it "not set Cache-Control if directive isn't present" do
59
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
60
- response = etag(app, nil, nil).call(request)
61
- response[1]['Cache-Control'].must_be_nil
62
- end
63
-
64
- it "not change ETag if it is already set" do
65
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
66
- response = etag(app).call(request)
67
- response[1]['ETag'].must_equal "\"abc\""
68
- end
69
-
70
- it "not set ETag if body is empty" do
71
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, []] }
72
- response = etag(app).call(request)
73
- response[1]['ETag'].must_be_nil
74
- end
75
-
76
- it "not set ETag if Last-Modified is set" do
77
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, ["Hello, World!"]] }
78
- response = etag(app).call(request)
79
- response[1]['ETag'].must_be_nil
80
- end
81
-
82
- it "not set ETag if a sendfile_body is given" do
83
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, sendfile_body] }
84
- response = etag(app).call(request)
85
- response[1]['ETag'].must_be_nil
86
- end
87
-
88
- it "not set ETag if a status is not 200 or 201" do
89
- app = lambda { |env| [401, {'Content-Type' => 'text/plain'}, ['Access denied.']] }
90
- response = etag(app).call(request)
91
- response[1]['ETag'].must_be_nil
92
- end
93
-
94
- it "not set ETag if no-cache is given" do
95
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache, must-revalidate'}, ['Hello, World!']] }
96
- response = etag(app).call(request)
97
- response[1]['ETag'].must_be_nil
98
- end
99
-
100
- it "close the original body" do
101
- body = StringIO.new
102
- app = lambda { |env| [200, {}, body] }
103
- response = etag(app).call(request)
104
- body.wont_be :closed?
105
- response[2].close
106
- body.must_be :closed?
107
- end
108
- end
@@ -1,133 +0,0 @@
1
- require 'helper'
2
- require 'rack/events'
3
-
4
- module Rack
5
- class TestEvents < Rack::TestCase
6
- class EventMiddleware
7
- attr_reader :events
8
-
9
- def initialize events
10
- @events = events
11
- end
12
-
13
- def on_start req, res
14
- events << [self, __method__]
15
- end
16
-
17
- def on_commit req, res
18
- events << [self, __method__]
19
- end
20
-
21
- def on_send req, res
22
- events << [self, __method__]
23
- end
24
-
25
- def on_finish req, res
26
- events << [self, __method__]
27
- end
28
-
29
- def on_error req, res, e
30
- events << [self, __method__]
31
- end
32
- end
33
-
34
- def test_events_fire
35
- events = []
36
- ret = [200, {}, []]
37
- app = lambda { |env| events << [app, :call]; ret }
38
- se = EventMiddleware.new events
39
- e = Events.new app, [se]
40
- triple = e.call({})
41
- response_body = []
42
- triple[2].each { |x| response_body << x }
43
- triple[2].close
44
- triple[2] = response_body
45
- assert_equal ret, triple
46
- assert_equal [[se, :on_start],
47
- [app, :call],
48
- [se, :on_commit],
49
- [se, :on_send],
50
- [se, :on_finish],
51
- ], events
52
- end
53
-
54
- def test_send_and_finish_are_not_run_until_body_is_sent
55
- events = []
56
- ret = [200, {}, []]
57
- app = lambda { |env| events << [app, :call]; ret }
58
- se = EventMiddleware.new events
59
- e = Events.new app, [se]
60
- triple = e.call({})
61
- assert_equal [[se, :on_start],
62
- [app, :call],
63
- [se, :on_commit],
64
- ], events
65
- end
66
-
67
- def test_send_is_called_on_each
68
- events = []
69
- ret = [200, {}, []]
70
- app = lambda { |env| events << [app, :call]; ret }
71
- se = EventMiddleware.new events
72
- e = Events.new app, [se]
73
- triple = e.call({})
74
- triple[2].each { |x| }
75
- assert_equal [[se, :on_start],
76
- [app, :call],
77
- [se, :on_commit],
78
- [se, :on_send],
79
- ], events
80
- end
81
-
82
- def test_finish_is_called_on_close
83
- events = []
84
- ret = [200, {}, []]
85
- app = lambda { |env| events << [app, :call]; ret }
86
- se = EventMiddleware.new events
87
- e = Events.new app, [se]
88
- triple = e.call({})
89
- triple[2].each { |x| }
90
- triple[2].close
91
- assert_equal [[se, :on_start],
92
- [app, :call],
93
- [se, :on_commit],
94
- [se, :on_send],
95
- [se, :on_finish],
96
- ], events
97
- end
98
-
99
- def test_finish_is_called_in_reverse_order
100
- events = []
101
- ret = [200, {}, []]
102
- app = lambda { |env| events << [app, :call]; ret }
103
- se1 = EventMiddleware.new events
104
- se2 = EventMiddleware.new events
105
- se3 = EventMiddleware.new events
106
-
107
- e = Events.new app, [se1, se2, se3]
108
- triple = e.call({})
109
- triple[2].each { |x| }
110
- triple[2].close
111
-
112
- groups = events.group_by { |x| x.last }
113
- assert_equal groups[:on_start].map(&:first), groups[:on_finish].map(&:first).reverse
114
- assert_equal groups[:on_commit].map(&:first), groups[:on_finish].map(&:first)
115
- assert_equal groups[:on_send].map(&:first), groups[:on_finish].map(&:first)
116
- end
117
-
118
- def test_finish_is_called_if_there_is_an_exception
119
- events = []
120
- ret = [200, {}, []]
121
- app = lambda { |env| raise }
122
- se = EventMiddleware.new events
123
- e = Events.new app, [se]
124
- assert_raises(RuntimeError) do
125
- e.call({})
126
- end
127
- assert_equal [[se, :on_start],
128
- [se, :on_error],
129
- [se, :on_finish],
130
- ], events
131
- end
132
- end
133
- end
@@ -1,85 +0,0 @@
1
- require 'helper'
2
-
3
- if defined? LIGHTTPD_PID
4
-
5
- require File.expand_path('../testrequest', __FILE__)
6
- require 'rack/handler/fastcgi'
7
-
8
- describe Rack::Handler::FastCGI do
9
- include TestRequest::Helpers
10
-
11
- before do
12
- @host = '127.0.0.1'
13
- @port = 9203
14
- end
15
-
16
- it "respond" do
17
- sleep 1
18
- GET("/test")
19
- response.wont_be :nil?
20
- end
21
-
22
- it "respond via rackup server" do
23
- GET("/sample_rackup.ru")
24
- status.must_equal 200
25
- end
26
-
27
- it "be a lighttpd" do
28
- GET("/test.fcgi")
29
- status.must_equal 200
30
- response["SERVER_SOFTWARE"].must_match(/lighttpd/)
31
- response["HTTP_VERSION"].must_equal "HTTP/1.1"
32
- response["SERVER_PROTOCOL"].must_equal "HTTP/1.1"
33
- response["SERVER_PORT"].must_equal @port.to_s
34
- response["SERVER_NAME"].must_equal @host
35
- end
36
-
37
- it "have rack headers" do
38
- GET("/test.fcgi")
39
- response["rack.version"].must_equal [1,3]
40
- assert_equal false, response["rack.multithread"]
41
- assert_equal true, response["rack.multiprocess"]
42
- assert_equal false, response["rack.run_once"]
43
- end
44
-
45
- it "have CGI headers on GET" do
46
- GET("/test.fcgi")
47
- response["REQUEST_METHOD"].must_equal "GET"
48
- response["SCRIPT_NAME"].must_equal "/test.fcgi"
49
- response["REQUEST_PATH"].must_equal "/"
50
- response["PATH_INFO"].must_equal ""
51
- response["QUERY_STRING"].must_equal ""
52
- response["test.postdata"].must_equal ""
53
-
54
- GET("/test.fcgi/foo?quux=1")
55
- response["REQUEST_METHOD"].must_equal "GET"
56
- response["SCRIPT_NAME"].must_equal "/test.fcgi"
57
- response["REQUEST_PATH"].must_equal "/"
58
- response["PATH_INFO"].must_equal "/foo"
59
- response["QUERY_STRING"].must_equal "quux=1"
60
- end
61
-
62
- it "have CGI headers on POST" do
63
- POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
64
- status.must_equal 200
65
- response["REQUEST_METHOD"].must_equal "POST"
66
- response["SCRIPT_NAME"].must_equal "/test.fcgi"
67
- response["REQUEST_PATH"].must_equal "/"
68
- response["QUERY_STRING"].must_equal ""
69
- response["HTTP_X_TEST_HEADER"].must_equal "42"
70
- response["test.postdata"].must_equal "rack-form-data=23"
71
- end
72
-
73
- it "support HTTP auth" do
74
- GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
75
- response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
76
- end
77
-
78
- it "set status" do
79
- GET("/test.fcgi?secret")
80
- status.must_equal 403
81
- response["rack.url_scheme"].must_equal "http"
82
- end
83
- end
84
-
85
- end # if defined? LIGHTTPD_PID
@@ -1,264 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/file'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::File do
7
- DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
8
-
9
- def file(*args)
10
- Rack::Lint.new Rack::File.new(*args)
11
- end
12
-
13
- it 'serves files with + in the file name' do
14
- Dir.mktmpdir do |dir|
15
- File.write File.join(dir, "you+me.txt"), "hello world"
16
- app = file(dir)
17
- env = Rack::MockRequest.env_for("/you+me.txt")
18
- status,_,body = app.call env
19
-
20
- assert_equal 200, status
21
-
22
- str = ''
23
- body.each { |x| str << x }
24
- assert_match "hello world", str
25
- end
26
- end
27
-
28
- it "serve files" do
29
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
30
-
31
- res.must_be :ok?
32
- assert_match(res, /ruby/)
33
- end
34
-
35
- it "set Last-Modified header" do
36
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
37
-
38
- path = File.join(DOCROOT, "/cgi/test")
39
-
40
- res.must_be :ok?
41
- res["Last-Modified"].must_equal File.mtime(path).httpdate
42
- end
43
-
44
- it "return 304 if file isn't modified since last serve" do
45
- path = File.join(DOCROOT, "/cgi/test")
46
- res = Rack::MockRequest.new(file(DOCROOT)).
47
- get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path).httpdate)
48
-
49
- res.status.must_equal 304
50
- res.body.must_be :empty?
51
- end
52
-
53
- it "return the file if it's modified since last serve" do
54
- path = File.join(DOCROOT, "/cgi/test")
55
- res = Rack::MockRequest.new(file(DOCROOT)).
56
- get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => (File.mtime(path) - 100).httpdate)
57
-
58
- res.must_be :ok?
59
- end
60
-
61
- it "serve files with URL encoded filenames" do
62
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%74%65%73%74") # "/cgi/test"
63
-
64
- res.must_be :ok?
65
- # res.must_match(/ruby/) # nope
66
- # (/ruby/).must_match res # This is wierd, but an oddity of minitest
67
- # assert_match(/ruby/, res) # nope
68
- assert_match(res, /ruby/)
69
- end
70
-
71
- it "serve uri with URL encoded null byte (%00) in filenames" do
72
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test%00")
73
- res.must_be :bad_request?
74
- end
75
-
76
- it "allow safe directory traversal" do
77
- req = Rack::MockRequest.new(file(DOCROOT))
78
-
79
- res = req.get('/cgi/../cgi/test')
80
- res.must_be :successful?
81
-
82
- res = req.get('.')
83
- res.must_be :not_found?
84
-
85
- res = req.get("test/..")
86
- res.must_be :not_found?
87
- end
88
-
89
- it "not allow unsafe directory traversal" do
90
- req = Rack::MockRequest.new(file(DOCROOT))
91
-
92
- res = req.get("/../README.rdoc")
93
- res.must_be :client_error?
94
-
95
- res = req.get("../test/spec_file.rb")
96
- res.must_be :client_error?
97
-
98
- res = req.get("../README.rdoc")
99
- res.must_be :client_error?
100
-
101
- res.must_be :not_found?
102
- end
103
-
104
- it "allow files with .. in their name" do
105
- req = Rack::MockRequest.new(file(DOCROOT))
106
- res = req.get("/cgi/..test")
107
- res.must_be :not_found?
108
-
109
- res = req.get("/cgi/test..")
110
- res.must_be :not_found?
111
-
112
- res = req.get("/cgi../test..")
113
- res.must_be :not_found?
114
- end
115
-
116
- it "not allow unsafe directory traversal with encoded periods" do
117
- res = Rack::MockRequest.new(file(DOCROOT)).get("/%2E%2E/README")
118
-
119
- res.must_be :client_error?
120
- res.must_be :not_found?
121
- end
122
-
123
- it "allow safe directory traversal with encoded periods" do
124
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%2E%2E/cgi/test")
125
-
126
- res.must_be :successful?
127
- end
128
-
129
- it "404 if it can't find the file" do
130
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/blubb")
131
-
132
- res.must_be :not_found?
133
- end
134
-
135
- it "detect SystemCallErrors" do
136
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi")
137
-
138
- res.must_be :not_found?
139
- end
140
-
141
- it "return bodies that respond to #to_path" do
142
- env = Rack::MockRequest.env_for("/cgi/test")
143
- status, _, body = Rack::File.new(DOCROOT).call(env)
144
-
145
- path = File.join(DOCROOT, "/cgi/test")
146
-
147
- status.must_equal 200
148
- body.must_respond_to :to_path
149
- body.to_path.must_equal path
150
- end
151
-
152
- it "return correct byte range in body" do
153
- env = Rack::MockRequest.env_for("/cgi/test")
154
- env["HTTP_RANGE"] = "bytes=22-33"
155
- res = Rack::MockResponse.new(*file(DOCROOT).call(env))
156
-
157
- res.status.must_equal 206
158
- res["Content-Length"].must_equal "12"
159
- res["Content-Range"].must_equal "bytes 22-33/193"
160
- res.body.must_equal "-*- ruby -*-"
161
- end
162
-
163
- it "return error for unsatisfiable byte range" do
164
- env = Rack::MockRequest.env_for("/cgi/test")
165
- env["HTTP_RANGE"] = "bytes=1234-5678"
166
- res = Rack::MockResponse.new(*file(DOCROOT).call(env))
167
-
168
- res.status.must_equal 416
169
- res["Content-Range"].must_equal "bytes */193"
170
- end
171
-
172
- it "support custom http headers" do
173
- env = Rack::MockRequest.env_for("/cgi/test")
174
- status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
175
- 'Access-Control-Allow-Origin' => '*').call(env)
176
-
177
- status.must_equal 200
178
- heads['Cache-Control'].must_equal 'public, max-age=38'
179
- heads['Access-Control-Allow-Origin'].must_equal '*'
180
- end
181
-
182
- it "support not add custom http headers if none are supplied" do
183
- env = Rack::MockRequest.env_for("/cgi/test")
184
- status, heads, _ = file(DOCROOT).call(env)
185
-
186
- status.must_equal 200
187
- heads['Cache-Control'].must_be_nil
188
- heads['Access-Control-Allow-Origin'].must_be_nil
189
- end
190
-
191
- it "only support GET, HEAD, and OPTIONS requests" do
192
- req = Rack::MockRequest.new(file(DOCROOT))
193
-
194
- forbidden = %w[post put patch delete]
195
- forbidden.each do |method|
196
- res = req.send(method, "/cgi/test")
197
- res.must_be :client_error?
198
- res.must_be :method_not_allowed?
199
- res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
200
- end
201
-
202
- allowed = %w[get head options]
203
- allowed.each do |method|
204
- res = req.send(method, "/cgi/test")
205
- res.must_be :successful?
206
- end
207
- end
208
-
209
- it "set Allow correctly for OPTIONS requests" do
210
- req = Rack::MockRequest.new(file(DOCROOT))
211
- res = req.options('/cgi/test')
212
- res.must_be :successful?
213
- res.headers['Allow'].wont_equal nil
214
- res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
215
- end
216
-
217
- it "set Content-Length correctly for HEAD requests" do
218
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
219
- res = req.head "/cgi/test"
220
- res.must_be :successful?
221
- res['Content-Length'].must_equal "193"
222
- end
223
-
224
- it "default to a mime type of text/plain" do
225
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
226
- res = req.get "/cgi/test"
227
- res.must_be :successful?
228
- res['Content-Type'].must_equal "text/plain"
229
- end
230
-
231
- it "allow the default mime type to be set" do
232
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, 'application/octet-stream')))
233
- res = req.get "/cgi/test"
234
- res.must_be :successful?
235
- res['Content-Type'].must_equal "application/octet-stream"
236
- end
237
-
238
- it "not set Content-Type if the mime type is not set" do
239
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
240
- res = req.get "/cgi/test"
241
- res.must_be :successful?
242
- res['Content-Type'].must_be_nil
243
- end
244
-
245
- it "return error when file not found for head request" do
246
- res = Rack::MockRequest.new(file(DOCROOT)).head("/cgi/missing")
247
- res.must_be :not_found?
248
- res.body.must_be :empty?
249
- end
250
-
251
- class MyFile < Rack::File
252
- def response_body
253
- "hello world"
254
- end
255
- end
256
-
257
- it "behaves gracefully if response_body is present" do
258
- file = Rack::Lint.new MyFile.new(DOCROOT)
259
- res = Rack::MockRequest.new(file).get("/cgi/test")
260
-
261
- res.must_be :ok?
262
- end
263
-
264
- end