rack-rewrite 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +23 -0
- data/README.rdoc +110 -19
- data/TODO +9 -4
- data/VERSION +1 -1
- data/lib/rack-rewrite.rb +1 -1
- data/lib/rack-rewrite/rule.rb +79 -28
- data/rack-rewrite.gemspec +3 -2
- data/test/geminstaller.yml +9 -0
- data/test/rule_test.rb +156 -9
- data/test/test_helper.rb +2 -0
- metadata +3 -2
- data/HISTORY.rdoc +0 -10
data/History.rdoc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
=== 0.2.0 / 2009-11-14
|
2
|
+
* API
|
3
|
+
* Allow Proc's to be be passed as the 'to' argument to rule declarations
|
4
|
+
* Introduce rule guard support using :if => Proc.new option.
|
5
|
+
* :send_file and :x_send_file rules
|
6
|
+
* proxy rack_env to rule guards for arbitrary rule writing
|
7
|
+
|
8
|
+
* Documentation
|
9
|
+
* Add example of writing capistrano maintenance page rewrite rules
|
10
|
+
* Add examples of rule guards and arbitrary rewriting
|
11
|
+
* Add examples of :send_file and :x_send_file rules
|
12
|
+
|
13
|
+
=== 0.1.3 / 2009-11-14
|
14
|
+
* Maintenance
|
15
|
+
* Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
|
16
|
+
* Documentation
|
17
|
+
* Add HISTORY.rdoc
|
18
|
+
|
19
|
+
=== 0.1.2 / 2009-10-13
|
20
|
+
|
21
|
+
* Initial Feature Set
|
22
|
+
* :r301, :r302 and :redirect are supported in the rewrite DSL
|
23
|
+
* Regex matching/substitution patterns supported in rules
|
data/README.rdoc
CHANGED
@@ -3,6 +3,29 @@
|
|
3
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
|
+
== Usage
|
7
|
+
|
8
|
+
=== Sample rackup file
|
9
|
+
|
10
|
+
gem 'rack-rewrite', '~> 0.1.3'
|
11
|
+
require 'rack-rewrite
|
12
|
+
use Rack::Rewrite do
|
13
|
+
rewrite '/wiki/John_Trupiano', '/john'
|
14
|
+
r301 '/wiki/Yair_Flicker', '/yair'
|
15
|
+
r302 '/wiki/Greg_Jastrab', '/greg'
|
16
|
+
r301 %r{/wiki/(\w+)_\w+}, '/$1'
|
17
|
+
end
|
18
|
+
|
19
|
+
=== Sample usage in a rails app
|
20
|
+
config.gem 'rack-rewrite', '~> 0.1.3'
|
21
|
+
require 'rack-rewrite
|
22
|
+
config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
|
23
|
+
rewrite '/wiki/John_Trupiano', '/john'
|
24
|
+
r301 '/wiki/Yair_Flicker', '/yair'
|
25
|
+
r302 '/wiki/Greg_Jastrab', '/greg'
|
26
|
+
r301 %r{/wiki/(\w+)_\w+}, '/$1'
|
27
|
+
end
|
28
|
+
|
6
29
|
== Use Cases
|
7
30
|
|
8
31
|
=== Rebuild of existing site in a new technology
|
@@ -30,27 +53,49 @@ to these routes and keep your routes.rb clean.
|
|
30
53
|
|
31
54
|
rewrite %r{/features(.*)}, '/facial_features$1'
|
32
55
|
|
33
|
-
|
34
|
-
|
35
|
-
gem 'rack-rewrite', '~> 0.1.2'
|
36
|
-
require 'rack-rewrite
|
37
|
-
use Rack::Rewrite do
|
38
|
-
rewrite '/wiki/John_Trupiano', '/john'
|
39
|
-
r301 '/wiki/Yair_Flicker', '/yair'
|
40
|
-
r302 '/wiki/Greg_Jastrab', '/greg'
|
41
|
-
r301 %r{/wiki/(\w+)_\w+}, '/$1'
|
42
|
-
end
|
56
|
+
=== Site Maintenance
|
43
57
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
Most capistrano users will be familiar with the following Apache rewrite rules:
|
59
|
+
|
60
|
+
RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$
|
61
|
+
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
|
62
|
+
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
|
63
|
+
RewriteRule ^.*$ /system/maintenance.html [L]
|
64
|
+
|
65
|
+
This rewrite rule says to render a maintenance page for all non-asset requests
|
66
|
+
if the maintenance file exists. In capistrano, you can quickly upload a
|
67
|
+
maintenance file using:
|
68
|
+
|
69
|
+
cap deploy:web:disable REASON=upgrade UNTIL=12:30PM
|
53
70
|
|
71
|
+
We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
|
72
|
+
|
73
|
+
maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
|
74
|
+
send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
|
75
|
+
File.exists?(maintenance_file) && !%w(css jpg png).any? {|ext| maintenance_file =~ Regexp.new("\.#{ext}$")}
|
76
|
+
}
|
77
|
+
|
78
|
+
If you're running Ruby 1.9, this rule is highly simplified:
|
79
|
+
|
80
|
+
maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
|
81
|
+
send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env|
|
82
|
+
File.exists?(maintenance_file)
|
83
|
+
}
|
84
|
+
|
85
|
+
For those using the oniguruma gem with their ruby 1.8 installation, you can
|
86
|
+
get away with this:
|
87
|
+
|
88
|
+
maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
|
89
|
+
send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenace_file, :if => Proc.new { |rack_env|
|
90
|
+
File.exists?(maintenance_file)
|
91
|
+
}
|
92
|
+
|
93
|
+
NOTE: These replacement rules actually issue redirects. The apache config
|
94
|
+
snippet referenced above actually performs a rewrite. With Rack::Rewrite
|
95
|
+
we currently have to issue a redirect because rails will not recognize the
|
96
|
+
maintenance route. If you have any ideas on how to fix this, I would love
|
97
|
+
to discuss it with you.
|
98
|
+
|
54
99
|
== Rewrite Rules
|
55
100
|
|
56
101
|
=== :rewrite
|
@@ -86,6 +131,19 @@ Recall that rules are interpreted from top to bottom. So you can install
|
|
86
131
|
"default" rewrite rules if you like. [2] is a sample default rule that
|
87
132
|
will redirect all other requests to the wiki to a google search.
|
88
133
|
|
134
|
+
=== :send_file, :x_send_file
|
135
|
+
|
136
|
+
Calls to #send_file and #x_send_file also have the same signature as #rewrite.
|
137
|
+
If the rule matches, the 'to' parameter is interpreted as a path to a file
|
138
|
+
to be rendered instead of passing the application call up the rack stack.
|
139
|
+
|
140
|
+
send_file /*/, 'public/spammers.htm', :if => Proc.new { |rack_env|
|
141
|
+
rack_env['HTTP_REFERER'] =~ 'spammers.com'
|
142
|
+
}
|
143
|
+
x_send_file /^blog\/.*/, 'public/blog_offline.htm', :if => Proc.new { |rack_env|
|
144
|
+
File.exists?('public/blog_offline.htm')
|
145
|
+
}
|
146
|
+
|
89
147
|
== Tips
|
90
148
|
|
91
149
|
=== Keeping your querystring
|
@@ -99,6 +157,39 @@ capture group and substitution pattern in your rewrite rule to achieve this.
|
|
99
157
|
This rule will store the querystring in a capture group (via '(?.*)' ) and
|
100
158
|
will substitute the querystring back into the rewritten URL (via $1).
|
101
159
|
|
160
|
+
=== Rule Guards
|
161
|
+
|
162
|
+
All rules support passing guards as Procs/lambdas. Guards simply return
|
163
|
+
true or false indicating whether the rule declaration is a match. The
|
164
|
+
following example demonstrates how the presence of a maintenance page
|
165
|
+
on the filesystem can be utilized to take your site(s) offline.
|
166
|
+
|
167
|
+
maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
|
168
|
+
x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
|
169
|
+
File.exists?(maintenance_file)
|
170
|
+
}
|
171
|
+
|
172
|
+
=== Arbitrary Rewriting
|
173
|
+
|
174
|
+
All rules support passing a Proc as the second argument allowing you to
|
175
|
+
perform arbitrary rewrites. The following rule will rewrite all requests
|
176
|
+
received between 12AM and 8AM to an unavailable page.
|
177
|
+
|
178
|
+
rewrite %r{(.*)}, lambda { |match, rack_env|
|
179
|
+
Time.now.hour < 8 ? "/unavailable.html" : match[1]
|
180
|
+
}
|
181
|
+
|
182
|
+
Note also that the rack environment is yielded to the lambda. The
|
183
|
+
following redirect rule will send all visitors coming from a
|
184
|
+
|
185
|
+
rewrite %r{(.*)}, lambda { |match, rack_env|
|
186
|
+
if rack_env['HTTP_REFERER'] =~ /microsoft\.com/
|
187
|
+
|
188
|
+
Time.now.hour < 8 ? "/unavailable.html" : match[1]
|
189
|
+
}
|
190
|
+
|
191
|
+
|
192
|
+
|
102
193
|
== Copyright
|
103
194
|
|
104
195
|
Copyright (c) 2009 John Trupiano. See LICENSE for details.
|
data/TODO
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
*
|
2
|
-
* Add :
|
3
|
-
* Add support for specifying a config file instead of passing a block (e.g. config/rewrite.rb)
|
4
|
-
* Better message than "Redirecting..." -- how about html that says where it's being redirected to?
|
1
|
+
* OUTSTANDING
|
2
|
+
* Add :host support to restrict which URL's a rewrite rule matches [10/15/09]
|
3
|
+
* Add support for specifying a config file instead of passing a block (e.g. config/rewrite.rb) [10/15/09]
|
4
|
+
* Better message than "Redirecting..." -- how about html that says where it's being redirected to? [10/16/09]
|
5
|
+
* Provide testing helpers (e.g. should_rewrite) to facilitate straightforward testing. [10/25/09]
|
6
|
+
* Allow rules to return arbitrary html (e.g. the contents of the maintenance page) [10/25/09]
|
7
|
+
|
8
|
+
* COMPLETED
|
9
|
+
* Add :if => lambda support for arbitrary conditional rule application (this will allow us to do the capistrano maintenance page w/o apache's mod_rewrite) [10/15/09]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/rack-rewrite.rb
CHANGED
data/lib/rack-rewrite/rule.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack/mime'
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
class Rewrite
|
3
5
|
class RuleSet
|
@@ -15,40 +17,64 @@ module Rack
|
|
15
17
|
# user's browser will continue to show the initially requested URL.
|
16
18
|
#
|
17
19
|
# rewrite '/wiki/John_Trupiano', '/john'
|
18
|
-
# rewrite %r{/wiki/(\w+)_\w+}, '/$1'
|
19
|
-
|
20
|
-
|
20
|
+
# rewrite %r{/wiki/(\w+)_\w+}, '/$1'
|
21
|
+
# rewrite %r{(.*)}, '/maintenance.html', :if => lambda { File.exists?('maintenance.html') }
|
22
|
+
def rewrite(from, to, *args)
|
23
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
24
|
+
@rules << Rule.new(:rewrite, from, to, options[:if])
|
21
25
|
end
|
22
26
|
|
23
27
|
# Creates a redirect rule that will send a 301 when matching.
|
24
28
|
#
|
25
29
|
# r301 '/wiki/John_Trupiano', '/john'
|
26
30
|
# r301 '/contact-us.php', '/contact-us'
|
27
|
-
def r301(from, to)
|
28
|
-
|
31
|
+
def r301(from, to, *args)
|
32
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
33
|
+
@rules << Rule.new(:r301, from, to, options[:if])
|
29
34
|
end
|
30
35
|
|
31
36
|
# Creates a redirect rule that will send a 302 when matching.
|
32
37
|
#
|
33
38
|
# r302 '/wiki/John_Trupiano', '/john'
|
34
39
|
# r302 '/wiki/(.*)', 'http://www.google.com/?q=$1'
|
35
|
-
def r302(from, to)
|
36
|
-
|
40
|
+
def r302(from, to, *args)
|
41
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
42
|
+
@rules << Rule.new(:r302, from, to, options[:if])
|
37
43
|
end
|
44
|
+
|
45
|
+
# Creates a rule that will render a file if matched.
|
46
|
+
#
|
47
|
+
# send_file /*/, 'public/system/maintenance.html',
|
48
|
+
# :if => { File.exists?('public/system/maintenance.html') }
|
49
|
+
def send_file(from, to, *args)
|
50
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
51
|
+
@rules << Rule.new(:send_file, from, to, options[:if])
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a rule that will render a file using x-send-file
|
55
|
+
# if matched.
|
56
|
+
#
|
57
|
+
# x_send_file /*/, 'public/system/maintenance.html',
|
58
|
+
# :if => { File.exists?('public/system/maintenance.html') }
|
59
|
+
def x_send_file(from, to, *args)
|
60
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
61
|
+
@rules << Rule.new(:x_send_file, from, to, options[:if])
|
62
|
+
end
|
38
63
|
end
|
39
64
|
|
40
65
|
# TODO: Break rules into subclasses
|
41
66
|
class Rule #:nodoc:
|
42
|
-
attr_reader :rule_type, :from, :to
|
43
|
-
def initialize(rule_type, from, to) #:nodoc:
|
44
|
-
@rule_type, @from, @to = rule_type, from, to
|
67
|
+
attr_reader :rule_type, :from, :to, :guard
|
68
|
+
def initialize(rule_type, from, to, guard=nil) #:nodoc:
|
69
|
+
@rule_type, @from, @to, @guard = rule_type, from, to, guard
|
45
70
|
end
|
46
71
|
|
47
|
-
def matches?(
|
48
|
-
|
49
|
-
|
72
|
+
def matches?(rack_env) #:nodoc:
|
73
|
+
return false if !guard.nil? && !guard.call(rack_env)
|
74
|
+
path = rack_env['REQUEST_URI']
|
75
|
+
if self.from.is_a?(Regexp) || (Object.const_defined?(:Oniguruma) && self.from.is_a?(Oniguruma::ORegexp))
|
50
76
|
path =~ self.from
|
51
|
-
|
77
|
+
elsif self.from.is_a?(String)
|
52
78
|
path == self.from
|
53
79
|
else
|
54
80
|
false
|
@@ -58,7 +84,7 @@ module Rack
|
|
58
84
|
# Either (a) return a Rack response (short-circuiting the Rack stack), or
|
59
85
|
# (b) alter env as necessary and return true
|
60
86
|
def apply!(env) #:nodoc:
|
61
|
-
interpreted_to = self.send(:interpret_to, env['REQUEST_URI'])
|
87
|
+
interpreted_to = self.send(:interpret_to, env['REQUEST_URI'], env)
|
62
88
|
case self.rule_type
|
63
89
|
when :r301
|
64
90
|
[301, {'Location' => interpreted_to, 'Content-Type' => 'text/html'}, ['Redirecting...']]
|
@@ -75,25 +101,50 @@ module Rack
|
|
75
101
|
env['QUERYSTRING'] = ''
|
76
102
|
end
|
77
103
|
true
|
104
|
+
when :send_file
|
105
|
+
[200, {
|
106
|
+
'Content-Length' => ::File.size(interpreted_to).to_s,
|
107
|
+
'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))
|
108
|
+
}, ::File.read(interpreted_to)]
|
109
|
+
when :x_send_file
|
110
|
+
[200, {
|
111
|
+
'X-Sendfile' => interpreted_to,
|
112
|
+
'Content-Length' => ::File.size(interpreted_to).to_s,
|
113
|
+
'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))
|
114
|
+
}, []]
|
78
115
|
else
|
79
116
|
raise Exception.new("Unsupported rule: #{self.rule_type}")
|
80
117
|
end
|
81
118
|
end
|
82
119
|
|
83
120
|
private
|
84
|
-
|
85
|
-
|
86
|
-
if
|
87
|
-
if from_match_data = self.from.match(path)
|
88
|
-
computed_to = self.to.dup
|
89
|
-
(from_match_data.size - 1).downto(1) do |num|
|
90
|
-
computed_to.gsub!("$#{num}", from_match_data[num])
|
91
|
-
end
|
92
|
-
return computed_to
|
93
|
-
end
|
94
|
-
end
|
121
|
+
def interpret_to(path, env={}) #:nodoc:
|
122
|
+
return interpret_to_proc(path, env) if self.to.is_a?(Proc)
|
123
|
+
return computed_to(path) if compute_to?(path)
|
95
124
|
self.to
|
96
125
|
end
|
97
|
-
|
126
|
+
|
127
|
+
def interpret_to_proc(path, env)
|
128
|
+
return self.to.call(match(path), env) if self.from.is_a?(Regexp)
|
129
|
+
self.to.call(self.from, env)
|
130
|
+
end
|
131
|
+
|
132
|
+
def compute_to?(path)
|
133
|
+
self.from.is_a?(Regexp) && match(path)
|
134
|
+
end
|
135
|
+
|
136
|
+
def match(path)
|
137
|
+
self.from.match(path)
|
138
|
+
end
|
139
|
+
|
140
|
+
def computed_to(path)
|
141
|
+
# is there a better way to do this?
|
142
|
+
computed_to = self.to.dup
|
143
|
+
(match(path).size - 1).downto(1) do |num|
|
144
|
+
computed_to.gsub!("$#{num}", match(path)[num])
|
145
|
+
end
|
146
|
+
return computed_to
|
147
|
+
end
|
148
|
+
end
|
98
149
|
end
|
99
|
-
end
|
150
|
+
end
|
data/rack-rewrite.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rack-rewrite}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Trupiano"]
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
21
|
".gitignore",
|
22
|
-
"
|
22
|
+
"History.rdoc",
|
23
23
|
"LICENSE",
|
24
24
|
"README.rdoc",
|
25
25
|
"Rakefile",
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
"lib/rack-rewrite.rb",
|
29
29
|
"lib/rack-rewrite/rule.rb",
|
30
30
|
"rack-rewrite.gemspec",
|
31
|
+
"test/geminstaller.yml",
|
31
32
|
"test/rack-rewrite_test.rb",
|
32
33
|
"test/rule_test.rb",
|
33
34
|
"test/test_helper.rb"
|
data/test/rule_test.rb
CHANGED
@@ -1,7 +1,36 @@
|
|
1
|
-
require 'test_helper'
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
2
|
|
3
3
|
class RuleTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def self.should_pass_maintenance_tests
|
6
|
+
context 'and the maintenance file does in fact exist' do
|
7
|
+
setup { File.stubs(:exists?).returns(true) }
|
4
8
|
|
9
|
+
should('match for the root') { assert @rule.matches?({'REQUEST_URI' => '/'}) }
|
10
|
+
should('match for a regular rails route') { assert @rule.matches?({'REQUEST_URI' => '/users/1'}) }
|
11
|
+
should('match for an html page') { assert @rule.matches?({'REQUEST_URI' => '/index.html'}) }
|
12
|
+
should('not match for a css file') { assert !@rule.matches?({'REQUEST_URI' => '/stylesheets/style.css'}) }
|
13
|
+
should('not match for a jpg file') { assert !@rule.matches?({'REQUEST_URI' => '/images/sls.jpg'}) }
|
14
|
+
should('not match for a png file') { assert !@rule.matches?({'REQUEST_URI' => '/images/sls.png'}) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.negative_lookahead_supported?
|
19
|
+
begin
|
20
|
+
require 'oniguruma'
|
21
|
+
rescue LoadError; end
|
22
|
+
RUBY_VERSION =~ /^1\.9/ || Object.const_defined?(:Oniguruma)
|
23
|
+
end
|
24
|
+
|
25
|
+
def negative_lookahead_regexp
|
26
|
+
if RUBY_VERSION =~ /^1\.9/
|
27
|
+
# have to use the constructor instead of the literal syntax b/c load errors occur in Ruby 1.8
|
28
|
+
Regexp.new("(.*)$(?<!css|png|jpg)")
|
29
|
+
else
|
30
|
+
Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
5
34
|
context '#Rule#apply' do
|
6
35
|
should 'set Location header to result of #interpret_to for a 301' do
|
7
36
|
rule = Rack::Rewrite::Rule.new(:r301, %r{/abc}, '/def')
|
@@ -40,6 +69,64 @@ class RuleTest < Test::Unit::TestCase
|
|
40
69
|
assert_equal 'text/html', rule.apply!(env)[1]['Content-Type']
|
41
70
|
end
|
42
71
|
end
|
72
|
+
|
73
|
+
context 'Given an :x_send_file rule that matches' do
|
74
|
+
setup do
|
75
|
+
@file = File.join(TEST_ROOT, 'geminstaller.yml')
|
76
|
+
@rule = Rack::Rewrite::Rule.new(:x_send_file, /.*/, @file)
|
77
|
+
env = {'PATH_INFO' => '/abc'}
|
78
|
+
@response = @rule.apply!(env)
|
79
|
+
end
|
80
|
+
|
81
|
+
should 'return 200' do
|
82
|
+
assert_equal 200, @response[0]
|
83
|
+
end
|
84
|
+
|
85
|
+
should 'return an X-Sendfile header' do
|
86
|
+
assert @response[1].has_key?('X-Sendfile')
|
87
|
+
end
|
88
|
+
|
89
|
+
should 'return a Content-Type of text/yaml' do
|
90
|
+
assert_equal 'text/yaml', @response[1]['Content-Type']
|
91
|
+
end
|
92
|
+
|
93
|
+
should 'return the proper Content-Length' do
|
94
|
+
assert_equal File.size(@file).to_s, @response[1]['Content-Length']
|
95
|
+
end
|
96
|
+
|
97
|
+
should 'return empty content' do
|
98
|
+
assert_equal [], @response[2]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'Given a :send_file rule that matches' do
|
103
|
+
setup do
|
104
|
+
@file = File.join(TEST_ROOT, 'geminstaller.yml')
|
105
|
+
@rule = Rack::Rewrite::Rule.new(:send_file, /.*/, @file)
|
106
|
+
env = {'PATH_INFO' => '/abc'}
|
107
|
+
@response = @rule.apply!(env)
|
108
|
+
end
|
109
|
+
|
110
|
+
should 'return 200' do
|
111
|
+
assert_equal 200, @response[0]
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'not return an X-Sendfile header' do
|
115
|
+
assert !@response[1].has_key?('X-Sendfile')
|
116
|
+
end
|
117
|
+
|
118
|
+
should 'return a Content-Type of text/yaml' do
|
119
|
+
assert_equal 'text/yaml', @response[1]['Content-Type']
|
120
|
+
end
|
121
|
+
|
122
|
+
should 'return the proper Content-Length' do
|
123
|
+
assert_equal File.size(@file).to_s, @response[1]['Content-Length']
|
124
|
+
end
|
125
|
+
|
126
|
+
should 'return the contents of geminstaller.yml' do
|
127
|
+
assert_equal File.read(@file), @response[2]
|
128
|
+
end
|
129
|
+
end
|
43
130
|
end
|
44
131
|
|
45
132
|
context 'Rule#matches' do
|
@@ -49,15 +136,15 @@ class RuleTest < Test::Unit::TestCase
|
|
49
136
|
end
|
50
137
|
|
51
138
|
should 'match PATH_INFO of /features' do
|
52
|
-
assert @rule.matches?("/features")
|
139
|
+
assert @rule.matches?({'REQUEST_URI' => "/features"})
|
53
140
|
end
|
54
141
|
|
55
142
|
should 'not match PATH_INFO of /features.xml' do
|
56
|
-
assert !@rule.matches?("/features.xml")
|
143
|
+
assert !@rule.matches?({'REQUEST_URI' => "/features.xml"})
|
57
144
|
end
|
58
145
|
|
59
146
|
should 'not match PATH_INFO of /my_features' do
|
60
|
-
assert !@rule.matches?("/my_features")
|
147
|
+
assert !@rule.matches?({'REQUEST_URI' => "/my_features"})
|
61
148
|
end
|
62
149
|
end
|
63
150
|
|
@@ -67,23 +154,72 @@ class RuleTest < Test::Unit::TestCase
|
|
67
154
|
end
|
68
155
|
|
69
156
|
should 'match PATH_INFO of /features' do
|
70
|
-
assert @rule.matches?("/features")
|
157
|
+
assert @rule.matches?({'REQUEST_URI' => "/features"})
|
71
158
|
end
|
72
159
|
|
73
160
|
should 'match PATH_INFO of /features.xml' do
|
74
|
-
assert @rule.matches?('/features.xml')
|
161
|
+
assert @rule.matches?({'REQUEST_URI' => '/features.xml'})
|
75
162
|
end
|
76
163
|
|
77
164
|
should 'match PATH_INFO of /features/1' do
|
78
|
-
assert @rule.matches?('/features/1')
|
165
|
+
assert @rule.matches?({'REQUEST_URI' => '/features/1'})
|
79
166
|
end
|
80
167
|
|
81
168
|
should 'match PATH_INFO of /features?filter_by=name' do
|
82
|
-
assert @rule.matches?('/features?filter_by_name=name')
|
169
|
+
assert @rule.matches?({'REQUEST_URI' => '/features?filter_by_name=name'})
|
83
170
|
end
|
84
171
|
|
85
172
|
should 'match PATH_INFO of /features/1?hide_bio=1' do
|
86
|
-
assert @rule.matches?('/features/1?hide_bio=1')
|
173
|
+
assert @rule.matches?({'REQUEST_URI' => '/features/1?hide_bio=1'})
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'Given a rule with a guard that checks for the presence of a file' do
|
178
|
+
setup do
|
179
|
+
@rule = Rack::Rewrite::Rule.new(:rewrite, %r{(.)*}, '/maintenance.html', lambda { |rack_env|
|
180
|
+
File.exists?('maintenance.html')
|
181
|
+
})
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'when the file exists' do
|
185
|
+
setup do
|
186
|
+
File.stubs(:exists?).returns(true)
|
187
|
+
end
|
188
|
+
|
189
|
+
should 'match' do
|
190
|
+
assert @rule.matches?({'REQUEST_URI' => '/anything/should/match'})
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'when the file does not exist' do
|
195
|
+
setup do
|
196
|
+
File.stubs(:exists?).returns(false)
|
197
|
+
end
|
198
|
+
|
199
|
+
should 'not match' do
|
200
|
+
assert !@rule.matches?({'REQUEST_URI' => '/nothing/should/match'})
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'Given the capistrano maintenance.html rewrite rule given in our README' do
|
206
|
+
setup do
|
207
|
+
@rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env|
|
208
|
+
maintenance_file = File.join('system', 'maintenance.html')
|
209
|
+
File.exists?(maintenance_file) && !%w(css jpg png).any? {|ext| rack_env['REQUEST_URI'] =~ Regexp.new("\.#{ext}$")}
|
210
|
+
})
|
211
|
+
end
|
212
|
+
should_pass_maintenance_tests
|
213
|
+
end
|
214
|
+
|
215
|
+
if negative_lookahead_supported?
|
216
|
+
context 'Given the negative lookahead regular expression version of the capistrano maintenance.html rewrite rule given in our README' do
|
217
|
+
setup do
|
218
|
+
@rule = Rack::Rewrite::Rule.new(:rewrite, negative_lookahead_regexp, '/system/maintenance.html', lambda { |rack_env|
|
219
|
+
File.exists?(File.join('public', 'system', 'maintenance.html'))
|
220
|
+
})
|
221
|
+
end
|
222
|
+
should_pass_maintenance_tests
|
87
223
|
end
|
88
224
|
end
|
89
225
|
end
|
@@ -109,5 +245,16 @@ class RuleTest < Test::Unit::TestCase
|
|
109
245
|
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')
|
110
246
|
assert_equal 'jihgfedcba', rule.send(:interpret_to, "abcdefghij")
|
111
247
|
end
|
248
|
+
|
249
|
+
should 'call to with from when it is a lambda' do
|
250
|
+
rule = Rack::Rewrite::Rule.new(:rewrite, 'a', lambda { |from, env| from * 2 })
|
251
|
+
assert_equal 'aa', rule.send(:interpret_to, 'a')
|
252
|
+
end
|
253
|
+
|
254
|
+
should 'call to with from match data' do
|
255
|
+
rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, lambda {|match, env| "people-#{match[1].to_i * 3}#{match[2]}"})
|
256
|
+
assert_equal 'people-3?show_bio=1', rule.send(:interpret_to, '/person_1?show_bio=1')
|
257
|
+
end
|
112
258
|
end
|
259
|
+
|
113
260
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-rewrite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Trupiano
|
@@ -34,7 +34,7 @@ extra_rdoc_files:
|
|
34
34
|
files:
|
35
35
|
- .document
|
36
36
|
- .gitignore
|
37
|
-
-
|
37
|
+
- History.rdoc
|
38
38
|
- LICENSE
|
39
39
|
- README.rdoc
|
40
40
|
- Rakefile
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/rack-rewrite.rb
|
44
44
|
- lib/rack-rewrite/rule.rb
|
45
45
|
- rack-rewrite.gemspec
|
46
|
+
- test/geminstaller.yml
|
46
47
|
- test/rack-rewrite_test.rb
|
47
48
|
- test/rule_test.rb
|
48
49
|
- test/test_helper.rb
|
data/HISTORY.rdoc
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
=== 0.1.3 / 2009-11-14
|
2
|
-
* Maintenance
|
3
|
-
* Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
|
4
|
-
* Documentation
|
5
|
-
* Add HISTORY.rdoc
|
6
|
-
|
7
|
-
=== 0.1.2 / 2009-10-15
|
8
|
-
* API
|
9
|
-
* rewrite, r301 and r302 rules
|
10
|
-
* regular expression matching and substitution rules
|