diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/http/url.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/http/url.rb | 176 |
1 files changed, 147 insertions, 29 deletions
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index a5858758c6..001b14ec97 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -12,10 +12,22 @@ module ActionDispatch self.tld_length = 1 class << self + # Returns the domain part of a host given the domain level. + # + # # Top-level domain example + # extract_domain('www.example.com', 1) # => "example.com" + # # Second-level domain example + # extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk" def extract_domain(host, tld_length) extract_domain_from(host, tld_length) if named_host?(host) end + # Returns the subdomains of a host as an Array given the domain level. + # + # # Top-level domain example + # extract_subdomains('www.example.com', 1) # => ["www"] + # # Second-level domain example + # extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"] def extract_subdomains(host, tld_length) if named_host?(host) extract_subdomains_from(host, tld_length) @@ -24,41 +36,61 @@ module ActionDispatch end end + # Returns the subdomains of a host as a String given the domain level. + # + # # Top-level domain example + # extract_subdomain('www.example.com', 1) # => "www" + # # Second-level domain example + # extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www" def extract_subdomain(host, tld_length) extract_subdomains(host, tld_length).join('.') end def url_for(options) - unless options[:host] || options[:only_path] + if options[:only_path] + path_for options + else + full_url_for options + end + end + + def full_url_for(options) + host = options[:host] + protocol = options[:protocol] + port = options[:port] + + unless host raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' end + build_host_url(host, port, protocol, options, path_for(options)) + end + + def path_for(options) path = options[:script_name].to_s.chomp("/") - path << options[:path].to_s + path << options[:path] if options.key?(:path) add_trailing_slash(path) if options[:trailing_slash] + add_params(path, options[:params]) if options.key?(:params) + add_anchor(path, options[:anchor]) if options.key?(:anchor) - result = path + path + end - unless options[:only_path] - result.prepend build_host_url(options) - end + private - if options.key? :params - params = options[:params].is_a?(Hash) ? - options[:params] : - { params: options[:params] } + def add_params(path, params) + params = { params: params } unless params.is_a?(Hash) + params.reject! { |_,v| v.to_param.nil? } + path << "?#{params.to_query}" unless params.empty? + end - params.reject! { |_,v| v.to_param.nil? } - result << "?#{params.to_query}" unless params.empty? + def add_anchor(path, anchor) + if anchor + path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}" end - - result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] - result end - private - def extract_domain_from(host, tld_length) host.split('.').last(1 + tld_length).join('.') end @@ -76,22 +108,17 @@ module ActionDispatch elsif !path.include?(".") path.sub!(/[^\/]\z|\A\z/, '\&/') end - - path end - def build_host_url(options) - protocol = options[:protocol] - host = options[:host] - port = options[:port] + def build_host_url(host, port, protocol, options, path) if match = host.match(HOST_REGEXP) - protocol ||= match[1] unless protocol == false - host = match[2] - port = match[3] unless options.key? :port + protocol ||= match[1] unless protocol == false + host = match[2] + port = match[3] unless options.key? :port end - protocol = normalize_protocol protocol - host = normalize_host(host, options) + protocol = normalize_protocol protocol + host = normalize_host(host, options) result = protocol.dup @@ -104,7 +131,7 @@ module ActionDispatch result << ":#{normalized_port}" } - result + result.concat path end def named_host?(host) @@ -164,16 +191,43 @@ module ActionDispatch end # Returns the complete URL used for this request. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com' + # req.url # => "http://example.com" def url protocol + host_with_port + fullpath end # Returns 'https://' if this is an SSL request and 'http://' otherwise. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com' + # req.protocol # => "http://" + # + # req = Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on' + # req.protocol # => "https://" def protocol @protocol ||= ssl? ? 'https://' : 'http://' end # Returns the \host for this request, such as "example.com". + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com' + # req.raw_host_with_port # => "example.com" + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.raw_host_with_port # => "example.com:8080" def raw_host_with_port if forwarded = env["HTTP_X_FORWARDED_HOST"] forwarded.split(/,\s?/).last @@ -183,17 +237,44 @@ module ActionDispatch end # Returns the host for this request, such as example.com. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.host # => "example.com" def host raw_host_with_port.sub(/:\d+$/, '') end # Returns a \host:\port string for this request, such as "example.com" or # "example.com:8080". + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req.host_with_port # => "example.com" + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.host_with_port # => "example.com:8080" def host_with_port "#{host}#{port_string}" end # Returns the port number of this request as an integer. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com' + # req.port # => 80 + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.port # => 8080 def port @port ||= begin if raw_host_with_port =~ /:(\d+)$/ @@ -205,6 +286,13 @@ module ActionDispatch end # Returns the standard \port number for this request's protocol. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.standard_port # => 80 def standard_port case protocol when 'https://' then 443 @@ -213,18 +301,48 @@ module ActionDispatch end # Returns whether this request is using the standard port + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req.standard_port? # => true + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.standard_port? # => false def standard_port? port == standard_port end # Returns a number \port suffix like 8080 if the \port number of this request # is not the default HTTP \port 80 or HTTPS \port 443. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req.optional_port # => nil + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.optional_port # => 8080 def optional_port standard_port? ? nil : port end # Returns a string \port suffix, including colon, like ":8080" if the \port # number of this request is not the default HTTP \port 80 or HTTPS \port 443. + # + # class Request < Rack::Request + # include ActionDispatch::Http::URL + # end + # + # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req.port_string # => "" + # + # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req.port_string # => ":8080" def port_string standard_port? ? '' : ":#{port}" end |