proxy 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +94 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +90 -0
- data/Rakefile +34 -0
- data/init.rb +1 -0
- data/lib/proxy.rb +49 -0
- data/lib/proxy/action_controller/abstract_request.rb +41 -0
- data/lib/proxy/action_controller/base.rb +130 -0
- data/lib/proxy/action_controller/named_route_collection.rb +30 -0
- data/lib/proxy/action_controller/url_rewriter.rb +21 -0
- data/lib/proxy/action_view/url_helper.rb +21 -0
- data/test/abstract_request_test.rb +68 -0
- data/test/base_test.rb +182 -0
- data/test/init.rb +103 -0
- data/test/named_route_collection_test.rb +28 -0
- data/test/proxy_test.rb +34 -0
- data/test/url_helper_test.rb +40 -0
- data/test/url_rewriter_test.rb +36 -0
- metadata +74 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
2009-06-05 - Sean Huber (shuber@huberry.com)
|
2
|
+
* Add multiple domain support for rack
|
3
|
+
* Update gemspec
|
4
|
+
* Update README
|
5
|
+
|
6
|
+
2009-06-04 - Sean Huber (shuber@huberry.com)
|
7
|
+
* Update test related rake tasks
|
8
|
+
* Remove huberry namespace
|
9
|
+
* Add support for multiple domains
|
10
|
+
* Update README
|
11
|
+
|
12
|
+
2009-05-20 - Sean Huber (shuber@huberry.com)
|
13
|
+
* Update date in gemspec so github rebuilds gem
|
14
|
+
|
15
|
+
2009-05-18 - Sean Huber (shuber@huberry.com)
|
16
|
+
* Fix compatibility issues with actionpack >= 2.2.2
|
17
|
+
|
18
|
+
2009-01-24 - Sean Huber (shuber@huberry.com)
|
19
|
+
* Add compatibility for edge/upcoming rails versions
|
20
|
+
|
21
|
+
2009-01-08 - Sean Huber (shuber@huberry.com)
|
22
|
+
* Add Proxy namespace
|
23
|
+
* Remove .gitignore
|
24
|
+
|
25
|
+
2008-12-09 - Sean Huber (shuber@huberry.com)
|
26
|
+
* Update README
|
27
|
+
|
28
|
+
2008-12-08 - Sean Huber (shuber@huberry.com)
|
29
|
+
* Fix bug - lib/proxy.rb was not included in gemspec
|
30
|
+
|
31
|
+
2008-11-14 - Sean Huber (shuber@huberry.com)
|
32
|
+
* Fix bug - "redirect_to some_path" now uses a forwarded host if it exists
|
33
|
+
* Gemify
|
34
|
+
* Update README
|
35
|
+
* Update proxy.gemspec
|
36
|
+
|
37
|
+
2008-10-30 - Sean Huber (shuber@huberry.com)
|
38
|
+
* Update documentation
|
39
|
+
* Move the logic that calculates the session_domain into its own method and update documentation
|
40
|
+
* Update README
|
41
|
+
|
42
|
+
2008-10-27 - Sean Huber (shuber@huberry.com)
|
43
|
+
* rewrite_url also adds the :host option as options is a Hash
|
44
|
+
* Move the logic that calculates the proxy_relative_url_root into its own method
|
45
|
+
|
46
|
+
2008-10-21 - Sean Huber (shuber@huberry.com)
|
47
|
+
* Fix bug - only add the :host option to url_helper if options is a Hash
|
48
|
+
|
49
|
+
2008-10-06 - Sean Huber (shuber@huberry.com)
|
50
|
+
* Add tests to ensure asset helpers work correctly
|
51
|
+
|
52
|
+
2008-10-05 - Sean Huber (shuber@huberry.com)
|
53
|
+
* Add failing named route test
|
54
|
+
* Named routes now work with forwarded hosts
|
55
|
+
* ActionView::Base#url_for uses forwarded hosts correctly
|
56
|
+
* Update README
|
57
|
+
* Update init.rb
|
58
|
+
|
59
|
+
2008-10-03 - Sean Huber (shuber@huberry.com)
|
60
|
+
* Add tests to ensure default host and relative_url_root are restored when an action redirects
|
61
|
+
* Update README
|
62
|
+
* The original session_domain is now restored after each request
|
63
|
+
|
64
|
+
2008-10-02 - Sean Huber (shuber@huberry.com)
|
65
|
+
* Remove Dispatcher and moved that logic into Base
|
66
|
+
* Add Rakefile
|
67
|
+
* Fix bug - referred to ActionController instead of ActionController::Base
|
68
|
+
* Fix bug - plugin was not being loaded properly
|
69
|
+
* Update README
|
70
|
+
* Fix bug - proxy_relative_url_root was not being set on every request
|
71
|
+
* Fix bug - relative_url_root was always being delegated to ActionController::AbstractRequest
|
72
|
+
|
73
|
+
2008-10-01 - Sean Huber (shuber@huberry.com)
|
74
|
+
* Move some forwarded host logic into AbstractRequest
|
75
|
+
* Add AbstractRequest tests and renamed BaseTest file
|
76
|
+
* Add more AbstractRequest tests
|
77
|
+
* ActionController::Base will delegate relative_url_root to AbstractRequest if necessary to support older versions of actionpack
|
78
|
+
* Add more Base tests
|
79
|
+
* Reorder requires and inclusions in proxy.rb
|
80
|
+
* Update CHANGELOG
|
81
|
+
* Update README
|
82
|
+
* Add UrlRewriter
|
83
|
+
* Add more tests
|
84
|
+
|
85
|
+
2008-09-29 - Sean Huber (shuber@huberry.com)
|
86
|
+
* Initial import
|
87
|
+
* Add some tests - still need to figure out how to test Dispatcher
|
88
|
+
* Base automatically detects HTTP_X_FORWARDED_URI and determines relative_url_root (can be overwritten)
|
89
|
+
* Update Base tests
|
90
|
+
* Base can now parse a comma separated string of forwarded uris
|
91
|
+
* The HTTP_X_FORWARDED_URI variable name can be changed to something else
|
92
|
+
* Update README
|
93
|
+
* Regex to determine relative root url is now properly escaped
|
94
|
+
* Fix bug - Base was not setting the class relative_url_root correctly
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sean Huber (shuber@huberry.com)
|
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.markdown
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Proxy
|
2
|
+
|
3
|
+
A gem/plugin that allows rails applications to dynamically respond to multiple domains and proxied requests by detecting forwarded host/uri headers and setting the session domain, default host, and relative url root. The plugin adds this functionality to calls to url\_for, named route helpers, and view url helpers while still allowing you to specifically set the :host and :only\_path options to override this behavior.
|
4
|
+
|
5
|
+
The original session domain, default host, and relative url root will be restored after each request.
|
6
|
+
|
7
|
+
Requires actionpack >= 2.0.0
|
8
|
+
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
script/plugin install git://github.com/shuber/proxy.git
|
13
|
+
OR
|
14
|
+
gem install proxy
|
15
|
+
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
### Proxied Requests
|
20
|
+
|
21
|
+
Let's say you have a suite of hosted applications all running on the same domain but mounted on different paths. One of them is an order/invoicing application located at:
|
22
|
+
|
23
|
+
http://client.example.com/orders
|
24
|
+
|
25
|
+
Imagine you sold an account to a client but the client wants the application to look like its running on his own domain, so they'll set up a proxy so they can access your application at:
|
26
|
+
|
27
|
+
http://clientdomain.com/orders
|
28
|
+
|
29
|
+
This plugin will automatically detect this forwarded host and set the session domain and default host (for url generation) accordingly.
|
30
|
+
|
31
|
+
|
32
|
+
### Proxied Requests with Custom URIs
|
33
|
+
|
34
|
+
Now imagine the client had an existing ordering system already running at /orders, and he wants to slowly migrate his data into your application, so he'll need both applications running for awhile. He wants to keep his original ordering application running at /orders and he wants your application running at:
|
35
|
+
|
36
|
+
http://clientdomain.com/neworders
|
37
|
+
|
38
|
+
All the client has to do is proxy /neworders to http://client.example.com/orders and this plugin will automatically detect the forwarded request uri and set the relative url root for your application accordingly. Now whenever urls are generated, they will correctly use /neworders as the relative url root instead of /orders.
|
39
|
+
|
40
|
+
Note: this plugin looks for a request header called 'HTTP\_X\_FORWARDED\_URI' to detect the relative root url by default, but this can be overwritten like so:
|
41
|
+
|
42
|
+
ActionController::AbstractRequest.forwarded_uri_header_name = 'SOME_CUSTOM_HEADER_NAME'
|
43
|
+
|
44
|
+
You can add that line in environment.rb or an initializer.
|
45
|
+
|
46
|
+
|
47
|
+
#### Relative Url Root Proxy Setup
|
48
|
+
|
49
|
+
The client's proxy must forward the request uri header in order for this plugin to automatically set the relative url root correctly. Here is how the client would setup a proxy in apache for the example above:
|
50
|
+
|
51
|
+
RewriteRule ^neworders(.*) http://client.example.com/orders$1 [P,QSA,L,E=originalUri:%{REQUEST_URI}]
|
52
|
+
RequestHeader append X_FORWARDED_URI %{originalUri}e e=originalUri
|
53
|
+
|
54
|
+
|
55
|
+
### Multiple Domains
|
56
|
+
|
57
|
+
Imagine you have a CMS that hosts multiple client sites. You want your users to manage their sites on your root domain `http://yourcmsapp.com` and you display a site's public content when it's accessed by its subdomain (e.g. `http://cool-site.yourcmsapp.com`). You'll probably be using [subdomain-fu](http://github.com/mbleigh/subdomain-fu) so you can route based on subdomains like:
|
58
|
+
|
59
|
+
ActionController::Routing::Routes.draw do |map|
|
60
|
+
# this routing controller has a before_filter callback that looks up a site by subdomain
|
61
|
+
map.public_page '*path', :controller => 'routing', :conditions => { :subdomain => /^[^\.]+$/ }
|
62
|
+
|
63
|
+
map.with_options :conditions => { :subdomain => nil } do |admin|
|
64
|
+
admin.resource :account, :controller => 'account'
|
65
|
+
admin.resources :sites
|
66
|
+
...
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Now, it gets tricky if you want `http://cool-site.com` to render `cool-site`'s public content because you can't tell if this request has a subdomain or not. In order for your routes to work, you must have all requests coming in from your domain `yourcmsapp.com`. You can accomplish this by calling the `Proxy.replace_host_with(&block)` method like so:
|
71
|
+
|
72
|
+
# config/initializers/proxy.rb
|
73
|
+
|
74
|
+
Proxy.replace_host_with do |request|
|
75
|
+
"#{Site.find_by_domain(request.host).try(:subdomain) || '-INVALID-'}.yourcmsapp.com" unless request.host =~ /(\.|^)yourcmsapp.com$/i
|
76
|
+
end
|
77
|
+
|
78
|
+
Let's examine what this block is doing:
|
79
|
+
|
80
|
+
* First, it checks if the current request's host is already on your domain. If it is, we don't need to do anything, otherwise...
|
81
|
+
* It checks if a site exists with a domain that matches the current request's host.
|
82
|
+
* If a site does exist, a new host is returned using the site's `subdomain` with your app domain and everything renders fine, otherwise...
|
83
|
+
* A fake host is returned (-INVALID-.yourcmsapp.com), and the request 404s once it gets to your `routing` controller and a site can't be found with the subdomain `-INVALID-`
|
84
|
+
|
85
|
+
If `nil, false, or an empty string` is returned when you call the `Proxy.replace_host_with` method, the current request's host is not modified. Otherwise, the `HTTP_X_FORWARDED_HOST` request header is set to: `"#{the_original_host}, #{the_new_host}"`. This allows your routes to use your domain when evaluating routing conditions and also allows all of the application's url generators to use the original host.
|
86
|
+
|
87
|
+
|
88
|
+
## Contact
|
89
|
+
|
90
|
+
Problems, comments, and suggestions all welcome: [shuber@huberry.com](mailto:shuber@huberry.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run the proxy tests'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
namespace :test do
|
9
|
+
desc 'Default: run the proxy tests for all versions of actionpack'
|
10
|
+
task :all do
|
11
|
+
versions = `gem list`.match(/actionpack \((.+)\)/).captures[0].split(/, /).select { |v| v[0,1].to_i > 1 }
|
12
|
+
versions.each do |version|
|
13
|
+
puts "\n\n============================================================="
|
14
|
+
puts "TESTING WITH ACTION PACK VERSION #{version}\n\n"
|
15
|
+
system "rake test ACTION_PACK_VERSION=#{version}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Test the proxy plugin.'
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
22
|
+
t.libs << 'lib'
|
23
|
+
t.pattern = 'test/*_test.rb'
|
24
|
+
t.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Generate documentation for the proxy plugin.'
|
28
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = 'Proxy'
|
31
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
32
|
+
rdoc.rdoc_files.include('README.markdown')
|
33
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
34
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_dependency 'proxy'
|
data/lib/proxy.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'proxy/action_controller/abstract_request'
|
2
|
+
require 'proxy/action_controller/base'
|
3
|
+
require 'proxy/action_controller/named_route_collection'
|
4
|
+
require 'proxy/action_controller/url_rewriter'
|
5
|
+
require 'proxy/action_view/url_helper'
|
6
|
+
|
7
|
+
module Proxy
|
8
|
+
mattr_accessor :replace_host_with_proc
|
9
|
+
self.replace_host_with_proc = proc { |request| }
|
10
|
+
|
11
|
+
def self.replace_host_with(&block)
|
12
|
+
self.replace_host_with_proc = block
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.before_dispatch(dispatcher)
|
18
|
+
request = dispatcher.instance_variable_get('@request') || dispatcher.instance_variable_get('@env')
|
19
|
+
request = Rack::Request.new(request) if request.is_a?(Hash)
|
20
|
+
new_host = replace_host_with_proc.call(request)
|
21
|
+
request.env['HTTP_X_FORWARDED_HOST'] = [request.host, new_host].join(', ') unless new_host.blank?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ActionController::Dispatcher.before_dispatch do |dispatcher|
|
26
|
+
Proxy.send :before_dispatch, dispatcher
|
27
|
+
end
|
28
|
+
|
29
|
+
ActionController::AbstractRequest = ActionController::Request if defined?(ActionController::Request)
|
30
|
+
ActionController::AbstractRequest.send :include, Proxy::ActionController::AbstractRequest
|
31
|
+
ActionController::Base.send :include, Proxy::ActionController::Base
|
32
|
+
ActionController::Routing::RouteSet::NamedRouteCollection.send :include, Proxy::ActionController::NamedRouteCollection
|
33
|
+
ActionController::UrlRewriter.send :include, Proxy::ActionController::UrlRewriter
|
34
|
+
ActionView::Base.send :include, Proxy::ActionView::UrlHelper
|
35
|
+
|
36
|
+
unless ActionController::UrlWriter.respond_to?(:default_url_options)
|
37
|
+
ActionController::Base.class_eval do
|
38
|
+
include ActionController::UrlWriter
|
39
|
+
|
40
|
+
def default_url_options_with_backwards_compatibility(*args)
|
41
|
+
default_url_options_without_backwards_compatibility
|
42
|
+
end
|
43
|
+
alias_method_chain :default_url_options, :backwards_compatibility
|
44
|
+
end
|
45
|
+
|
46
|
+
class << ActionController::UrlWriter
|
47
|
+
delegate :default_url_options, :default_url_options=, :to => ::ActionController::Base
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Proxy
|
2
|
+
module ActionController
|
3
|
+
module AbstractRequest
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
mattr_accessor :forwarded_uri_header_name
|
7
|
+
self.forwarded_uri_header_name = 'HTTP_X_FORWARDED_URI'
|
8
|
+
memoize :forwarded_hosts, :forwarded_uris if respond_to? :memoize
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Parses the forwarded host header and returns an array of forwarded hosts
|
13
|
+
#
|
14
|
+
# For example:
|
15
|
+
#
|
16
|
+
# If the HTTP_X_FORWARDED_HOST header was set to
|
17
|
+
# 'some-domain.com, some-other-domain.com, and-another-domain.com'
|
18
|
+
#
|
19
|
+
# This method would return ['some-domain.com', 'some-other-domain.com', 'and-another-domain.com']
|
20
|
+
#
|
21
|
+
# Returns an empty array if there aren't any forwarded hosts
|
22
|
+
def forwarded_hosts
|
23
|
+
env['HTTP_X_FORWARDED_HOST'].to_s.split(/,\s*/)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parses the forwarded uri header and returns an array of forwarded uris
|
27
|
+
#
|
28
|
+
# For example:
|
29
|
+
#
|
30
|
+
# If the HTTP_X_FORWARDED_URI header was set to
|
31
|
+
# '/some/path, /some/other/path, /and/another/path'
|
32
|
+
#
|
33
|
+
# This method would return ['/some/path, '/some/other/path', '/and/another/path']
|
34
|
+
#
|
35
|
+
# Returns an empty array if there aren't any forwarded uris
|
36
|
+
def forwarded_uris
|
37
|
+
env[self.forwarded_uri_header_name].to_s.split(/,\s*/)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Proxy
|
2
|
+
module ActionController
|
3
|
+
module Base
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
before_filter :set_proxy_relative_url_root
|
7
|
+
around_filter :swap_default_host
|
8
|
+
around_filter :swap_relative_url_root
|
9
|
+
around_filter :swap_session_domain
|
10
|
+
cattr_accessor :original_relative_url_root
|
11
|
+
cattr_accessor :proxy_relative_url_root
|
12
|
+
alias_method_chain :redirect_to, :proxy
|
13
|
+
class << self; delegate :relative_url_root, :relative_url_root=, :to => ::ActionController::AbstractRequest unless ::ActionController::Base.respond_to?(:relative_url_root); end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
# Calculates the <tt>relative_url_root</tt> by parsing the request path out of the
|
20
|
+
# first forwarded uri
|
21
|
+
#
|
22
|
+
# For example:
|
23
|
+
#
|
24
|
+
# http://example.com/manage/videos/new
|
25
|
+
# gets proxied to
|
26
|
+
# http://your-domain.com/videos/new
|
27
|
+
#
|
28
|
+
# The first forwarded uri would be: /manage/videos/new
|
29
|
+
# and the request path would be: /videos/new
|
30
|
+
#
|
31
|
+
# So this method would return: /manage
|
32
|
+
def parse_proxy_relative_url_root
|
33
|
+
request.forwarded_uris.first.gsub(/#{Regexp.escape(request.path)}$/, '')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Calculates the <tt>session_domain</tt> by parsing the first domain.tld out of the
|
37
|
+
# first forwarded host and prepending a '.'
|
38
|
+
#
|
39
|
+
# For example:
|
40
|
+
#
|
41
|
+
# http://example.com/manage/videos/new
|
42
|
+
# http://some.other-domain.com/videos/new
|
43
|
+
# both get proxied to
|
44
|
+
# http://your-domain.com/videos/new
|
45
|
+
#
|
46
|
+
# The resulting session domain for the first url would be: '.example.com'
|
47
|
+
# The resulting session domain for the second url would be: '.other-domain.com'
|
48
|
+
def parse_session_domain
|
49
|
+
".#{$1}" if /([^\.]+\.[^\.]+)$/.match(request.forwarded_hosts.first)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Forces redirects to use the <tt>default_url_options[:host]</tt> if it exists unless a host
|
53
|
+
# is already set
|
54
|
+
#
|
55
|
+
# For example:
|
56
|
+
#
|
57
|
+
# http://example.com
|
58
|
+
# gets proxied to
|
59
|
+
# http://your-domain.com
|
60
|
+
#
|
61
|
+
# If you have an action that calls <tt>redirect_to new_videos_path</tt>, the example.com domain
|
62
|
+
# would be used instead of your-domain.com
|
63
|
+
def redirect_to_with_proxy(*args)
|
64
|
+
args[0] = request.protocol + url_options[:host] + args.first if args.first.is_a?(String) && !%r{^\w+://.*}.match(args.first) && !url_options[:host].blank?
|
65
|
+
redirect_to_without_proxy(*args)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns ::ActionController::Base.session_options
|
69
|
+
def session_options
|
70
|
+
::ActionController::Base.session_options
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets the <tt>proxy_relative_url_root</tt> using the +parse_proxy_relative_url_root+ method
|
74
|
+
# to calculate it
|
75
|
+
#
|
76
|
+
# Sets the <tt>proxy_relative_url_root</tt> to nil if there aren't any forwarded uris
|
77
|
+
def set_proxy_relative_url_root
|
78
|
+
::ActionController::Base.proxy_relative_url_root = request.forwarded_uris.empty? ? nil : parse_proxy_relative_url_root
|
79
|
+
end
|
80
|
+
|
81
|
+
# Sets the <tt>default_url_options[:host]</tt> to the first forwarded host if there are any
|
82
|
+
#
|
83
|
+
# The original default host is restored after each request and can be accessed by calling
|
84
|
+
# <tt>ActionController::UrlWriter.default_url_options[:original_host]</tt>
|
85
|
+
def swap_default_host
|
86
|
+
url_options[:original_host] = url_options[:host]
|
87
|
+
url_options[:host] = request.forwarded_hosts.first unless request.forwarded_hosts.empty?
|
88
|
+
begin
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
url_options[:host] = url_options[:original_host]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sets the <tt>relative_url_root</tt> to the <tt>proxy_relative_url_root</tt> unless it's nil
|
96
|
+
#
|
97
|
+
# The original relative url root is restored after each request and can be accessed by calling
|
98
|
+
# <tt>ActionController::Base.original_relative_url_root</tt>
|
99
|
+
def swap_relative_url_root
|
100
|
+
::ActionController::Base.original_relative_url_root = ::ActionController::Base.relative_url_root
|
101
|
+
::ActionController::Base.relative_url_root = ::ActionController::Base.proxy_relative_url_root unless ::ActionController::Base.proxy_relative_url_root.nil?
|
102
|
+
begin
|
103
|
+
yield
|
104
|
+
ensure
|
105
|
+
::ActionController::Base.relative_url_root = ::ActionController::Base.original_relative_url_root
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Sets the <tt>session_options[:session_domain]</tt> to the result of the +parse_session_domain+ method
|
110
|
+
# unless there aren't any forwarded hosts
|
111
|
+
#
|
112
|
+
# The original session domain is restored after each request and can be accessed by calling
|
113
|
+
# <tt>ActionController::Base.session_options[:original_session_domain]</tt>
|
114
|
+
def swap_session_domain
|
115
|
+
session_options[:original_session_domain] = session_options[:session_domain] || session_options[:domain]
|
116
|
+
session_options[:session_domain] = session_options[:domain] = parse_session_domain unless request.forwarded_hosts.empty?
|
117
|
+
begin
|
118
|
+
yield
|
119
|
+
ensure
|
120
|
+
session_options[:session_domain] = session_options[:domain] = session_options[:original_session_domain]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns ::ActionController::UrlWriter.default_url_options
|
125
|
+
def url_options
|
126
|
+
::ActionController::UrlWriter.default_url_options
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Proxy
|
2
|
+
module ActionController
|
3
|
+
module NamedRouteCollection
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval { alias_method_chain :define_url_helper, :proxy }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Named route url helpers (not path helpers) don't seem to work correctly
|
9
|
+
# with forwarded hosts unless we explicitly set the option:
|
10
|
+
#
|
11
|
+
# :only_path => false
|
12
|
+
#
|
13
|
+
# This method only sets that option if it isn't set already
|
14
|
+
def define_url_helper_with_proxy(route, name, kind, options)
|
15
|
+
define_url_helper_without_proxy(route, name, kind, options)
|
16
|
+
if kind == :url
|
17
|
+
selector = url_helper_name(name, kind)
|
18
|
+
@module.module_eval do
|
19
|
+
define_method "#{selector}_with_proxy" do |*args|
|
20
|
+
args << {} unless args.last.is_a? Hash
|
21
|
+
args.last[:only_path] ||= false
|
22
|
+
send "#{selector}_without_proxy", *args
|
23
|
+
end
|
24
|
+
alias_method_chain selector, :proxy
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Proxy
|
2
|
+
module ActionController
|
3
|
+
module UrlRewriter
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval { alias_method_chain :rewrite_url, :proxy }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Adds the default :host option unless already specified
|
9
|
+
#
|
10
|
+
# It will not set the :host option if <tt>options</tt> is not a hash or
|
11
|
+
# if the <tt>ActionController::UrlWriter.default_url_options[:host]</tt> is blank
|
12
|
+
def rewrite_url_with_proxy(options)
|
13
|
+
if options.is_a?(Hash)
|
14
|
+
options[:host] ||= ::ActionController::UrlWriter.default_url_options[:host] unless ::ActionController::UrlWriter.default_url_options[:host].blank?
|
15
|
+
options.delete(:original_host)
|
16
|
+
end
|
17
|
+
rewrite_url_without_proxy(options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Proxy
|
2
|
+
module ActionView
|
3
|
+
module UrlHelper
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval { alias_method_chain :url_for, :proxy }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Adds the default :host option unless already specified
|
9
|
+
#
|
10
|
+
# It will not set the :host option if <tt>options</tt> is not a hash or
|
11
|
+
# if the <tt>ActionController::UrlWriter.default_url_options[:host]</tt> is blank
|
12
|
+
def url_for_with_proxy(options = {})
|
13
|
+
if options.is_a?(Hash)
|
14
|
+
options[:host] ||= ::ActionController::UrlWriter.default_url_options[:host] unless ::ActionController::UrlWriter.default_url_options[:host].blank?
|
15
|
+
options.delete(:original_host)
|
16
|
+
end
|
17
|
+
url_for_without_proxy(options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class AbstractRequestTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@request = ActionController::TestRequest.new
|
7
|
+
@request.host = 'example.com'
|
8
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
9
|
+
ActionController::Base.relative_url_root = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_forwarded_hosts_should_be_empty
|
13
|
+
assert_equal [], @request.forwarded_hosts
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_should_parse_empty_forwarded_hosts_into_an_array
|
17
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = ''
|
18
|
+
assert_equal [], @request.forwarded_hosts
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_parse_nil_forwarded_hosts_into_an_array
|
22
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = nil
|
23
|
+
assert_equal [], @request.forwarded_hosts
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_forwarded_host_string_should_be_parsed_into_an_array
|
27
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = 'forwarded.com'
|
28
|
+
assert_equal ['forwarded.com'], @request.forwarded_hosts
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_comma_separated_forwarded_host_string_should_be_parsed_into_an_array
|
32
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = 'forwarded.com,something.com, test.com, testing.com'
|
33
|
+
assert_equal ['forwarded.com', 'something.com', 'test.com', 'testing.com'], @request.forwarded_hosts
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_forwarded_uris_should_be_empty
|
37
|
+
assert_equal [], @request.forwarded_uris
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_should_parse_empty_forwarded_uris_into_an_array
|
41
|
+
@request.env['HTTP_X_FORWARDED_URI'] = ''
|
42
|
+
assert_equal [], @request.forwarded_uris
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_parse_nil_forwarded_uris_into_an_array
|
46
|
+
@request.env['HTTP_X_FORWARDED_URI'] = nil
|
47
|
+
assert_equal [], @request.forwarded_uris
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_forwarded_uri_string_should_be_parsed_into_an_array
|
51
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing'
|
52
|
+
assert_equal ['/test/ing'], @request.forwarded_uris
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_comma_separated_forwarded_uri_string_should_be_parsed_into_an_array
|
56
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing,/whoa, /uh/oh, /mmm/kay'
|
57
|
+
assert_equal ['/test/ing', '/whoa', '/uh/oh', '/mmm/kay'], @request.forwarded_uris
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_should_be_able_to_use_custom_forwarded_uri_header_name
|
61
|
+
@original_header_name = ActionController::AbstractRequest.forwarded_uri_header_name
|
62
|
+
@request.env['HTTP_CUSTOM_FORWARDED_URI'] = '/test/ing'
|
63
|
+
ActionController::AbstractRequest.forwarded_uri_header_name = 'HTTP_CUSTOM_FORWARDED_URI'
|
64
|
+
assert_equal ['/test/ing'], @request.forwarded_uris
|
65
|
+
ActionController::AbstractRequest.forwarded_uri_header_name = @original_header_name
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class BaseTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@controller = TestController.new
|
7
|
+
@request = ActionController::TestRequest.new
|
8
|
+
@response = ActionController::TestResponse.new
|
9
|
+
@request.host = 'example.com'
|
10
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
11
|
+
ActionController::Base.relative_url_root = '/app'
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_get_normal_action
|
15
|
+
get :normal_action
|
16
|
+
assert_equal "http://#{@request.host}/normal_action", @response.body
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_set_a_forwarded_host_as_a_default_host
|
20
|
+
add_forwarded_host_headers
|
21
|
+
get :normal_action
|
22
|
+
assert_equal "http://domain.com/app/normal_action", @response.body
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_set_forwarded_host_in_a_named_route
|
26
|
+
add_forwarded_host_headers
|
27
|
+
get :named_route_action
|
28
|
+
assert_equal "http://domain.com/app/normal_action", @response.body
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_restore_the_original_default_host
|
32
|
+
::ActionController::UrlWriter.default_url_options[:host] = 'some-other-domain.com'
|
33
|
+
add_forwarded_host_headers
|
34
|
+
get :normal_action
|
35
|
+
assert_equal "http://domain.com/app/normal_action", @response.body
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_url_generators_in_views_should_use_forwarded_host
|
39
|
+
add_forwarded_host_headers
|
40
|
+
get :view_action
|
41
|
+
assert_equal "/app/normal_action, http://domain.com/app/normal_action, http://domain.com/app/normal_action, /app/normal_action", @response.body
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_asset_tag_helpers_should_not_use_forwarded_host
|
45
|
+
add_forwarded_host_headers
|
46
|
+
get :asset_action
|
47
|
+
assert_nil(/domain\.com/.match(@response.body))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_should_set_the_session_domain_with_a_forwarded_host
|
51
|
+
add_forwarded_host_headers
|
52
|
+
get :session_action
|
53
|
+
assert_equal '.domain.com', @response.body
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_should_restore_original_session_domain
|
57
|
+
::ActionController::Base.session_options[:session_domain] = '.example.com'
|
58
|
+
add_forwarded_host_headers
|
59
|
+
get :session_action
|
60
|
+
assert_equal '.domain.com', @response.body
|
61
|
+
assert_equal '.example.com', ::ActionController::Base.session_options[:session_domain]
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_should_restore_original_session_domain_with_domain_key
|
65
|
+
::ActionController::Base.session_options[:domain] = '.example.com'
|
66
|
+
add_forwarded_host_headers
|
67
|
+
get :session_action
|
68
|
+
assert_equal '.domain.com', @response.body
|
69
|
+
assert_equal '.example.com', ::ActionController::Base.session_options[:domain]
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_should_restore_original_session_if_exception_is_raised
|
73
|
+
::ActionController::Base.session_options[:session_domain] = '.example.com'
|
74
|
+
add_forwarded_host_headers
|
75
|
+
assert_raises(RuntimeError) { get :exception_action }
|
76
|
+
assert_equal '.example.com', ::ActionController::Base.session_options[:session_domain]
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_restore_original_session_if_redirected
|
80
|
+
::ActionController::Base.session_options[:session_domain] = '.example.com'
|
81
|
+
add_forwarded_host_headers
|
82
|
+
get :redirect_action
|
83
|
+
assert_equal '.example.com', ::ActionController::Base.session_options[:session_domain]
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_should_restore_original_host_if_exception_is_raised
|
87
|
+
::ActionController::UrlWriter.default_url_options[:host] = 'some-other-domain.com'
|
88
|
+
add_forwarded_host_headers
|
89
|
+
assert_raises(RuntimeError) { get :exception_action }
|
90
|
+
assert_equal 'some-other-domain.com', ::ActionController::UrlWriter.default_url_options[:host]
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_should_restore_original_host_if_redirected
|
94
|
+
::ActionController::UrlWriter.default_url_options[:host] = 'some-other-domain.com'
|
95
|
+
add_forwarded_host_headers
|
96
|
+
get :redirect_action
|
97
|
+
assert_equal 'some-other-domain.com', ::ActionController::UrlWriter.default_url_options[:host]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_should_get_normal_action
|
101
|
+
get :normal_action
|
102
|
+
assert_equal "http://#{@request.host}/app/normal_action", @response.body
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_should_swap_relative_url_root
|
106
|
+
add_forwarded_uri_headers
|
107
|
+
get :normal_action
|
108
|
+
assert_equal "http://#{@request.host}/test/ing/normal_action", @response.body
|
109
|
+
assert_equal '/app', ActionController::Base.relative_url_root
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_should_set_proxy_relative_url_root
|
113
|
+
add_forwarded_uri_headers
|
114
|
+
get :normal_action
|
115
|
+
assert_equal '/test/ing', ActionController::Base.proxy_relative_url_root
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_should_set_proxy_relative_url_root_in_a_named_route
|
119
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/named_route_action'
|
120
|
+
@request.env['PATH_INFO'] = '/named_route_action'
|
121
|
+
get :named_route_action
|
122
|
+
assert_equal "http://#{@request.host}/test/ing/normal_action", @response.body
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_should_set_original_relative_url_root
|
126
|
+
add_forwarded_uri_headers
|
127
|
+
get :normal_action
|
128
|
+
assert_equal '/app', ActionController::Base.original_relative_url_root
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_should_restore_relative_url_root_if_exception_is_raised
|
132
|
+
add_forwarded_uri_headers
|
133
|
+
assert_raises(RuntimeError) { get :exception_action }
|
134
|
+
assert_equal '/app', ActionController::Base.relative_url_root
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_should_restore_relative_url_root_if_exception_is_raised
|
138
|
+
add_forwarded_uri_headers
|
139
|
+
get :redirect_action
|
140
|
+
assert_equal '/app', ActionController::Base.relative_url_root
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_url_generators_in_views_should_use_forwarded_uri
|
144
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/view_action'
|
145
|
+
@request.env['PATH_INFO'] = '/view_action'
|
146
|
+
get :view_action
|
147
|
+
assert_equal "/test/ing/normal_action, http://example.com/test/ing/normal_action, /test/ing/normal_action, /test/ing/normal_action", @response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_asset_tag_helpers_should_use_forwarded_uri
|
151
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/asset_action'
|
152
|
+
@request.env['PATH_INFO'] = '/asset_action'
|
153
|
+
get :asset_action
|
154
|
+
assert !@response.body.scan(/img[^>]+src\="\/test\/ing\/images\/test\.gif"/).empty?
|
155
|
+
assert !@response.body.scan(/script[^>]+src\="\/test\/ing\/javascripts\/test\.js"/).empty?
|
156
|
+
assert !@response.body.scan(/link[^>]+href\="\/test\/ing\/stylesheets\/test\.css"/).empty?
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_should_use_forwarded_host_in_a_redirect
|
160
|
+
add_forwarded_host_headers
|
161
|
+
get :redirect_action
|
162
|
+
assert_redirected_to 'http://domain.com/app/normal_action'
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_should_use_forwarded_host_in_a_redirect_with_named_routes
|
166
|
+
add_forwarded_host_headers
|
167
|
+
get :redirect_with_named_route_action
|
168
|
+
assert_redirected_to 'http://domain.com/app/normal_action'
|
169
|
+
end
|
170
|
+
|
171
|
+
protected
|
172
|
+
|
173
|
+
def add_forwarded_host_headers
|
174
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = 'domain.com'
|
175
|
+
end
|
176
|
+
|
177
|
+
def add_forwarded_uri_headers
|
178
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/normal_action'
|
179
|
+
@request.env['PATH_INFO'] = '/normal_action'
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
data/test/init.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
$:.reject! { |path| path.include? 'TextMate' }
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Load rubygems
|
5
|
+
#
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
# Load ActionPack
|
9
|
+
#
|
10
|
+
args = ['actionpack']
|
11
|
+
args << ENV['ACTION_PACK_VERSION'] if ENV['ACTION_PACK_VERSION']
|
12
|
+
gem *args
|
13
|
+
require 'action_pack'
|
14
|
+
require 'action_controller'
|
15
|
+
require 'action_controller/dispatcher'
|
16
|
+
require 'action_controller/routing'
|
17
|
+
require 'action_controller/session_management'
|
18
|
+
require 'action_controller/url_rewriter'
|
19
|
+
require 'action_controller/test_process'
|
20
|
+
require 'action_view'
|
21
|
+
|
22
|
+
Test::Unit::TestCase.class_eval do
|
23
|
+
include ActionController::TestProcess
|
24
|
+
|
25
|
+
unless instance_methods.include?('assert_redirected_to')
|
26
|
+
def assert_redirected_to(url)
|
27
|
+
assert @response.redirect?
|
28
|
+
assert_equal url, @response.location
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Routing
|
34
|
+
#
|
35
|
+
class ActionController::Routing::RouteSet
|
36
|
+
def append
|
37
|
+
yield Mapper.new(self)
|
38
|
+
install_helpers
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
ActionController::Base.session_options.merge! :key => '_proxy_session', :secret => '60447f093cd3f5d57686dd5ca1ced83216c846047db0ec97480a5e85411d9bd41ec5587cc4aafac27a4f0e649f0c628b0955b315856b78787a96168671dc96d4'
|
43
|
+
|
44
|
+
# Require the main proxy.rb file
|
45
|
+
#
|
46
|
+
require File.join(File.dirname(File.dirname(__FILE__)), 'lib', 'proxy')
|
47
|
+
|
48
|
+
# Test controller
|
49
|
+
#
|
50
|
+
class TestController < ActionController::Base
|
51
|
+
|
52
|
+
def asset_action
|
53
|
+
render :inline => '<%= image_tag "test.gif" %>, <%= javascript_include_tag "test" %>, <%= stylesheet_link_tag "test" %>'
|
54
|
+
end
|
55
|
+
|
56
|
+
def exception_action
|
57
|
+
raise 'Uh oh'
|
58
|
+
end
|
59
|
+
|
60
|
+
def named_route_action
|
61
|
+
render :text => normal_action_url
|
62
|
+
end
|
63
|
+
|
64
|
+
def normal_action
|
65
|
+
render :text => url_for(:controller => 'test', :action => 'normal_action')
|
66
|
+
end
|
67
|
+
|
68
|
+
def redirect_action
|
69
|
+
redirect_to :action => 'normal_action'
|
70
|
+
end
|
71
|
+
|
72
|
+
def redirect_with_named_route_action
|
73
|
+
redirect_to normal_action_path
|
74
|
+
end
|
75
|
+
|
76
|
+
def session_action
|
77
|
+
render :text => ActionController::Base.session_options[:session_domain]
|
78
|
+
end
|
79
|
+
|
80
|
+
def view_action
|
81
|
+
render :inline => '<%= normal_action_path %>, <%= normal_action_url %>, <%= url_for(:controller => "test", :action => "normal_action") %>, <%= url_for(:controller => "test", :action => "normal_action", :only_path => true) %>'
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def rescue_action(e)
|
87
|
+
raise e
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Test routes
|
92
|
+
#
|
93
|
+
ActionController::Routing::Routes.append do |map|
|
94
|
+
map.connect 'asset_action', :controller => 'test', :action => 'asset_action'
|
95
|
+
map.connect 'exception_action', :controller => 'test', :action => 'exception_action'
|
96
|
+
map.connect 'named_route_action', :controller => 'test', :action => 'named_route_action'
|
97
|
+
map.connect 'normal_action', :controller => 'test', :action => 'normal_action'
|
98
|
+
map.connect 'redirect_action', :controller => 'test', :action => 'redirect_action'
|
99
|
+
map.connect 'redirect_with_named_route_action', :controller => 'test', :action => 'redirect_with_named_route_action'
|
100
|
+
map.connect 'session_action', :controller => 'test', :action => 'session_action'
|
101
|
+
map.connect 'view_action', :controller => 'test', :action => 'view_action'
|
102
|
+
map.normal_action 'normal_action', :controller => 'test', :action => 'normal_action'
|
103
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class NamedRouteCollectionTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@controller = TestController.new
|
7
|
+
@request = ActionController::TestRequest.new
|
8
|
+
@response = ActionController::TestResponse.new
|
9
|
+
@request.host = 'example.com'
|
10
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
11
|
+
ActionController::Base.relative_url_root = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_alias_method_chain_url_helpers
|
15
|
+
[ActionController::Base, ActionView::Base].each do |klass|
|
16
|
+
assert klass.method_defined?(:normal_action_url_with_proxy)
|
17
|
+
assert klass.method_defined?(:normal_action_url_without_proxy)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_not_alias_method_chain_path_helpers
|
22
|
+
[ActionController::Base, ActionView::Base].each do |klass|
|
23
|
+
assert !klass.method_defined?(:normal_action_path_with_proxy)
|
24
|
+
assert !klass.method_defined?(:normal_action_path_without_proxy)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/test/proxy_test.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class ProxyTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@controller = TestController.new
|
7
|
+
@request = ActionController::TestRequest.new
|
8
|
+
def @request.host; env['HTTP_X_FORWARDED_HOST'].blank? ? env['HTTP_HOST'] : env['HTTP_X_FORWARDED_HOST'].split(/,\s/).last; end
|
9
|
+
@response = ActionController::TestResponse.new
|
10
|
+
@dispatcher = ActionController::Dispatcher.new(StringIO.new)
|
11
|
+
@dispatcher.instance_variable_set('@request', @request)
|
12
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
13
|
+
ActionController::Base.relative_url_root = nil
|
14
|
+
|
15
|
+
Proxy.replace_host_with do |request|
|
16
|
+
'replaced.com' if request.host == 'replace-me.com'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_not_replace_host
|
21
|
+
@request.env['HTTP_HOST'] = 'dont-replace-me.com'
|
22
|
+
assert_equal 'dont-replace-me.com', @request.host
|
23
|
+
Proxy.send(:before_dispatch, @dispatcher)
|
24
|
+
assert_equal 'dont-replace-me.com', @request.host
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_should_replace_host
|
28
|
+
@request.env['HTTP_HOST'] = 'replace-me.com'
|
29
|
+
assert_equal 'replace-me.com', @request.host
|
30
|
+
Proxy.send(:before_dispatch, @dispatcher)
|
31
|
+
assert_equal 'replaced.com', @request.host
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class UrlHelperTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@controller = TestController.new
|
7
|
+
@request = ActionController::TestRequest.new
|
8
|
+
@response = ActionController::TestResponse.new
|
9
|
+
@request.host = 'example.com'
|
10
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
11
|
+
ActionController::Base.relative_url_root = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_render_urls_normally
|
15
|
+
get :view_action
|
16
|
+
assert_equal '/normal_action, http://example.com/normal_action, /normal_action, /normal_action', @response.body
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_render_urls_with_forwarded_hosts_while_respecting_the_only_path_option
|
20
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = 'domain.com'
|
21
|
+
get :view_action
|
22
|
+
assert_equal '/normal_action, http://domain.com/normal_action, http://domain.com/normal_action, /normal_action', @response.body
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_render_urls_with_forwarded_uris
|
26
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/view_action'
|
27
|
+
@request.env['PATH_INFO'] = '/view_action'
|
28
|
+
get :view_action
|
29
|
+
assert_equal '/test/ing/normal_action, http://example.com/test/ing/normal_action, /test/ing/normal_action, /test/ing/normal_action', @response.body
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_render_urls_with_forwarded_hosts_and_uris
|
33
|
+
@request.env['HTTP_X_FORWARDED_HOST'] = 'domain.com'
|
34
|
+
@request.env['HTTP_X_FORWARDED_URI'] = '/test/ing/view_action'
|
35
|
+
@request.env['PATH_INFO'] = '/view_action'
|
36
|
+
get :view_action
|
37
|
+
assert_equal '/test/ing/normal_action, http://domain.com/test/ing/normal_action, http://domain.com/test/ing/normal_action, /test/ing/normal_action', @response.body
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
class UrlRewriter < ::ActionController::UrlRewriter
|
4
|
+
public
|
5
|
+
def rewrite_url
|
6
|
+
super :action => :normal_action, :controller => :test
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class UrlRewriterTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@controller = TestController.new
|
14
|
+
@request = ActionController::TestRequest.new
|
15
|
+
@response = ActionController::TestResponse.new
|
16
|
+
@request.host = 'example.com'
|
17
|
+
@url_rewriter = UrlRewriter.new(@request, {})
|
18
|
+
ActionController::UrlWriter.default_url_options[:host] = nil
|
19
|
+
ActionController::Base.relative_url_root = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_rewrite_normal_action_with_request_host
|
23
|
+
assert_equal 'http://example.com/normal_action', @url_rewriter.rewrite_url
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_should_rewrite_normal_action_with_request_host_if_default_host_is_empty
|
27
|
+
ActionController::UrlWriter.default_url_options[:host] = ''
|
28
|
+
assert_equal 'http://example.com/normal_action', @url_rewriter.rewrite_url
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_rewrite_normal_action_with_default_host
|
32
|
+
ActionController::UrlWriter.default_url_options[:host] = 'test.com'
|
33
|
+
assert_equal 'http://test.com/normal_action', @url_rewriter.rewrite_url
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: proxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Huber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-08 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A gem/plugin that allows rails applications to respond to multiple domains and proxied requests
|
17
|
+
email: shuber@huberry.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- CHANGELOG
|
26
|
+
- init.rb
|
27
|
+
- lib/proxy/action_controller/abstract_request.rb
|
28
|
+
- lib/proxy/action_controller/base.rb
|
29
|
+
- lib/proxy/action_controller/named_route_collection.rb
|
30
|
+
- lib/proxy/action_controller/url_rewriter.rb
|
31
|
+
- lib/proxy/action_view/url_helper.rb
|
32
|
+
- lib/proxy.rb
|
33
|
+
- MIT-LICENSE
|
34
|
+
- Rakefile
|
35
|
+
- README.markdown
|
36
|
+
- test/init.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/shuber/proxy
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --line-numbers
|
44
|
+
- --inline-source
|
45
|
+
- --main
|
46
|
+
- README.markdown
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.3.5
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: A gem/plugin that allows rails applications to respond to multiple domains and proxied requests
|
68
|
+
test_files:
|
69
|
+
- test/abstract_request_test.rb
|
70
|
+
- test/base_test.rb
|
71
|
+
- test/named_route_collection_test.rb
|
72
|
+
- test/proxy_test.rb
|
73
|
+
- test/url_helper_test.rb
|
74
|
+
- test/url_rewriter_test.rb
|