rack-rewrite-matches 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ end
@@ -0,0 +1,61 @@
1
+ === 1.2.1 / 2011-09-20
2
+ * Maintenance
3
+ * Use Rack::Request to match the host
4
+
5
+ === 1.2.0 / 2011-09-20
6
+ * API
7
+ * :headers option to send additional headers with the response
8
+
9
+ === 1.1.0 / 2011-08-15
10
+ * API
11
+ * :host and :method option to match SERVER_NAME and REQUEST_METHOD env params.
12
+ * :not option to negative match against path.
13
+ * Maintenance
14
+ * Refactored internals a bit.
15
+
16
+ === 1.0.2 / 2010-10-01
17
+ * Maintenance
18
+ * :send_file rules return content in an Array for Ruby 1.9.2 compatibility
19
+
20
+ === 1.0.1 / 2010-09-17
21
+ * Maintenance
22
+ * Set Content-Type based on file extension of file/location being redirected to. Addresses GitHub Issue #8.
23
+
24
+ === 1.0.0 / 2010-05-13
25
+ * API
26
+ * Fix rack 1.1.0 / rails3 compatibility by eliminating reliance on REQUEST_URI env param. Paths are now constructed with PATH_INFO and QUERY_STRING
27
+ * Follow rack directory/require convention: require 'rack/rewrite' instead of 'rack-rewrite'
28
+ * Include an HTML anchor tag linked to where the URL being redirected to in the body of 301's and 302's
29
+
30
+ === 0.2.1 / 2010-01-06
31
+ * API
32
+ * Implement $& substitution pattern (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
33
+
34
+ * Maintenance
35
+ * Ignore empty captures instead of failing during subsitution (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
36
+ * Play nice with Rack::Test requests which only set PATH_INFO and not REQUEST_URI (thanks to {@docunext}[http://github.com/docunext])
37
+ * Use QUERY_STRING instead of QUERYSTRING as per Rack spec. Closes Issue #1.
38
+
39
+ === 0.2.0 / 2009-11-14
40
+ * API
41
+ * Allow Proc's to be be passed as the 'to' argument to rule declarations
42
+ * Introduce rule guard support using :if => Proc.new option.
43
+ * :send_file and :x_send_file rules
44
+ * proxy rack_env to rule guards for arbitrary rule writing
45
+
46
+ * Documentation
47
+ * Add example of writing capistrano maintenance page rewrite rules
48
+ * Add examples of rule guards and arbitrary rewriting
49
+ * Add examples of :send_file and :x_send_file rules
50
+
51
+ === 0.1.3 / 2009-11-14
52
+ * Maintenance
53
+ * Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
54
+ * Documentation
55
+ * Add HISTORY.rdoc
56
+
57
+ === 0.1.2 / 2009-10-13
58
+
59
+ * Initial Feature Set
60
+ * :r301, :r302 and :redirect are supported in the rewrite DSL
61
+ * Regex matching/substitution patterns supported in rules
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 — John Trupiano, Travis Jeffery
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,332 @@
1
+ # rack-rewrite
2
+
3
+ A rack middleware for defining and applying rewrite rules. In many cases you
4
+ can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
5
+
6
+ ## Usage Examples
7
+
8
+ * [Rack::Rewrite for Site Maintenance and Downtime](http://blog.smartlogicsolutions.com/2009/11/16/rack-rewrite-for-site-maintenance-and-downtime/)
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
+
11
+ ## Usage Details
12
+
13
+ ### Sample rackup file
14
+
15
+ ```ruby
16
+ gem 'rack-rewrite', '~> 1.2.1'
17
+ require 'rack/rewrite'
18
+ use Rack::Rewrite do
19
+ rewrite '/wiki/John_Trupiano', '/john'
20
+ r301 '/wiki/Yair_Flicker', '/yair'
21
+ r302 '/wiki/Greg_Jastrab', '/greg'
22
+ r301 %r{/wiki/(\w+)_\w+}, '/$1'
23
+ end
24
+ ```
25
+
26
+ ### Sample usage in a rails app
27
+
28
+ ```ruby
29
+ config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
30
+ rewrite '/wiki/John_Trupiano', '/john'
31
+ r301 '/wiki/Yair_Flicker', '/yair'
32
+ r302 '/wiki/Greg_Jastrab', '/greg'
33
+ r301 %r{/wiki/(\w+)_\w+}, '/$1'
34
+ end
35
+ ```
36
+
37
+ ## Redirection codes
38
+
39
+ All redirect status codes from the [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) are supported:
40
+
41
+ * 301 moved permanently
42
+ * 302 found
43
+ * 303 see other
44
+ * 307 temporary redirect
45
+
46
+ These translate to the following methods inside the Rack::Rewrite block:
47
+
48
+ ```ruby
49
+ r301 '/wiki/John_Trupiano', '/john'
50
+ moved_permanently '/wiki/John_Trupiano', '/john'
51
+ p '/wiki/John_Trupiano', '/john' # shortcut alias
52
+
53
+ r302 '/wiki/John_Trupiano', '/john'
54
+ found '/wiki/John_Trupiano', '/john'
55
+
56
+ r303 '/wiki/John_Trupiano', '/john'
57
+ see_other '/wiki/John_Trupiano', '/john'
58
+
59
+ r307 '/wiki/John_Trupiano', '/john'
60
+ temporary_redirect '/wiki/John_Trupiano', '/john'
61
+ t '/wiki/John_Trupiano', '/john' # shortcut alias
62
+ ```
63
+
64
+ The 303 and 307 codes were added to the HTTP spec to make unambiguously clear
65
+ what clients should do with the request method. 303 means that the new request
66
+ should always be made via GET. 307 means that the new request should use the
67
+ same method as the original request. Status code 302 was left as it is, since
68
+ it was already in use by the time these issues came to light. In practice it
69
+ behaves the same as 303.
70
+
71
+ ## Use Cases
72
+
73
+ ### Rebuild of existing site in a new technology
74
+
75
+ It's very common for sites built in older technologies to be rebuilt with the
76
+ latest and greatest. Let's consider a site that has already established quite
77
+ a bit of "google juice." When we launch the new site, we don't want to lose
78
+ that hard-earned reputation. By writing rewrite rules that issue 301's for
79
+ old URL's, we can "transfer" that google ranking to the new site. An example
80
+ rule might look like:
81
+
82
+ ```ruby
83
+ r301 '/contact-us.php', '/contact-us'
84
+ r301 '/wiki/John_Trupiano', '/john'
85
+ ```
86
+
87
+ ### Retiring old routes
88
+
89
+ As a web application evolves you will undoubtedly reach a point where you need
90
+ to change the name of something (a model, e.g.). This name change will
91
+ typically require a similar change to your routing. The danger here is that
92
+ any URL's previously generated (in a transactional email for instance) will
93
+ have the URL hard-coded. In order for your rails app to continue to serve
94
+ this URL, you'll need to add an extra entry to your routes file.
95
+ Alternatively, you could use rack-rewrite to redirect or pass through requests
96
+ to these routes and keep your routes.rb clean.
97
+
98
+ ```ruby
99
+ rewrite %r{/features(.*)}, '/facial_features$1'
100
+ ```
101
+
102
+ ### CNAME alternative
103
+
104
+ In the event that you do not control your DNS, you can leverage Rack::Rewrite
105
+ to redirect to a canonical domain. In the following rule we utilize the
106
+ $& substitution operator to capture the entire request URI.
107
+
108
+ ```ruby
109
+ r301 %r{.*}, 'http://mynewdomain.com$&', :if => Proc.new {|rack_env|
110
+ rack_env['SERVER_NAME'] != 'mynewdomain.com'
111
+ }
112
+ ```
113
+
114
+ ### Site Maintenance
115
+
116
+ Most capistrano users will be familiar with the following Apache rewrite rules:
117
+
118
+ ```
119
+ RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$
120
+ RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
121
+ RewriteCond %{SCRIPT_FILENAME} !maintenance.html
122
+ RewriteRule ^.*$ /system/maintenance.html [L]
123
+ ```
124
+
125
+ 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
127
+ maintenance file using:
128
+
129
+ `cap deploy:web:disable REASON=upgrade UNTIL=12:30PM`
130
+
131
+ We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
132
+
133
+ ```ruby
134
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
135
+ send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
136
+ File.exists?(maintenance_file) && rack_env['PATH_INFO'] !~ /\.(css|jpg|png)/
137
+ }
138
+ ```
139
+
140
+ If you're running Ruby 1.9, this rule is simplified:
141
+
142
+ ```ruby
143
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
144
+ send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env|
145
+ File.exists?(maintenance_file)
146
+ }
147
+ ```
148
+
149
+ For those using the oniguruma gem with their ruby 1.8 installation, you can
150
+ get away with:
151
+
152
+ ```ruby
153
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
154
+ send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenance_file, :if => Proc.new { |rack_env|
155
+ File.exists?(maintenance_file)
156
+ }
157
+ ```
158
+
159
+ ## Rewrite Rules
160
+
161
+ ### :rewrite
162
+
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.
166
+ See these examples:
167
+
168
+ ```ruby
169
+ rewrite '/wiki/John_Trupiano', '/john' # [1]
170
+ rewrite %r{/wiki/(\w+)_\w+}, '/$1' # [2]
171
+ ```
172
+
173
+ 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
175
+ will be changed to /john for subsequent nodes in the Rack stack. Rails
176
+ reads these headers to determine which routes will match.
177
+
178
+ Rule [2] showcases the use of regular expressions and substitutions. [2] is a
179
+ 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
182
+ ( http://www.smartlogicsolutions.com ).
183
+
184
+ ### :r301, :r302, :r303, :r307
185
+
186
+ Calls to #r301 and #r302 have the same signature as #rewrite. The difference,
187
+ however, is that these actually short-circuit the rack stack and send back
188
+ their respective status codes. See these examples:
189
+
190
+ ```ruby
191
+ r301 '/wiki/John_Trupiano', '/john' # [1]
192
+ r301 '/wiki/(.*)', 'http://www.google.com/?q=$1' # [2]
193
+ ```
194
+
195
+ Recall that rules are interpreted from top to bottom. So you can install
196
+ "default" rewrite rules if you like. [2] is a sample default rule that
197
+ will redirect all other requests to the wiki to a google search.
198
+
199
+ ### :send_file, :x_send_file
200
+
201
+ Calls to #send_file and #x_send_file also have the same signature as #rewrite.
202
+ If the rule matches, the 'to' parameter is interpreted as a path to a file
203
+ to be rendered instead of passing the application call up the rack stack.
204
+
205
+ ```ruby
206
+ send_file /*/, 'public/spammers.htm', :if => Proc.new { |rack_env|
207
+ rack_env['HTTP_REFERER'] =~ 'spammers.com'
208
+ }
209
+ x_send_file /^blog\/.*/, 'public/blog_offline.htm', :if => Proc.new { |rack_env|
210
+ File.exists?('public/blog_offline.htm')
211
+ }
212
+ ```
213
+
214
+ ## Options Parameter
215
+
216
+ Each rewrite rule takes an optional options parameter. The following options
217
+ are supported.
218
+
219
+ ### :host
220
+
221
+ Using the :host option you can match requests to a specific hostname.
222
+
223
+ ```ruby
224
+ r301 "/features", "/facial_features", :host => "facerecognizer.com"
225
+ ```
226
+ This rule will only match when the hostname is "facerecognizer.com"
227
+
228
+ ### :headers
229
+
230
+ Using the :headers option you can set custom response headers e.g. for HTTP
231
+ caching instructions.
232
+
233
+ ```ruby
234
+ r301 "/features", "/facial_features", :headers => {'Cache-Control' => 'no-cache'}
235
+ ```
236
+
237
+ Please be aware that the :headers value above is evaluated only once at app boot and shared amongst all matching requests.
238
+
239
+ Use a Proc as the :headers option if you wish to determine the additional headers at request-time. For example:
240
+
241
+ ```ruby
242
+ # We want the Expires value to always be 1 year in the future from now. If
243
+ # we didn't use a Proc here, then the Expires value would be set just once
244
+ # at app startup. The Proc will be evaluated for each matching request.
245
+ send_file /^.+\.(?:ico|jpg|jpeg|png|gif|)$/,
246
+ 'public/$&',
247
+ :headers => lambda { { 'Expires' => 1.year.from_now.httpdate } }
248
+ ```
249
+
250
+ ### :method
251
+
252
+ Using the :method option you can restrict the matching of a rule by the HTTP
253
+ method of a given request.
254
+
255
+ ```ruby
256
+ # redirect GET's one way
257
+ r301 "/players", "/current_players", :method => :get
258
+
259
+ # and redirect POST's another way
260
+ r302 "/players", "/no_longer_available.html?message=No&longer&supported", :method => :post
261
+ ```
262
+
263
+ ### :if
264
+
265
+ 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
268
+ maintenance page on the filesystem can be utilized to take your site(s) offline.
269
+
270
+ ```ruby
271
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
272
+ x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
273
+ File.exists?(maintenance_file)
274
+ }
275
+ ```
276
+
277
+ ### :not
278
+
279
+ Using the :not option you can negatively match against the path. This can
280
+ be useful when writing a regular expression match is difficult.
281
+
282
+ ```ruby
283
+ rewrite %r{^\/features}, '/facial_features', :not => '/features'
284
+ ```
285
+
286
+ This will not match the relative URL /features but would match /features.xml.
287
+
288
+ ## Tips
289
+
290
+ ### Keeping your querystring
291
+
292
+ When rewriting a URL, you may want to keep your querystring in tact (for
293
+ example if you're tracking traffic sources). You will need to include a
294
+ capture group and substitution pattern in your rewrite rule to achieve this.
295
+
296
+ ```ruby
297
+ rewrite %r{/wiki/John_Trupiano(\?.*)?}, '/john$1'
298
+ ```
299
+
300
+ This rule will store the querystring in a capture group (via `(?.*)` ) and
301
+ will substitute the querystring back into the rewritten URL (via `$1`).
302
+
303
+ ### Arbitrary Rewriting
304
+
305
+ All rules support passing a Proc as the second argument allowing you to
306
+ perform arbitrary rewrites. The following rule will rewrite all requests
307
+ received between 12AM and 8AM to an unavailable page.
308
+
309
+ ```ruby
310
+ rewrite %r{(.*)}, lambda { |match, rack_env|
311
+ Time.now.hour < 8 ? "/unavailable.html" : match[1]
312
+ }
313
+ ```
314
+
315
+ ## Contribute
316
+
317
+ rack-rewrite is maintained by [@travisjeffery](http://github.com/travisjeffery).
318
+
319
+ Here's the most direct way to get your work merged into the project.
320
+
321
+ - Fork the project
322
+ - Clone down your fork
323
+ - Create a feature branch
324
+ - Hack away and add tests, not necessarily in that order
325
+ - Make sure everything still passes by running tests
326
+ - If necessary, rebase your commits into logical chunks without errors
327
+ - Push the branch up to your fork
328
+ - Send a pull request for your branch
329
+
330
+ ## Copyright
331
+
332
+ Copyright (c) 2012 — John Trupiano, Travis Jeffery. See LICENSE for details.
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rdoc/task'
5
+
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'lib' << 'test' << '.'
8
+ test.pattern = 'test/**/*_test.rb'
9
+ test.verbose = true
10
+ end
11
+
12
+ begin
13
+ require 'rcov/rcovtask'
14
+ Rcov::RcovTask.new do |test|
15
+ test.libs << 'test'
16
+ test.pattern = 'test/**/*_test.rb'
17
+ test.verbose = true
18
+ end
19
+ rescue LoadError
20
+ task :rcov do
21
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
22
+ end
23
+ end
24
+
25
+ task :default => :test
26
+
27
+ Rake::RDocTask.new do |rdoc|
28
+ if File.exist?('VERSION')
29
+ version = File.read('VERSION')
30
+ else
31
+ version = ""
32
+ end
33
+
34
+ rdoc.rdoc_dir = 'rdoc'
35
+ rdoc.title = "rack-rewrite #{version}"
36
+ rdoc.rdoc_files.include('README*')
37
+ rdoc.rdoc_files.include('History.rdoc')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end