tricycle-rack-contrib 0.9.5 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -3
- data/lib/rack/contrib/response_cache.rb +26 -17
- data/test/spec_rack_response_cache.rb +64 -42
- data/tricycle-rack-contrib.gemspec +2 -2
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -50,11 +50,11 @@ interface:
|
|
50
50
|
|
51
51
|
Git is the quickest way to the rack-contrib sources:
|
52
52
|
|
53
|
-
git clone git://github.com/
|
53
|
+
git clone git://github.com/tricycle/rack-contrib.git
|
54
54
|
|
55
|
-
Gems are currently available from
|
55
|
+
Gems are currently available from Gemcutter:
|
56
56
|
|
57
|
-
gem install
|
57
|
+
gem install tricycle-rack-contrib --source=http://gemcutter.org/
|
58
58
|
|
59
59
|
Requiring 'rack/contrib' will add autoloads to the Rack modules for all of the
|
60
60
|
components included. The following example shows what a simple rackup
|
@@ -73,6 +73,7 @@ components included. The following example shows what a simple rackup
|
|
73
73
|
=== Links
|
74
74
|
|
75
75
|
rack-contrib on GitHub:: <http://github.com/rack/rack-contrib>
|
76
|
+
tricycle-rack-contrib on GitHub:: <http://github.com/tricycle/rack-contrib>
|
76
77
|
Rack:: <http://rack.rubyforge.org/>
|
77
78
|
Rack On GitHub:: <http://github.org/rack/rack>
|
78
79
|
rack-devel mailing list:: <http://groups.google.com/group/rack-devel>
|
@@ -7,6 +7,18 @@ require 'rack'
|
|
7
7
|
# Rails' page caching, allowing you to cache dynamic pages to static files that can
|
8
8
|
# be served directly by a front end webserver.
|
9
9
|
class Rack::ResponseCache
|
10
|
+
CONTENT_TYPES = {
|
11
|
+
"application/pdf" => %w[pdf],
|
12
|
+
"application/xhtml+xml" => %w[xhtml],
|
13
|
+
"text/css" => %w[css],
|
14
|
+
"text/csv" => %w[csv],
|
15
|
+
"text/html" => %w[html htm],
|
16
|
+
"text/javascript" => %w[js], "application/javascript" => %w[js],
|
17
|
+
"text/plain" => %w[txt],
|
18
|
+
"text/xml" => %w[xml],
|
19
|
+
}
|
20
|
+
ALLOWED_EXTENSIONS = CONTENT_TYPES.collect {|k, v| v }.flatten.uniq
|
21
|
+
|
10
22
|
# The default proc used if a block is not provided to .new
|
11
23
|
# Doesn't cache unless path does not contain '..', Content-Type is
|
12
24
|
# whitelisted, and path agrees with Content-Type
|
@@ -15,34 +27,31 @@ class Rack::ResponseCache
|
|
15
27
|
DEFAULT_PATH_PROC = proc do |env, res|
|
16
28
|
path = Rack::Utils.unescape(env['PATH_INFO'])
|
17
29
|
|
18
|
-
|
19
|
-
|
20
|
-
"application/xhtml+xml" => %w[xhtml],
|
21
|
-
"text/css" => %w[css],
|
22
|
-
"text/csv" => %w[csv],
|
23
|
-
"text/html" => %w[html htm],
|
24
|
-
"text/javascript" => %w[js], "application/javascript" => %w[js],
|
25
|
-
"text/plain" => %w[txt],
|
26
|
-
"text/xml" => %w[xml],
|
27
|
-
}
|
28
|
-
content_type = res[1]['Content-Type'].to_s
|
30
|
+
content_type = res[1]['Content-Type'].to_s.split(';').first
|
31
|
+
extension = File.extname(path)[1..-1]
|
29
32
|
|
30
|
-
if !path.include?('..') and
|
33
|
+
if !path.include?('..') and (allowed_extensions_for_content_type = CONTENT_TYPES[content_type])
|
31
34
|
# path doesn't include '..' and Content-Type is whitelisted
|
32
35
|
case
|
33
36
|
when path.match(/\/$/) && content_type == "text/html"
|
34
37
|
# path ends in / and Content-Type is text/html
|
35
38
|
path << "index.html"
|
36
|
-
when
|
37
|
-
#
|
38
|
-
path
|
39
|
-
when
|
40
|
-
|
39
|
+
when path.match(/\/$/) && content_type != "text/html"
|
40
|
+
# path ends in / and Content-Type is not text/html - don't cache
|
41
|
+
path = nil
|
42
|
+
when File.extname(path) == "" ||
|
43
|
+
(!ALLOWED_EXTENSIONS.include?(extension) && content_type == "text/html")
|
44
|
+
# no extension OR
|
45
|
+
# unrecognized extension AND content_type is text/html
|
46
|
+
path << ".#{allowed_extensions_for_content_type.first}"
|
47
|
+
when !allowed_extensions_for_content_type.include?(extension)
|
48
|
+
# extension doesn't agree with Content-Type (but extension is recognized) - don't cache
|
41
49
|
path = nil
|
42
50
|
else
|
43
51
|
# do nothing, path is alright
|
44
52
|
end
|
45
53
|
else
|
54
|
+
# don't cache
|
46
55
|
path = nil
|
47
56
|
end
|
48
57
|
|
@@ -23,40 +23,40 @@ context Rack::ResponseCache do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
specify "should cache results to disk if cache is a string" do
|
26
|
-
request(:cache
|
26
|
+
request(:cache => @def_disk_cache)
|
27
27
|
F.read(F.join(@def_disk_cache, 'path', 'to', 'blah.html')).should.equal @def_value.first
|
28
|
-
request(:path=>'/path/3', :cache
|
28
|
+
request(:path => '/path/3', :cache => @def_disk_cache)
|
29
29
|
F.read(F.join(@def_disk_cache, 'path', '3.html')).should.equal @def_value.first
|
30
30
|
end
|
31
31
|
|
32
32
|
specify "should cache results to given cache if cache is not a string" do
|
33
33
|
request
|
34
|
-
@cache.should.equal('/path/to/blah.html'
|
35
|
-
request(:path=>'/path/3')
|
36
|
-
@cache.should.equal('/path/to/blah.html'
|
34
|
+
@cache.should.equal('/path/to/blah.html' => @def_value)
|
35
|
+
request(:path => '/path/3')
|
36
|
+
@cache.should.equal('/path/to/blah.html' => @def_value, '/path/3.html' => @def_value)
|
37
37
|
end
|
38
38
|
|
39
39
|
specify "should not cache results if request method is not GET" do
|
40
|
-
request(:meth
|
40
|
+
request(:meth => :post)
|
41
41
|
@cache.should.equal({})
|
42
|
-
request(:meth
|
42
|
+
request(:meth => :put)
|
43
43
|
@cache.should.equal({})
|
44
|
-
request(:meth
|
44
|
+
request(:meth => :delete)
|
45
45
|
@cache.should.equal({})
|
46
46
|
end
|
47
47
|
|
48
|
-
specify "should not cache results if there is a query string" do
|
49
|
-
request(:path=>'/path/to/blah?id=1')
|
48
|
+
specify "should not cache results if there is a non-empty query string" do
|
49
|
+
request(:path => '/path/to/blah?id=1')
|
50
50
|
@cache.should.equal({})
|
51
|
-
request(:path=>'/path/to/?id=1')
|
51
|
+
request(:path => '/path/to/?id=1')
|
52
52
|
@cache.should.equal({})
|
53
|
-
request(:path=>'/?id=1')
|
53
|
+
request(:path => '/?id=1')
|
54
54
|
@cache.should.equal({})
|
55
55
|
end
|
56
56
|
|
57
57
|
specify "should cache results if there is an empty query string" do
|
58
|
-
request(:path=>'/?')
|
59
|
-
@cache.should.equal('/index.html'
|
58
|
+
request(:path => '/?')
|
59
|
+
@cache.should.equal('/index.html' => @def_value)
|
60
60
|
end
|
61
61
|
|
62
62
|
specify "should not cache results if the request is not sucessful (status 200)" do
|
@@ -95,38 +95,38 @@ context Rack::ResponseCache do
|
|
95
95
|
end
|
96
96
|
|
97
97
|
specify "should not cache results if the block returns nil or false" do
|
98
|
-
request(:rc_block=>proc{false})
|
98
|
+
request(:rc_block => proc{false})
|
99
99
|
@cache.should.equal({})
|
100
|
-
request(:rc_block=>proc{nil})
|
100
|
+
request(:rc_block => proc{nil})
|
101
101
|
@cache.should.equal({})
|
102
102
|
end
|
103
103
|
|
104
104
|
specify "should cache results to path returned by block" do
|
105
|
-
request(:rc_block=>proc{"1"})
|
106
|
-
@cache.should.equal("1"
|
107
|
-
request(:rc_block=>proc{"2"})
|
108
|
-
@cache.should.equal("1"
|
105
|
+
request(:rc_block => proc{"1"})
|
106
|
+
@cache.should.equal("1" => @def_value)
|
107
|
+
request(:rc_block => proc{"2"})
|
108
|
+
@cache.should.equal("1" => @def_value, "2" => @def_value)
|
109
109
|
end
|
110
110
|
|
111
111
|
specify "should pass the environment and response to the block" do
|
112
112
|
e, r = nil, nil
|
113
|
-
request(:rc_block=>proc{|env,res| e, r = env, res; nil})
|
113
|
+
request(:rc_block => proc{|env,res| e, r = env, res; nil})
|
114
114
|
e['PATH_INFO'].should.equal @def_path
|
115
115
|
e['REQUEST_METHOD'].should.equal 'GET'
|
116
116
|
e['QUERY_STRING'].should.equal ''
|
117
|
-
r.should.equal([200, {"Content-Type"=>"text/html"}, ["rack-response-cache"]])
|
117
|
+
r.should.equal([200, {"Content-Type" => "text/html"}, ["rack-response-cache"]])
|
118
118
|
end
|
119
119
|
|
120
120
|
specify "should unescape the path by default" do
|
121
|
-
request(:path=>'/path%20with%20spaces')
|
122
|
-
@cache.should.equal('/path with spaces.html'
|
123
|
-
request(:path=>'/path%3chref%3e')
|
124
|
-
@cache.should.equal('/path with spaces.html'
|
121
|
+
request(:path => '/path%20with%20spaces')
|
122
|
+
@cache.should.equal('/path with spaces.html' => @def_value)
|
123
|
+
request(:path => '/path%3chref%3e')
|
124
|
+
@cache.should.equal('/path with spaces.html' => @def_value, '/path<href>.html' => @def_value)
|
125
125
|
end
|
126
126
|
|
127
127
|
specify "should cache html mime_type without extension at .html" do
|
128
|
-
request(:path=>'/a')
|
129
|
-
@cache.should.equal('/a.html'
|
128
|
+
request(:path => '/a')
|
129
|
+
@cache.should.equal('/a.html' => @def_value)
|
130
130
|
end
|
131
131
|
|
132
132
|
{
|
@@ -141,36 +141,58 @@ context Rack::ResponseCache do
|
|
141
141
|
}.each do |extension, mime_types|
|
142
142
|
mime_types.each do |mime_type|
|
143
143
|
specify "should cache #{mime_type} responses with the extension ('#{extension}') unchanged" do
|
144
|
-
request(:path=>"/a.#{extension}", :headers=>{'CT'=>mime_type})
|
145
|
-
@cache.should.equal("/a.#{extension}"
|
144
|
+
request(:path => "/a.#{extension}", :headers => {'CT' => mime_type})
|
145
|
+
@cache.should.equal("/a.#{extension}" => @def_value)
|
146
146
|
end
|
147
147
|
|
148
148
|
specify "should cache #{mime_type} responses with the relevant extension ('#{extension}') added if not already present" do
|
149
|
-
request(:path=>'/a', :headers=>{'CT'=>mime_type})
|
150
|
-
@cache.should.equal("/a.#{extension}"
|
149
|
+
request(:path => '/a', :headers => {'CT' => mime_type})
|
150
|
+
@cache.should.equal("/a.#{extension}" => @def_value)
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
155
155
|
specify "should cache 'text/html' responses with the extension ('htm') unchanged" do
|
156
|
-
request(:path=>"/a.htm", :headers=>{'CT'=>"text/html"})
|
157
|
-
@cache.should.equal("/a.htm"
|
156
|
+
request(:path => "/a.htm", :headers => {'CT' => "text/html"})
|
157
|
+
@cache.should.equal("/a.htm" => @def_value)
|
158
158
|
end
|
159
159
|
|
160
160
|
[:css, :xml, :xhtml, :js, :txt, :pdf, :csv].each do |extension|
|
161
161
|
specify "should not cache if extension and content-type don't agree" do
|
162
|
-
request(:path=>"/d.#{extension}", :headers=>{'CT'=>'text/html'})
|
162
|
+
request(:path => "/d.#{extension}", :headers => {'CT' => 'text/html'})
|
163
163
|
@cache.should.equal({})
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
-
specify "should cache html responses with empty basename to index.html
|
168
|
-
request(:path=>'/')
|
169
|
-
|
170
|
-
request(:path=>'/blah/')
|
171
|
-
@cache.should.equal(
|
172
|
-
|
173
|
-
|
167
|
+
specify "should cache text/html responses with empty basename to index.html" do
|
168
|
+
request(:path => '/', :headers => {'CT' => "text/html"})
|
169
|
+
request(:path => '/blah/', :headers => {'CT' => "text/html"})
|
170
|
+
request(:path => '/blah/2/', :headers => {'CT' => "text/html"})
|
171
|
+
@cache.should.equal("/index.html" => @def_value,
|
172
|
+
"/blah/index.html" => @def_value,
|
173
|
+
"/blah/2/index.html" => @def_value)
|
174
|
+
end
|
175
|
+
|
176
|
+
specify "should not cache non-text/html responses with empty basename" do
|
177
|
+
request(:path => '/', :headers => {'CT' => "text/csv"})
|
178
|
+
request(:path => '/blah/', :headers => {'CT' => "text/css"})
|
179
|
+
request(:path => '/blah/2/', :headers => {'CT' => "text/plain"})
|
180
|
+
@cache.should.equal({})
|
181
|
+
end
|
182
|
+
|
183
|
+
specify "should cache unrecognized extensions with text/html content-type at .html" do
|
184
|
+
request(:path => "/a.seo", :headers => {'CT' => "text/html"})
|
185
|
+
@cache.should.equal("/a.seo.html" => @def_value)
|
186
|
+
end
|
187
|
+
|
188
|
+
specify "should not cache unrecognized content-types" do
|
189
|
+
request(:path => "/a", :headers => {'CT' => "text/unrecognised"})
|
190
|
+
@cache.should.equal({})
|
191
|
+
end
|
192
|
+
|
193
|
+
specify "should recognize content-types with supplied parameters (eg. charset)" do
|
194
|
+
request(:path => "/a", :headers => {'CT' => "text/html; charset=utf-8"})
|
195
|
+
@cache.should.equal("/a.html" => @def_value)
|
174
196
|
end
|
175
197
|
|
176
198
|
specify "should raise an error if a cache argument is not provided" do
|
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'tricycle-rack-contrib'
|
6
|
-
s.version = '0.9.
|
7
|
-
s.date = '2010-01-
|
6
|
+
s.version = '0.9.6'
|
7
|
+
s.date = '2010-01-07'
|
8
8
|
|
9
9
|
s.description = "Contributed Rack Middleware and Utilities, including Tricycle's modifications"
|
10
10
|
s.summary = "Contributed Rack Middleware and Utilities, including Tricycle's modifications"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tricycle-rack-contrib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tricycle
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2010-01-
|
13
|
+
date: 2010-01-07 00:00:00 +11:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|