corntrace-rack-contrib 1.0.2
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.
- data/AUTHORS +26 -0
- data/COPYING +18 -0
- data/README.rdoc +87 -0
- data/Rakefile +89 -0
- data/lib/rack/contrib/accept_format.rb +46 -0
- data/lib/rack/contrib/access.rb +85 -0
- data/lib/rack/contrib/backstage.rb +20 -0
- data/lib/rack/contrib/bounce_favicon.rb +16 -0
- data/lib/rack/contrib/callbacks.rb +37 -0
- data/lib/rack/contrib/config.rb +16 -0
- data/lib/rack/contrib/cookies.rb +50 -0
- data/lib/rack/contrib/csshttprequest.rb +39 -0
- data/lib/rack/contrib/deflect.rb +137 -0
- data/lib/rack/contrib/evil.rb +12 -0
- data/lib/rack/contrib/expectation_cascade.rb +32 -0
- data/lib/rack/contrib/garbagecollector.rb +14 -0
- data/lib/rack/contrib/host_meta.rb +47 -0
- data/lib/rack/contrib/jsonp.rb +78 -0
- data/lib/rack/contrib/lighttpd_script_name_fix.rb +16 -0
- data/lib/rack/contrib/locale.rb +31 -0
- data/lib/rack/contrib/mailexceptions.rb +120 -0
- data/lib/rack/contrib/nested_params.rb +143 -0
- data/lib/rack/contrib/not_found.rb +18 -0
- data/lib/rack/contrib/post_body_content_type_parser.rb +40 -0
- data/lib/rack/contrib/proctitle.rb +30 -0
- data/lib/rack/contrib/profiler.rb +108 -0
- data/lib/rack/contrib/relative_redirect.rb +44 -0
- data/lib/rack/contrib/response_cache.rb +59 -0
- data/lib/rack/contrib/response_headers.rb +24 -0
- data/lib/rack/contrib/route_exceptions.rb +49 -0
- data/lib/rack/contrib/runtime.rb +31 -0
- data/lib/rack/contrib/sendfile.rb +142 -0
- data/lib/rack/contrib/signals.rb +63 -0
- data/lib/rack/contrib/simple_endpoint.rb +81 -0
- data/lib/rack/contrib/static_cache.rb +93 -0
- data/lib/rack/contrib/time_zone.rb +25 -0
- data/lib/rack/contrib.rb +39 -0
- data/rack-contrib.gemspec +104 -0
- data/test/404.html +1 -0
- data/test/Maintenance.html +1 -0
- data/test/documents/test +1 -0
- data/test/mail_settings.rb +12 -0
- data/test/spec_rack_accept_format.rb +72 -0
- data/test/spec_rack_access.rb +154 -0
- data/test/spec_rack_backstage.rb +26 -0
- data/test/spec_rack_callbacks.rb +65 -0
- data/test/spec_rack_config.rb +22 -0
- data/test/spec_rack_contrib.rb +8 -0
- data/test/spec_rack_cookies.rb +56 -0
- data/test/spec_rack_csshttprequest.rb +66 -0
- data/test/spec_rack_deflect.rb +107 -0
- data/test/spec_rack_evil.rb +19 -0
- data/test/spec_rack_expectation_cascade.rb +72 -0
- data/test/spec_rack_garbagecollector.rb +13 -0
- data/test/spec_rack_host_meta.rb +50 -0
- data/test/spec_rack_jsonp.rb +83 -0
- data/test/spec_rack_lighttpd_script_name_fix.rb +16 -0
- data/test/spec_rack_mailexceptions.rb +97 -0
- data/test/spec_rack_nested_params.rb +46 -0
- data/test/spec_rack_not_found.rb +17 -0
- data/test/spec_rack_post_body_content_type_parser.rb +32 -0
- data/test/spec_rack_proctitle.rb +26 -0
- data/test/spec_rack_profiler.rb +37 -0
- data/test/spec_rack_relative_redirect.rb +78 -0
- data/test/spec_rack_response_cache.rb +137 -0
- data/test/spec_rack_response_headers.rb +35 -0
- data/test/spec_rack_runtime.rb +35 -0
- data/test/spec_rack_sendfile.rb +86 -0
- data/test/spec_rack_simple_endpoint.rb +95 -0
- data/test/spec_rack_static_cache.rb +91 -0
- data/test/statics/test +1 -0
- metadata +234 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack/mock'
|
3
|
+
require 'rack/contrib/relative_redirect'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
context Rack::RelativeRedirect do
|
7
|
+
def request(opts={}, &block)
|
8
|
+
@def_status = opts[:status] if opts[:status]
|
9
|
+
@def_location = opts[:location] if opts[:location]
|
10
|
+
yield Rack::MockRequest.new(Rack::RelativeRedirect.new(@def_app, &opts[:block])).get(opts[:path]||@def_path, opts[:headers]||{})
|
11
|
+
end
|
12
|
+
|
13
|
+
setup do
|
14
|
+
@def_path = '/path/to/blah'
|
15
|
+
@def_status = 301
|
16
|
+
@def_location = '/redirect/to/blah'
|
17
|
+
@def_app = lambda { |env| [@def_status, {'Location' => @def_location}, [""]]}
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should make the location url an absolute url if currently a relative url" do
|
21
|
+
request do |r|
|
22
|
+
r.status.should.equal(301)
|
23
|
+
r.headers['Location'].should.equal('http://example.org/redirect/to/blah')
|
24
|
+
end
|
25
|
+
request(:status=>302, :location=>'/redirect') do |r|
|
26
|
+
r.status.should.equal(302)
|
27
|
+
r.headers['Location'].should.equal('http://example.org/redirect')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should use the request path if the relative url is given and doesn't start with a slash" do
|
32
|
+
request(:status=>303, :location=>'redirect/to/blah') do |r|
|
33
|
+
r.status.should.equal(303)
|
34
|
+
r.headers['Location'].should.equal('http://example.org/path/to/redirect/to/blah')
|
35
|
+
end
|
36
|
+
request(:status=>303, :location=>'redirect') do |r|
|
37
|
+
r.status.should.equal(303)
|
38
|
+
r.headers['Location'].should.equal('http://example.org/path/to/redirect')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should use a given block to make the url absolute" do
|
43
|
+
request(:block=>proc{|env, res| "https://example.org"}) do |r|
|
44
|
+
r.status.should.equal(301)
|
45
|
+
r.headers['Location'].should.equal('https://example.org/redirect/to/blah')
|
46
|
+
end
|
47
|
+
request(:status=>303, :location=>'/redirect', :block=>proc{|env, res| "https://e.org:9999/blah"}) do |r|
|
48
|
+
r.status.should.equal(303)
|
49
|
+
r.headers['Location'].should.equal('https://e.org:9999/blah/redirect')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "should not modify the location url unless the response is a redirect" do
|
54
|
+
status = 200
|
55
|
+
@def_app = lambda { |env| [status, {'Content-Type' => "text/html"}, [""]]}
|
56
|
+
request do |r|
|
57
|
+
r.status.should.equal(200)
|
58
|
+
r.headers.should.not.include?('Location')
|
59
|
+
end
|
60
|
+
status = 404
|
61
|
+
@def_app = lambda { |env| [status, {'Content-Type' => "text/html", 'Location' => 'redirect'}, [""]]}
|
62
|
+
request do |r|
|
63
|
+
r.status.should.equal(404)
|
64
|
+
r.headers['Location'].should.equal('redirect')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "should not modify the location url if it is already an absolute url" do
|
69
|
+
request(:location=>'https://example.org/') do |r|
|
70
|
+
r.status.should.equal(301)
|
71
|
+
r.headers['Location'].should.equal('https://example.org/')
|
72
|
+
end
|
73
|
+
request(:status=>302, :location=>'https://e.org:9999/redirect') do |r|
|
74
|
+
r.status.should.equal(302)
|
75
|
+
r.headers['Location'].should.equal('https://e.org:9999/redirect')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack/mock'
|
3
|
+
require 'rack/contrib/response_cache'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
context Rack::ResponseCache do
|
7
|
+
F = ::File
|
8
|
+
|
9
|
+
def request(opts={}, &block)
|
10
|
+
Rack::MockRequest.new(Rack::ResponseCache.new(block||@def_app, opts[:cache]||@cache, &opts[:rc_block])).send(opts[:meth]||:get, opts[:path]||@def_path, opts[:headers]||{})
|
11
|
+
end
|
12
|
+
|
13
|
+
setup do
|
14
|
+
@cache = {}
|
15
|
+
@def_disk_cache = F.join(F.dirname(__FILE__), 'response_cache_test_disk_cache')
|
16
|
+
@def_value = ["rack-response-cache"]
|
17
|
+
@def_path = '/path/to/blah'
|
18
|
+
@def_app = lambda { |env| [200, {'Content-Type' => env['CT'] || 'text/html'}, @def_value]}
|
19
|
+
end
|
20
|
+
teardown do
|
21
|
+
FileUtils.rm_rf(@def_disk_cache)
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "should cache results to disk if cache is a string" do
|
25
|
+
request(:cache=>@def_disk_cache)
|
26
|
+
F.read(F.join(@def_disk_cache, 'path', 'to', 'blah.html')).should.equal @def_value.first
|
27
|
+
request(:path=>'/path/3', :cache=>@def_disk_cache)
|
28
|
+
F.read(F.join(@def_disk_cache, 'path', '3.html')).should.equal @def_value.first
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should cache results to given cache if cache is not a string" do
|
32
|
+
request
|
33
|
+
@cache.should.equal('/path/to/blah.html'=>@def_value)
|
34
|
+
request(:path=>'/path/3')
|
35
|
+
@cache.should.equal('/path/to/blah.html'=>@def_value, '/path/3.html'=>@def_value)
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should not CACHE RESults if request method is not GET" do
|
39
|
+
request(:meth=>:post)
|
40
|
+
@cache.should.equal({})
|
41
|
+
request(:meth=>:put)
|
42
|
+
@cache.should.equal({})
|
43
|
+
request(:meth=>:delete)
|
44
|
+
@cache.should.equal({})
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should not cache results if there is a query string" do
|
48
|
+
request(:path=>'/path/to/blah?id=1')
|
49
|
+
@cache.should.equal({})
|
50
|
+
request(:path=>'/path/to/?id=1')
|
51
|
+
@cache.should.equal({})
|
52
|
+
request(:path=>'/?id=1')
|
53
|
+
@cache.should.equal({})
|
54
|
+
end
|
55
|
+
|
56
|
+
specify "should cache results if there is an empty query string" do
|
57
|
+
request(:path=>'/?')
|
58
|
+
@cache.should.equal('/index.html'=>@def_value)
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "should not cache results if the request is not sucessful (status 200)" do
|
62
|
+
request{|env| [404, {'Content-Type' => 'text/html'}, ['']]}
|
63
|
+
@cache.should.equal({})
|
64
|
+
request{|env| [500, {'Content-Type' => 'text/html'}, ['']]}
|
65
|
+
@cache.should.equal({})
|
66
|
+
request{|env| [302, {'Content-Type' => 'text/html'}, ['']]}
|
67
|
+
@cache.should.equal({})
|
68
|
+
end
|
69
|
+
|
70
|
+
specify "should not cache results if the block returns nil or false" do
|
71
|
+
request(:rc_block=>proc{false})
|
72
|
+
@cache.should.equal({})
|
73
|
+
request(:rc_block=>proc{nil})
|
74
|
+
@cache.should.equal({})
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should cache results to path returned by block" do
|
78
|
+
request(:rc_block=>proc{"1"})
|
79
|
+
@cache.should.equal("1"=>@def_value)
|
80
|
+
request(:rc_block=>proc{"2"})
|
81
|
+
@cache.should.equal("1"=>@def_value, "2"=>@def_value)
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should pass the environment and response to the block" do
|
85
|
+
e, r = nil, nil
|
86
|
+
request(:rc_block=>proc{|env,res| e, r = env, res; nil})
|
87
|
+
e['PATH_INFO'].should.equal @def_path
|
88
|
+
e['REQUEST_METHOD'].should.equal 'GET'
|
89
|
+
e['QUERY_STRING'].should.equal ''
|
90
|
+
r.should.equal([200, {"Content-Type"=>"text/html"}, ["rack-response-cache"]])
|
91
|
+
end
|
92
|
+
|
93
|
+
specify "should unescape the path by default" do
|
94
|
+
request(:path=>'/path%20with%20spaces')
|
95
|
+
@cache.should.equal('/path with spaces.html'=>@def_value)
|
96
|
+
request(:path=>'/path%3chref%3e')
|
97
|
+
@cache.should.equal('/path with spaces.html'=>@def_value, '/path<href>.html'=>@def_value)
|
98
|
+
end
|
99
|
+
|
100
|
+
specify "should cache html, css, and xml responses by default" do
|
101
|
+
request(:path=>'/a')
|
102
|
+
@cache.should.equal('/a.html'=>@def_value)
|
103
|
+
request(:path=>'/b', :headers=>{'CT'=>'text/xml'})
|
104
|
+
@cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value)
|
105
|
+
request(:path=>'/c', :headers=>{'CT'=>'text/css'})
|
106
|
+
@cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value, '/c.css'=>@def_value)
|
107
|
+
end
|
108
|
+
|
109
|
+
specify "should cache responses by default with the extension added if not already present" do
|
110
|
+
request(:path=>'/a.html')
|
111
|
+
@cache.should.equal('/a.html'=>@def_value)
|
112
|
+
request(:path=>'/b.xml', :headers=>{'CT'=>'text/xml'})
|
113
|
+
@cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value)
|
114
|
+
request(:path=>'/c.css', :headers=>{'CT'=>'text/css'})
|
115
|
+
@cache.should.equal('/a.html'=>@def_value, '/b.xml'=>@def_value, '/c.css'=>@def_value)
|
116
|
+
end
|
117
|
+
|
118
|
+
specify "should not delete existing extensions" do
|
119
|
+
request(:path=>'/d.css', :headers=>{'CT'=>'text/html'})
|
120
|
+
@cache.should.equal('/d.css.html'=>@def_value)
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should cache html responses with empty basename to index.html by default" do
|
124
|
+
request(:path=>'/')
|
125
|
+
@cache.should.equal('/index.html'=>@def_value)
|
126
|
+
request(:path=>'/blah/')
|
127
|
+
@cache.should.equal('/index.html'=>@def_value, '/blah/index.html'=>@def_value)
|
128
|
+
request(:path=>'/blah/2/')
|
129
|
+
@cache.should.equal('/index.html'=>@def_value, '/blah/index.html'=>@def_value, '/blah/2/index.html'=>@def_value)
|
130
|
+
end
|
131
|
+
|
132
|
+
specify "should raise an error if a cache argument is not provided" do
|
133
|
+
app = Rack::Builder.new{use Rack::ResponseCache; run lambda { |env| [200, {'Content-Type' => 'text/plain'}, Rack::Request.new(env).POST]}}
|
134
|
+
proc{Rack::MockRequest.new(app).get('/')}.should.raise(ArgumentError)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack'
|
3
|
+
require 'rack/contrib/response_headers'
|
4
|
+
|
5
|
+
context "Rack::ResponseHeaders" do
|
6
|
+
|
7
|
+
specify "yields a HeaderHash of response headers" do
|
8
|
+
orig_headers = {'X-Foo' => 'foo', 'X-Bar' => 'bar'}
|
9
|
+
app = Proc.new {[200, orig_headers, []]}
|
10
|
+
middleware = Rack::ResponseHeaders.new(app) do |headers|
|
11
|
+
assert_instance_of Rack::Utils::HeaderHash, headers
|
12
|
+
orig_headers.should == headers
|
13
|
+
end
|
14
|
+
middleware.call({})
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "allows adding headers" do
|
18
|
+
app = Proc.new {[200, {'X-Foo' => 'foo'}, []]}
|
19
|
+
middleware = Rack::ResponseHeaders.new(app) do |headers|
|
20
|
+
headers['X-Bar'] = 'bar'
|
21
|
+
end
|
22
|
+
r = middleware.call({})
|
23
|
+
r[1].should == {'X-Foo' => 'foo', 'X-Bar' => 'bar'}
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "allows deleting headers" do
|
27
|
+
app = Proc.new {[200, {'X-Foo' => 'foo', 'X-Bar' => 'bar'}, []]}
|
28
|
+
middleware = Rack::ResponseHeaders.new(app) do |headers|
|
29
|
+
headers.delete('X-Bar')
|
30
|
+
end
|
31
|
+
r = middleware.call({})
|
32
|
+
r[1].should == {'X-Foo' => 'foo'}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack/mock'
|
3
|
+
require 'rack/contrib/runtime'
|
4
|
+
|
5
|
+
context "Rack::Runtime" do
|
6
|
+
specify "sets X-Runtime is none is set" do
|
7
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
8
|
+
response = Rack::Runtime.new(app).call({})
|
9
|
+
response[1]['X-Runtime'].should =~ /[\d\.]+/
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "does not set the X-Runtime if it is already set" do
|
13
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
14
|
+
response = Rack::Runtime.new(app).call({})
|
15
|
+
response[1]['X-Runtime'].should == "foobar"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "should allow a suffix to be set" do
|
19
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
20
|
+
response = Rack::Runtime.new(app, "Test").call({})
|
21
|
+
response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "should allow multiple timers to be set" do
|
25
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
26
|
+
runtime1 = Rack::Runtime.new(app, "App")
|
27
|
+
runtime2 = Rack::Runtime.new(runtime1, "All")
|
28
|
+
response = runtime2.call({})
|
29
|
+
|
30
|
+
response[1]['X-Runtime-App'].should =~ /[\d\.]+/
|
31
|
+
response[1]['X-Runtime-All'].should =~ /[\d\.]+/
|
32
|
+
|
33
|
+
Float(response[1]['X-Runtime-All']).should > Float(response[1]['X-Runtime-App'])
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack/mock'
|
3
|
+
require 'rack/contrib/sendfile'
|
4
|
+
|
5
|
+
context "Rack::File" do
|
6
|
+
specify "should respond to #to_path" do
|
7
|
+
Rack::File.new(Dir.pwd).should.respond_to :to_path
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "Rack::Sendfile" do
|
12
|
+
def sendfile_body
|
13
|
+
res = ['Hello World']
|
14
|
+
def res.to_path ; "/tmp/hello.txt" ; end
|
15
|
+
res
|
16
|
+
end
|
17
|
+
|
18
|
+
def simple_app(body=sendfile_body)
|
19
|
+
lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
20
|
+
end
|
21
|
+
|
22
|
+
def sendfile_app(body=sendfile_body)
|
23
|
+
Rack::Sendfile.new(simple_app(body))
|
24
|
+
end
|
25
|
+
|
26
|
+
setup do
|
27
|
+
@request = Rack::MockRequest.new(sendfile_app)
|
28
|
+
end
|
29
|
+
|
30
|
+
def request(headers={})
|
31
|
+
yield @request.get('/', headers)
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "does nothing when no X-Sendfile-Type header present" do
|
35
|
+
request do |response|
|
36
|
+
response.should.be.ok
|
37
|
+
response.body.should.equal 'Hello World'
|
38
|
+
response.headers.should.not.include 'X-Sendfile'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "sets X-Sendfile response header and discards body" do
|
43
|
+
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
44
|
+
response.should.be.ok
|
45
|
+
response.body.should.be.empty
|
46
|
+
response.headers['X-Sendfile'].should.equal '/tmp/hello.txt'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "sets X-Lighttpd-Send-File response header and discards body" do
|
51
|
+
request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
|
52
|
+
response.should.be.ok
|
53
|
+
response.body.should.be.empty
|
54
|
+
response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
specify "sets X-Accel-Redirect response header and discards body" do
|
59
|
+
headers = {
|
60
|
+
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
|
61
|
+
'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
|
62
|
+
}
|
63
|
+
request headers do |response|
|
64
|
+
response.should.be.ok
|
65
|
+
response.body.should.be.empty
|
66
|
+
response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
specify 'writes to rack.error when no X-Accel-Mapping is specified' do
|
71
|
+
request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
|
72
|
+
response.should.be.ok
|
73
|
+
response.body.should.equal 'Hello World'
|
74
|
+
response.headers.should.not.include 'X-Accel-Redirect'
|
75
|
+
response.errors.should.include 'X-Accel-Mapping'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
specify 'does nothing when body does not respond to #to_path' do
|
80
|
+
@request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
|
81
|
+
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
82
|
+
response.body.should.equal 'Not a file...'
|
83
|
+
response.headers.should.not.include 'X-Sendfile'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'rack'
|
3
|
+
require 'rack/contrib/simple_endpoint'
|
4
|
+
|
5
|
+
context "Rack::SimpleEndpoint" do
|
6
|
+
setup do
|
7
|
+
@app = Proc.new { Rack::Response.new {|r| r.write "Downstream app"}.finish }
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "calls downstream app when no match" do
|
11
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { 'bar' }
|
12
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/baz'))
|
13
|
+
status.should == 200
|
14
|
+
body.body.should == ['Downstream app']
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "calls downstream app when path matches but method does not" do
|
18
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => :get) { 'bar' }
|
19
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo', :method => 'post'))
|
20
|
+
status.should == 200
|
21
|
+
body.body.should == ['Downstream app']
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "calls downstream app when path matches but block returns :pass" do
|
25
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { :pass }
|
26
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
|
27
|
+
status.should == 200
|
28
|
+
body.body.should == ['Downstream app']
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "returns endpoint response when path matches" do
|
32
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') { 'bar' }
|
33
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
|
34
|
+
status.should == 200
|
35
|
+
body.body.should == ['bar']
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "returns endpoint response when path and single method requirement match" do
|
39
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => :get) { 'bar' }
|
40
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
|
41
|
+
status.should == 200
|
42
|
+
body.body.should == ['bar']
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "returns endpoint response when path and one of multiple method requirements match" do
|
46
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo' => [:get, :post]) { 'bar' }
|
47
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo', :method => 'post'))
|
48
|
+
status.should == 200
|
49
|
+
body.body.should == ['bar']
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "returns endpoint response when path matches regex" do
|
53
|
+
endpoint = Rack::SimpleEndpoint.new(@app, /foo/) { 'bar' }
|
54
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/bar/foo'))
|
55
|
+
status.should == 200
|
56
|
+
body.body.should == ['bar']
|
57
|
+
end
|
58
|
+
|
59
|
+
specify "block yields Rack::Request and Rack::Response objects" do
|
60
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') do |req, res|
|
61
|
+
assert_instance_of ::Rack::Request, req
|
62
|
+
assert_instance_of ::Rack::Response, res
|
63
|
+
end
|
64
|
+
endpoint.call(Rack::MockRequest.env_for('/foo'))
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "block yields MatchData object when Regex path matcher specified" do
|
68
|
+
endpoint = Rack::SimpleEndpoint.new(@app, /foo(.+)/) do |req, res, match|
|
69
|
+
assert_instance_of MatchData, match
|
70
|
+
assert_equal 'bar', match[1]
|
71
|
+
end
|
72
|
+
endpoint.call(Rack::MockRequest.env_for('/foobar'))
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "block does NOT yield MatchData object when String path matcher specified" do
|
76
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') do |req, res, match|
|
77
|
+
assert_nil match
|
78
|
+
end
|
79
|
+
endpoint.call(Rack::MockRequest.env_for('/foo'))
|
80
|
+
end
|
81
|
+
|
82
|
+
specify "response honors headers set in block" do
|
83
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') {|req, res| res['X-Foo'] = 'bar'; 'baz' }
|
84
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
|
85
|
+
status.should == 200
|
86
|
+
headers['X-Foo'].should == 'bar'
|
87
|
+
body.body.should == ['baz']
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "sets Content-Length header" do
|
91
|
+
endpoint = Rack::SimpleEndpoint.new(@app, '/foo') {|req, res| 'bar' }
|
92
|
+
status, headers, body = endpoint.call(Rack::MockRequest.env_for('/foo'))
|
93
|
+
headers['Content-Length'].should == '3'
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/contrib/static_cache'
|
5
|
+
require 'rack/mock'
|
6
|
+
|
7
|
+
class DummyApp
|
8
|
+
def call(env)
|
9
|
+
[200, {}, ["Hello World"]]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Rack::StaticCache" do
|
14
|
+
|
15
|
+
setup do
|
16
|
+
@root = ::File.expand_path(::File.dirname(__FILE__))
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should serve files with required headers" do
|
20
|
+
default_app_request
|
21
|
+
res = @request.get("/statics/test")
|
22
|
+
res.should.be.ok
|
23
|
+
res.body.should =~ /rubyrack/
|
24
|
+
res.headers['Cache-Control'].should == 'max-age=31536000, public'
|
25
|
+
next_year = Time.now().year + 1
|
26
|
+
res.headers['Expires'].should =~ Regexp.new(
|
27
|
+
"[A-Z][a-z]{2}[,][\s][0-9]{2}[\s][A-Z][a-z]{2}[\s]" << "#{next_year}" <<
|
28
|
+
"[\s][0-9]{2}[:][0-9]{2}[:][0-9]{2} GMT$")
|
29
|
+
res.headers.has_key?('Etag').should == false
|
30
|
+
res.headers.has_key?('Pragma').should == false
|
31
|
+
res.headers.has_key?('Last-Modified').should == false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return 404s if url root is known but it can't find the file" do
|
35
|
+
default_app_request
|
36
|
+
res = @request.get("/statics/foo")
|
37
|
+
res.should.be.not_found
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should call down the chain if url root is not known" do
|
41
|
+
default_app_request
|
42
|
+
res = @request.get("/something/else")
|
43
|
+
res.should.be.ok
|
44
|
+
res.body.should == "Hello World"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should serve files if requested with version number and versioning is enabled" do
|
48
|
+
default_app_request
|
49
|
+
res = @request.get("/statics/test-0.0.1")
|
50
|
+
res.should.be.ok
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should change cache duration if specified thorugh option" do
|
54
|
+
configured_app_request
|
55
|
+
res = @request.get("/statics/test")
|
56
|
+
res.should.be.ok
|
57
|
+
res.body.should =~ /rubyrack/
|
58
|
+
next_next_year = Time.now().year + 2
|
59
|
+
res.headers['Expires'].should =~ Regexp.new("#{next_next_year}")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return 404s if requested with version number but versioning is disabled" do
|
63
|
+
configured_app_request
|
64
|
+
res = @request.get("/statics/test-0.0.1")
|
65
|
+
res.should.be.not_found
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should serve files with plain headers when * is added to the directory name" do
|
69
|
+
configured_app_request
|
70
|
+
res = @request.get("/documents/test")
|
71
|
+
res.should.be.ok
|
72
|
+
res.body.should =~ /nocache/
|
73
|
+
next_next_year = Time.now().year + 2
|
74
|
+
res.headers['Expires'].should.not =~ Regexp.new("#{next_next_year}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_app_request
|
78
|
+
@options = {:urls => ["/statics"], :root => @root}
|
79
|
+
request
|
80
|
+
end
|
81
|
+
|
82
|
+
def configured_app_request
|
83
|
+
@options = {:urls => ["/statics", "/documents*"], :root => @root, :versioning => false, :duration => 2}
|
84
|
+
request
|
85
|
+
end
|
86
|
+
|
87
|
+
def request
|
88
|
+
@request = Rack::MockRequest.new(Rack::StaticCache.new(DummyApp.new, @options))
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/test/statics/test
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rubyrack
|