edgar-rack 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +21 -0
  3. data/README +401 -0
  4. data/Rakefile +101 -0
  5. data/SPEC +171 -0
  6. data/bin/rackup +4 -0
  7. data/contrib/rack_logo.svg +111 -0
  8. data/example/lobster.ru +4 -0
  9. data/example/protectedlobster.rb +14 -0
  10. data/example/protectedlobster.ru +8 -0
  11. data/lib/rack.rb +81 -0
  12. data/lib/rack/auth/abstract/handler.rb +37 -0
  13. data/lib/rack/auth/abstract/request.rb +43 -0
  14. data/lib/rack/auth/basic.rb +58 -0
  15. data/lib/rack/auth/digest/md5.rb +124 -0
  16. data/lib/rack/auth/digest/nonce.rb +51 -0
  17. data/lib/rack/auth/digest/params.rb +53 -0
  18. data/lib/rack/auth/digest/request.rb +40 -0
  19. data/lib/rack/builder.rb +80 -0
  20. data/lib/rack/cascade.rb +41 -0
  21. data/lib/rack/chunked.rb +52 -0
  22. data/lib/rack/commonlogger.rb +49 -0
  23. data/lib/rack/conditionalget.rb +63 -0
  24. data/lib/rack/config.rb +15 -0
  25. data/lib/rack/content_length.rb +29 -0
  26. data/lib/rack/content_type.rb +23 -0
  27. data/lib/rack/deflater.rb +96 -0
  28. data/lib/rack/directory.rb +157 -0
  29. data/lib/rack/etag.rb +59 -0
  30. data/lib/rack/file.rb +118 -0
  31. data/lib/rack/handler.rb +88 -0
  32. data/lib/rack/handler/cgi.rb +61 -0
  33. data/lib/rack/handler/evented_mongrel.rb +8 -0
  34. data/lib/rack/handler/fastcgi.rb +90 -0
  35. data/lib/rack/handler/lsws.rb +61 -0
  36. data/lib/rack/handler/mongrel.rb +90 -0
  37. data/lib/rack/handler/scgi.rb +59 -0
  38. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  39. data/lib/rack/handler/thin.rb +17 -0
  40. data/lib/rack/handler/webrick.rb +73 -0
  41. data/lib/rack/head.rb +19 -0
  42. data/lib/rack/lint.rb +567 -0
  43. data/lib/rack/lobster.rb +65 -0
  44. data/lib/rack/lock.rb +44 -0
  45. data/lib/rack/logger.rb +18 -0
  46. data/lib/rack/methodoverride.rb +27 -0
  47. data/lib/rack/mime.rb +210 -0
  48. data/lib/rack/mock.rb +185 -0
  49. data/lib/rack/nulllogger.rb +18 -0
  50. data/lib/rack/recursive.rb +61 -0
  51. data/lib/rack/reloader.rb +109 -0
  52. data/lib/rack/request.rb +307 -0
  53. data/lib/rack/response.rb +151 -0
  54. data/lib/rack/rewindable_input.rb +104 -0
  55. data/lib/rack/runtime.rb +27 -0
  56. data/lib/rack/sendfile.rb +139 -0
  57. data/lib/rack/server.rb +289 -0
  58. data/lib/rack/session/abstract/id.rb +348 -0
  59. data/lib/rack/session/cookie.rb +152 -0
  60. data/lib/rack/session/memcache.rb +93 -0
  61. data/lib/rack/session/pool.rb +79 -0
  62. data/lib/rack/showexceptions.rb +378 -0
  63. data/lib/rack/showstatus.rb +113 -0
  64. data/lib/rack/static.rb +53 -0
  65. data/lib/rack/urlmap.rb +55 -0
  66. data/lib/rack/utils.rb +698 -0
  67. data/rack.gemspec +39 -0
  68. data/test/cgi/lighttpd.conf +25 -0
  69. data/test/cgi/rackup_stub.rb +6 -0
  70. data/test/cgi/sample_rackup.ru +5 -0
  71. data/test/cgi/test +9 -0
  72. data/test/cgi/test.fcgi +8 -0
  73. data/test/cgi/test.ru +5 -0
  74. data/test/gemloader.rb +6 -0
  75. data/test/multipart/bad_robots +259 -0
  76. data/test/multipart/binary +0 -0
  77. data/test/multipart/empty +10 -0
  78. data/test/multipart/fail_16384_nofile +814 -0
  79. data/test/multipart/file1.txt +1 -0
  80. data/test/multipart/filename_and_modification_param +7 -0
  81. data/test/multipart/filename_with_escaped_quotes +6 -0
  82. data/test/multipart/filename_with_escaped_quotes_and_modification_param +7 -0
  83. data/test/multipart/filename_with_percent_escaped_quotes +6 -0
  84. data/test/multipart/filename_with_unescaped_quotes +6 -0
  85. data/test/multipart/ie +6 -0
  86. data/test/multipart/nested +10 -0
  87. data/test/multipart/none +9 -0
  88. data/test/multipart/semicolon +6 -0
  89. data/test/multipart/text +15 -0
  90. data/test/rackup/config.ru +31 -0
  91. data/test/spec_auth_basic.rb +70 -0
  92. data/test/spec_auth_digest.rb +241 -0
  93. data/test/spec_builder.rb +123 -0
  94. data/test/spec_cascade.rb +45 -0
  95. data/test/spec_cgi.rb +102 -0
  96. data/test/spec_chunked.rb +60 -0
  97. data/test/spec_commonlogger.rb +56 -0
  98. data/test/spec_conditionalget.rb +86 -0
  99. data/test/spec_config.rb +23 -0
  100. data/test/spec_content_length.rb +36 -0
  101. data/test/spec_content_type.rb +29 -0
  102. data/test/spec_deflater.rb +125 -0
  103. data/test/spec_directory.rb +57 -0
  104. data/test/spec_etag.rb +75 -0
  105. data/test/spec_fastcgi.rb +107 -0
  106. data/test/spec_file.rb +92 -0
  107. data/test/spec_handler.rb +49 -0
  108. data/test/spec_head.rb +30 -0
  109. data/test/spec_lint.rb +515 -0
  110. data/test/spec_lobster.rb +43 -0
  111. data/test/spec_lock.rb +142 -0
  112. data/test/spec_logger.rb +28 -0
  113. data/test/spec_methodoverride.rb +58 -0
  114. data/test/spec_mock.rb +241 -0
  115. data/test/spec_mongrel.rb +182 -0
  116. data/test/spec_nulllogger.rb +12 -0
  117. data/test/spec_recursive.rb +69 -0
  118. data/test/spec_request.rb +774 -0
  119. data/test/spec_response.rb +245 -0
  120. data/test/spec_rewindable_input.rb +118 -0
  121. data/test/spec_runtime.rb +39 -0
  122. data/test/spec_sendfile.rb +83 -0
  123. data/test/spec_server.rb +8 -0
  124. data/test/spec_session_abstract_id.rb +43 -0
  125. data/test/spec_session_cookie.rb +171 -0
  126. data/test/spec_session_memcache.rb +289 -0
  127. data/test/spec_session_pool.rb +200 -0
  128. data/test/spec_showexceptions.rb +87 -0
  129. data/test/spec_showstatus.rb +79 -0
  130. data/test/spec_static.rb +48 -0
  131. data/test/spec_thin.rb +86 -0
  132. data/test/spec_urlmap.rb +213 -0
  133. data/test/spec_utils.rb +678 -0
  134. data/test/spec_webrick.rb +141 -0
  135. data/test/testrequest.rb +78 -0
  136. data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
  137. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
  138. metadata +329 -0
@@ -0,0 +1,245 @@
1
+ require 'set'
2
+ require 'rack/response'
3
+
4
+ describe Rack::Response do
5
+ should "have sensible default values" do
6
+ response = Rack::Response.new
7
+ status, header, body = response.finish
8
+ status.should.equal 200
9
+ header.should.equal "Content-Type" => "text/html"
10
+ body.each { |part|
11
+ part.should.equal ""
12
+ }
13
+
14
+ response = Rack::Response.new
15
+ status, header, body = *response
16
+ status.should.equal 200
17
+ header.should.equal "Content-Type" => "text/html"
18
+ body.each { |part|
19
+ part.should.equal ""
20
+ }
21
+ end
22
+
23
+ it "can be written to" do
24
+ response = Rack::Response.new
25
+
26
+ _, _, body = response.finish do
27
+ response.write "foo"
28
+ response.write "bar"
29
+ response.write "baz"
30
+ end
31
+
32
+ parts = []
33
+ body.each { |part| parts << part }
34
+
35
+ parts.should.equal ["foo", "bar", "baz"]
36
+ end
37
+
38
+ it "can set and read headers" do
39
+ response = Rack::Response.new
40
+ response["Content-Type"].should.equal "text/html"
41
+ response["Content-Type"] = "text/plain"
42
+ response["Content-Type"].should.equal "text/plain"
43
+ end
44
+
45
+ it "can override the initial Content-Type with a different case" do
46
+ response = Rack::Response.new("", 200, "content-type" => "text/plain")
47
+ response["Content-Type"].should.equal "text/plain"
48
+ end
49
+
50
+ it "can set cookies" do
51
+ response = Rack::Response.new
52
+
53
+ response.set_cookie "foo", "bar"
54
+ response["Set-Cookie"].should.equal "foo=bar"
55
+ response.set_cookie "foo2", "bar2"
56
+ response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"].join("\n")
57
+ response.set_cookie "foo3", "bar3"
58
+ response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"].join("\n")
59
+ end
60
+
61
+ it "can set cookies with the same name for multiple domains" do
62
+ response = Rack::Response.new
63
+ response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
64
+ response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
65
+ response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
66
+ end
67
+
68
+ it "formats the Cookie expiration date accordingly to RFC 2109" do
69
+ response = Rack::Response.new
70
+
71
+ response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
72
+ response["Set-Cookie"].should.match(
73
+ /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
74
+ end
75
+
76
+ it "can set secure cookies" do
77
+ response = Rack::Response.new
78
+ response.set_cookie "foo", {:value => "bar", :secure => true}
79
+ response["Set-Cookie"].should.equal "foo=bar; secure"
80
+ end
81
+
82
+ it "can set http only cookies" do
83
+ response = Rack::Response.new
84
+ response.set_cookie "foo", {:value => "bar", :httponly => true}
85
+ response["Set-Cookie"].should.equal "foo=bar; HttpOnly"
86
+ end
87
+
88
+ it "can delete cookies" do
89
+ response = Rack::Response.new
90
+ response.set_cookie "foo", "bar"
91
+ response.set_cookie "foo2", "bar2"
92
+ response.delete_cookie "foo"
93
+ response["Set-Cookie"].should.equal [
94
+ "foo2=bar2",
95
+ "foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"
96
+ ].join("\n")
97
+ end
98
+
99
+ it "can delete cookies with the same name from multiple domains" do
100
+ response = Rack::Response.new
101
+ response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
102
+ response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
103
+ response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
104
+ response.delete_cookie "foo", :domain => ".example.com"
105
+ response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
106
+ response.delete_cookie "foo", :domain => "sample.example.com"
107
+ response["Set-Cookie"].should.equal ["foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT",
108
+ "foo=; domain=sample.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
109
+ end
110
+
111
+ it "can do redirects" do
112
+ response = Rack::Response.new
113
+ response.redirect "/foo"
114
+ status, header, body = response.finish
115
+
116
+ status.should.equal 302
117
+ header["Location"].should.equal "/foo"
118
+
119
+ response = Rack::Response.new
120
+ response.redirect "/foo", 307
121
+ status, header, body = response.finish
122
+
123
+ status.should.equal 307
124
+ end
125
+
126
+ it "has a useful constructor" do
127
+ r = Rack::Response.new("foo")
128
+ status, header, body = r.finish
129
+ str = ""; body.each { |part| str << part }
130
+ str.should.equal "foo"
131
+
132
+ r = Rack::Response.new(["foo", "bar"])
133
+ status, header, body = r.finish
134
+ str = ""; body.each { |part| str << part }
135
+ str.should.equal "foobar"
136
+
137
+ r = Rack::Response.new(["foo", "bar"].to_set)
138
+ r.write "foo"
139
+ status, header, body = r.finish
140
+ str = ""; body.each { |part| str << part }
141
+ str.should.equal "foobarfoo"
142
+
143
+ r = Rack::Response.new([], 500)
144
+ r.status.should.equal 500
145
+
146
+ r = Rack::Response.new([], "200 OK")
147
+ r.status.should.equal 200
148
+ end
149
+
150
+ it "has a constructor that can take a block" do
151
+ r = Rack::Response.new { |res|
152
+ res.status = 404
153
+ res.write "foo"
154
+ }
155
+ status, _, body = r.finish
156
+ str = ""; body.each { |part| str << part }
157
+ str.should.equal "foo"
158
+ status.should.equal 404
159
+ end
160
+
161
+ it "doesn't return invalid responses" do
162
+ r = Rack::Response.new(["foo", "bar"], 204)
163
+ _, header, body = r.finish
164
+ str = ""; body.each { |part| str << part }
165
+ str.should.be.empty
166
+ header["Content-Type"].should.equal nil
167
+
168
+ lambda {
169
+ Rack::Response.new(Object.new)
170
+ }.should.raise(TypeError).
171
+ message.should =~ /stringable or iterable required/
172
+ end
173
+
174
+ it "knows if it's empty" do
175
+ r = Rack::Response.new
176
+ r.should.be.empty
177
+ r.write "foo"
178
+ r.should.not.be.empty
179
+
180
+ r = Rack::Response.new
181
+ r.should.be.empty
182
+ r.finish
183
+ r.should.be.empty
184
+
185
+ r = Rack::Response.new
186
+ r.should.be.empty
187
+ r.finish { }
188
+ r.should.not.be.empty
189
+ end
190
+
191
+ should "provide access to the HTTP status" do
192
+ res = Rack::Response.new
193
+ res.status = 200
194
+ res.should.be.successful
195
+ res.should.be.ok
196
+
197
+ res.status = 404
198
+ res.should.not.be.successful
199
+ res.should.be.client_error
200
+ res.should.be.not_found
201
+
202
+ res.status = 501
203
+ res.should.not.be.successful
204
+ res.should.be.server_error
205
+
206
+ res.status = 307
207
+ res.should.be.redirect
208
+ end
209
+
210
+ should "provide access to the HTTP headers" do
211
+ res = Rack::Response.new
212
+ res["Content-Type"] = "text/yaml"
213
+
214
+ res.should.include "Content-Type"
215
+ res.headers["Content-Type"].should.equal "text/yaml"
216
+ res["Content-Type"].should.equal "text/yaml"
217
+ res.content_type.should.equal "text/yaml"
218
+ res.content_length.should.be.nil
219
+ res.location.should.be.nil
220
+ end
221
+
222
+ it "does not add or change Content-Length when #finish()ing" do
223
+ res = Rack::Response.new
224
+ res.status = 200
225
+ res.finish
226
+ res.headers["Content-Length"].should.be.nil
227
+
228
+ res = Rack::Response.new
229
+ res.status = 200
230
+ res.headers["Content-Length"] = "10"
231
+ res.finish
232
+ res.headers["Content-Length"].should.equal "10"
233
+ end
234
+
235
+ it "updates Content-Length when body appended to using #write" do
236
+ res = Rack::Response.new
237
+ res.status = 200
238
+ res.headers["Content-Length"].should.be.nil
239
+ res.write "Hi"
240
+ res.headers["Content-Length"].should.equal "2"
241
+ res.write " there"
242
+ res.headers["Content-Length"].should.equal "8"
243
+ end
244
+
245
+ end
@@ -0,0 +1,118 @@
1
+ require 'stringio'
2
+ require 'rack/rewindable_input'
3
+
4
+ shared "a rewindable IO object" do
5
+ before do
6
+ @rio = Rack::RewindableInput.new(@io)
7
+ end
8
+
9
+ should "be able to handle to read()" do
10
+ @rio.read.should.equal "hello world"
11
+ end
12
+
13
+ should "be able to handle to read(nil)" do
14
+ @rio.read(nil).should.equal "hello world"
15
+ end
16
+
17
+ should "be able to handle to read(length)" do
18
+ @rio.read(1).should.equal "h"
19
+ end
20
+
21
+ should "be able to handle to read(length, buffer)" do
22
+ buffer = ""
23
+ result = @rio.read(1, buffer)
24
+ result.should.equal "h"
25
+ result.object_id.should.equal buffer.object_id
26
+ end
27
+
28
+ should "be able to handle to read(nil, buffer)" do
29
+ buffer = ""
30
+ result = @rio.read(nil, buffer)
31
+ result.should.equal "hello world"
32
+ result.object_id.should.equal buffer.object_id
33
+ end
34
+
35
+ should "rewind to the beginning when #rewind is called" do
36
+ @rio.read(1)
37
+ @rio.rewind
38
+ @rio.read.should.equal "hello world"
39
+ end
40
+
41
+ should "be able to handle gets" do
42
+ @rio.gets.should == "hello world"
43
+ end
44
+
45
+ should "be able to handle each" do
46
+ array = []
47
+ @rio.each do |data|
48
+ array << data
49
+ end
50
+ array.should.equal(["hello world"])
51
+ end
52
+
53
+ should "not buffer into a Tempfile if no data has been read yet" do
54
+ @rio.instance_variable_get(:@rewindable_io).should.be.nil
55
+ end
56
+
57
+ should "buffer into a Tempfile when data has been consumed for the first time" do
58
+ @rio.read(1)
59
+ tempfile = @rio.instance_variable_get(:@rewindable_io)
60
+ tempfile.should.not.be.nil
61
+ @rio.read(1)
62
+ tempfile2 = @rio.instance_variable_get(:@rewindable_io)
63
+ tempfile2.path.should == tempfile.path
64
+ end
65
+
66
+ should "close the underlying tempfile upon calling #close" do
67
+ @rio.read(1)
68
+ tempfile = @rio.instance_variable_get(:@rewindable_io)
69
+ @rio.close
70
+ tempfile.should.be.closed
71
+ end
72
+
73
+ should "be possible to call #close when no data has been buffered yet" do
74
+ lambda{ @rio.close }.should.not.raise
75
+ end
76
+
77
+ should "be possible to call #close multiple times" do
78
+ lambda{
79
+ @rio.close
80
+ @rio.close
81
+ }.should.not.raise
82
+ end
83
+
84
+ @rio.close
85
+ @rio = nil
86
+ end
87
+
88
+ describe Rack::RewindableInput do
89
+ describe "given an IO object that is already rewindable" do
90
+ before do
91
+ @io = StringIO.new("hello world")
92
+ end
93
+
94
+ behaves_like "a rewindable IO object"
95
+ end
96
+
97
+ describe "given an IO object that is not rewindable" do
98
+ before do
99
+ @io = StringIO.new("hello world")
100
+ @io.instance_eval do
101
+ undef :rewind
102
+ end
103
+ end
104
+
105
+ behaves_like "a rewindable IO object"
106
+ end
107
+
108
+ describe "given an IO object whose rewind method raises Errno::ESPIPE" do
109
+ before 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
+ behaves_like "a rewindable IO object"
117
+ end
118
+ end
@@ -0,0 +1,39 @@
1
+ require 'rack/runtime'
2
+
3
+ describe Rack::Runtime do
4
+ it "sets X-Runtime is none is set" do
5
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
6
+ response = Rack::Runtime.new(app).call({})
7
+ response[1]['X-Runtime'].should =~ /[\d\.]+/
8
+ end
9
+
10
+ it "doesn't set the X-Runtime if it is already set" do
11
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
12
+ response = Rack::Runtime.new(app).call({})
13
+ response[1]['X-Runtime'].should == "foobar"
14
+ end
15
+
16
+ should "allow a suffix to be set" do
17
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
18
+ response = Rack::Runtime.new(app, "Test").call({})
19
+ response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
20
+ end
21
+
22
+ should "allow multiple timers to be set" do
23
+ app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
24
+ runtime = Rack::Runtime.new(app, "App")
25
+
26
+ # wrap many times to guarantee a measurable difference
27
+ 100.times do |i|
28
+ runtime = Rack::Runtime.new(runtime, i.to_s)
29
+ end
30
+ runtime = Rack::Runtime.new(runtime, "All")
31
+
32
+ response = runtime.call({})
33
+
34
+ response[1]['X-Runtime-App'].should =~ /[\d\.]+/
35
+ response[1]['X-Runtime-All'].should =~ /[\d\.]+/
36
+
37
+ Float(response[1]['X-Runtime-All']).should > Float(response[1]['X-Runtime-App'])
38
+ end
39
+ end
@@ -0,0 +1,83 @@
1
+ require 'rack/sendfile'
2
+ require 'rack/mock'
3
+
4
+ describe Rack::File do
5
+ should "respond to #to_path" do
6
+ Rack::File.new(Dir.pwd).should.respond_to :to_path
7
+ end
8
+ end
9
+
10
+ describe Rack::Sendfile do
11
+ def sendfile_body
12
+ res = ['Hello World']
13
+ def res.to_path ; "/tmp/hello.txt" ; end
14
+ res
15
+ end
16
+
17
+ def simple_app(body=sendfile_body)
18
+ lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
19
+ end
20
+
21
+ def sendfile_app(body=sendfile_body)
22
+ Rack::Sendfile.new(simple_app(body))
23
+ end
24
+
25
+ @request = Rack::MockRequest.new(sendfile_app)
26
+
27
+ def request(headers={})
28
+ yield @request.get('/', headers)
29
+ end
30
+
31
+ it "does nothing when no X-Sendfile-Type header present" do
32
+ request do |response|
33
+ response.should.be.ok
34
+ response.body.should.equal 'Hello World'
35
+ response.headers.should.not.include 'X-Sendfile'
36
+ end
37
+ end
38
+
39
+ it "sets X-Sendfile response header and discards body" do
40
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
41
+ response.should.be.ok
42
+ response.body.should.be.empty
43
+ response.headers['X-Sendfile'].should.equal '/tmp/hello.txt'
44
+ end
45
+ end
46
+
47
+ it "sets X-Lighttpd-Send-File response header and discards body" do
48
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
49
+ response.should.be.ok
50
+ response.body.should.be.empty
51
+ response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt'
52
+ end
53
+ end
54
+
55
+ it "sets X-Accel-Redirect response header and discards body" do
56
+ headers = {
57
+ 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
58
+ 'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
59
+ }
60
+ request headers do |response|
61
+ response.should.be.ok
62
+ response.body.should.be.empty
63
+ response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt'
64
+ end
65
+ end
66
+
67
+ it 'writes to rack.error when no X-Accel-Mapping is specified' do
68
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
69
+ response.should.be.ok
70
+ response.body.should.equal 'Hello World'
71
+ response.headers.should.not.include 'X-Accel-Redirect'
72
+ response.errors.should.include 'X-Accel-Mapping'
73
+ end
74
+ end
75
+
76
+ it 'does nothing when body does not respond to #to_path' do
77
+ @request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
78
+ request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
79
+ response.body.should.equal 'Not a file...'
80
+ response.headers.should.not.include 'X-Sendfile'
81
+ end
82
+ end
83
+ end