rack-rewrite 1.3.3 → 1.4.1
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.
- checksums.yaml +7 -0
- data/History.rdoc +13 -3
- data/README.markdown +91 -23
- data/VERSION +1 -1
- data/lib/rack/rewrite.rb +6 -2
- data/lib/rack/rewrite/rule.rb +7 -2
- data/rack-rewrite.gemspec +4 -2
- data/test/rule_test.rb +83 -61
- data/test/test_helper.rb +5 -0
- metadata +10 -20
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d85860482ab49561638787391c367e8144173e8
|
4
|
+
data.tar.gz: 93e9dcb2b6c38c85e38dc0bd07938929fb010a5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e5532f91f14dcfb454f4392ff15bf482a7f0e129695183579498c545aa8a89bcad7facc38ce81e3de9eed2e9954e62d2b3413e631784c04924e178a274374ef5
|
7
|
+
data.tar.gz: 20faa15a94a838718c64702436b030885b1b8595753e430958a9ca86176f77313b37383ec4ee4bc220a141b3e695dfa0a123529f9f61630a62d2f432322a17ac
|
data/History.rdoc
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 1.4.1 / 2013-11-07
|
2
|
+
* API
|
3
|
+
* Add support for external loaders (#50)
|
4
|
+
|
5
|
+
=== 1.4.01 / 2013-09-13
|
6
|
+
* API
|
7
|
+
* Add support for lambda matchers
|
8
|
+
* Maintenance
|
9
|
+
* Update README for usage with Rails 4 and threading, :scheme option
|
10
|
+
|
1
11
|
=== 1.2.1 / 2011-09-20
|
2
12
|
* Maintenance
|
3
13
|
* Use Rack::Request to match the host
|
@@ -30,7 +40,7 @@
|
|
30
40
|
=== 0.2.1 / 2010-01-06
|
31
41
|
* API
|
32
42
|
* Implement $& substitution pattern (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
|
33
|
-
|
43
|
+
|
34
44
|
* Maintenance
|
35
45
|
* Ignore empty captures instead of failing during subsitution (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
|
36
46
|
* Play nice with Rack::Test requests which only set PATH_INFO and not REQUEST_URI (thanks to {@docunext}[http://github.com/docunext])
|
@@ -46,14 +56,14 @@
|
|
46
56
|
* Documentation
|
47
57
|
* Add example of writing capistrano maintenance page rewrite rules
|
48
58
|
* Add examples of rule guards and arbitrary rewriting
|
49
|
-
* Add examples of :send_file and :x_send_file rules
|
59
|
+
* Add examples of :send_file and :x_send_file rules
|
50
60
|
|
51
61
|
=== 0.1.3 / 2009-11-14
|
52
62
|
* Maintenance
|
53
63
|
* Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
|
54
64
|
* Documentation
|
55
65
|
* Add HISTORY.rdoc
|
56
|
-
|
66
|
+
|
57
67
|
=== 0.1.2 / 2009-10-13
|
58
68
|
|
59
69
|
* Initial Feature Set
|
data/README.markdown
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# rack-rewrite
|
2
2
|
|
3
|
-
A rack middleware for defining and applying rewrite rules. In many cases you
|
3
|
+
A rack middleware for defining and applying rewrite rules. In many cases you
|
4
4
|
can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
|
5
5
|
|
6
6
|
## Usage Examples
|
7
7
|
|
8
8
|
* [Rack::Rewrite for Site Maintenance and Downtime](http://blog.smartlogicsolutions.com/2009/11/16/rack-rewrite-for-site-maintenance-and-downtime/)
|
9
9
|
* [Rack::Rewrite + Google Analytics Makes Site Transitions Seamless](http://blog.smartlogicsolutions.com/2009/11/24/rack-rewrite-google-analytics-makes-site-transitions-seamless/)
|
10
|
+
* [Rack::Rewrite for serving gzipped pipeline assets on Heroku](https://gist.github.com/eliotsykes/6049536)
|
10
11
|
|
11
12
|
## Usage Details
|
12
13
|
|
13
14
|
### Sample rackup file
|
14
|
-
|
15
|
+
|
15
16
|
```ruby
|
16
17
|
gem 'rack-rewrite', '~> 1.2.1'
|
17
18
|
require 'rack/rewrite'
|
@@ -34,6 +35,24 @@ config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
|
|
34
35
|
end
|
35
36
|
```
|
36
37
|
|
38
|
+
If you use `config.threadsafe`, you'll need to `insert_before(Rack::Runtime, Rack::Rewrite)` as `Rack::Lock` does
|
39
|
+
not exist when `config.allow_concurrency == true`:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
config.middleware.insert_before(Rack::Runtime, Rack::Rewrite) do
|
43
|
+
rewrite '/wiki/John_Trupiano', '/john'
|
44
|
+
r301 '/wiki/Yair_Flicker', '/yair'
|
45
|
+
r302 '/wiki/Greg_Jastrab', '/greg'
|
46
|
+
r301 %r{/wiki/(\w+)_\w+}, '/$1'
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Or insert Rack::Rewrite to the top of the stack:
|
51
|
+
|
52
|
+
``` ruby
|
53
|
+
config.middleware.insert 0, 'Rack::Rewrite' {}
|
54
|
+
```
|
55
|
+
|
37
56
|
## Redirection codes
|
38
57
|
|
39
58
|
All redirect status codes from the [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) are supported:
|
@@ -72,7 +91,7 @@ behaves the same as 303.
|
|
72
91
|
|
73
92
|
### Rebuild of existing site in a new technology
|
74
93
|
|
75
|
-
It's very common for sites built in older technologies to be rebuilt with the
|
94
|
+
It's very common for sites built in older technologies to be rebuilt with the
|
76
95
|
latest and greatest. Let's consider a site that has already established quite
|
77
96
|
a bit of "google juice." When we launch the new site, we don't want to lose
|
78
97
|
that hard-earned reputation. By writing rewrite rules that issue 301's for
|
@@ -123,11 +142,11 @@ RewriteRule ^.*$ /system/maintenance.html [L]
|
|
123
142
|
```
|
124
143
|
|
125
144
|
This rewrite rule says to render a maintenance page for all non-asset requests
|
126
|
-
if the maintenance file exists. In capistrano, you can quickly upload a
|
145
|
+
if the maintenance file exists. In capistrano, you can quickly upload a
|
127
146
|
maintenance file using:
|
128
147
|
|
129
148
|
`cap deploy:web:disable REASON=upgrade UNTIL=12:30PM`
|
130
|
-
|
149
|
+
|
131
150
|
We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
|
132
151
|
|
133
152
|
```ruby
|
@@ -146,7 +165,7 @@ send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env
|
|
146
165
|
}
|
147
166
|
```
|
148
167
|
|
149
|
-
For those using the oniguruma gem with their ruby 1.8 installation, you can
|
168
|
+
For those using the oniguruma gem with their ruby 1.8 installation, you can
|
150
169
|
get away with:
|
151
170
|
|
152
171
|
```ruby
|
@@ -160,9 +179,9 @@ send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenance_file, :if
|
|
160
179
|
|
161
180
|
### :rewrite
|
162
181
|
|
163
|
-
Calls to #rewrite will simply update the PATH_INFO, QUERY_STRING and
|
164
|
-
REQUEST_URI HTTP header values and pass the request onto the next chain in
|
165
|
-
the Rack stack. The URL that a user's browser will show will not be changed.
|
182
|
+
Calls to #rewrite will simply update the PATH_INFO, QUERY_STRING and
|
183
|
+
REQUEST_URI HTTP header values and pass the request onto the next chain in
|
184
|
+
the Rack stack. The URL that a user's browser will show will not be changed.
|
166
185
|
See these examples:
|
167
186
|
|
168
187
|
```ruby
|
@@ -171,14 +190,14 @@ rewrite %r{/wiki/(\w+)_\w+}, '/$1' # [2]
|
|
171
190
|
```
|
172
191
|
|
173
192
|
For [1], the user's browser will continue to display /wiki/John_Trupiano, but
|
174
|
-
the actual HTTP header values for PATH_INFO and REQUEST_URI in the request
|
193
|
+
the actual HTTP header values for PATH_INFO and REQUEST_URI in the request
|
175
194
|
will be changed to /john for subsequent nodes in the Rack stack. Rails
|
176
195
|
reads these headers to determine which routes will match.
|
177
196
|
|
178
|
-
Rule [2] showcases the use of regular expressions and substitutions. [2] is a
|
197
|
+
Rule [2] showcases the use of regular expressions and substitutions. [2] is a
|
179
198
|
generalized version of [1] that will match any /wiki/FirstName_LastName URL's
|
180
|
-
and rewrite them as the first name only. This is an actual catch-all rule we
|
181
|
-
applied when we rebuilt our website in September 2009
|
199
|
+
and rewrite them as the first name only. This is an actual catch-all rule we
|
200
|
+
applied when we rebuilt our website in September 2009
|
182
201
|
( http://www.smartlogicsolutions.com ).
|
183
202
|
|
184
203
|
### :r301, :r302, :r303, :r307
|
@@ -189,10 +208,10 @@ their respective status codes. See these examples:
|
|
189
208
|
|
190
209
|
```ruby
|
191
210
|
r301 '/wiki/John_Trupiano', '/john' # [1]
|
192
|
-
r301
|
211
|
+
r301 %r{/wiki/(.*)}, 'http://www.google.com/?q=$1' # [2]
|
193
212
|
```
|
194
213
|
|
195
|
-
Recall that rules are interpreted from top to bottom. So you can install
|
214
|
+
Recall that rules are interpreted from top to bottom. So you can install
|
196
215
|
"default" rewrite rules if you like. [2] is a sample default rule that
|
197
216
|
will redirect all other requests to the wiki to a google search.
|
198
217
|
|
@@ -223,11 +242,13 @@ Using the :host option you can match requests to a specific hostname.
|
|
223
242
|
```ruby
|
224
243
|
r301 "/features", "/facial_features", :host => "facerecognizer.com"
|
225
244
|
```
|
226
|
-
This rule will only match when the hostname is "facerecognizer.com"
|
245
|
+
This rule will only match when the hostname is "facerecognizer.com".
|
246
|
+
|
247
|
+
The :host option accepts a symbol, string, or regexp.
|
227
248
|
|
228
249
|
### :headers
|
229
250
|
|
230
|
-
Using the :headers option you can set custom response headers e.g. for HTTP
|
251
|
+
Using the :headers option you can set custom response headers e.g. for HTTP
|
231
252
|
caching instructions.
|
232
253
|
|
233
254
|
```ruby
|
@@ -247,9 +268,20 @@ send_file /^.+\.(?:ico|jpg|jpeg|png|gif|)$/,
|
|
247
268
|
:headers => lambda { { 'Expires' => 1.year.from_now.httpdate } }
|
248
269
|
```
|
249
270
|
|
271
|
+
### :scheme
|
272
|
+
|
273
|
+
Using the :scheme option you can restrict the matching of a rule by the protocol of a given request.
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
# Redirect all http traffic to https
|
277
|
+
r301 %r{.*}, 'https://www.example.tld$&', :scheme => 'http'
|
278
|
+
```
|
279
|
+
|
280
|
+
The :scheme option accepts a symbol, string, or regexp.
|
281
|
+
|
250
282
|
### :method
|
251
283
|
|
252
|
-
Using the :method option you can restrict the matching of a rule by the HTTP
|
284
|
+
Using the :method option you can restrict the matching of a rule by the HTTP
|
253
285
|
method of a given request.
|
254
286
|
|
255
287
|
```ruby
|
@@ -260,16 +292,18 @@ r301 "/players", "/current_players", :method => :get
|
|
260
292
|
r302 "/players", "/no_longer_available.html?message=No&longer&supported", :method => :post
|
261
293
|
```
|
262
294
|
|
295
|
+
The :method option accepts a symbol, string, or regexp.
|
296
|
+
|
263
297
|
### :if
|
264
298
|
|
265
299
|
Using the :if option you can define arbitrary rule guards. Guards are any
|
266
|
-
object responding to #call that return true or false indicating whether the
|
267
|
-
rule matches. The following example demonstrates how the presence of a
|
300
|
+
object responding to #call that return true or false indicating whether the
|
301
|
+
rule matches. The following example demonstrates how the presence of a
|
268
302
|
maintenance page on the filesystem can be utilized to take your site(s) offline.
|
269
303
|
|
270
304
|
```ruby
|
271
305
|
maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
|
272
|
-
x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
|
306
|
+
x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
|
273
307
|
File.exists?(maintenance_file)
|
274
308
|
}
|
275
309
|
```
|
@@ -289,7 +323,7 @@ This will not match the relative URL /features but would match /features.xml.
|
|
289
323
|
|
290
324
|
### Keeping your querystring
|
291
325
|
|
292
|
-
When rewriting a URL, you may want to keep your querystring
|
326
|
+
When rewriting a URL, you may want to keep your querystring intact (for
|
293
327
|
example if you're tracking traffic sources). You will need to include a
|
294
328
|
capture group and substitution pattern in your rewrite rule to achieve this.
|
295
329
|
|
@@ -302,7 +336,7 @@ will substitute the querystring back into the rewritten URL (via `$1`).
|
|
302
336
|
|
303
337
|
### Arbitrary Rewriting
|
304
338
|
|
305
|
-
All rules support passing a Proc as the second argument allowing you to
|
339
|
+
All rules support passing a Proc as the first or second argument allowing you to
|
306
340
|
perform arbitrary rewrites. The following rule will rewrite all requests
|
307
341
|
received between 12AM and 8AM to an unavailable page.
|
308
342
|
|
@@ -312,6 +346,40 @@ received between 12AM and 8AM to an unavailable page.
|
|
312
346
|
}
|
313
347
|
```
|
314
348
|
|
349
|
+
This rule will redirect all requests paths starting with a current date
|
350
|
+
string to /today.html
|
351
|
+
|
352
|
+
```ruby
|
353
|
+
r301 lambda { "/#{Time.current.strftime(%m%d%Y)}.html" }, '/today.html'
|
354
|
+
```
|
355
|
+
|
356
|
+
|
357
|
+
##Alternative loaders
|
358
|
+
|
359
|
+
rack-rewrite can also be driven by external loaders. Bundled with this library is a loader for YAML files.
|
360
|
+
|
361
|
+
```
|
362
|
+
config.middleware.insert_before(Rack::Lock, Rack::Rewrite,
|
363
|
+
:klass => Rack::Rewrite::YamlRuleSet,
|
364
|
+
:options => {:file_name => @file_name})
|
365
|
+
```
|
366
|
+
|
367
|
+
Using syntax like
|
368
|
+
|
369
|
+
```
|
370
|
+
-
|
371
|
+
method: r301
|
372
|
+
from: !ruby/regexp '/(.*)/print'
|
373
|
+
to : '$1/printer_friendly'
|
374
|
+
options :
|
375
|
+
host : 'example.com'
|
376
|
+
```
|
377
|
+
|
378
|
+
Any class can be used here as long as:
|
379
|
+
|
380
|
+
- the class take an options hash
|
381
|
+
- `#rules` returns an array of `Rack::Rewrite::Rule` instances
|
382
|
+
|
315
383
|
## Contribute
|
316
384
|
|
317
385
|
rack-rewrite is maintained by [@travisjeffery](http://github.com/travisjeffery).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.1
|
data/lib/rack/rewrite.rb
CHANGED
@@ -5,9 +5,13 @@ module Rack
|
|
5
5
|
# A rack middleware for defining and applying rewrite rules. In many cases you
|
6
6
|
# can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
|
7
7
|
class Rewrite
|
8
|
-
def initialize(app, &rule_block)
|
8
|
+
def initialize(app, given_options = {}, &rule_block)
|
9
|
+
options = {
|
10
|
+
:klass => RuleSet,
|
11
|
+
:options => {}
|
12
|
+
}.merge(given_options)
|
9
13
|
@app = app
|
10
|
-
@rule_set =
|
14
|
+
@rule_set = options[:klass].new(options[:options])
|
11
15
|
@rule_set.instance_eval(&rule_block) if block_given?
|
12
16
|
end
|
13
17
|
|
data/lib/rack/rewrite/rule.rb
CHANGED
@@ -4,7 +4,7 @@ module Rack
|
|
4
4
|
class Rewrite
|
5
5
|
class RuleSet
|
6
6
|
attr_reader :rules
|
7
|
-
def initialize #:nodoc:
|
7
|
+
def initialize(options = {})#:nodoc:
|
8
8
|
@rules = []
|
9
9
|
end
|
10
10
|
|
@@ -99,7 +99,7 @@ module Rack
|
|
99
99
|
|
100
100
|
# TODO: Break rules into subclasses
|
101
101
|
class Rule #:nodoc:
|
102
|
-
attr_reader :rule_type, :
|
102
|
+
attr_reader :rule_type, :to, :options
|
103
103
|
def initialize(rule_type, from, to, options={}) #:nodoc:
|
104
104
|
@rule_type, @from, @to, @options = rule_type, from, to, normalize_options(options)
|
105
105
|
end
|
@@ -111,6 +111,11 @@ module Rack
|
|
111
111
|
self.match_options?(rack_env) && string_matches?(path, self.from)
|
112
112
|
end
|
113
113
|
|
114
|
+
def from
|
115
|
+
return @static_from if @static_from
|
116
|
+
@from.respond_to?(:call) ? @from.call : @static_from = @from
|
117
|
+
end
|
118
|
+
|
114
119
|
# Either (a) return a Rack response (short-circuiting the Rack stack), or
|
115
120
|
# (b) alter env as necessary and return true
|
116
121
|
def apply!(env) #:nodoc:
|
data/rack-rewrite.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = 'rack-rewrite'
|
3
5
|
s.version = File.read('VERSION')
|
@@ -41,12 +43,12 @@ Gem::Specification.new do |s|
|
|
41
43
|
"test/rule_test.rb",
|
42
44
|
"test/test_helper.rb"
|
43
45
|
]
|
44
|
-
|
46
|
+
|
45
47
|
s.add_development_dependency 'bundler'
|
46
48
|
s.add_development_dependency 'shoulda', '~> 2.10.2'
|
47
49
|
s.add_development_dependency 'mocha', '~> 0.9.7'
|
48
50
|
s.add_development_dependency 'rack'
|
49
|
-
|
51
|
+
|
50
52
|
if s.respond_to? :specification_version then
|
51
53
|
s.specification_version = 3
|
52
54
|
end
|
data/test/rule_test.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class RuleTest < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
TEST_ROOT = File.dirname(__FILE__)
|
6
|
-
|
6
|
+
|
7
7
|
def self.should_pass_maintenance_tests
|
8
8
|
context 'and the maintenance file does in fact exist' do
|
9
9
|
setup { File.stubs(:exists?).returns(true) }
|
@@ -16,14 +16,14 @@ class RuleTest < Test::Unit::TestCase
|
|
16
16
|
should('not match for a png file') { assert !@rule.matches?(rack_env_for('/images/sls.png')) }
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def self.negative_lookahead_supported?
|
21
21
|
begin
|
22
22
|
require 'oniguruma'
|
23
23
|
rescue LoadError; end
|
24
24
|
RUBY_VERSION =~ /^1\.9/ || Object.const_defined?(:Oniguruma)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def negative_lookahead_regexp
|
28
28
|
if RUBY_VERSION =~ /^1\.9/
|
29
29
|
# have to use the constructor instead of the literal syntax b/c load errors occur in Ruby 1.8
|
@@ -32,7 +32,7 @@ class RuleTest < Test::Unit::TestCase
|
|
32
32
|
Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)")
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
context '#Rule#apply' do
|
37
37
|
supported_status_codes.each do |rule_type|
|
38
38
|
should "set Location header to result of #interpret_to for a #{rule_type}" do
|
@@ -41,7 +41,7 @@ class RuleTest < Test::Unit::TestCase
|
|
41
41
|
assert_equal rule.send(:interpret_to, '/abc'), rule.apply!(env)[1]['Location']
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
supported_status_codes.each do |rule_type|
|
46
46
|
should "include a link to the result of #interpret_to for a #{rule_type}" do
|
47
47
|
rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def')
|
@@ -49,13 +49,13 @@ class RuleTest < Test::Unit::TestCase
|
|
49
49
|
assert_match /\/def/, rule.apply!(env)[2][0]
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
should 'keep the QUERY_STRING when a 301 rule matches a URL with a querystring' do
|
54
54
|
rule = Rack::Rewrite::Rule.new(:r301, %r{/john(.*)}, '/yair$1')
|
55
55
|
env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
|
56
56
|
assert_equal '/yair?show_bio=1', rule.apply!(env)[1]['Location']
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
should 'keep the QUERY_STRING when a rewrite rule that requires a querystring matches a URL with a querystring' do
|
60
60
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/john(\?.*)}, '/yair$1')
|
61
61
|
env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
|
@@ -64,7 +64,7 @@ class RuleTest < Test::Unit::TestCase
|
|
64
64
|
assert_equal 'show_bio=1', env['QUERY_STRING']
|
65
65
|
assert_equal '/yair?show_bio=1', env['REQUEST_URI']
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
should 'update the QUERY_STRING when a rewrite rule changes its value' do
|
69
69
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/(\w+)\?show_bio=(\d)}, '/$1?bio=$2')
|
70
70
|
env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
|
@@ -81,21 +81,21 @@ class RuleTest < Test::Unit::TestCase
|
|
81
81
|
assert_equal 'text/html', rule.apply!(env)[1]['Content-Type']
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
should 'set Content-Type header to text/css for a 301 and 302 request for a .css page' do
|
86
86
|
supported_status_codes.each do |rule_type|
|
87
87
|
rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css')
|
88
88
|
env = {'PATH_INFO' => '/abc'}
|
89
89
|
assert_equal 'text/css', rule.apply!(env)[1]['Content-Type']
|
90
|
-
end
|
90
|
+
end
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
should 'set additional headers for a 301 and 302 request' do
|
94
94
|
[:r301, :r302].each do |rule_type|
|
95
95
|
rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css', {:headers => {'Cache-Control' => 'no-cache'}})
|
96
96
|
env = {'PATH_INFO' => '/abc'}
|
97
97
|
assert_equal 'no-cache', rule.apply!(env)[1]['Cache-Control']
|
98
|
-
end
|
98
|
+
end
|
99
99
|
end
|
100
100
|
|
101
101
|
should 'evaluate additional headers block once per redirect request' do
|
@@ -119,7 +119,7 @@ class RuleTest < Test::Unit::TestCase
|
|
119
119
|
assert_equal 'bar', rule.apply!(env)[1]['X-Foobar']
|
120
120
|
end
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
context 'Given an :x_send_file rule that matches' do
|
124
124
|
setup do
|
125
125
|
@file = File.join(TEST_ROOT, 'geminstaller.yml')
|
@@ -127,23 +127,23 @@ class RuleTest < Test::Unit::TestCase
|
|
127
127
|
env = {'PATH_INFO' => '/abc'}
|
128
128
|
@response = @rule.apply!(env)
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
should 'return 200' do
|
132
132
|
assert_equal 200, @response[0]
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
should 'return an X-Sendfile header' do
|
136
136
|
assert @response[1].has_key?('X-Sendfile')
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
should 'return a Content-Type of text/yaml' do
|
140
140
|
assert_equal 'text/yaml', @response[1]['Content-Type']
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
should 'return the proper Content-Length' do
|
144
144
|
assert_equal File.size(@file).to_s, @response[1]['Content-Length']
|
145
145
|
end
|
146
|
-
|
146
|
+
|
147
147
|
should 'return additional headers' do
|
148
148
|
assert_equal 'no-cache', @response[1]['Cache-Control']
|
149
149
|
end
|
@@ -152,7 +152,7 @@ class RuleTest < Test::Unit::TestCase
|
|
152
152
|
assert_equal [], @response[2]
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
context 'Given a :send_file rule that matches' do
|
157
157
|
setup do
|
158
158
|
@file = File.join(TEST_ROOT, 'geminstaller.yml')
|
@@ -160,27 +160,27 @@ class RuleTest < Test::Unit::TestCase
|
|
160
160
|
env = {'PATH_INFO' => '/abc'}
|
161
161
|
@response = @rule.apply!(env)
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
should 'return 200' do
|
165
165
|
assert_equal 200, @response[0]
|
166
166
|
end
|
167
|
-
|
167
|
+
|
168
168
|
should 'not return an X-Sendfile header' do
|
169
169
|
assert !@response[1].has_key?('X-Sendfile')
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
should 'return a Content-Type of text/yaml' do
|
173
173
|
assert_equal 'text/yaml', @response[1]['Content-Type']
|
174
174
|
end
|
175
|
-
|
175
|
+
|
176
176
|
should 'return the proper Content-Length' do
|
177
177
|
assert_equal File.size(@file).to_s, @response[1]['Content-Length']
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
should 'return additional headers' do
|
181
181
|
assert_equal 'no-cache', @response[1]['Cache-Control']
|
182
182
|
end
|
183
|
-
|
183
|
+
|
184
184
|
should 'return the contents of geminstaller.yml in an array for Ruby 1.9.2 compatibility' do
|
185
185
|
assert_equal [File.read(@file)], @response[2]
|
186
186
|
end
|
@@ -196,7 +196,7 @@ class RuleTest < Test::Unit::TestCase
|
|
196
196
|
end
|
197
197
|
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
context 'Rule#matches' do
|
201
201
|
context 'Given rule with :not option which matches "from" string' do
|
202
202
|
setup do
|
@@ -209,16 +209,16 @@ class RuleTest < Test::Unit::TestCase
|
|
209
209
|
assert @rule.matches?(rack_env_for("/features.xml"))
|
210
210
|
end
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
context 'Given rule with :host option of testapp.com' do
|
214
214
|
setup do
|
215
215
|
@rule = Rack::Rewrite::Rule.new(:rewrite, /^\/features/, '/facial_features', :host => 'testapp.com')
|
216
216
|
end
|
217
|
-
|
217
|
+
|
218
218
|
should 'match PATH_INFO of /features and HOST of testapp.com' do
|
219
219
|
assert @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'testapp.com', "SERVER_PORT" => "8080"))
|
220
220
|
end
|
221
|
-
|
221
|
+
|
222
222
|
should 'not match PATH_INFO of /features and HOST of nottestapp.com' do
|
223
223
|
assert ! @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'nottestapp.com', "SERVER_PORT" => "8080"))
|
224
224
|
end
|
@@ -231,39 +231,39 @@ class RuleTest < Test::Unit::TestCase
|
|
231
231
|
assert !@rule.matches?(rack_env_for("/features", "SERVER_NAME" => "127.0.0.1", "SERVER_PORT" => "8080", "HTTP_X_FORWARDED_HOST" => "nottestapp.com"))
|
232
232
|
end
|
233
233
|
end
|
234
|
-
|
234
|
+
|
235
235
|
context 'Given rule with :method option of POST' do
|
236
236
|
setup do
|
237
237
|
@rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features', :method => 'POST')
|
238
238
|
end
|
239
|
-
|
239
|
+
|
240
240
|
should 'match PATH_INFO of /features and REQUEST_METHOD of POST' do
|
241
241
|
assert @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'POST'))
|
242
242
|
end
|
243
|
-
|
243
|
+
|
244
244
|
should 'not match PATH_INFO of /features and REQUEST_METHOD of DELETE' do
|
245
245
|
assert ! @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'DELETE'))
|
246
246
|
end
|
247
247
|
end
|
248
|
-
|
248
|
+
|
249
249
|
context 'Given any rule with a "from" string of /features' do
|
250
250
|
setup do
|
251
251
|
@rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features')
|
252
252
|
end
|
253
|
-
|
253
|
+
|
254
254
|
should 'match PATH_INFO of /features' do
|
255
255
|
assert @rule.matches?(rack_env_for("/features"))
|
256
256
|
end
|
257
|
-
|
257
|
+
|
258
258
|
should 'not match PATH_INFO of /features.xml' do
|
259
259
|
assert !@rule.matches?(rack_env_for("/features.xml"))
|
260
260
|
end
|
261
|
-
|
261
|
+
|
262
262
|
should 'not match PATH_INFO of /my_features' do
|
263
263
|
assert !@rule.matches?(rack_env_for("/my_features"))
|
264
264
|
end
|
265
265
|
end
|
266
|
-
|
266
|
+
|
267
267
|
context 'Given a rule with the ^ operator' do
|
268
268
|
setup do
|
269
269
|
@rule = Rack::Rewrite::Rule.new(:rewrite, %r{^/jason}, '/steve')
|
@@ -271,66 +271,66 @@ class RuleTest < Test::Unit::TestCase
|
|
271
271
|
should 'match with the ^ operator if match is at the beginning of the path' do
|
272
272
|
assert @rule.matches?(rack_env_for('/jason'))
|
273
273
|
end
|
274
|
-
|
274
|
+
|
275
275
|
should 'not match with the ^ operator when match is deeply nested' do
|
276
276
|
assert !@rule.matches?(rack_env_for('/foo/bar/jason'))
|
277
277
|
end
|
278
278
|
end
|
279
|
-
|
279
|
+
|
280
280
|
context 'Given any rule with a "from" regular expression of /features(.*)' do
|
281
281
|
setup do
|
282
282
|
@rule = Rack::Rewrite::Rule.new(:rewrite, %r{/features(.*)}, '/facial_features$1')
|
283
283
|
end
|
284
|
-
|
284
|
+
|
285
285
|
should 'match PATH_INFO of /features' do
|
286
286
|
assert @rule.matches?(rack_env_for("/features"))
|
287
287
|
end
|
288
|
-
|
288
|
+
|
289
289
|
should 'match PATH_INFO of /features.xml' do
|
290
290
|
assert @rule.matches?(rack_env_for('/features.xml'))
|
291
291
|
end
|
292
|
-
|
292
|
+
|
293
293
|
should 'match PATH_INFO of /features/1' do
|
294
294
|
assert @rule.matches?(rack_env_for('/features/1'))
|
295
295
|
end
|
296
|
-
|
296
|
+
|
297
297
|
should 'match PATH_INFO of /features?filter_by=name' do
|
298
298
|
assert @rule.matches?(rack_env_for('/features?filter_by_name=name'))
|
299
299
|
end
|
300
|
-
|
300
|
+
|
301
301
|
should 'match PATH_INFO of /features/1?hide_bio=1' do
|
302
302
|
assert @rule.matches?(rack_env_for('/features/1?hide_bio=1'))
|
303
303
|
end
|
304
304
|
end
|
305
|
-
|
305
|
+
|
306
306
|
context 'Given a rule with a guard that checks for the presence of a file' do
|
307
307
|
setup do
|
308
308
|
@rule = Rack::Rewrite::Rule.new(:rewrite, %r{(.)*}, '/maintenance.html', lambda { |rack_env|
|
309
309
|
File.exists?('maintenance.html')
|
310
310
|
})
|
311
311
|
end
|
312
|
-
|
312
|
+
|
313
313
|
context 'when the file exists' do
|
314
314
|
setup do
|
315
315
|
File.stubs(:exists?).returns(true)
|
316
316
|
end
|
317
|
-
|
317
|
+
|
318
318
|
should 'match' do
|
319
319
|
assert @rule.matches?(rack_env_for('/anything/should/match'))
|
320
320
|
end
|
321
321
|
end
|
322
|
-
|
322
|
+
|
323
323
|
context 'when the file does not exist' do
|
324
324
|
setup do
|
325
325
|
File.stubs(:exists?).returns(false)
|
326
326
|
end
|
327
|
-
|
327
|
+
|
328
328
|
should 'not match' do
|
329
329
|
assert !@rule.matches?(rack_env_for('/nothing/should/match'))
|
330
330
|
end
|
331
331
|
end
|
332
332
|
end
|
333
|
-
|
333
|
+
|
334
334
|
context 'Given the capistrano maintenance.html rewrite rule given in our README' do
|
335
335
|
setup do
|
336
336
|
@rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env|
|
@@ -340,7 +340,7 @@ class RuleTest < Test::Unit::TestCase
|
|
340
340
|
end
|
341
341
|
should_pass_maintenance_tests
|
342
342
|
end
|
343
|
-
|
343
|
+
|
344
344
|
if negative_lookahead_supported?
|
345
345
|
context 'Given the negative lookahead regular expression version of the capistrano maintenance.html rewrite rule given in our README' do
|
346
346
|
setup do
|
@@ -351,43 +351,57 @@ class RuleTest < Test::Unit::TestCase
|
|
351
351
|
should_pass_maintenance_tests
|
352
352
|
end
|
353
353
|
end
|
354
|
-
|
354
|
+
|
355
355
|
context 'Given the CNAME alternative rewrite rule in our README' do
|
356
356
|
setup do
|
357
357
|
@rule = Rack::Rewrite::Rule.new(:r301, %r{.*}, 'http://mynewdomain.com$&', lambda {|rack_env|
|
358
358
|
rack_env['SERVER_NAME'] != 'mynewdomain.com'
|
359
359
|
})
|
360
360
|
end
|
361
|
-
|
361
|
+
|
362
362
|
should 'match requests for domain myolddomain.com and redirect to mynewdomain.com' do
|
363
363
|
env = {'PATH_INFO' => '/anything', 'QUERY_STRING' => 'abc=1', 'SERVER_NAME' => 'myolddomain.com'}
|
364
364
|
assert @rule.matches?(env)
|
365
365
|
rack_response = @rule.apply!(env)
|
366
366
|
assert_equal 'http://mynewdomain.com/anything?abc=1', rack_response[1]['Location']
|
367
367
|
end
|
368
|
-
|
368
|
+
|
369
369
|
should 'not match requests for domain mynewdomain.com' do
|
370
370
|
assert !@rule.matches?({'PATH_INFO' => '/anything', 'SERVER_NAME' => 'mynewdomain.com'})
|
371
371
|
end
|
372
372
|
end
|
373
|
+
|
374
|
+
context 'Given a lambda matcher' do
|
375
|
+
setup do
|
376
|
+
@rule = Rack::Rewrite::Rule.new(:r302, ->{ Thread.current[:test_matcher] }, '/today' )
|
377
|
+
end
|
378
|
+
should 'call the lambda and match appropriately' do
|
379
|
+
Thread.current[:test_matcher] = '/abcd'
|
380
|
+
assert @rule.matches?(rack_env_for("/abcd"))
|
381
|
+
assert !@rule.matches?(rack_env_for("/DEFG"))
|
382
|
+
Thread.current[:test_matcher] = /DEFG$/
|
383
|
+
assert !@rule.matches?(rack_env_for("/abcd"))
|
384
|
+
assert @rule.matches?(rack_env_for("/DEFG"))
|
385
|
+
end
|
386
|
+
end
|
373
387
|
end
|
374
|
-
|
388
|
+
|
375
389
|
context 'Rule#interpret_to' do
|
376
390
|
should 'return #to when #from is a string' do
|
377
391
|
rule = Rack::Rewrite::Rule.new(:rewrite, '/abc', '/def')
|
378
392
|
assert_equal '/def', rule.send(:interpret_to, rack_env_for('/abc'))
|
379
393
|
end
|
380
|
-
|
394
|
+
|
381
395
|
should 'replace $1 on a match' do
|
382
396
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)}, '/people/$1')
|
383
397
|
assert_equal '/people/1', rule.send(:interpret_to, rack_env_for("/person_1"))
|
384
398
|
end
|
385
|
-
|
399
|
+
|
386
400
|
should 'be able to catch querystrings with a regexp match' do
|
387
401
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, '/people/$1$2')
|
388
402
|
assert_equal '/people/1?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1'))
|
389
403
|
end
|
390
|
-
|
404
|
+
|
391
405
|
should 'be able to make 10 replacements' do
|
392
406
|
# regexp to reverse 10 characters
|
393
407
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)}, '$10$9$8$7$6$5$4$3$2$1')
|
@@ -413,15 +427,23 @@ class RuleTest < Test::Unit::TestCase
|
|
413
427
|
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, lambda {|match, env| "people-#{match[1].to_i * 3}#{match[2]}"})
|
414
428
|
assert_equal 'people-3?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1'))
|
415
429
|
end
|
430
|
+
|
431
|
+
should 'call to with from lambda match data' do
|
432
|
+
rule = Rack::Rewrite::Rule.new(:rewrite, ->{ Thread.current[:test_matcher]}, ->(match, env){ match[1][0] })
|
433
|
+
Thread.current[:test_matcher] = /^\/(alpha|beta|gamma)$/
|
434
|
+
assert_equal 'b', rule.send(:interpret_to, rack_env_for('/beta'))
|
435
|
+
Thread.current[:test_matcher] = /^\/(zulu)/
|
436
|
+
assert_equal 'z', rule.send(:interpret_to, rack_env_for('/zulu'))
|
437
|
+
end
|
416
438
|
end
|
417
|
-
|
439
|
+
|
418
440
|
context 'Mongel 1.2.0.pre2 edge case: root url with a query string' do
|
419
441
|
should 'handle a nil PATH_INFO variable without errors' do
|
420
442
|
rule = Rack::Rewrite::Rule.new(:r301, '/a', '/')
|
421
443
|
assert_equal '?exists', rule.send(:build_path_from_env, {'QUERY_STRING' => 'exists'})
|
422
444
|
end
|
423
445
|
end
|
424
|
-
|
446
|
+
|
425
447
|
def rack_env_for(url, options = {})
|
426
448
|
components = url.split('?')
|
427
449
|
{'PATH_INFO' => components[0], 'QUERY_STRING' => components[1] || ''}.merge(options)
|
data/test/test_helper.rb
CHANGED
@@ -8,6 +8,11 @@ require 'test/unit'
|
|
8
8
|
class Test::Unit::TestCase
|
9
9
|
end
|
10
10
|
|
11
|
+
def rack_env_for(url, options = {})
|
12
|
+
components = url.split('?')
|
13
|
+
{'PATH_INFO' => components[0], 'QUERY_STRING' => components[1] || ''}.merge(options)
|
14
|
+
end
|
15
|
+
|
11
16
|
def supported_status_codes
|
12
17
|
[:r301, :r302, :r303, :r307]
|
13
18
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-rewrite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.4.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Travis Jeffery
|
@@ -10,28 +9,25 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-
|
12
|
+
date: 2013-11-07 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: bundler
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: '0'
|
23
21
|
type: :development
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
|
-
- -
|
25
|
+
- - '>='
|
29
26
|
- !ruby/object:Gem::Version
|
30
27
|
version: '0'
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: shoulda
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
32
|
- - ~>
|
37
33
|
- !ruby/object:Gem::Version
|
@@ -39,7 +35,6 @@ dependencies:
|
|
39
35
|
type: :development
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
39
|
- - ~>
|
45
40
|
- !ruby/object:Gem::Version
|
@@ -47,7 +42,6 @@ dependencies:
|
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: mocha
|
49
44
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
45
|
requirements:
|
52
46
|
- - ~>
|
53
47
|
- !ruby/object:Gem::Version
|
@@ -55,7 +49,6 @@ dependencies:
|
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
52
|
requirements:
|
60
53
|
- - ~>
|
61
54
|
- !ruby/object:Gem::Version
|
@@ -63,17 +56,15 @@ dependencies:
|
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
57
|
name: rack
|
65
58
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
59
|
requirements:
|
68
|
-
- -
|
60
|
+
- - '>='
|
69
61
|
- !ruby/object:Gem::Version
|
70
62
|
version: '0'
|
71
63
|
type: :development
|
72
64
|
prerelease: false
|
73
65
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
66
|
requirements:
|
76
|
-
- -
|
67
|
+
- - '>='
|
77
68
|
- !ruby/object:Gem::Version
|
78
69
|
version: '0'
|
79
70
|
description: A rack middleware for enforcing rewrite rules. In many cases you can
|
@@ -102,26 +93,25 @@ files:
|
|
102
93
|
- test/test_helper.rb
|
103
94
|
homepage: http://github.com/jtrupiano/rack-rewrite
|
104
95
|
licenses: []
|
96
|
+
metadata: {}
|
105
97
|
post_install_message:
|
106
98
|
rdoc_options:
|
107
99
|
- --charset=UTF-8
|
108
100
|
require_paths:
|
109
101
|
- lib
|
110
102
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
-
none: false
|
112
103
|
requirements:
|
113
|
-
- -
|
104
|
+
- - '>='
|
114
105
|
- !ruby/object:Gem::Version
|
115
106
|
version: '0'
|
116
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
-
none: false
|
118
108
|
requirements:
|
119
|
-
- -
|
109
|
+
- - '>='
|
120
110
|
- !ruby/object:Gem::Version
|
121
111
|
version: '0'
|
122
112
|
requirements: []
|
123
113
|
rubyforge_project: johntrupiano
|
124
|
-
rubygems_version:
|
114
|
+
rubygems_version: 2.0.3
|
125
115
|
signing_key:
|
126
116
|
specification_version: 3
|
127
117
|
summary: A rack middleware for enforcing rewrite rules
|