rack 1.6.12 → 2.0.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 (142) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +17 -25
  5. data/Rakefile +6 -14
  6. data/SPEC +10 -11
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack.rb +70 -21
  11. data/lib/rack/auth/abstract/request.rb +5 -1
  12. data/lib/rack/auth/digest/params.rb +2 -3
  13. data/lib/rack/auth/digest/request.rb +1 -1
  14. data/lib/rack/body_proxy.rb +14 -9
  15. data/lib/rack/builder.rb +3 -3
  16. data/lib/rack/chunked.rb +5 -5
  17. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  18. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  19. data/lib/rack/content_length.rb +2 -2
  20. data/lib/rack/deflater.rb +4 -39
  21. data/lib/rack/directory.rb +66 -54
  22. data/lib/rack/etag.rb +4 -3
  23. data/lib/rack/events.rb +154 -0
  24. data/lib/rack/file.rb +64 -40
  25. data/lib/rack/handler.rb +3 -25
  26. data/lib/rack/handler/cgi.rb +15 -16
  27. data/lib/rack/handler/fastcgi.rb +13 -14
  28. data/lib/rack/handler/lsws.rb +11 -11
  29. data/lib/rack/handler/scgi.rb +15 -15
  30. data/lib/rack/handler/thin.rb +3 -0
  31. data/lib/rack/handler/webrick.rb +24 -26
  32. data/lib/rack/head.rb +15 -17
  33. data/lib/rack/lint.rb +40 -40
  34. data/lib/rack/lobster.rb +1 -1
  35. data/lib/rack/lock.rb +6 -10
  36. data/lib/rack/logger.rb +2 -2
  37. data/lib/rack/media_type.rb +38 -0
  38. data/lib/rack/{methodoverride.rb → method_override.rb} +6 -10
  39. data/lib/rack/mime.rb +18 -5
  40. data/lib/rack/mock.rb +36 -54
  41. data/lib/rack/multipart.rb +35 -6
  42. data/lib/rack/multipart/generator.rb +5 -5
  43. data/lib/rack/multipart/parser.rb +272 -158
  44. data/lib/rack/multipart/uploaded_file.rb +1 -2
  45. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  46. data/lib/rack/query_parser.rb +192 -0
  47. data/lib/rack/recursive.rb +8 -8
  48. data/lib/rack/request.rb +383 -307
  49. data/lib/rack/response.rb +130 -57
  50. data/lib/rack/rewindable_input.rb +1 -12
  51. data/lib/rack/runtime.rb +10 -18
  52. data/lib/rack/sendfile.rb +5 -7
  53. data/lib/rack/server.rb +30 -23
  54. data/lib/rack/session/abstract/id.rb +108 -138
  55. data/lib/rack/session/cookie.rb +26 -28
  56. data/lib/rack/session/memcache.rb +8 -14
  57. data/lib/rack/session/pool.rb +14 -21
  58. data/lib/rack/show_exceptions.rb +386 -0
  59. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  60. data/lib/rack/static.rb +30 -5
  61. data/lib/rack/tempfile_reaper.rb +2 -2
  62. data/lib/rack/urlmap.rb +15 -14
  63. data/lib/rack/utils.rb +136 -211
  64. data/rack.gemspec +7 -5
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/filename_with_single_quote +7 -0
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +37 -35
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +85 -49
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +120 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +164 -199
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +69 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/{spec_methodoverride.rb → spec_method_override.rb} +22 -37
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +206 -144
  104. data/test/spec_multipart.rb +322 -200
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +768 -607
  108. data/test/spec_response.rb +215 -112
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +45 -0
  115. data/test/spec_session_cookie.rb +99 -67
  116. data/test/spec_session_memcache.rb +63 -101
  117. data/test/spec_session_pool.rb +48 -84
  118. data/test/spec_show_exceptions.rb +80 -0
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +93 -68
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +102 -66
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_mongrel.rb +0 -182
  142. data/test/spec_showexceptions.rb +0 -98
@@ -1,3 +1,4 @@
1
+ require 'minitest/autorun'
1
2
  require 'rack/etag'
2
3
  require 'rack/lint'
3
4
  require 'rack/mock'
@@ -7,101 +8,101 @@ describe Rack::ETag do
7
8
  def etag(app, *args)
8
9
  Rack::Lint.new Rack::ETag.new(app, *args)
9
10
  end
10
-
11
+
11
12
  def request
12
13
  Rack::MockRequest.env_for
13
14
  end
14
-
15
+
15
16
  def sendfile_body
16
17
  res = ['Hello World']
17
18
  def res.to_path ; "/tmp/hello.txt" ; end
18
19
  res
19
20
  end
20
21
 
21
- should "set ETag if none is set if status is 200" do
22
+ it "set ETag if none is set if status is 200" do
22
23
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
23
24
  response = etag(app).call(request)
24
- response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
25
+ response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
25
26
  end
26
27
 
27
- should "set ETag if none is set if status is 201" do
28
+ it "set ETag if none is set if status is 201" do
28
29
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
29
30
  response = etag(app).call(request)
30
- response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
31
+ response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
31
32
  end
32
33
 
33
- should "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
34
+ it "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
34
35
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
35
36
  response = etag(app).call(request)
36
- response[1]['Cache-Control'].should.equal 'max-age=0, private, must-revalidate'
37
+ response[1]['Cache-Control'].must_equal 'max-age=0, private, must-revalidate'
37
38
  end
38
39
 
39
- should "set Cache-Control to chosen one if none is set" do
40
+ it "set Cache-Control to chosen one if none is set" do
40
41
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
41
42
  response = etag(app, nil, 'public').call(request)
42
- response[1]['Cache-Control'].should.equal 'public'
43
+ response[1]['Cache-Control'].must_equal 'public'
43
44
  end
44
45
 
45
- should "set a given Cache-Control even if digest could not be calculated" do
46
+ it "set a given Cache-Control even if digest could not be calculated" do
46
47
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, []] }
47
48
  response = etag(app, 'no-cache').call(request)
48
- response[1]['Cache-Control'].should.equal 'no-cache'
49
+ response[1]['Cache-Control'].must_equal 'no-cache'
49
50
  end
50
51
 
51
- should "not set Cache-Control if it is already set" do
52
+ it "not set Cache-Control if it is already set" do
52
53
  app = lambda { |env| [201, {'Content-Type' => 'text/plain', 'Cache-Control' => 'public'}, ["Hello, World!"]] }
53
54
  response = etag(app).call(request)
54
- response[1]['Cache-Control'].should.equal 'public'
55
+ response[1]['Cache-Control'].must_equal 'public'
55
56
  end
56
57
 
57
- should "not set Cache-Control if directive isn't present" do
58
+ it "not set Cache-Control if directive isn't present" do
58
59
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
59
60
  response = etag(app, nil, nil).call(request)
60
- response[1]['Cache-Control'].should.equal nil
61
+ response[1]['Cache-Control'].must_be_nil
61
62
  end
62
63
 
63
- should "not change ETag if it is already set" do
64
+ it "not change ETag if it is already set" do
64
65
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
65
66
  response = etag(app).call(request)
66
- response[1]['ETag'].should.equal "\"abc\""
67
+ response[1]['ETag'].must_equal "\"abc\""
67
68
  end
68
69
 
69
- should "not set ETag if body is empty" do
70
+ it "not set ETag if body is empty" do
70
71
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, []] }
71
72
  response = etag(app).call(request)
72
- response[1]['ETag'].should.be.nil
73
+ response[1]['ETag'].must_be_nil
73
74
  end
74
75
 
75
- should "not set ETag if Last-Modified is set" do
76
+ it "not set ETag if Last-Modified is set" do
76
77
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, ["Hello, World!"]] }
77
78
  response = etag(app).call(request)
78
- response[1]['ETag'].should.be.nil
79
+ response[1]['ETag'].must_be_nil
79
80
  end
80
81
 
81
- should "not set ETag if a sendfile_body is given" do
82
+ it "not set ETag if a sendfile_body is given" do
82
83
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, sendfile_body] }
83
84
  response = etag(app).call(request)
84
- response[1]['ETag'].should.be.nil
85
+ response[1]['ETag'].must_be_nil
85
86
  end
86
87
 
87
- should "not set ETag if a status is not 200 or 201" do
88
+ it "not set ETag if a status is not 200 or 201" do
88
89
  app = lambda { |env| [401, {'Content-Type' => 'text/plain'}, ['Access denied.']] }
89
90
  response = etag(app).call(request)
90
- response[1]['ETag'].should.be.nil
91
+ response[1]['ETag'].must_be_nil
91
92
  end
92
93
 
93
- should "not set ETag if no-cache is given" do
94
+ it "not set ETag if no-cache is given" do
94
95
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache, must-revalidate'}, ['Hello, World!']] }
95
96
  response = etag(app).call(request)
96
- response[1]['ETag'].should.be.nil
97
+ response[1]['ETag'].must_be_nil
97
98
  end
98
99
 
99
- should "close the original body" do
100
+ it "close the original body" do
100
101
  body = StringIO.new
101
102
  app = lambda { |env| [200, {}, body] }
102
103
  response = etag(app).call(request)
103
- body.should.not.be.closed
104
+ body.wont_be :closed?
104
105
  response[2].close
105
- body.should.be.closed
106
+ body.must_be :closed?
106
107
  end
107
108
  end
@@ -0,0 +1,133 @@
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,107 +1,85 @@
1
- begin
1
+ require 'helper'
2
+
3
+ if defined? LIGHTTPD_PID
4
+
2
5
  require File.expand_path('../testrequest', __FILE__)
3
6
  require 'rack/handler/fastcgi'
4
7
 
5
8
  describe Rack::Handler::FastCGI do
6
- extend TestRequest::Helpers
9
+ include TestRequest::Helpers
7
10
 
8
- @host = '127.0.0.1'
9
- @port = 9203
10
-
11
- if `which lighttpd` && !$?.success?
12
- raise "lighttpd not found"
11
+ before do
12
+ @host = '127.0.0.1'
13
+ @port = 9203
13
14
  end
14
15
 
15
- # Keep this first.
16
- $pid = fork {
17
- ENV['RACK_ENV'] = 'deployment'
18
- ENV['RUBYLIB'] = [
19
- File.expand_path('../../lib', __FILE__),
20
- ENV['RUBYLIB'],
21
- ].compact.join(':')
22
-
23
- Dir.chdir(File.expand_path("../cgi", __FILE__)) do
24
- exec "lighttpd -D -f lighttpd.conf"
25
- end
26
- }
27
-
28
- should "respond" do
16
+ it "respond" do
29
17
  sleep 1
30
18
  GET("/test")
31
- response.should.not.be.nil
19
+ response.wont_be :nil?
32
20
  end
33
21
 
34
- should "respond via rackup server" do
22
+ it "respond via rackup server" do
35
23
  GET("/sample_rackup.ru")
36
- status.should.equal 200
24
+ status.must_equal 200
37
25
  end
38
26
 
39
- should "be a lighttpd" do
27
+ it "be a lighttpd" do
40
28
  GET("/test.fcgi")
41
- status.should.equal 200
42
- response["SERVER_SOFTWARE"].should =~ /lighttpd/
43
- response["HTTP_VERSION"].should.equal "HTTP/1.1"
44
- response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
45
- response["SERVER_PORT"].should.equal @port.to_s
46
- response["SERVER_NAME"].should.equal @host
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
47
35
  end
48
36
 
49
- should "have rack headers" do
37
+ it "have rack headers" do
50
38
  GET("/test.fcgi")
51
- response["rack.version"].should.equal [1,3]
52
- response["rack.multithread"].should.be.false
53
- response["rack.multiprocess"].should.be.true
54
- response["rack.run_once"].should.be.false
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"]
55
43
  end
56
44
 
57
- should "have CGI headers on GET" do
45
+ it "have CGI headers on GET" do
58
46
  GET("/test.fcgi")
59
- response["REQUEST_METHOD"].should.equal "GET"
60
- response["SCRIPT_NAME"].should.equal "/test.fcgi"
61
- response["REQUEST_PATH"].should.equal "/"
62
- response["PATH_INFO"].should.equal ""
63
- response["QUERY_STRING"].should.equal ""
64
- response["test.postdata"].should.equal ""
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 ""
65
53
 
66
54
  GET("/test.fcgi/foo?quux=1")
67
- response["REQUEST_METHOD"].should.equal "GET"
68
- response["SCRIPT_NAME"].should.equal "/test.fcgi"
69
- response["REQUEST_PATH"].should.equal "/"
70
- response["PATH_INFO"].should.equal "/foo"
71
- response["QUERY_STRING"].should.equal "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"
72
60
  end
73
61
 
74
- should "have CGI headers on POST" do
62
+ it "have CGI headers on POST" do
75
63
  POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
76
- status.should.equal 200
77
- response["REQUEST_METHOD"].should.equal "POST"
78
- response["SCRIPT_NAME"].should.equal "/test.fcgi"
79
- response["REQUEST_PATH"].should.equal "/"
80
- response["QUERY_STRING"].should.equal ""
81
- response["HTTP_X_TEST_HEADER"].should.equal "42"
82
- response["test.postdata"].should.equal "rack-form-data=23"
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"
83
71
  end
84
72
 
85
- should "support HTTP auth" do
73
+ it "support HTTP auth" do
86
74
  GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
87
- response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
75
+ response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
88
76
  end
89
77
 
90
- should "set status" do
78
+ it "set status" do
91
79
  GET("/test.fcgi?secret")
92
- status.should.equal 403
93
- response["rack.url_scheme"].should.equal "http"
94
- end
95
-
96
- # Keep this last.
97
- should "shutdown" do
98
- Process.kill 15, $pid
99
- Process.wait($pid).should.equal $pid
80
+ status.must_equal 403
81
+ response["rack.url_scheme"].must_equal "http"
100
82
  end
101
83
  end
102
84
 
103
- rescue RuntimeError
104
- $stderr.puts "Skipping Rack::Handler::FastCGI tests (lighttpd is required). Install lighttpd and try again."
105
- rescue LoadError
106
- $stderr.puts "Skipping Rack::Handler::FastCGI tests (FCGI is required). `gem install fcgi` and try again."
107
- end
85
+ end # if defined? LIGHTTPD_PID
@@ -1,3 +1,4 @@
1
+ require 'minitest/autorun'
1
2
  require 'rack/file'
2
3
  require 'rack/lint'
3
4
  require 'rack/mock'
@@ -9,213 +10,255 @@ describe Rack::File do
9
10
  Rack::Lint.new Rack::File.new(*args)
10
11
  end
11
12
 
12
- should "serve files" do
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
13
29
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
14
30
 
15
- res.should.be.ok
16
- res.should =~ /ruby/
31
+ res.must_be :ok?
32
+ assert_match(res, /ruby/)
17
33
  end
18
34
 
19
- should "set Last-Modified header" do
35
+ it "set Last-Modified header" do
20
36
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
21
37
 
22
38
  path = File.join(DOCROOT, "/cgi/test")
23
39
 
24
- res.should.be.ok
25
- res["Last-Modified"].should.equal File.mtime(path).httpdate
40
+ res.must_be :ok?
41
+ res["Last-Modified"].must_equal File.mtime(path).httpdate
26
42
  end
27
43
 
28
- should "return 304 if file isn't modified since last serve" do
44
+ it "return 304 if file isn't modified since last serve" do
29
45
  path = File.join(DOCROOT, "/cgi/test")
30
46
  res = Rack::MockRequest.new(file(DOCROOT)).
31
47
  get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path).httpdate)
32
48
 
33
- res.status.should.equal 304
34
- res.body.should.be.empty
49
+ res.status.must_equal 304
50
+ res.body.must_be :empty?
35
51
  end
36
52
 
37
- should "return the file if it's modified since last serve" do
53
+ it "return the file if it's modified since last serve" do
38
54
  path = File.join(DOCROOT, "/cgi/test")
39
55
  res = Rack::MockRequest.new(file(DOCROOT)).
40
56
  get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => (File.mtime(path) - 100).httpdate)
41
57
 
42
- res.should.be.ok
58
+ res.must_be :ok?
43
59
  end
44
60
 
45
- should "serve files with URL encoded filenames" do
61
+ it "serve files with URL encoded filenames" do
46
62
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%74%65%73%74") # "/cgi/test"
47
63
 
48
- res.should.be.ok
49
- res.should =~ /ruby/
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?
50
74
  end
51
75
 
52
- should "allow safe directory traversal" do
76
+ it "allow safe directory traversal" do
53
77
  req = Rack::MockRequest.new(file(DOCROOT))
54
78
 
55
79
  res = req.get('/cgi/../cgi/test')
56
- res.should.be.successful
80
+ res.must_be :successful?
57
81
 
58
82
  res = req.get('.')
59
- res.should.be.not_found
83
+ res.must_be :not_found?
60
84
 
61
85
  res = req.get("test/..")
62
- res.should.be.not_found
86
+ res.must_be :not_found?
63
87
  end
64
88
 
65
- should "not allow unsafe directory traversal" do
89
+ it "not allow unsafe directory traversal" do
66
90
  req = Rack::MockRequest.new(file(DOCROOT))
67
91
 
68
92
  res = req.get("/../README.rdoc")
69
- res.should.be.client_error
93
+ res.must_be :client_error?
70
94
 
71
95
  res = req.get("../test/spec_file.rb")
72
- res.should.be.client_error
96
+ res.must_be :client_error?
73
97
 
74
98
  res = req.get("../README.rdoc")
75
- res.should.be.client_error
99
+ res.must_be :client_error?
76
100
 
77
- res.should.be.not_found
101
+ res.must_be :not_found?
78
102
  end
79
103
 
80
- should "allow files with .. in their name" do
104
+ it "allow files with .. in their name" do
81
105
  req = Rack::MockRequest.new(file(DOCROOT))
82
106
  res = req.get("/cgi/..test")
83
- res.should.be.not_found
107
+ res.must_be :not_found?
84
108
 
85
109
  res = req.get("/cgi/test..")
86
- res.should.be.not_found
110
+ res.must_be :not_found?
87
111
 
88
112
  res = req.get("/cgi../test..")
89
- res.should.be.not_found
113
+ res.must_be :not_found?
90
114
  end
91
115
 
92
- should "not allow unsafe directory traversal with encoded periods" do
116
+ it "not allow unsafe directory traversal with encoded periods" do
93
117
  res = Rack::MockRequest.new(file(DOCROOT)).get("/%2E%2E/README")
94
118
 
95
- res.should.be.client_error?
96
- res.should.be.not_found
119
+ res.must_be :client_error?
120
+ res.must_be :not_found?
97
121
  end
98
122
 
99
- should "allow safe directory traversal with encoded periods" do
123
+ it "allow safe directory traversal with encoded periods" do
100
124
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%2E%2E/cgi/test")
101
125
 
102
- res.should.be.successful
126
+ res.must_be :successful?
103
127
  end
104
128
 
105
- should "404 if it can't find the file" do
129
+ it "404 if it can't find the file" do
106
130
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/blubb")
107
131
 
108
- res.should.be.not_found
132
+ res.must_be :not_found?
109
133
  end
110
134
 
111
- should "detect SystemCallErrors" do
135
+ it "detect SystemCallErrors" do
112
136
  res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi")
113
137
 
114
- res.should.be.not_found
138
+ res.must_be :not_found?
115
139
  end
116
140
 
117
- should "return bodies that respond to #to_path" do
141
+ it "return bodies that respond to #to_path" do
118
142
  env = Rack::MockRequest.env_for("/cgi/test")
119
143
  status, _, body = Rack::File.new(DOCROOT).call(env)
120
144
 
121
145
  path = File.join(DOCROOT, "/cgi/test")
122
146
 
123
- status.should.equal 200
124
- body.should.respond_to :to_path
125
- body.to_path.should.equal path
147
+ status.must_equal 200
148
+ body.must_respond_to :to_path
149
+ body.to_path.must_equal path
126
150
  end
127
151
 
128
- should "return correct byte range in body" do
152
+ it "return correct byte range in body" do
129
153
  env = Rack::MockRequest.env_for("/cgi/test")
130
154
  env["HTTP_RANGE"] = "bytes=22-33"
131
155
  res = Rack::MockResponse.new(*file(DOCROOT).call(env))
132
156
 
133
- res.status.should.equal 206
134
- res["Content-Length"].should.equal "12"
135
- res["Content-Range"].should.equal "bytes 22-33/193"
136
- res.body.should.equal "-*- ruby -*-"
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 -*-"
137
161
  end
138
162
 
139
- should "return error for unsatisfiable byte range" do
163
+ it "return error for unsatisfiable byte range" do
140
164
  env = Rack::MockRequest.env_for("/cgi/test")
141
165
  env["HTTP_RANGE"] = "bytes=1234-5678"
142
166
  res = Rack::MockResponse.new(*file(DOCROOT).call(env))
143
167
 
144
- res.status.should.equal 416
145
- res["Content-Range"].should.equal "bytes */193"
168
+ res.status.must_equal 416
169
+ res["Content-Range"].must_equal "bytes */193"
146
170
  end
147
171
 
148
- should "support custom http headers" do
172
+ it "support custom http headers" do
149
173
  env = Rack::MockRequest.env_for("/cgi/test")
150
174
  status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
151
175
  'Access-Control-Allow-Origin' => '*').call(env)
152
176
 
153
- status.should.equal 200
154
- heads['Cache-Control'].should.equal 'public, max-age=38'
155
- heads['Access-Control-Allow-Origin'].should.equal '*'
177
+ status.must_equal 200
178
+ heads['Cache-Control'].must_equal 'public, max-age=38'
179
+ heads['Access-Control-Allow-Origin'].must_equal '*'
156
180
  end
157
181
 
158
- should "support not add custom http headers if none are supplied" do
182
+ it "support not add custom http headers if none are supplied" do
159
183
  env = Rack::MockRequest.env_for("/cgi/test")
160
184
  status, heads, _ = file(DOCROOT).call(env)
161
185
 
162
- status.should.equal 200
163
- heads['Cache-Control'].should.equal nil
164
- heads['Access-Control-Allow-Origin'].should.equal nil
186
+ status.must_equal 200
187
+ heads['Cache-Control'].must_be_nil
188
+ heads['Access-Control-Allow-Origin'].must_be_nil
165
189
  end
166
190
 
167
- should "only support GET, HEAD, and OPTIONS requests" do
191
+ it "only support GET, HEAD, and OPTIONS requests" do
168
192
  req = Rack::MockRequest.new(file(DOCROOT))
169
193
 
170
194
  forbidden = %w[post put patch delete]
171
195
  forbidden.each do |method|
172
196
  res = req.send(method, "/cgi/test")
173
- res.should.be.client_error
174
- res.should.be.method_not_allowed
175
- res.headers['Allow'].split(/, */).sort.should == %w(GET HEAD OPTIONS)
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)
176
200
  end
177
201
 
178
202
  allowed = %w[get head options]
179
203
  allowed.each do |method|
180
204
  res = req.send(method, "/cgi/test")
181
- res.should.be.successful
205
+ res.must_be :successful?
182
206
  end
183
207
  end
184
208
 
185
- should "set Allow correctly for OPTIONS requests" do
209
+ it "set Allow correctly for OPTIONS requests" do
186
210
  req = Rack::MockRequest.new(file(DOCROOT))
187
211
  res = req.options('/cgi/test')
188
- res.should.be.successful
189
- res.headers['Allow'].should.not.equal nil
190
- res.headers['Allow'].split(/, */).sort.should == %w(GET HEAD OPTIONS)
212
+ res.must_be :successful?
213
+ res.headers['Allow'].wont_equal nil
214
+ res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
191
215
  end
192
216
 
193
- should "set Content-Length correctly for HEAD requests" do
217
+ it "set Content-Length correctly for HEAD requests" do
194
218
  req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
195
219
  res = req.head "/cgi/test"
196
- res.should.be.successful
197
- res['Content-Length'].should.equal "193"
220
+ res.must_be :successful?
221
+ res['Content-Length'].must_equal "193"
198
222
  end
199
223
 
200
- should "default to a mime type of text/plain" do
224
+ it "default to a mime type of text/plain" do
201
225
  req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
202
226
  res = req.get "/cgi/test"
203
- res.should.be.successful
204
- res['Content-Type'].should.equal "text/plain"
227
+ res.must_be :successful?
228
+ res['Content-Type'].must_equal "text/plain"
205
229
  end
206
230
 
207
- should "allow the default mime type to be set" do
231
+ it "allow the default mime type to be set" do
208
232
  req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, 'application/octet-stream')))
209
233
  res = req.get "/cgi/test"
210
- res.should.be.successful
211
- res['Content-Type'].should.equal "application/octet-stream"
234
+ res.must_be :successful?
235
+ res['Content-Type'].must_equal "application/octet-stream"
212
236
  end
213
237
 
214
- should "not set Content-Type if the mime type is not set" do
238
+ it "not set Content-Type if the mime type is not set" do
215
239
  req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
216
240
  res = req.get "/cgi/test"
217
- res.should.be.successful
218
- res['Content-Type'].should.equal nil
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?
219
262
  end
220
263
 
221
264
  end