rack-rewrite 0.1.3 → 0.2.0
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/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
|