refraction 0.1.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/MIT-LICENSE +20 -0
- data/README.md +117 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/geminstaller.yml +12 -0
- data/install.rb +21 -0
- data/lib/refraction.rb +141 -0
- data/spec/refraction_spec.rb +180 -0
- data/spec/spec_helper.rb +3 -0
- metadata +76 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Pivotal Labs
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
Refraction
|
2
|
+
==========
|
3
|
+
|
4
|
+
Refraction is a Rack middleware replacement for `mod_rewrite`. It can rewrite URLs before they are
|
5
|
+
processed by your web application, and can redirect using 301 and 302 status codes. Refraction is
|
6
|
+
thread-safe, so it doesn't need to be guarded by Rack::Lock.
|
7
|
+
|
8
|
+
The best thing about Refraction is that rewrite rules are written in plain old Ruby code, not some
|
9
|
+
funky web server config syntax. That means you can use Ruby regular expressions, case statements,
|
10
|
+
conditionals, and whatever else you feel like.
|
11
|
+
|
12
|
+
For example:
|
13
|
+
|
14
|
+
Refraction.configure do |req|
|
15
|
+
feedburner = "http://feeds.pivotallabs.com/pivotallabs"
|
16
|
+
|
17
|
+
if req.env['HTTP_USER_AGENT'] !~ /FeedBurner|FeedValidator/ && req.host =~ /pivotallabs\.com/
|
18
|
+
case req.path
|
19
|
+
when %r{^/(talks|blabs|blog)\.(atom|rss)$} ; req.found! "#{feedburner}/#{$1}.#{$2}"
|
20
|
+
when %r{^/users/(chris|edward)/blog\.(atom|rss)$} ; req.found! "#{feedburner}/#{$1}.#{$2}"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
case req.host
|
24
|
+
when 'tweed.pivotallabs.com'
|
25
|
+
req.rewrite! "http://pivotallabs.com/tweed#{req.path}"
|
26
|
+
when /([-\w]+\.)?pivotallabs\.com/
|
27
|
+
# passthrough with no change
|
28
|
+
else # wildcard domains (e.g. pivotalabs.com)
|
29
|
+
req.permanent! :host => "pivotallabs.com"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Notice the use of regular expressions, the $1, $2, etc pseudo-variables, and string interpolation.
|
35
|
+
This is an easy way to match URL patterns and assemble the new URL based on what was matched.
|
36
|
+
|
37
|
+
## Installation (Rails)
|
38
|
+
|
39
|
+
Refraction can be installed in a Rails application as a plugin.
|
40
|
+
|
41
|
+
$ script/plugin install git://github.com/pivotal/refraction.git
|
42
|
+
|
43
|
+
In `environments/production.rb`, add Refraction at or near the top of your middleware stack.
|
44
|
+
|
45
|
+
config.middleware.insert_before(::Rack::Lock, ::Refraction, {})
|
46
|
+
|
47
|
+
You may want to occasionally turn on Refraction in the development environment for testing
|
48
|
+
purposes, but if your rules redirect to other servers that can be a problem.
|
49
|
+
|
50
|
+
Put your rules in `config/initializers/refraction_rules.rb` (see example above). The file name
|
51
|
+
doesn't actually matter, but convention is useful.
|
52
|
+
|
53
|
+
## Server Configuration
|
54
|
+
|
55
|
+
If your application is serving multiple virtual hosts, it's probably easiest to configure your web
|
56
|
+
server to handle a wildcard server name and let Refraction handle managing the virtual hosts. For
|
57
|
+
example, in nginx, that is done with a `server_name _;` directive.
|
58
|
+
|
59
|
+
## Writing Rules
|
60
|
+
|
61
|
+
Set up your rewrite/redirection rules during your app initialization using `Refraction.configure`.
|
62
|
+
The `configure` method takes a block which is run for every request to process the rules. The block
|
63
|
+
is passed a RequestContext object that contains information about the request URL and environment.
|
64
|
+
The request object also has a small API for effecting rewrites and redirects.
|
65
|
+
|
66
|
+
> Important note: don't do a `return` from within the configuration
|
67
|
+
> block. That would be bad (meaning your entire application would
|
68
|
+
> break). That's just how blocks work in Ruby.
|
69
|
+
|
70
|
+
### `RequestContext#set(options)`
|
71
|
+
|
72
|
+
The `set` method takes an options hash that sets pieces of the rewritten URL or redirect location
|
73
|
+
header.
|
74
|
+
|
75
|
+
* :scheme - Usually `http` or `https`.
|
76
|
+
* :host - The server name.
|
77
|
+
* :port - The server port. Usually not needed, as the scheme implies a default value.
|
78
|
+
* :path - The path of the URL.
|
79
|
+
* :query - Added at the end of the URL after a question mark (?)
|
80
|
+
|
81
|
+
Any URL components not explicitly set remain unchanged from the original request URL. You can use
|
82
|
+
`set` before calls to `rewrite!`, `permanent!`, or `found!` to set common values. Subsequent
|
83
|
+
methods will merge their component values into values from `set`.
|
84
|
+
|
85
|
+
### `RequestContext#rewrite!(options)`
|
86
|
+
|
87
|
+
The `rewrite!` method modifies the request URL and relevant pieces of the environment. When
|
88
|
+
Refraction rule processing results in a `rewrite!`, the request is passed on down the Rack stack
|
89
|
+
to the app or the next middleware component. `rewrite!` can take a single argument, either an
|
90
|
+
options hash that uses the same options as the `set` method, or a string that sets all components
|
91
|
+
of the URL.
|
92
|
+
|
93
|
+
### `RequestContext#permanent!(options)`
|
94
|
+
|
95
|
+
The `permanent!` method tells Refraction to return a response with a `301 Moved Permanently`
|
96
|
+
status, and sets the URL for the Location header. Like `rewrite!` it can take either a string or
|
97
|
+
hash argument to set the URL or some of its components.
|
98
|
+
|
99
|
+
### `RequestContext#found!(options)`
|
100
|
+
|
101
|
+
The `found!` method tells Refraction to return a response with a `302 Found` status, and sets the
|
102
|
+
URL for the Location header. Like `#rewrite!` it can take either a string or hash argument to set
|
103
|
+
the URL or some of its components.
|
104
|
+
|
105
|
+
### URL components
|
106
|
+
|
107
|
+
The request object provides the following components of the URL for matching requests: `scheme`,
|
108
|
+
`host`, `port`, `path`, and `query`. It also provides a full environment hash as the `env`
|
109
|
+
attribute. For example, `req.env['HTTP_USER_AGENT']` can be used to access the request's user
|
110
|
+
agent property.
|
111
|
+
|
112
|
+
## Contributors
|
113
|
+
|
114
|
+
* Josh Susser (maintainer)
|
115
|
+
* Sam Pierson
|
116
|
+
* Wai Lun Mang
|
117
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc 'Test the refraction plugin.'
|
9
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'jeweler'
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
gem.name = "refraction"
|
18
|
+
gem.summary = %Q{Rack middleware replacement for mod_rewrite}
|
19
|
+
gem.description = %Q{Reflection is a Rails plugin and standalone Rack middleware library. Give up quirky config syntax and use plain old Ruby for your rewrite and redirection rules.}
|
20
|
+
gem.email = "gems@pivotallabs.com"
|
21
|
+
gem.homepage = "http://github.com/pivotal/refraction"
|
22
|
+
gem.authors = ["Pivotal Labs", "Josh Susser", "Sam Pierson", "Wai Lun Mang"]
|
23
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
24
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
25
|
+
end
|
26
|
+
rescue LoadError
|
27
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
28
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/geminstaller.yml
ADDED
data/install.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# generate refraction_rules.rb
|
2
|
+
|
3
|
+
init_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "config", "initializers"))
|
4
|
+
if test(?d, init_dir)
|
5
|
+
rules_file = File.join(init_dir, "refraction_rules.rb")
|
6
|
+
unless File.exists?(rules_file)
|
7
|
+
File.open(rules_file, "w") do |f|
|
8
|
+
f.puts(<<'EOF')
|
9
|
+
Refraction.configure do |req|
|
10
|
+
# req.permanent! "http://example.com/"
|
11
|
+
end
|
12
|
+
EOF
|
13
|
+
puts "Generated starter rules file in #{rules_file}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
puts ""
|
19
|
+
puts "Make sure to add Refraction to your middleware stack in your production environment:"
|
20
|
+
puts ' config.middleware.insert_before(::Rack::Lock, ::Refraction, {})'
|
21
|
+
puts ""
|
data/lib/refraction.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
class Refraction
|
4
|
+
class RequestContext
|
5
|
+
attr_reader :env
|
6
|
+
attr_reader :status, :message, :action
|
7
|
+
|
8
|
+
def initialize(env)
|
9
|
+
@action = nil
|
10
|
+
@env = env
|
11
|
+
|
12
|
+
hostname = env['SERVER_NAME'] # because the rack mock doesn't set the HTTP_HOST
|
13
|
+
hostname = env['HTTP_HOST'].split(':').first if env['HTTP_HOST']
|
14
|
+
env_path = env['PATH_INFO'] || env['REQUEST_PATH']
|
15
|
+
|
16
|
+
@uri = URI::Generic.build(
|
17
|
+
:scheme => env['rack.url_scheme'],
|
18
|
+
:host => hostname,
|
19
|
+
:path => env_path.empty? ? '/' : env_path
|
20
|
+
)
|
21
|
+
unless [URI::HTTP::DEFAULT_PORT, URI::HTTPS::DEFAULT_PORT].include?(env['SERVER_PORT'].to_i)
|
22
|
+
@uri.port = env['SERVER_PORT']
|
23
|
+
end
|
24
|
+
@uri.query = env['QUERY_STRING'] if env['QUERY_STRING'] && !env['QUERY_STRING'].empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def response
|
28
|
+
headers = {
|
29
|
+
'Location' => location,
|
30
|
+
'Content-Type' => 'text/plain',
|
31
|
+
'Content-Length' => message.length.to_s
|
32
|
+
}
|
33
|
+
[status, headers, message]
|
34
|
+
end
|
35
|
+
|
36
|
+
# URI part accessors
|
37
|
+
|
38
|
+
def scheme
|
39
|
+
@uri.scheme
|
40
|
+
end
|
41
|
+
|
42
|
+
def host
|
43
|
+
@uri.host
|
44
|
+
end
|
45
|
+
|
46
|
+
def port
|
47
|
+
@uri.port
|
48
|
+
end
|
49
|
+
|
50
|
+
def path
|
51
|
+
@uri.path
|
52
|
+
end
|
53
|
+
|
54
|
+
def query
|
55
|
+
@uri.query
|
56
|
+
end
|
57
|
+
|
58
|
+
def method
|
59
|
+
@env['REQUEST_METHOD']
|
60
|
+
end
|
61
|
+
|
62
|
+
# actions
|
63
|
+
|
64
|
+
def set(options)
|
65
|
+
if options.is_a?(String)
|
66
|
+
@uri = URI.parse(options)
|
67
|
+
else
|
68
|
+
@uri.port = nil
|
69
|
+
options.each do |k,v|
|
70
|
+
k = 'scheme' if k == :protocol
|
71
|
+
@uri.send("#{k}=", v)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def rewrite!(options)
|
77
|
+
@action = :rewrite
|
78
|
+
set(options)
|
79
|
+
end
|
80
|
+
|
81
|
+
def permanent!(options)
|
82
|
+
@action = :permanent
|
83
|
+
@status = 301
|
84
|
+
set(options)
|
85
|
+
@message = "moved to #{@uri}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def found!(options)
|
89
|
+
@action = :found
|
90
|
+
@status = 302
|
91
|
+
set(options)
|
92
|
+
@message = "moved to #{@uri}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def location
|
96
|
+
@uri.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
end # RequestContext
|
100
|
+
|
101
|
+
def self.configure(&block)
|
102
|
+
@rules = block
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.rules
|
106
|
+
@rules
|
107
|
+
end
|
108
|
+
|
109
|
+
def initialize(app)
|
110
|
+
@app = app
|
111
|
+
end
|
112
|
+
|
113
|
+
def rules
|
114
|
+
self.class.rules
|
115
|
+
end
|
116
|
+
|
117
|
+
def call(env)
|
118
|
+
if self.rules
|
119
|
+
context = RequestContext.new(env)
|
120
|
+
|
121
|
+
self.rules.call(context)
|
122
|
+
|
123
|
+
case context.action
|
124
|
+
when :permanent, :found
|
125
|
+
context.response
|
126
|
+
when :rewrite
|
127
|
+
env["rack.url_scheme"] = context.scheme
|
128
|
+
env["HTTP_HOST"] = env["SERVER_NAME"] = context.host
|
129
|
+
env["HTTP_PORT"] = context.port if context.port
|
130
|
+
env["PATH_INFO"] = env["REQUEST_PATH"] = context.path
|
131
|
+
env["QUERY_STRING"] = context.query
|
132
|
+
env["REQUEST_URI"] = context.query ? "#{context.path}?#{context.query}" : context.path
|
133
|
+
@app.call(env)
|
134
|
+
else
|
135
|
+
@app.call(env)
|
136
|
+
end
|
137
|
+
else
|
138
|
+
@app.call(env)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "refraction")
|
3
|
+
|
4
|
+
describe Refraction do
|
5
|
+
|
6
|
+
describe "if no rules have been configured" do
|
7
|
+
before do
|
8
|
+
Refraction.configure
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does nothing" do
|
12
|
+
env = Rack::MockRequest.env_for('http://bar.com/about', :method => 'get')
|
13
|
+
app = mock('app')
|
14
|
+
app.should_receive(:call) { |resp|
|
15
|
+
resp['rack.url_scheme'].should == 'http'
|
16
|
+
resp['SERVER_NAME'].should == 'bar.com'
|
17
|
+
resp['PATH_INFO'].should == '/about'
|
18
|
+
[200, {}, ["body"]]
|
19
|
+
}
|
20
|
+
response = Refraction.new(app).call(env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "path" do
|
25
|
+
before do
|
26
|
+
Refraction.configure do |req|
|
27
|
+
if req.path == '/'
|
28
|
+
req.permanent! 'http://yes.com/'
|
29
|
+
elsif req.path == ''
|
30
|
+
req.permanent! 'http://no.com/'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be set to / if empty" do
|
36
|
+
env = Rack::MockRequest.env_for('http://bar.com', :method => 'get')
|
37
|
+
env['PATH_INFO'] = '/'
|
38
|
+
app = mock('app')
|
39
|
+
response = Refraction.new(app).call(env)
|
40
|
+
response[0].should == 301
|
41
|
+
response[1]['Location'].should == "http://yes.com/"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "permanent redirection" do
|
46
|
+
|
47
|
+
describe "using string arguments" do
|
48
|
+
before do
|
49
|
+
Refraction.configure do |req|
|
50
|
+
req.permanent! "http://foo.com/bar?baz"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should redirect everything to foo.com" do
|
55
|
+
env = Rack::MockRequest.env_for('http://bar.com', :method => 'get')
|
56
|
+
app = mock('app')
|
57
|
+
response = Refraction.new(app).call(env)
|
58
|
+
response[0].should == 301
|
59
|
+
response[1]['Location'].should == "http://foo.com/bar?baz"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "using hash arguments" do
|
64
|
+
before do
|
65
|
+
Refraction.configure do |req|
|
66
|
+
req.permanent! :host => "foo.com", :path => "/bar", :query => "baz"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should redirect http://bar.com to http://foo.com" do
|
71
|
+
env = Rack::MockRequest.env_for('http://bar.com', :method => 'get')
|
72
|
+
app = mock('app')
|
73
|
+
response = Refraction.new(app).call(env)
|
74
|
+
response[0].should == 301
|
75
|
+
response[1]['Location'].should == "http://foo.com/bar?baz"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should redirect https://bar.com to https://foo.com" do
|
79
|
+
env = Rack::MockRequest.env_for('https://bar.com', :method => 'get')
|
80
|
+
app = mock('app')
|
81
|
+
response = Refraction.new(app).call(env)
|
82
|
+
response[0].should == 301
|
83
|
+
response[1]['Location'].should == "https://foo.com/bar?baz"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should clear the port unless set explicitly" do
|
87
|
+
env = Rack::MockRequest.env_for('http://bar.com:3000/', :method => 'get')
|
88
|
+
app = mock('app')
|
89
|
+
response = Refraction.new(app).call(env)
|
90
|
+
response[0].should == 301
|
91
|
+
response[1]['Location'].should == "http://foo.com/bar?baz"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "temporary redirect for found" do
|
97
|
+
before(:each) do
|
98
|
+
Refraction.configure do |req|
|
99
|
+
if req.path =~ %r{^/users/(josh|edward)/blog\.(atom|rss)$}
|
100
|
+
req.found! "http://feeds.pivotallabs.com/pivotallabs/#{$1}.#{$2}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should temporarily redirect to feedburner.com" do
|
106
|
+
env = Rack::MockRequest.env_for('http://bar.com/users/josh/blog.atom', :method => 'get')
|
107
|
+
app = mock('app')
|
108
|
+
response = Refraction.new(app).call(env)
|
109
|
+
response[0].should == 302
|
110
|
+
response[1]['Location'].should == "http://feeds.pivotallabs.com/pivotallabs/josh.atom"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not redirect when no match" do
|
114
|
+
env = Rack::MockRequest.env_for('http://bar.com/users/sam/blog.rss', :method => 'get')
|
115
|
+
app = mock('app')
|
116
|
+
app.should_receive(:call) { |resp|
|
117
|
+
resp['rack.url_scheme'].should == 'http'
|
118
|
+
resp['SERVER_NAME'].should == 'bar.com'
|
119
|
+
resp['PATH_INFO'].should == '/users/sam/blog.rss'
|
120
|
+
[200, {}, ["body"]]
|
121
|
+
}
|
122
|
+
response = Refraction.new(app).call(env)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "rewrite url" do
|
127
|
+
before(:each) do
|
128
|
+
Refraction.configure do |req|
|
129
|
+
if req.host =~ /(tweed|pockets)\.example\.com/
|
130
|
+
req.rewrite! :host => 'example.com', :path => "/#{$1}#{req.path == '/' ? '' : req.path}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should rewrite subdomain to scope the path for matching subdomains" do
|
136
|
+
env = Rack::MockRequest.env_for('http://tweed.example.com', :method => 'get')
|
137
|
+
app = mock('app')
|
138
|
+
app.should_receive(:call) { |resp|
|
139
|
+
resp['rack.url_scheme'].should == 'http'
|
140
|
+
resp['SERVER_NAME'].should == 'example.com'
|
141
|
+
resp['PATH_INFO'].should == '/tweed'
|
142
|
+
[200, {}, ["body"]]
|
143
|
+
}
|
144
|
+
Refraction.new(app).call(env)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should not rewrite if the subdomain does not match" do
|
148
|
+
env = Rack::MockRequest.env_for('http://foo.example.com', :method => 'get')
|
149
|
+
app = mock('app')
|
150
|
+
app.should_receive(:call) { |resp|
|
151
|
+
resp['rack.url_scheme'].should == 'http'
|
152
|
+
resp['SERVER_NAME'].should == 'foo.example.com'
|
153
|
+
resp['PATH_INFO'].should == '/'
|
154
|
+
[200, {}, ["body"]]
|
155
|
+
}
|
156
|
+
Refraction.new(app).call(env)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "environment" do
|
161
|
+
before(:each) do
|
162
|
+
Refraction.configure do |req|
|
163
|
+
if req.env['HTTP_USER_AGENT'] =~ /FeedBurner/
|
164
|
+
req.permanent! "http://yes.com/"
|
165
|
+
else
|
166
|
+
req.permanent! "http://no.com/"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should expose environment settings" do
|
172
|
+
env = Rack::MockRequest.env_for('http://foo.com/', :method => 'get')
|
173
|
+
env['HTTP_USER_AGENT'] = 'FeedBurner'
|
174
|
+
app = mock('app')
|
175
|
+
response = Refraction.new(app).call(env)
|
176
|
+
response[0].should == 301
|
177
|
+
response[1]['Location'].should == "http://yes.com/"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: refraction
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pivotal Labs
|
8
|
+
- Josh Susser
|
9
|
+
- Sam Pierson
|
10
|
+
- Wai Lun Mang
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
|
15
|
+
date: 2009-10-29 00:00:00 -07:00
|
16
|
+
default_executable:
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: rspec
|
20
|
+
type: :development
|
21
|
+
version_requirement:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.9
|
27
|
+
version:
|
28
|
+
description: Reflection is a Rails plugin and standalone Rack middleware library. Give up quirky config syntax and use plain old Ruby for your rewrite and redirection rules.
|
29
|
+
email: gems@pivotallabs.com
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README.md
|
36
|
+
files:
|
37
|
+
- MIT-LICENSE
|
38
|
+
- README.md
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- geminstaller.yml
|
42
|
+
- install.rb
|
43
|
+
- lib/refraction.rb
|
44
|
+
- spec/refraction_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/pivotal/refraction
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options:
|
52
|
+
- --charset=UTF-8
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Rack middleware replacement for mod_rewrite
|
74
|
+
test_files:
|
75
|
+
- spec/refraction_spec.rb
|
76
|
+
- spec/spec_helper.rb
|