diff options
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/CHANGELOG.md | 6 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/base.rb | 10 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/headers.rb | 23 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/url.rb | 26 | ||||
-rw-r--r-- | actionpack/test/controller/routing_test.rb | 9 | ||||
-rw-r--r-- | actionpack/test/controller/url_for_test.rb | 12 | ||||
-rw-r--r-- | actionpack/test/dispatch/url_generation_test.rb | 12 |
7 files changed, 75 insertions, 23 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index d52ccd3d5e..5123713c6b 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,9 @@ +* Always use the provided port if the protocol is relative. + + Fixes #15043. + + *Guilherme Cavalcanti*, *Andrew White* + * Moved `params[request_forgery_protection_token]` into its own method and improved tests. diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 6d200a0333..c00f0d0c6f 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -8,7 +8,8 @@ module AbstractController class Error < StandardError #:nodoc: end - class ActionNotFound < StandardError #:nodoc: + # Raised when a non-existing controller action is triggered. + class ActionNotFound < StandardError end # <tt>AbstractController::Base</tt> is a low-level API. Nobody should be @@ -120,7 +121,7 @@ module AbstractController # # The actual method that is called is determined by calling # #method_for_action. If no method can handle the action, then an - # ActionNotFound error is raised. + # AbstractController::ActionNotFound error is raised. # # ==== Returns # * <tt>self</tt> @@ -215,7 +216,8 @@ module AbstractController # # ==== Returns # * <tt>string</tt> - The name of the method that handles the action - # * false - No valid method name could be found. Raise ActionNotFound. + # * false - No valid method name could be found. + # Raise AbstractController::ActionNotFound. def _find_action_name(action_name) _valid_action_name?(action_name) && method_for_action(action_name) end @@ -235,7 +237,7 @@ module AbstractController # the case. # # If none of these conditions are true, and method_for_action - # returns nil, an ActionNotFound exception will be raised. + # returns nil, an AbstractController::ActionNotFound exception will be raised. # # ==== Parameters # * <tt>action_name</tt> - An action name to find a method name for diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb index 788eed8b89..3e607bbde1 100644 --- a/actionpack/lib/action_dispatch/http/headers.rb +++ b/actionpack/lib/action_dispatch/http/headers.rb @@ -1,5 +1,10 @@ module ActionDispatch module Http + # Provides access to the request's HTTP headers from the environment. + # + # env = { "CONTENT_TYPE" => "text/plain" } + # headers = ActionDispatch::Http::Headers.new(env) + # headers["Content-Type"] # => "text/plain" class Headers CGI_VARIABLES = %w( CONTENT_TYPE CONTENT_LENGTH @@ -14,14 +19,16 @@ module ActionDispatch include Enumerable attr_reader :env - def initialize(env = {}) + def initialize(env = {}) # :nodoc: @env = env end + # Returns the value for the given key mapped to @env. def [](key) @env[env_name(key)] end + # Sets the given value for the key mapped to @env. def []=(key, value) @env[env_name(key)] = value end @@ -31,6 +38,13 @@ module ActionDispatch end alias :include? :key? + # Returns the value for the given key mapped to @env. + # + # If the key is not found and an optional code block is not provided, + # raises a <tt>KeyError</tt> exception. + # + # If the code block is provided, then it will be run and + # its result returned. def fetch(key, *args, &block) @env.fetch env_name(key), *args, &block end @@ -39,12 +53,17 @@ module ActionDispatch @env.each(&block) end + # Returns a new Http::Headers instance containing the contents of + # <tt>headers_or_env</tt> and the original instance. def merge(headers_or_env) headers = Http::Headers.new(env.dup) headers.merge!(headers_or_env) headers end + # Adds the contents of <tt>headers_or_env</tt> to original instance + # entries; duplicate keys are overwritten with the values from + # <tt>headers_or_env</tt>. def merge!(headers_or_env) headers_or_env.each do |key, value| self[env_name(key)] = value @@ -52,6 +71,8 @@ module ActionDispatch end private + # Converts a HTTP header name to an environment variable name if it is + # not contained within the headers hash. def env_name(key) key = key.to_s if key =~ HTTP_HEADER diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 6f5a52c568..c9860af909 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -29,15 +29,12 @@ module ActionDispatch extract_subdomains(host, tld_length).join('.') end - def url_for(options = {}) - options = options.dup - path = options.delete(:script_name).to_s.chomp("/") - path << options.delete(:path).to_s - - params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params) - params.reject! { |_,v| v.to_param.nil? } + def url_for(options) + path = options[:script_name].to_s.chomp("/") + path << options[:path].to_s result = build_host_url(options) + if options[:trailing_slash] if path.include?('?') result << path.sub(/\?/, '/\&') @@ -47,7 +44,16 @@ module ActionDispatch else result << path end - result << "?#{params.to_query}" unless params.empty? + + if options.key? :params + params = options[:params].is_a?(Hash) ? + options[:params] : + { params: options[:params] } + + params.reject! { |_,v| v.to_param.nil? } + result << "?#{params.to_query}" unless params.empty? + end + result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] result end @@ -55,7 +61,7 @@ module ActionDispatch private def build_host_url(options) - if options[:host].blank? && options[:only_path].blank? + unless options[:host] || options[:only_path] raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' end @@ -130,7 +136,7 @@ module ActionDispatch case options[:protocol] when "//" - nil + options[:port] when "https://" options[:port].to_i == 443 ? nil : options[:port] else diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index df453a0251..b22bc2dc25 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -419,14 +419,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase get 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com' end routes = setup_for_named_route - routes.expects(:url_for).with({ - :host => 'foo.com', - :only_path => false, - :controller => 'content', - :action => 'show_page', - :use_route => 'pages' - }).once - routes.send(:pages_url) + assert_equal "http://foo.com/page", routes.pages_url end def setup_for_named_route(options = {}) diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index a8035e5bd7..0c6df16325 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -169,6 +169,18 @@ module AbstractController ) end + def test_without_protocol_and_with_port + add_host! + add_port! + + assert_equal('//www.basecamphq.com:3000/c/a/i', + W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => '//') + ) + assert_equal('//www.basecamphq.com:3000/c/a/i', + W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => false) + ) + end + def test_trailing_slash add_host! options = {:controller => 'foo', :trailing_slash => true, :action => 'bar', :id => '33'} diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index fdea27e2d2..910ff8a80f 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -64,18 +64,30 @@ module TestUrlGeneration test "port is extracted from the host" do assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8080", protocol: "http://") + assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com:8080", protocol: "//") + assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com:80", protocol: "//") + end + + test "port option is used" do + assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com", protocol: "http://", port: 8080) + assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com", protocol: "//", port: 8080) + assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com", protocol: "//", port: 80) end test "port option overrides the host" do assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: 8080) + assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: 8080) + assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com:443", protocol: "//", port: 80) end test "port option disables the host when set to nil" do assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: nil) + assert_equal "//www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: nil) end test "port option disables the host when set to false" do assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: false) + assert_equal "//www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: false) end test "keep subdomain when key is true" do |