shuber-proxy 1.3.0 → 1.3.1

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/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 2009-06-04 - Sean Huber (shuber@huberry.com)
2
+ * Update test related rake tasks
3
+ * Remove huberry namespace
4
+ * Add support for multiple domains
5
+ * Update README
6
+
1
7
  2009-05-20 - Sean Huber (shuber@huberry.com)
2
8
  * Update date in gemspec so github rebuilds gem
3
9
 
data/README.markdown CHANGED
@@ -1,25 +1,24 @@
1
- Proxy
2
- =====
1
+ # Proxy
3
2
 
4
- A gem/plugin that allows rails applications to dynamically respond to 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.
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.
5
4
 
6
5
  The original session domain, default host, and relative url root will be restored after each request.
7
6
 
8
7
  Requires actionpack version >= 2.0.0
9
8
 
10
9
 
11
- Installation
12
- ------------
10
+ ## Installation
13
11
 
14
12
  script/plugin install git://github.com/shuber/proxy.git
15
13
  OR
16
14
  gem install shuber-proxy --source http://gems.github.com
17
15
 
18
16
 
19
- Usage
20
- -----
17
+ ## Usage
21
18
 
22
- Lets 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:
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:
23
22
 
24
23
  http://client.example.com/orders
25
24
 
@@ -29,6 +28,9 @@ Imagine you sold an account to a client but the client wants the application to
29
28
 
30
29
  This plugin will automatically detect this forwarded host and set the session domain and default host (for url generation) accordingly.
31
30
 
31
+
32
+ ### Proxied Requests with Custom URIs
33
+
32
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:
33
35
 
34
36
  http://clientdomain.com/neworders
@@ -42,8 +44,7 @@ Note: this plugin looks for a request header called 'HTTP\_X\_FORWARDED\_URI' to
42
44
  You can add that line in environment.rb or an initializer.
43
45
 
44
46
 
45
- Relative Url Root Proxy Setup
46
- -----------------------------
47
+ #### Relative Url Root Proxy Setup
47
48
 
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:
49
50
 
@@ -51,7 +52,42 @@ The client's proxy must forward the request uri header in order for this plugin
51
52
  RequestHeader append X_FORWARDED_URI %{originalUri}e e=originalUri
52
53
 
53
54
 
54
- Contact
55
- -------
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
+ class ApplicationController < ActionController::Base
73
+
74
+ # you can put this in an initializer or something instead if you'd like
75
+ Proxy.replace_host_with do |request|
76
+ "#{Site.find_by_domain(request.host).try(:subdomain) || '-INVALID-'}.yourcmsapp.com" unless request.host =~ /(.*\.|^)yourcmsapp.com$/i
77
+ end
78
+
79
+ end
80
+
81
+ Let's examine what this block is doing:
82
+
83
+ * 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...
84
+ * It checks if a site exists with a domain that matches the current request's host.
85
+ * If a site does exist, a new host is returned using the site's `subdomain` with your app domain and everything renders fine, otherwise...
86
+ * 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-`
87
+
88
+ 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.
89
+
90
+
91
+ ## Contact
56
92
 
57
93
  Problems, comments, and suggestions all welcome: [shuber@huberry.com](mailto:shuber@huberry.com)
data/Rakefile CHANGED
@@ -3,15 +3,17 @@ require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
5
  desc 'Default: run the proxy tests'
6
- task :default => :test_all_versions
6
+ task :default => :test
7
7
 
8
- desc 'Default: run the proxy tests for all versions of actionpack'
9
- task :test_all_versions do
10
- versions = `gem list`.match(/actionpack \((.+)\)/).captures[0].split(/, /).select { |v| v[0,1].to_i > 1 }
11
- versions.each do |version|
12
- puts "\n\n============================================================="
13
- puts "TESTING WITH ACTION PACK VERSION #{version}\n\n"
14
- system "rake test ACTION_PACK_VERSION=#{version}"
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
15
17
  end
16
18
  end
17
19
 
data/lib/proxy.rb CHANGED
@@ -1,15 +1,36 @@
1
- require 'huberry/proxy/action_controller/abstract_request'
2
- require 'huberry/proxy/action_controller/base'
3
- require 'huberry/proxy/action_controller/named_route_collection'
4
- require 'huberry/proxy/action_controller/url_rewriter'
5
- require 'huberry/proxy/action_view/url_helper'
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')
19
+ new_host = replace_host_with_proc.call(request)
20
+ request.env['HTTP_X_FORWARDED_HOST'] = [request.host, new_host].join(', ') unless new_host.blank?
21
+ end
22
+ end
23
+
24
+ ActionController::Dispatcher.before_dispatch do |dispatcher|
25
+ Proxy.send :before_dispatch, dispatcher
26
+ end
6
27
 
7
28
  ActionController::AbstractRequest = ActionController::Request if defined?(ActionController::Request)
8
- ActionController::AbstractRequest.send :include, Huberry::Proxy::ActionController::AbstractRequest
9
- ActionController::Base.send :include, Huberry::Proxy::ActionController::Base
10
- ActionController::Routing::RouteSet::NamedRouteCollection.send :include, Huberry::Proxy::ActionController::NamedRouteCollection
11
- ActionController::UrlRewriter.send :include, Huberry::Proxy::ActionController::UrlRewriter
12
- ActionView::Base.send :include, Huberry::Proxy::ActionView::UrlHelper
29
+ ActionController::AbstractRequest.send :include, Proxy::ActionController::AbstractRequest
30
+ ActionController::Base.send :include, Proxy::ActionController::Base
31
+ ActionController::Routing::RouteSet::NamedRouteCollection.send :include, Proxy::ActionController::NamedRouteCollection
32
+ ActionController::UrlRewriter.send :include, Proxy::ActionController::UrlRewriter
33
+ ActionView::Base.send :include, Proxy::ActionView::UrlHelper
13
34
 
14
35
  unless ActionController::UrlWriter.respond_to?(:default_url_options)
15
36
  ActionController::Base.class_eval do
@@ -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,120 @@
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 + ::ActionController::UrlWriter.default_url_options[:host] + args.first if args.first.is_a?(String) && !%r{^\w+://.*}.match(args.first) && !::ActionController::UrlWriter.default_url_options[:host].blank?
65
+ redirect_to_without_proxy(*args)
66
+ end
67
+
68
+ # Sets the <tt>proxy_relative_url_root</tt> using the +parse_proxy_relative_url_root+ method
69
+ # to calculate it
70
+ #
71
+ # Sets the <tt>proxy_relative_url_root</tt> to nil if there aren't any forwarded uris
72
+ def set_proxy_relative_url_root
73
+ ::ActionController::Base.proxy_relative_url_root = request.forwarded_uris.empty? ? nil : parse_proxy_relative_url_root
74
+ end
75
+
76
+ # Sets the <tt>default_url_options[:host]</tt> to the first forwarded host if there are any
77
+ #
78
+ # The original default host is restored after each request and can be accessed by calling
79
+ # <tt>ActionController::UrlWriter.default_url_options[:original_host]</tt>
80
+ def swap_default_host
81
+ ::ActionController::UrlWriter.default_url_options[:original_host] = ::ActionController::UrlWriter.default_url_options[:host]
82
+ ::ActionController::UrlWriter.default_url_options[:host] = request.forwarded_hosts.first unless request.forwarded_hosts.empty?
83
+ begin
84
+ yield
85
+ ensure
86
+ ::ActionController::UrlWriter.default_url_options[:host] = ::ActionController::UrlWriter.default_url_options[:original_host]
87
+ end
88
+ end
89
+
90
+ # Sets the <tt>relative_url_root</tt> to the <tt>proxy_relative_url_root</tt> unless it's nil
91
+ #
92
+ # The original relative url root is restored after each request and can be accessed by calling
93
+ # <tt>ActionController::Base.original_relative_url_root</tt>
94
+ def swap_relative_url_root
95
+ ::ActionController::Base.original_relative_url_root = ::ActionController::Base.relative_url_root
96
+ ::ActionController::Base.relative_url_root = ::ActionController::Base.proxy_relative_url_root unless ::ActionController::Base.proxy_relative_url_root.nil?
97
+ begin
98
+ yield
99
+ ensure
100
+ ::ActionController::Base.relative_url_root = ::ActionController::Base.original_relative_url_root
101
+ end
102
+ end
103
+
104
+ # Sets the <tt>session_options[:session_domain]</tt> to the result of the +parse_session_domain+ method
105
+ # unless there aren't any forwarded hosts
106
+ #
107
+ # The original session domain is restored after each request and can be accessed by calling
108
+ # <tt>ActionController::Base.session_options[:original_session_domain]</tt>
109
+ def swap_session_domain
110
+ ::ActionController::Base.session_options[:original_session_domain] = ::ActionController::Base.session_options[:session_domain]
111
+ ::ActionController::Base.session_options[:session_domain] = parse_session_domain unless request.forwarded_hosts.empty?
112
+ begin
113
+ yield
114
+ ensure
115
+ ::ActionController::Base.session_options[:session_domain] = ::ActionController::Base.session_options[:original_session_domain]
116
+ end
117
+ end
118
+ end
119
+ end
120
+ 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,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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shuber-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-20 00:00:00 -07:00
12
+ date: 2009-06-04 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: A gem/plugin that allows rails applications to dynamically respond to proxied requests by detecting forwarded host/uri headers and setting the session domain, default host, and relative url root
16
+ description: A gem/plugin that allows rails applications to respond to multiple domains and proxied requests
17
17
  email: shuber@huberry.com
18
18
  executables: []
19
19
 
@@ -24,11 +24,11 @@ extra_rdoc_files: []
24
24
  files:
25
25
  - CHANGELOG
26
26
  - init.rb
27
- - lib/huberry/proxy/action_controller/abstract_request.rb
28
- - lib/huberry/proxy/action_controller/base.rb
29
- - lib/huberry/proxy/action_controller/named_route_collection.rb
30
- - lib/huberry/proxy/action_controller/url_rewriter.rb
31
- - lib/huberry/proxy/action_view/url_helper.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
32
  - lib/proxy.rb
33
33
  - MIT-LICENSE
34
34
  - Rakefile
@@ -61,10 +61,11 @@ rubyforge_project:
61
61
  rubygems_version: 1.2.0
62
62
  signing_key:
63
63
  specification_version: 2
64
- summary: A gem/plugin that allows rails applications to dynamically respond to proxied requests
64
+ summary: A gem/plugin that allows rails applications to respond to multiple domains and proxied requests
65
65
  test_files:
66
66
  - test/abstract_request_test.rb
67
67
  - test/base_test.rb
68
68
  - test/named_route_collection_test.rb
69
+ - test/proxy_test.rb
69
70
  - test/url_helper_test.rb
70
71
  - test/url_rewriter_test.rb
@@ -1,43 +0,0 @@
1
- module Huberry
2
- module Proxy
3
- module ActionController
4
- module AbstractRequest
5
- def self.included(base)
6
- base.class_eval do
7
- mattr_accessor :forwarded_uri_header_name
8
- self.forwarded_uri_header_name = 'HTTP_X_FORWARDED_URI'
9
- memoize :forwarded_hosts, :forwarded_uris if respond_to? :memoize
10
- end
11
- end
12
-
13
- # Parses the forwarded host header and returns an array of forwarded hosts
14
- #
15
- # For example:
16
- #
17
- # If the HTTP_X_FORWARDED_HOST header was set to
18
- # 'some-domain.com, some-other-domain.com, and-another-domain.com'
19
- #
20
- # This method would return ['some-domain.com', 'some-other-domain.com', 'and-another-domain.com']
21
- #
22
- # Returns an empty array if there aren't any forwarded hosts
23
- def forwarded_hosts
24
- env['HTTP_X_FORWARDED_HOST'].to_s.split(/,\s*/)
25
- end
26
-
27
- # Parses the forwarded uri header and returns an array of forwarded uris
28
- #
29
- # For example:
30
- #
31
- # If the HTTP_X_FORWARDED_URI header was set to
32
- # '/some/path, /some/other/path, /and/another/path'
33
- #
34
- # This method would return ['/some/path, '/some/other/path', '/and/another/path']
35
- #
36
- # Returns an empty array if there aren't any forwarded uris
37
- def forwarded_uris
38
- env[self.forwarded_uri_header_name].to_s.split(/,\s*/)
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,122 +0,0 @@
1
- module Huberry
2
- module Proxy
3
- module ActionController
4
- module Base
5
- def self.included(base)
6
- base.class_eval do
7
- before_filter :set_proxy_relative_url_root
8
- around_filter :swap_default_host
9
- around_filter :swap_relative_url_root
10
- around_filter :swap_session_domain
11
- cattr_accessor :original_relative_url_root
12
- cattr_accessor :proxy_relative_url_root
13
- alias_method_chain :redirect_to, :proxy
14
- class << self; delegate :relative_url_root, :relative_url_root=, :to => ::ActionController::AbstractRequest unless ::ActionController::Base.respond_to?(:relative_url_root); end
15
- end
16
- end
17
-
18
- protected
19
-
20
- # Calculates the <tt>relative_url_root</tt> by parsing the request path out of the
21
- # first forwarded uri
22
- #
23
- # For example:
24
- #
25
- # http://example.com/manage/videos/new
26
- # gets proxied to
27
- # http://your-domain.com/videos/new
28
- #
29
- # The first forwarded uri would be: /manage/videos/new
30
- # and the request path would be: /videos/new
31
- #
32
- # So this method would return: /manage
33
- def parse_proxy_relative_url_root
34
- request.forwarded_uris.first.gsub(/#{Regexp.escape(request.path)}$/, '')
35
- end
36
-
37
- # Calculates the <tt>session_domain</tt> by parsing the first domain.tld out of the
38
- # first forwarded host and prepending a '.'
39
- #
40
- # For example:
41
- #
42
- # http://example.com/manage/videos/new
43
- # http://some.other-domain.com/videos/new
44
- # both get proxied to
45
- # http://your-domain.com/videos/new
46
- #
47
- # The resulting session domain for the first url would be: '.example.com'
48
- # The resulting session domain for the second url would be: '.other-domain.com'
49
- def parse_session_domain
50
- ".#{$1}" if /([^\.]+\.[^\.]+)$/.match(request.forwarded_hosts.first)
51
- end
52
-
53
- # Forces redirects to use the <tt>default_url_options[:host]</tt> if it exists unless a host
54
- # is already set
55
- #
56
- # For example:
57
- #
58
- # http://example.com
59
- # gets proxied to
60
- # http://your-domain.com
61
- #
62
- # If you have an action that calls <tt>redirect_to new_videos_path</tt>, the example.com domain
63
- # would be used instead of your-domain.com
64
- def redirect_to_with_proxy(*args)
65
- args[0] = request.protocol + ::ActionController::UrlWriter.default_url_options[:host] + args.first if args.first.is_a?(String) && !%r{^\w+://.*}.match(args.first) && !::ActionController::UrlWriter.default_url_options[:host].blank?
66
- redirect_to_without_proxy(*args)
67
- end
68
-
69
- # Sets the <tt>proxy_relative_url_root</tt> using the +parse_proxy_relative_url_root+ method
70
- # to calculate it
71
- #
72
- # Sets the <tt>proxy_relative_url_root</tt> to nil if there aren't any forwarded uris
73
- def set_proxy_relative_url_root
74
- ::ActionController::Base.proxy_relative_url_root = request.forwarded_uris.empty? ? nil : parse_proxy_relative_url_root
75
- end
76
-
77
- # Sets the <tt>default_url_options[:host]</tt> to the first forwarded host if there are any
78
- #
79
- # The original default host is restored after each request and can be accessed by calling
80
- # <tt>ActionController::UrlWriter.default_url_options[:original_host]</tt>
81
- def swap_default_host
82
- ::ActionController::UrlWriter.default_url_options[:original_host] = ::ActionController::UrlWriter.default_url_options[:host]
83
- ::ActionController::UrlWriter.default_url_options[:host] = request.forwarded_hosts.first unless request.forwarded_hosts.empty?
84
- begin
85
- yield
86
- ensure
87
- ::ActionController::UrlWriter.default_url_options[:host] = ::ActionController::UrlWriter.default_url_options[:original_host]
88
- end
89
- end
90
-
91
- # Sets the <tt>relative_url_root</tt> to the <tt>proxy_relative_url_root</tt> unless it's nil
92
- #
93
- # The original relative url root is restored after each request and can be accessed by calling
94
- # <tt>ActionController::Base.original_relative_url_root</tt>
95
- def swap_relative_url_root
96
- ::ActionController::Base.original_relative_url_root = ::ActionController::Base.relative_url_root
97
- ::ActionController::Base.relative_url_root = ::ActionController::Base.proxy_relative_url_root unless ::ActionController::Base.proxy_relative_url_root.nil?
98
- begin
99
- yield
100
- ensure
101
- ::ActionController::Base.relative_url_root = ::ActionController::Base.original_relative_url_root
102
- end
103
- end
104
-
105
- # Sets the <tt>session_options[:session_domain]</tt> to the result of the +parse_session_domain+ method
106
- # unless there aren't any forwarded hosts
107
- #
108
- # The original session domain is restored after each request and can be accessed by calling
109
- # <tt>ActionController::Base.session_options[:original_session_domain]</tt>
110
- def swap_session_domain
111
- ::ActionController::Base.session_options[:original_session_domain] = ::ActionController::Base.session_options[:session_domain]
112
- ::ActionController::Base.session_options[:session_domain] = parse_session_domain unless request.forwarded_hosts.empty?
113
- begin
114
- yield
115
- ensure
116
- ::ActionController::Base.session_options[:session_domain] = ::ActionController::Base.session_options[:original_session_domain]
117
- end
118
- end
119
- end
120
- end
121
- end
122
- end
@@ -1,32 +0,0 @@
1
- module Huberry
2
- module Proxy
3
- module ActionController
4
- module NamedRouteCollection
5
- def self.included(base)
6
- base.class_eval { alias_method_chain :define_url_helper, :proxy }
7
- end
8
-
9
- # Named route url helpers (not path helpers) don't seem to work correctly
10
- # with forwarded hosts unless we explicitly set the option:
11
- #
12
- # :only_path => false
13
- #
14
- # This method only sets that option if it isn't set already
15
- def define_url_helper_with_proxy(route, name, kind, options)
16
- define_url_helper_without_proxy(route, name, kind, options)
17
- if kind == :url
18
- selector = url_helper_name(name, kind)
19
- @module.module_eval do
20
- define_method "#{selector}_with_proxy" do |*args|
21
- args << {} unless args.last.is_a? Hash
22
- args.last[:only_path] ||= false
23
- send "#{selector}_without_proxy", *args
24
- end
25
- alias_method_chain selector, :proxy
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,23 +0,0 @@
1
- module Huberry
2
- module Proxy
3
- module ActionController
4
- module UrlRewriter
5
- def self.included(base)
6
- base.class_eval { alias_method_chain :rewrite_url, :proxy }
7
- end
8
-
9
- # Adds the default :host option unless already specified
10
- #
11
- # It will not set the :host option if <tt>options</tt> is not a hash or
12
- # if the <tt>ActionController::UrlWriter.default_url_options[:host]</tt> is blank
13
- def rewrite_url_with_proxy(options)
14
- if options.is_a?(Hash)
15
- options[:host] ||= ::ActionController::UrlWriter.default_url_options[:host] unless ::ActionController::UrlWriter.default_url_options[:host].blank?
16
- options.delete(:original_host)
17
- end
18
- rewrite_url_without_proxy(options)
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- module Huberry
2
- module Proxy
3
- module ActionView
4
- module UrlHelper
5
- def self.included(base)
6
- base.class_eval { alias_method_chain :url_for, :proxy }
7
- end
8
-
9
- # Adds the default :host option unless already specified
10
- #
11
- # It will not set the :host option if <tt>options</tt> is not a hash or
12
- # if the <tt>ActionController::UrlWriter.default_url_options[:host]</tt> is blank
13
- def url_for_with_proxy(options = {})
14
- if options.is_a?(Hash)
15
- options[:host] ||= ::ActionController::UrlWriter.default_url_options[:host] unless ::ActionController::UrlWriter.default_url_options[:host].blank?
16
- options.delete(:original_host)
17
- end
18
- url_for_without_proxy(options)
19
- end
20
- end
21
- end
22
- end
23
- end