aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb18
-rw-r--r--actionpack/lib/action_dispatch/http/content_security_policy.rb20
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb10
-rw-r--r--actionpack/lib/action_dispatch/http/filter_redirect.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb7
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb85
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb16
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb23
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb162
-rw-r--r--actionpack/lib/action_dispatch/journey/nodes/node.rb13
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb3
-rw-r--r--actionpack/lib/action_dispatch/journey/router/utils.rb16
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb38
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb64
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_locks.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_view.rb50
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/host_authorization.rb103
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb14
-rw-r--r--actionpack/lib/action_dispatch/middleware/request_id.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb10
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb5
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb47
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb16
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb11
33 files changed, 423 insertions, 358 deletions
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index a7c7cfc1e5..f67b13f657 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -4,8 +4,8 @@ module ActionDispatch
module Http
module Cache
module Request
- HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
- HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
+ HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
+ HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
def if_modified_since
if since = get_header(HTTP_IF_MODIFIED_SINCE)
@@ -124,8 +124,8 @@ module ActionDispatch
private
- DATE = "Date".freeze
- LAST_MODIFIED = "Last-Modified".freeze
+ DATE = "Date"
+ LAST_MODIFIED = "Last-Modified"
SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
def generate_weak_etag(validators)
@@ -166,11 +166,11 @@ module ActionDispatch
@cache_control = cache_control_headers
end
- DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze
- NO_CACHE = "no-cache".freeze
- PUBLIC = "public".freeze
- PRIVATE = "private".freeze
- MUST_REVALIDATE = "must-revalidate".freeze
+ DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
+ NO_CACHE = "no-cache"
+ PUBLIC = "public"
+ PRIVATE = "private"
+ MUST_REVALIDATE = "must-revalidate"
def handle_conditional_get!
# Normally default cache control setting is handled by ETag
diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb
index 855be5ce2e..b1e5a28be5 100644
--- a/actionpack/lib/action_dispatch/http/content_security_policy.rb
+++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb
@@ -5,9 +5,9 @@ require "active_support/core_ext/object/deep_dup"
module ActionDispatch #:nodoc:
class ContentSecurityPolicy
class Middleware
- CONTENT_TYPE = "Content-Type".freeze
- POLICY = "Content-Security-Policy".freeze
- POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only".freeze
+ CONTENT_TYPE = "Content-Type"
+ POLICY = "Content-Security-Policy"
+ POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"
def initialize(app)
@app = app
@@ -22,7 +22,8 @@ module ActionDispatch #:nodoc:
if policy = request.content_security_policy
nonce = request.content_security_policy_nonce
- headers[header_name(request)] = policy.build(request.controller_instance, nonce)
+ context = request.controller_instance || request
+ headers[header_name(request)] = policy.build(context, nonce)
end
response
@@ -50,10 +51,10 @@ module ActionDispatch #:nodoc:
end
module Request
- POLICY = "action_dispatch.content_security_policy".freeze
- POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only".freeze
- NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator".freeze
- NONCE = "action_dispatch.content_security_policy_nonce".freeze
+ POLICY = "action_dispatch.content_security_policy"
+ POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only"
+ NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator"
+ NONCE = "action_dispatch.content_security_policy_nonce"
def content_security_policy
get_header(POLICY)
@@ -257,7 +258,8 @@ module ActionDispatch #:nodoc:
if context.nil?
raise RuntimeError, "Missing context for the dynamic content security policy source: #{source.inspect}"
else
- context.instance_exec(&source)
+ resolved = context.instance_exec(&source)
+ resolved.is_a?(Symbol) ? apply_mapping(resolved) : resolved
end
else
raise RuntimeError, "Unexpected content security policy source: #{source.inspect}"
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index ec012ad02d..cbb772175c 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "action_dispatch/http/parameter_filter"
+require "active_support/parameter_filter"
module ActionDispatch
module Http
@@ -28,8 +28,8 @@ module ActionDispatch
# => reverses the value to all keys matching /secret/i
module FilterParameters
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
- NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
- NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
+ NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
+ NULL_ENV_FILTER = ActiveSupport::ParameterFilter.new ENV_MATCH # :nodoc:
def initialize
super
@@ -41,6 +41,8 @@ module ActionDispatch
# Returns a hash of parameters with all sensitive data replaced.
def filtered_parameters
@filtered_parameters ||= parameter_filter.filter(parameters)
+ rescue ActionDispatch::Http::Parameters::ParseError
+ @filtered_parameters = {}
end
# Returns a hash of request.env with all sensitive data replaced.
@@ -69,7 +71,7 @@ module ActionDispatch
end
def parameter_filter_for(filters) # :doc:
- ParameterFilter.new(filters)
+ ActiveSupport::ParameterFilter.new(filters)
end
KV_RE = "[^&;=]+"
diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb
index 25394fe5dd..8c4e852235 100644
--- a/actionpack/lib/action_dispatch/http/filter_redirect.rb
+++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb
@@ -3,7 +3,7 @@
module ActionDispatch
module Http
module FilterRedirect
- FILTERED = "[FILTERED]".freeze # :nodoc:
+ FILTERED = "[FILTERED]" # :nodoc:
def filtered_location # :nodoc:
if location_filter_match?
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index be129965d1..498b1e6695 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -7,6 +7,11 @@ module ActionDispatch
module MimeNegotiation
extend ActiveSupport::Concern
+ RESCUABLE_MIME_FORMAT_ERRORS = [
+ ActionController::BadRequest,
+ ActionDispatch::Http::Parameters::ParseError,
+ ]
+
included do
mattr_accessor :ignore_accept_header, default: false
end
@@ -59,7 +64,7 @@ module ActionDispatch
fetch_header("action_dispatch.request.formats") do |k|
params_readable = begin
parameters[:format]
- rescue ActionController::BadRequest
+ rescue *RESCUABLE_MIME_FORMAT_ERRORS
false
end
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 295539281f..c3e0ea3c89 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-# -*- frozen-string-literal: true -*-
-
require "singleton"
require "active_support/core_ext/string/starts_ends_with"
@@ -74,7 +72,7 @@ module Mime
def initialize(index, name, q = nil)
@index = index
@name = name
- q ||= 0.0 if @name == "*/*".freeze # Default wildcard match to end of list.
+ q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
@q = ((q || 1.0).to_f * 100).to_i
end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index 09aab631ed..ddeb3d81e2 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -1,87 +1,12 @@
# frozen_string_literal: true
-require "active_support/core_ext/object/duplicable"
-require "active_support/core_ext/array/extract"
+require "active_support/deprecation/constant_accessor"
+require "active_support/parameter_filter"
module ActionDispatch
module Http
- class ParameterFilter
- FILTERED = "[FILTERED]".freeze # :nodoc:
-
- def initialize(filters = [])
- @filters = filters
- end
-
- def filter(params)
- compiled_filter.call(params)
- end
-
- private
-
- def compiled_filter
- @compiled_filter ||= CompiledFilter.compile(@filters)
- end
-
- class CompiledFilter # :nodoc:
- def self.compile(filters)
- return lambda { |params| params.dup } if filters.empty?
-
- strings, regexps, blocks = [], [], []
-
- filters.each do |item|
- case item
- when Proc
- blocks << item
- when Regexp
- regexps << item
- else
- strings << Regexp.escape(item.to_s)
- end
- end
-
- deep_regexps = regexps.extract! { |r| r.to_s.include?("\\.".freeze) }
- deep_strings = strings.extract! { |s| s.include?("\\.".freeze) }
-
- regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
- deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
-
- new regexps, deep_regexps, blocks
- end
-
- attr_reader :regexps, :deep_regexps, :blocks
-
- def initialize(regexps, deep_regexps, blocks)
- @regexps = regexps
- @deep_regexps = deep_regexps.any? ? deep_regexps : nil
- @blocks = blocks
- end
-
- def call(params, parents = [], original_params = params)
- filtered_params = params.class.new
-
- params.each do |key, value|
- parents.push(key) if deep_regexps
- if regexps.any? { |r| key =~ r }
- value = FILTERED
- elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
- value = FILTERED
- elsif value.is_a?(Hash)
- value = call(value, parents, original_params)
- elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? call(v, parents, original_params) : v }
- elsif blocks.any?
- key = key.dup if key.duplicable?
- value = value.dup if value.duplicable?
- blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
- end
- parents.pop if deep_regexps
-
- filtered_params[key] = value
- end
-
- filtered_params
- end
- end
- end
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
+ deprecate_constant "ParameterFilter", "ActiveSupport::ParameterFilter",
+ message: "ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead."
end
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 8d7431fd6b..13d0963a33 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -111,13 +111,23 @@ module ActionDispatch
begin
strategy.call(raw_post)
rescue # JSON or Ruby code block errors.
- my_logger = logger || ActiveSupport::Logger.new($stderr)
- my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
-
+ log_parse_error_once
raise ParseError
end
end
+ def log_parse_error_once
+ @parse_error_logged ||= begin
+ parse_logger = logger || ActiveSupport::Logger.new($stderr)
+ parse_logger.debug <<~MSG.chomp
+ Error occurred while parsing request parameters.
+ Contents:
+
+ #{raw_post}
+ MSG
+ end
+ end
+
def params_parsers
ActionDispatch::Request.parameter_parsers
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 3838b84a7a..44f23940d3 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -136,11 +136,11 @@ module ActionDispatch
end
def routes # :nodoc:
- get_header("action_dispatch.routes".freeze)
+ get_header("action_dispatch.routes")
end
def routes=(routes) # :nodoc:
- set_header("action_dispatch.routes".freeze, routes)
+ set_header("action_dispatch.routes", routes)
end
def engine_script_name(_routes) # :nodoc:
@@ -158,11 +158,11 @@ module ActionDispatch
end
def controller_instance # :nodoc:
- get_header("action_controller.instance".freeze)
+ get_header("action_controller.instance")
end
def controller_instance=(controller) # :nodoc:
- set_header("action_controller.instance".freeze, controller)
+ set_header("action_controller.instance", controller)
end
def http_auth_salt
@@ -173,7 +173,7 @@ module ActionDispatch
# We're treating `nil` as "unset", and we want the default setting to be
# `true`. This logic should be extracted to `env_config` and calculated
# once.
- !(get_header("action_dispatch.show_exceptions".freeze) == false)
+ !(get_header("action_dispatch.show_exceptions") == false)
end
# Returns a symbol form of the #request_method.
@@ -280,10 +280,10 @@ module ActionDispatch
end
def remote_ip=(remote_ip)
- set_header "action_dispatch.remote_ip".freeze, remote_ip
+ set_header "action_dispatch.remote_ip", remote_ip
end
- ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
# Returns the unique request id, which is based on either the X-Request-Id header that can
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
@@ -383,9 +383,6 @@ module ActionDispatch
end
self.request_parameters = Request::Utils.normalize_encode_params(pr)
end
- rescue Http::Parameters::ParseError # one of the parse strategies blew up
- self.request_parameters = Request::Utils.normalize_encode_params(super || {})
- raise
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
end
@@ -407,18 +404,18 @@ module ActionDispatch
def request_parameters=(params)
raise if params.nil?
- set_header("action_dispatch.request.request_parameters".freeze, params)
+ set_header("action_dispatch.request.request_parameters", params)
end
def logger
- get_header("action_dispatch.logger".freeze)
+ get_header("action_dispatch.logger")
end
def commit_flash
end
def ssl?
- super || scheme == "wss".freeze
+ super || scheme == "wss"
end
private
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index f07be831d4..1d38942a31 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -78,9 +78,9 @@ module ActionDispatch # :nodoc:
x
end
- CONTENT_TYPE = "Content-Type".freeze
- SET_COOKIE = "Set-Cookie".freeze
- LOCATION = "Location".freeze
+ CONTENT_TYPE = "Content-Type"
+ SET_COOKIE = "Set-Cookie"
+ LOCATION = "Location"
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
cattr_accessor :default_charset, default: "utf-8"
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index db6d8188d3..8227749986 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -67,7 +67,7 @@ module ActionDispatch
end
def path_for(options)
- path = options[:script_name].to_s.chomp("/".freeze)
+ path = options[:script_name].to_s.chomp("/")
path << options[:path] if options.key?(:path)
add_trailing_slash(path) if options[:trailing_slash]
@@ -79,108 +79,108 @@ module ActionDispatch
private
- def add_params(path, params)
- params = { params: params } unless params.is_a?(Hash)
- params.reject! { |_, v| v.to_param.nil? }
- query = params.to_query
- path << "?#{query}" unless query.empty?
- end
-
- def add_anchor(path, anchor)
- if anchor
- path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
+ def add_params(path, params)
+ params = { params: params } unless params.is_a?(Hash)
+ params.reject! { |_, v| v.to_param.nil? }
+ query = params.to_query
+ path << "?#{query}" unless query.empty?
end
- end
- def extract_domain_from(host, tld_length)
- host.split(".").last(1 + tld_length).join(".")
- end
+ def add_anchor(path, anchor)
+ if anchor
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
+ end
+ end
- def extract_subdomains_from(host, tld_length)
- parts = host.split(".")
- parts[0..-(tld_length + 2)]
- end
+ def extract_domain_from(host, tld_length)
+ host.split(".").last(1 + tld_length).join(".")
+ end
- def add_trailing_slash(path)
- if path.include?("?")
- path.sub!(/\?/, '/\&')
- elsif !path.include?(".")
- path.sub!(/[^\/]\z|\A\z/, '\&/')
+ def extract_subdomains_from(host, tld_length)
+ parts = host.split(".")
+ parts[0..-(tld_length + 2)]
end
- end
- 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
+ def add_trailing_slash(path)
+ if path.include?("?")
+ path.sub!(/\?/, '/\&')
+ elsif !path.include?(".")
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
+ end
end
- protocol = normalize_protocol protocol
- host = normalize_host(host, options)
+ 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
+ end
- result = protocol.dup
+ protocol = normalize_protocol protocol
+ host = normalize_host(host, options)
- if options[:user] && options[:password]
- result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
- end
+ result = protocol.dup
- result << host
- normalize_port(port, protocol) { |normalized_port|
- result << ":#{normalized_port}"
- }
+ if options[:user] && options[:password]
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
+ end
- result.concat path
- end
+ result << host
+ normalize_port(port, protocol) { |normalized_port|
+ result << ":#{normalized_port}"
+ }
- def named_host?(host)
- IP_HOST_REGEXP !~ host
- end
+ result.concat path
+ end
- def normalize_protocol(protocol)
- case protocol
- when nil
- "http://"
- when false, "//"
- "//"
- when PROTOCOL_REGEXP
- "#{$1}://"
- else
- raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
+ def named_host?(host)
+ IP_HOST_REGEXP !~ host
end
- end
- def normalize_host(_host, options)
- return _host unless named_host?(_host)
+ def normalize_protocol(protocol)
+ case protocol
+ when nil
+ "http://"
+ when false, "//"
+ "//"
+ when PROTOCOL_REGEXP
+ "#{$1}://"
+ else
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
+ end
+ end
- tld_length = options[:tld_length] || @@tld_length
- subdomain = options.fetch :subdomain, true
- domain = options[:domain]
+ def normalize_host(_host, options)
+ return _host unless named_host?(_host)
- host = +""
- if subdomain == true
- return _host if domain.nil?
+ tld_length = options[:tld_length] || @@tld_length
+ subdomain = options.fetch :subdomain, true
+ domain = options[:domain]
- host << extract_subdomains_from(_host, tld_length).join(".")
- elsif subdomain
- host << subdomain.to_param
+ host = +""
+ if subdomain == true
+ return _host if domain.nil?
+
+ host << extract_subdomains_from(_host, tld_length).join(".")
+ elsif subdomain
+ host << subdomain.to_param
+ end
+ host << "." unless host.empty?
+ host << (domain || extract_domain_from(_host, tld_length))
+ host
end
- host << "." unless host.empty?
- host << (domain || extract_domain_from(_host, tld_length))
- host
- end
- def normalize_port(port, protocol)
- return unless port
+ def normalize_port(port, protocol)
+ return unless port
- case protocol
- when "//" then yield port
- when "https://"
- yield port unless port.to_i == 443
- else
- yield port unless port.to_i == 80
+ case protocol
+ when "//" then yield port
+ when "https://"
+ yield port unless port.to_i == 443
+ else
+ yield port unless port.to_i == 80
+ end
end
- end
end
def initialize
@@ -231,7 +231,7 @@ module ActionDispatch
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.host # => "example.com"
def host
- raw_host_with_port.sub(/:\d+$/, "".freeze)
+ raw_host_with_port.sub(/:\d+$/, "")
end
# Returns a \host:\port string for this request, such as "example.com" or
diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb
index 32f632800c..086d6a3e07 100644
--- a/actionpack/lib/action_dispatch/journey/nodes/node.rb
+++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb
@@ -65,12 +65,12 @@ module ActionDispatch
def literal?; false; end
end
- %w{ Symbol Slash Dot }.each do |t|
- class_eval <<-eoruby, __FILE__, __LINE__ + 1
- class #{t} < Terminal;
- def type; :#{t.upcase}; end
- end
- eoruby
+ class Slash < Terminal # :nodoc:
+ def type; :SLASH; end
+ end
+
+ class Dot < Terminal # :nodoc:
+ def type; :DOT; end
end
class Symbol < Terminal # :nodoc:
@@ -89,6 +89,7 @@ module ActionDispatch
regexp == DEFAULT_EXP
end
+ def type; :SYMBOL; end
def symbol?; true; end
end
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 30af3ff930..89a164f968 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -15,9 +15,6 @@ require "action_dispatch/journey/path/pattern"
module ActionDispatch
module Journey # :nodoc:
class Router # :nodoc:
- class RoutingError < ::StandardError # :nodoc:
- end
-
attr_accessor :routes
def initialize(routes)
diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb
index 3bbb187f5c..3c8b9a6eaa 100644
--- a/actionpack/lib/action_dispatch/journey/router/utils.rb
+++ b/actionpack/lib/action_dispatch/journey/router/utils.rb
@@ -18,10 +18,10 @@ module ActionDispatch
path ||= ""
encoding = path.encoding
path = +"/#{path}"
- path.squeeze!("/".freeze)
- path.sub!(%r{/+\Z}, "".freeze)
+ path.squeeze!("/")
+ path.sub!(%r{/+\Z}, "")
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
- path = +"/" if path == "".freeze
+ path = +"/" if path == ""
path.force_encoding(encoding)
path
end
@@ -29,16 +29,16 @@ module ActionDispatch
# URI path and fragment escaping
# https://tools.ietf.org/html/rfc3986
class UriEncoder # :nodoc:
- ENCODE = "%%%02X".freeze
+ ENCODE = "%%%02X"
US_ASCII = Encoding::US_ASCII
UTF_8 = Encoding::UTF_8
EMPTY = (+"").force_encoding(US_ASCII).freeze
DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
- ALPHA = "a-zA-Z".freeze
- DIGIT = "0-9".freeze
- UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~".freeze
- SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;=".freeze
+ ALPHA = "a-zA-Z"
+ DIGIT = "0-9"
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index 3395471a85..d2619cbf3a 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -40,7 +40,7 @@ module ActionDispatch
@parameters.each do |index|
param = parts[index]
value = hash[param.name]
- return "".freeze unless value
+ return "" unless value
parts[index] = param.escape value
end
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 5b2ad36dd5..87fe19225b 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -24,10 +24,8 @@ module ActionDispatch
def call(env)
error = nil
result = run_callbacks :call do
- begin
- @app.call(env)
- rescue => error
- end
+ @app.call(env)
+ rescue => error
end
raise error if error
result
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 34331b7e4b..26d3fd936f 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -9,7 +9,7 @@ require "rack/utils"
module ActionDispatch
class Request
def cookie_jar
- fetch_header("action_dispatch.cookies".freeze) do
+ fetch_header("action_dispatch.cookies") do
self.cookie_jar = Cookies::CookieJar.build(self, cookies)
end
end
@@ -22,11 +22,11 @@ module ActionDispatch
}
def have_cookie_jar?
- has_header? "action_dispatch.cookies".freeze
+ has_header? "action_dispatch.cookies"
end
def cookie_jar=(jar)
- set_header "action_dispatch.cookies".freeze, jar
+ set_header "action_dispatch.cookies", jar
end
def key_generator
@@ -172,21 +172,21 @@ module ActionDispatch
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
# only HTTP. Defaults to +false+.
class Cookies
- HTTP_HEADER = "Set-Cookie".freeze
- GENERATOR_KEY = "action_dispatch.key_generator".freeze
- SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt".freeze
- ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt".freeze
- ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
- AUTHENTICATED_ENCRYPTED_COOKIE_SALT = "action_dispatch.authenticated_encrypted_cookie_salt".freeze
- USE_AUTHENTICATED_COOKIE_ENCRYPTION = "action_dispatch.use_authenticated_cookie_encryption".freeze
- ENCRYPTED_COOKIE_CIPHER = "action_dispatch.encrypted_cookie_cipher".freeze
- SIGNED_COOKIE_DIGEST = "action_dispatch.signed_cookie_digest".freeze
- SECRET_TOKEN = "action_dispatch.secret_token".freeze
- SECRET_KEY_BASE = "action_dispatch.secret_key_base".freeze
- COOKIES_SERIALIZER = "action_dispatch.cookies_serializer".freeze
- COOKIES_DIGEST = "action_dispatch.cookies_digest".freeze
- COOKIES_ROTATIONS = "action_dispatch.cookies_rotations".freeze
- USE_COOKIES_WITH_METADATA = "action_dispatch.use_cookies_with_metadata".freeze
+ HTTP_HEADER = "Set-Cookie"
+ GENERATOR_KEY = "action_dispatch.key_generator"
+ SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt"
+ ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt"
+ ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt"
+ AUTHENTICATED_ENCRYPTED_COOKIE_SALT = "action_dispatch.authenticated_encrypted_cookie_salt"
+ USE_AUTHENTICATED_COOKIE_ENCRYPTION = "action_dispatch.use_authenticated_cookie_encryption"
+ ENCRYPTED_COOKIE_CIPHER = "action_dispatch.encrypted_cookie_cipher"
+ SIGNED_COOKIE_DIGEST = "action_dispatch.signed_cookie_digest"
+ SECRET_TOKEN = "action_dispatch.secret_token"
+ SECRET_KEY_BASE = "action_dispatch.secret_key_base"
+ COOKIES_SERIALIZER = "action_dispatch.cookies_serializer"
+ COOKIES_DIGEST = "action_dispatch.cookies_digest"
+ COOKIES_ROTATIONS = "action_dispatch.cookies_rotations"
+ USE_COOKIES_WITH_METADATA = "action_dispatch.use_cookies_with_metadata"
# Cookies can typically store 4096 bytes.
MAX_COOKIE_SIZE = 4096
@@ -535,7 +535,7 @@ module ActionDispatch
end
module SerializedCookieJars # :nodoc:
- MARSHAL_SIGNATURE = "\x04\x08".freeze
+ MARSHAL_SIGNATURE = "\x04\x08"
SERIALIZER = ActiveSupport::MessageEncryptor::NullSerializer
protected
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 5f5fdbc66a..61773d97a2 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -3,53 +3,14 @@
require "action_dispatch/http/request"
require "action_dispatch/middleware/exception_wrapper"
require "action_dispatch/routing/inspector"
+
require "action_view"
require "action_view/base"
-require "pp"
-
module ActionDispatch
# This middleware is responsible for logging exceptions and
# showing a debugging page in case the request is local.
class DebugExceptions
- RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
-
- class DebugView < ActionView::Base
- def debug_params(params)
- clean_params = params.clone
- clean_params.delete("action")
- clean_params.delete("controller")
-
- if clean_params.empty?
- "None"
- else
- PP.pp(clean_params, +"", 200)
- end
- end
-
- def debug_headers(headers)
- if headers.present?
- headers.inspect.gsub(",", ",\n")
- else
- "None"
- end
- end
-
- def debug_hash(object)
- object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
- end
-
- def render(*)
- logger = ActionView::Base.logger
-
- if logger && logger.respond_to?(:silence)
- logger.silence { super }
- else
- super
- end
- end
- end
-
cattr_reader :interceptors, instance_accessor: false, default: []
def self.register_interceptor(object = nil, &block)
@@ -87,11 +48,9 @@ module ActionDispatch
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
@interceptors.each do |interceptor|
- begin
- interceptor.call(request, exception)
- rescue Exception
- log_error(request, wrapper)
- end
+ interceptor.call(request, exception)
+ rescue Exception
+ log_error(request, wrapper)
end
end
@@ -152,7 +111,7 @@ module ActionDispatch
end
def create_template(request, wrapper)
- DebugView.new([RESCUES_TEMPLATE_PATH],
+ DebugView.new(
request: request,
exception_wrapper: wrapper,
exception: wrapper.exception,
@@ -180,11 +139,14 @@ module ActionDispatch
trace = wrapper.framework_trace if trace.empty?
ActiveSupport::Deprecation.silence do
- logger.fatal " "
- logger.fatal "#{exception.class} (#{exception.message}):"
- log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
- logger.fatal " "
- log_array logger, trace
+ message = []
+ message << " "
+ message << "#{exception.class} (#{exception.message}):"
+ message.concat(exception.annoted_source_code) if exception.respond_to?(:annoted_source_code)
+ message << " "
+ message.concat(trace)
+
+ log_array(logger, message)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_locks.rb b/actionpack/lib/action_dispatch/middleware/debug_locks.rb
index d39377f174..93c6c85a71 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_locks.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_locks.rb
@@ -32,7 +32,7 @@ module ActionDispatch
req = ActionDispatch::Request.new env
if req.get?
- path = req.path_info.chomp("/".freeze)
+ path = req.path_info.chomp("/")
if path == @path
return render_details(req)
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_view.rb b/actionpack/lib/action_dispatch/middleware/debug_view.rb
new file mode 100644
index 0000000000..ac12dc13a1
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/debug_view.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require "pp"
+
+require "action_view"
+require "action_view/base"
+
+module ActionDispatch
+ class DebugView < ActionView::Base # :nodoc:
+ RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
+
+ def initialize(assigns)
+ super([RESCUES_TEMPLATE_PATH], assigns)
+ end
+
+ def debug_params(params)
+ clean_params = params.clone
+ clean_params.delete("action")
+ clean_params.delete("controller")
+
+ if clean_params.empty?
+ "None"
+ else
+ PP.pp(clean_params, +"", 200)
+ end
+ end
+
+ def debug_headers(headers)
+ if headers.present?
+ headers.inspect.gsub(",", ",\n")
+ else
+ "None"
+ end
+ end
+
+ def debug_hash(object)
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
+ end
+
+ def render(*)
+ logger = ActionView::Base.logger
+
+ if logger && logger.respond_to?(:silence)
+ logger.silence { super }
+ else
+ super
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index fd05eec172..cf9165d008 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -38,7 +38,7 @@ module ActionDispatch
#
# See docs on the FlashHash class for more details about the flash.
class Flash
- KEY = "action_dispatch.request.flash_hash".freeze
+ KEY = "action_dispatch.request.flash_hash"
module RequestMethods
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
diff --git a/actionpack/lib/action_dispatch/middleware/host_authorization.rb b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
new file mode 100644
index 0000000000..447b70112a
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+require "action_dispatch/http/request"
+
+module ActionDispatch
+ # This middleware guards from DNS rebinding attacks by white-listing the
+ # hosts a request can be sent to.
+ #
+ # When a request comes to an unauthorized host, the +response_app+
+ # application will be executed and rendered. If no +response_app+ is given, a
+ # default one will run, which responds with +403 Forbidden+.
+ class HostAuthorization
+ class Permissions # :nodoc:
+ def initialize(hosts)
+ @hosts = sanitize_hosts(hosts)
+ end
+
+ def empty?
+ @hosts.empty?
+ end
+
+ def allows?(host)
+ @hosts.any? do |allowed|
+ allowed === host
+ rescue
+ # IPAddr#=== raises an error if you give it a hostname instead of
+ # IP. Treat similar errors as blocked access.
+ false
+ end
+ end
+
+ private
+
+ def sanitize_hosts(hosts)
+ Array(hosts).map do |host|
+ case host
+ when Regexp then sanitize_regexp(host)
+ when String then sanitize_string(host)
+ else host
+ end
+ end
+ end
+
+ def sanitize_regexp(host)
+ /\A#{host}\z/
+ end
+
+ def sanitize_string(host)
+ if host.start_with?(".")
+ /\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/
+ else
+ host
+ end
+ end
+ end
+
+ DEFAULT_RESPONSE_APP = -> env do
+ request = Request.new(env)
+
+ format = request.xhr? ? "text/plain" : "text/html"
+ template = DebugView.new(host: request.host)
+ body = template.render(template: "rescues/blocked_host", layout: "rescues/layout")
+
+ [403, {
+ "Content-Type" => "#{format}; charset=#{Response.default_charset}",
+ "Content-Length" => body.bytesize.to_s,
+ }, [body]]
+ end
+
+ def initialize(app, hosts, response_app = nil)
+ @app = app
+ @permissions = Permissions.new(hosts)
+ @response_app = response_app || DEFAULT_RESPONSE_APP
+ end
+
+ def call(env)
+ return @app.call(env) if @permissions.empty?
+
+ request = Request.new(env)
+
+ if authorized?(request)
+ mark_as_authorized(request)
+ @app.call(env)
+ else
+ @response_app.call(env)
+ end
+ end
+
+ private
+
+ def authorized?(request)
+ origin_host = request.get_header("HTTP_HOST").to_s.sub(/:\d+\z/, "")
+ forwarded_host = request.x_forwarded_host.to_s.split(/,\s?/).last.to_s.sub(/:\d+\z/, "")
+
+ @permissions.allows?(origin_host) &&
+ (forwarded_host.blank? || @permissions.allows?(forwarded_host))
+ end
+
+ def mark_as_authorized(request)
+ request.set_header("action_dispatch.authorized_host", request.host)
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 35158f9062..a5667573f4 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -162,14 +162,12 @@ module ActionDispatch
# Split the comma-separated list into an array of strings.
ips = header.strip.split(/[,\s]+/)
ips.select do |ip|
- begin
- # Only return IPs that are valid according to the IPAddr#new method.
- range = IPAddr.new(ip).to_range
- # We want to make sure nobody is sneaking a netmask in.
- range.begin == range.end
- rescue ArgumentError
- nil
- end
+ # Only return IPs that are valid according to the IPAddr#new method.
+ range = IPAddr.new(ip).to_range
+ # We want to make sure nobody is sneaking a netmask in.
+ range.begin == range.end
+ rescue ArgumentError
+ nil
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb
index da2871b551..fcc0c72240 100644
--- a/actionpack/lib/action_dispatch/middleware/request_id.rb
+++ b/actionpack/lib/action_dispatch/middleware/request_id.rb
@@ -15,7 +15,7 @@ module ActionDispatch
# The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
# from multiple pieces of the stack.
class RequestId
- X_REQUEST_ID = "X-Request-Id".freeze #:nodoc:
+ X_REQUEST_ID = "X-Request-Id" #:nodoc:
def initialize(app)
@app = app
@@ -30,7 +30,7 @@ module ActionDispatch
private
def make_request_id(request_id)
if request_id.presence
- request_id.gsub(/[^\w\-@]/, "".freeze).first(255)
+ request_id.gsub(/[^\w\-@]/, "").first(255)
else
internal_request_id
end
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index 9c9ccfa16f..00902ede21 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -83,7 +83,7 @@ module ActionDispatch
private
def set_hsts_header!(headers)
- headers["Strict-Transport-Security".freeze] ||= @hsts_header
+ headers["Strict-Transport-Security"] ||= @hsts_header
end
def normalize_hsts_options(options)
@@ -109,16 +109,16 @@ module ActionDispatch
end
def flag_cookies_as_secure!(headers)
- if cookies = headers["Set-Cookie".freeze]
- cookies = cookies.split("\n".freeze)
+ if cookies = headers["Set-Cookie"]
+ cookies = cookies.split("\n")
- headers["Set-Cookie".freeze] = cookies.map { |cookie|
+ headers["Set-Cookie"] = cookies.map { |cookie|
if !/;\s*secure\s*(;|$)/i.match?(cookie)
"#{cookie}; secure"
else
cookie
end
- }.join("\n".freeze)
+ }.join("\n")
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 277074f216..1f2f7757a3 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -79,7 +79,7 @@ module ActionDispatch
end
def content_type(path)
- ::Rack::Mime.mime_type(::File.extname(path), "text/plain".freeze)
+ ::Rack::Mime.mime_type(::File.extname(path), "text/plain")
end
def gzip_encoding_accepted?(request)
@@ -116,7 +116,7 @@ module ActionDispatch
req = Rack::Request.new env
if req.get? || req.head?
- path = req.path_info.chomp("/".freeze)
+ path = req.path_info.chomp("/")
if match = @file_handler.match?(path)
req.path_info = match
return @file_handler.serve(req)
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb
new file mode 100644
index 0000000000..2fa78dd385
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb
@@ -0,0 +1,7 @@
+<header>
+ <h1>Blocked host: <%= @host %></h1>
+</header>
+<div id="container">
+ <h2>To allow requests to <%= @host %>, add the following configuration:</h2>
+ <pre>Rails.application.config.hosts &lt;&lt; "<%= @host %>"</pre>
+</div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb
new file mode 100644
index 0000000000..4e2d1d0b08
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb
@@ -0,0 +1,5 @@
+Blocked host: <%= @host %>
+
+To allow requests to <%= @host %>, add the following configuration:
+
+ Rails.application.config.hosts << "<%= @host %>"
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 3f7cf0950d..d67044b4ac 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -50,7 +50,19 @@ module ActionDispatch
private
def constraint_args(constraint, request)
- constraint.arity == 1 ? [request] : [request.path_parameters, request]
+ arity = if constraint.respond_to?(:arity)
+ constraint.arity
+ else
+ constraint.method(:call).arity
+ end
+
+ if arity < 1
+ []
+ elsif arity == 1
+ [request]
+ else
+ [request.path_parameters, request]
+ end
end
end
@@ -148,17 +160,8 @@ module ActionDispatch
end
def make_route(name, precedence)
- route = Journey::Route.new(name,
- application,
- path,
- conditions,
- required_defaults,
- defaults,
- request_method,
- precedence,
- @internal)
-
- route
+ Journey::Route.new(name, application, path, conditions, required_defaults,
+ defaults, request_method, precedence, @internal)
end
def application
@@ -390,7 +393,7 @@ module ActionDispatch
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
path = Journey::Router::Utils.normalize_path(path)
- path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^)]+\)$}
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/(\(+[^)]+\)){1,}$}
path
end
@@ -644,7 +647,7 @@ module ActionDispatch
# Query if the following named route was already defined.
def has_named_route?(name)
- @set.named_routes.key? name
+ @set.named_routes.key?(name)
end
private
@@ -668,7 +671,7 @@ module ActionDispatch
script_namer = ->(options) do
prefix_options = options.slice(*_route.segment_keys)
- prefix_options[:relative_url_root] = "".freeze
+ prefix_options[:relative_url_root] = ""
if options[:_recall]
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
@@ -1159,10 +1162,16 @@ module ActionDispatch
end
def actions
+ if @except
+ available_actions - Array(@except).map(&:to_sym)
+ else
+ available_actions
+ end
+ end
+
+ def available_actions
if @only
Array(@only).map(&:to_sym)
- elsif @except
- default_actions - Array(@except).map(&:to_sym)
else
default_actions
end
@@ -1934,9 +1943,7 @@ module ActionDispatch
end
def match_root_route(options)
- name = has_named_route?(name_for_action(:root, nil)) ? nil : :root
- args = ["/", { as: name, via: :get }.merge!(options)]
-
+ args = ["/", { as: :root, via: :get }.merge(options)]
match(*args)
end
end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index e17ccaf986..4de5f9e2f7 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -181,8 +181,8 @@ module ActionDispatch
CACHE[type].fetch(action) { build action, type }
end
- def self.url; CACHE["url".freeze][nil]; end
- def self.path; CACHE["path".freeze][nil]; end
+ def self.url; CACHE["url"][nil]; end
+ def self.path; CACHE["path"][nil]; end
def self.build(action, type)
prefix = action ? "#{action}_" : ""
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index acce8a7ef3..2966c969f6 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -90,11 +90,11 @@ module ActionDispatch
def clear!
@path_helpers.each do |helper|
- @path_helpers_module.send :remove_method, helper
+ @path_helpers_module.remove_method helper
end
@url_helpers.each do |helper|
- @url_helpers_module.send :remove_method, helper
+ @url_helpers_module.remove_method helper
end
@routes.clear
@@ -108,8 +108,8 @@ module ActionDispatch
url_name = :"#{name}_url"
if routes.key? key
- @path_helpers_module.send :undef_method, path_name
- @url_helpers_module.send :undef_method, url_name
+ @path_helpers_module.undef_method path_name
+ @url_helpers_module.undef_method url_name
end
routes[key] = route
define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
@@ -377,7 +377,7 @@ module ActionDispatch
@prepend = []
@disable_clear_and_finalize = false
@finalized = false
- @env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze
+ @env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
@set = Journey::Routes.new
@router = Journey::Router.new @set
@@ -729,7 +729,7 @@ module ActionDispatch
# Remove leading slashes from controllers
def normalize_controller!
if controller
- if controller.start_with?("/".freeze)
+ if controller.start_with?("/")
@options[:controller] = controller[1..-1]
else
@options[:controller] = controller
@@ -820,10 +820,6 @@ module ActionDispatch
path, params = generate(route_name, path_options, recall)
- if options.key? :params
- params.merge! options[:params]
- end
-
options[:path] = path
options[:script_name] = script_name
options[:params] = params
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
index e47d5020f4..600e9c733b 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
@@ -17,8 +17,11 @@ module ActionDispatch
end
def after_teardown
- take_failed_screenshot
- Capybara.reset_sessions!
+ begin
+ take_failed_screenshot
+ ensure
+ Capybara.reset_sessions!
+ end
ensure
super
end
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 1e6b21f235..7c1202dc0e 100644
--- a/actionpack/lib/action_dispatch/testing/test_response.rb
+++ b/actionpack/lib/action_dispatch/testing/test_response.rb
@@ -14,11 +14,6 @@ module ActionDispatch
new response.status, response.headers, response.body
end
- def initialize(*) # :nodoc:
- super
- @response_parser = RequestEncoder.parser(content_type)
- end
-
# Was the response successful?
def success?
ActiveSupport::Deprecation.warn(<<-MSG.squish)
@@ -47,7 +42,11 @@ module ActionDispatch
end
def parsed_body
- @parsed_body ||= @response_parser.call(body)
+ @parsed_body ||= response_parser.call(body)
+ end
+
+ def response_parser
+ @response_parser ||= RequestEncoder.parser(content_type)
end
end
end