aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller.rb6
-rw-r--r--actionpack/lib/abstract_controller/caching.rb62
-rw-r--r--actionpack/lib/abstract_controller/caching/fragments.rb (renamed from actionpack/lib/action_controller/caching/fragments.rb)11
-rw-r--r--actionpack/lib/action_controller.rb10
-rw-r--r--actionpack/lib/action_controller/caching.rb67
-rw-r--r--actionpack/lib/action_controller/metal.rb5
-rw-r--r--actionpack/lib/action_controller/metal/basic_implicit_render.rb2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb14
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb91
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb3
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb34
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb12
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_types.rb3
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb21
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/backwards.rb5
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb7
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb15
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/executor.rb19
-rw-r--r--actionpack/lib/action_dispatch/middleware/load_interlock.rb21
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb66
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb22
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb17
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb2
-rw-r--r--actionpack/lib/action_pack/gem_version.rb2
38 files changed, 336 insertions, 232 deletions
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 56c4033387..1e57cbaac4 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -6,6 +6,7 @@ module AbstractController
extend ActiveSupport::Autoload
autoload :Base
+ autoload :Caching
autoload :Callbacks
autoload :Collector
autoload :DoubleRenderError, "abstract_controller/rendering"
@@ -15,4 +16,9 @@ module AbstractController
autoload :Translation
autoload :AssetPaths
autoload :UrlFor
+
+ def self.eager_load!
+ super
+ AbstractController::Caching.eager_load!
+ end
end
diff --git a/actionpack/lib/abstract_controller/caching.rb b/actionpack/lib/abstract_controller/caching.rb
new file mode 100644
index 0000000000..0dea50889a
--- /dev/null
+++ b/actionpack/lib/abstract_controller/caching.rb
@@ -0,0 +1,62 @@
+module AbstractController
+ module Caching
+ extend ActiveSupport::Concern
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Fragments
+ end
+
+ module ConfigMethods
+ def cache_store
+ config.cache_store
+ end
+
+ def cache_store=(store)
+ config.cache_store = ActiveSupport::Cache.lookup_store(store)
+ end
+
+ private
+ def cache_configured?
+ perform_caching && cache_store
+ end
+ end
+
+ include ConfigMethods
+ include AbstractController::Caching::Fragments
+
+ included do
+ extend ConfigMethods
+
+ config_accessor :default_static_extension
+ self.default_static_extension ||= '.html'
+
+ config_accessor :perform_caching
+ self.perform_caching = true if perform_caching.nil?
+
+ class_attribute :_view_cache_dependencies
+ self._view_cache_dependencies = []
+ helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ end
+
+ module ClassMethods
+ def view_cache_dependency(&dependency)
+ self._view_cache_dependencies += [dependency]
+ end
+ end
+
+ def view_cache_dependencies
+ self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
+ end
+
+ protected
+ # Convenience accessor.
+ def cache(key, options = {}, &block)
+ if cache_configured?
+ cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
+ else
+ yield
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb
index b9ad51a9cf..3257a731ed 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/abstract_controller/caching/fragments.rb
@@ -1,4 +1,4 @@
-module ActionController
+module AbstractController
module Caching
# Fragment caching is used for caching various blocks within
# views without caching the entire action as a whole. This is
@@ -135,13 +135,8 @@ module ActionController
end
def instrument_fragment_cache(name, key) # :nodoc:
- payload = {
- controller: controller_name,
- action: action_name,
- key: key
- }
-
- ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
+ payload = instrument_payload(key)
+ ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", payload) { yield }
end
end
end
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 40f33a9de0..62f5905205 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -9,12 +9,15 @@ module ActionController
autoload :API
autoload :Base
- autoload :Caching
autoload :Metal
autoload :Middleware
autoload :Renderer
autoload :FormBuilder
+ eager_autoload do
+ autoload :Caching
+ end
+
autoload_under "metal" do
autoload :ConditionalGet
autoload :Cookies
@@ -47,11 +50,6 @@ module ActionController
autoload :TestCase, 'action_controller/test_case'
autoload :TemplateAssertions, 'action_controller/test_case'
-
- def self.eager_load!
- super
- ActionController::Caching.eager_load!
- end
end
# Common Active Support usage in Action Controller
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 0b8fa2ea09..a9a8508abc 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -1,6 +1,3 @@
-require 'fileutils'
-require 'uri'
-
module ActionController
# \Caching is a cheap way of speeding up slow applications by keeping the result of
# calculations, renderings, and database calls around for subsequent requests.
@@ -23,65 +20,25 @@ module ActionController
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
# config.action_controller.cache_store = MyOwnStore.new('parameter')
module Caching
- extend ActiveSupport::Concern
extend ActiveSupport::Autoload
-
- eager_autoload do
- autoload :Fragments
- end
-
- module ConfigMethods
- def cache_store
- config.cache_store
- end
-
- def cache_store=(store)
- config.cache_store = ActiveSupport::Cache.lookup_store(store)
- end
-
- private
- def cache_configured?
- perform_caching && cache_store
- end
- end
-
- include AbstractController::Callbacks
-
- include ConfigMethods
- include Fragments
+ extend ActiveSupport::Concern
included do
- extend ConfigMethods
-
- config_accessor :default_static_extension
- self.default_static_extension ||= '.html'
-
- config_accessor :perform_caching
- self.perform_caching = true if perform_caching.nil?
-
- class_attribute :_view_cache_dependencies
- self._view_cache_dependencies = []
- helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ include AbstractController::Caching
end
- module ClassMethods
- def view_cache_dependency(&dependency)
- self._view_cache_dependencies += [dependency]
- end
- end
+ private
- def view_cache_dependencies
- self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
- end
+ def instrument_payload(key)
+ {
+ controller: controller_name,
+ action: action_name,
+ key: key
+ }
+ end
- protected
- # Convenience accessor.
- def cache(key, options = {}, &block)
- if cache_configured?
- cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
- else
- yield
- end
+ def instrument_name
+ "action_controller"
end
end
end
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 1641d01c30..f6e67b02d7 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -175,10 +175,7 @@ module ActionController
body = [body] unless body.nil? || body.respond_to?(:each)
response.reset_body!
return unless body
- body.each { |part|
- next if part.empty?
- response.write part
- }
+ response.body = body
super
end
diff --git a/actionpack/lib/action_controller/metal/basic_implicit_render.rb b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
index 6c6f8381ff..cef65a362c 100644
--- a/actionpack/lib/action_controller/metal/basic_implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
@@ -1,5 +1,5 @@
module ActionController
- module BasicImplicitRender
+ module BasicImplicitRender # :nodoc:
def send_action(method, *args)
super.tap { default_render unless performed? }
end
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index f8e0d9cf6c..35befc05e1 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -185,7 +185,7 @@ module ActionController
!request.fresh?(response)
end
- # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a +private+
+ # Sets an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+
# instruction, so that intermediate caches must not cache the response.
#
# expires_in 20.minutes
@@ -195,7 +195,7 @@ module ActionController
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
#
- # The method will also ensure a HTTP Date header for client compatibility.
+ # The method will also ensure an HTTP Date header for client compatibility.
def expires_in(seconds, options = {})
response.cache_control.merge!(
:max_age => seconds,
@@ -208,7 +208,7 @@ module ActionController
response.date = Time.now unless response.date?
end
- # Sets a HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should
+ # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should
# occur by the browser or intermediate caches (like caching proxy servers).
def expires_now
response.cache_control.replace(:no_cache => true)
@@ -216,18 +216,16 @@ module ActionController
# Cache or yield the block. The cache is supposed to never expire.
#
- # You can use this method when you have a HTTP response that never changes,
+ # You can use this method when you have an HTTP response that never changes,
# and the browser and proxies should cache it indefinitely.
#
# * +public+: By default, HTTP responses are private, cached only on the
# user's web browser. To allow proxies to cache the response, set +true+ to
# indicate that they can serve the cached response to all users.
- #
- # * +version+: the version passed as a key for the cache.
- def http_cache_forever(public: false, version: 'v1')
+ def http_cache_forever(public: false)
expires_in 100.years, public: public
- yield if stale?(etag: "#{version}-#{request.fullpath}",
+ yield if stale?(etag: request.fullpath,
last_modified: Time.new(2011, 1, 1).utc,
public: public)
end
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index 17fcc2fa02..3a6f784507 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -1,29 +1,80 @@
+require 'active_support/core_ext/string/strip'
+
module ActionController
+ # Handles implicit rendering for a controller action when it did not
+ # explicitly indicate an appropiate response via methods such as +render+,
+ # +respond_to+, +redirect+ or +head+.
+ #
+ # For API controllers, the implicit render always renders "204 No Content"
+ # and does not account for any templates.
+ #
+ # For other controllers, the following conditions are checked:
+ #
+ # First, if a template exists for the controller action, it is rendered.
+ # This template lookup takes into account the action name, locales, format,
+ # variant, template handlers, etc. (see +render+ for details).
+ #
+ # Second, if other templates exist for the controller action but is not in
+ # the right format (or variant, etc.), an <tt>ActionController::UnknownFormat</tt>
+ # is raised. The list of available templates is assumed to be a complete
+ # enumeration of all the possible formats (or variants, etc.); that is,
+ # having only HTML and JSON templates indicate that the controller action is
+ # not meant to handle XML requests.
+ #
+ # Third, if the current request is an "interactive" browser request (the user
+ # navigated here by entering the URL in the address bar, submiting a form,
+ # clicking on a link, etc. as opposed to an XHR or non-browser API request),
+ # <tt>ActionView::UnknownFormat</tt> is raised to display a helpful error
+ # message.
+ #
+ # Finally, it falls back to the same "204 No Content" behavior as API controllers.
module ImplicitRender
+ # :stopdoc:
include BasicImplicitRender
- # Renders the template corresponding to the controller action, if it exists.
- # The action name, format, and variant are all taken into account.
- # For example, the "new" action with an HTML format and variant "phone"
- # would try to render the <tt>new.html+phone.erb</tt> template.
- #
- # If no template is found <tt>ActionController::BasicImplicitRender</tt>'s implementation is called, unless
- # a block is passed. In that case, it will override the super implementation.
- #
- # default_render do
- # head 404 # No template was found
- # end
def default_render(*args)
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
render(*args)
- else
- if block_given?
- yield(*args)
- else
- logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
- super
+ elsif any_templates?(action_name.to_s, _prefixes)
+ message = "#{self.class.name}\##{action_name} does not know how to respond " \
+ "to this request. There are other templates available for this controller " \
+ "action but none of them were suitable for this request.\n\n" \
+ "This usually happens when the client requested an unsupported format " \
+ "(e.g. requesting HTML content from a JSON endpoint or vice versa), but " \
+ "it might also be failing due to other constraints, such as locales or " \
+ "variants.\n"
+
+ if request.formats.any?
+ message << "\nRequested format(s): #{request.formats.join(", ")}"
end
+
+ if request.variant.any?
+ message << "\nRequested variant(s): #{request.variant.join(", ")}"
+ end
+
+ raise ActionController::UnknownFormat, message
+ elsif interactive_browser_request?
+ message = "You did not define any templates for #{self.class.name}\##{action_name}. " \
+ "This is not necessarily a problem (e.g. you might be building an API endpoint " \
+ "that does not require any templates), and the controller would usually respond " \
+ "with `head :no_content` for your convenience.\n\n" \
+ "However, you appear to have navigated here from an interactive browser request – " \
+ "such as by navigating to this URL directly, clicking on a link or submitting a form. " \
+ "Rendering a `head :no_content` in this case could have resulted in unexpected UI " \
+ "behavior in the browser.\n\n" \
+ "If you expected the `head :no_content` response, you do not need to take any " \
+ "actions – requests coming from an XHR (AJAX) request or other non-browser clients " \
+ "will receive the \"204 No Content\" response as expected.\n\n" \
+ "If you did not expect this behavior, you can resolve this error by adding a " \
+ "template for this controller action (usually `#{action_name}.html.erb`) or " \
+ "otherwise indicate the appropriate response in the action using `render`, " \
+ "`redirect_to`, `head`, etc.\n"
+
+ raise ActionController::UnknownFormat, message
+ else
+ logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
+ super
end
end
@@ -32,5 +83,11 @@ module ActionController
"default_render"
end
end
+
+ private
+
+ def interactive_browser_request?
+ request.format == Mime[:html] && !request.xhr?
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 6586985ff5..b2f0b382b9 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -379,7 +379,8 @@ module ActionController #:nodoc:
def xor_byte_strings(s1, s2)
s2_bytes = s2.bytes
- s1.bytes.map.with_index { |c1, i| c1 ^ s2_bytes[i] }.pack('c*')
+ s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
+ s2_bytes.pack('C*')
end
# The form's authenticity parameter. Override to provide your own.
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index ad3c765d9e..a01110d474 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -109,7 +109,7 @@ module ActionController
cattr_accessor :permit_all_parameters, instance_accessor: false
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
- delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?, :inspect,
+ delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
:as_json, to: :@parameters
# By default, never raise an UnpermittedParameters exception if these
@@ -144,17 +144,21 @@ module ActionController
end
# Returns true if another +Parameters+ object contains the same content and
- # permitted flag, or other Hash-like object contains the same content. This
- # override is in place so you can perform a comparison with `Hash`.
- def ==(other_hash)
- if other_hash.respond_to?(:permitted?)
- super
+ # permitted flag.
+ def ==(other)
+ if other.respond_to?(:permitted?)
+ self.permitted? == other.permitted? && self.parameters == other.parameters
+ elsif other.is_a?(Hash)
+ ActiveSupport::Deprecation.warn <<-WARNING.squish
+ Comparing equality between `ActionController::Parameters` and a
+ `Hash` is deprecated and will be removed in Rails 5.1. Please only do
+ comparisons between instances of `ActionController::Parameters`. If
+ you need to compare to a hash, first convert it using
+ `ActionController::Parameters#new`.
+ WARNING
+ @parameters == other.with_indifferent_access
else
- if other_hash.is_a?(Hash)
- @parameters == other_hash.with_indifferent_access
- else
- @parameters == other_hash
- end
+ @parameters == other
end
end
@@ -574,6 +578,10 @@ module ActionController
dup
end
+ def inspect
+ "<#{self.class} #{@parameters} permitted: #{@permitted}>"
+ end
+
def method_missing(method_sym, *args, &block)
if @parameters.respond_to?(method_sym)
message = <<-DEPRECATE.squish
@@ -593,12 +601,14 @@ module ActionController
end
protected
+ attr_reader :parameters
+
def permitted=(new_permitted)
@permitted = new_permitted
end
def fields_for_style?
- @parameters.all? { |k, v| k =~ /\A-?\d+\z/ && v.is_a?(Hash) }
+ @parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
end
private
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 0c4b661214..ecd21f29ce 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -52,7 +52,7 @@ module ActionController
self.session = session
self.session_options = TestSession::DEFAULT_OPTIONS
@custom_param_parsers = {
- Mime[:xml] => lambda { |raw_post| Hash.from_xml(raw_post)['hash'] }
+ xml: lambda { |raw_post| Hash.from_xml(raw_post)['hash'] }
}
end
@@ -105,7 +105,7 @@ module ActionController
when :url_encoded_form
data = non_path_parameters.to_query
else
- @custom_param_parsers[content_mime_type] = ->(_) { non_path_parameters }
+ @custom_param_parsers[content_mime_type.symbol] = ->(_) { non_path_parameters }
data = non_path_parameters.to_query
end
end
@@ -428,7 +428,7 @@ module ActionController
end
alias xhr :xml_http_request
- # Simulate a HTTP request to +action+ by specifying request method,
+ # Simulate an HTTP request to +action+ by specifying request method,
# parameters and set/volley the response.
#
# - +action+: The controller action to call.
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 1e4df07d6e..01d49475de 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -51,8 +51,8 @@ module ActionDispatch
autoload :Cookies
autoload :DebugExceptions
autoload :ExceptionWrapper
+ autoload :Executor
autoload :Flash
- autoload :LoadInterlock
autoload :ParamsParser
autoload :PublicExceptions
autoload :Reloader
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 9dcab79c3a..041eca48ca 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -4,9 +4,11 @@ module ActionDispatch
module Http
# Allows you to specify sensitive parameters which will be replaced from
# the request log by looking in the query string of the request and all
- # sub-hashes of the params hash to filter. If a block is given, each key and
- # value of the params hash and all sub-hashes is passed to it, the value
- # or key can be replaced using String#replace or similar method.
+ # sub-hashes of the params hash to filter. Filtering only certain sub-keys
+ # from a hash is possible by using the dot notation: 'credit_card.number'.
+ # If a block is given, each key and value of the params hash and all
+ # sub-hashes is passed to it, the value or key can be replaced using
+ # String#replace or similar method.
#
# env["action_dispatch.parameter_filter"] = [:password]
# => replaces the value to all keys matching /password/i with "[FILTERED]"
@@ -14,6 +16,10 @@ module ActionDispatch
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
#
+ # env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
+ # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
+ # change { file: { code: "xxxx"} }
+ #
# env["action_dispatch.parameter_filter"] = -> (k, v) do
# v.reverse! if k =~ /secret/i
# end
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 8e899174c6..5c3b7245d6 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -115,7 +115,7 @@ module ActionDispatch
private
- # Converts a HTTP header name to an environment variable name if it is
+ # Converts an 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
diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb
index 8356d1a238..66cea88256 100644
--- a/actionpack/lib/action_dispatch/http/mime_types.rb
+++ b/actionpack/lib/action_dispatch/http/mime_types.rb
@@ -28,7 +28,8 @@ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
# http://www.ietf.org/rfc/rfc4627.txt
# http://www.json.org/JSONRequest.html
-Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/vnd.api+json )
+Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
Mime::Type.register "application/pdf", :pdf, [], %w(pdf)
Mime::Type.register "application/zip", :zip, [], %w(zip)
+Mime::Type.register "application/gzip", :gzip, %w(application/x-gzip), %w(gz)
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index cca7376ffa..ff5031d7d5 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -1,22 +1,31 @@
module ActionDispatch
module Http
module Parameters
+ extend ActiveSupport::Concern
+
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
DEFAULT_PARSERS = {
- Mime[:json] => lambda { |raw_post|
+ Mime[:json].symbol => -> (raw_post) {
data = ActiveSupport::JSON.decode(raw_post)
data.is_a?(Hash) ? data : {:_json => data}
}
}
- def self.included(klass)
- class << klass
- attr_accessor :parameter_parsers
+ included do
+ class << self
+ attr_reader :parameter_parsers
end
- klass.parameter_parsers = DEFAULT_PARSERS
+ self.parameter_parsers = DEFAULT_PARSERS
end
+
+ module ClassMethods
+ def parameter_parsers=(parsers) # :nodoc:
+ @parameter_parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
+ end
+ end
+
# Returns both GET and POST \parameters in a single hash.
def parameters
params = get_header("action_dispatch.request.parameters")
@@ -51,7 +60,7 @@ module ActionDispatch
def parse_formatted_parameters(parsers)
return yield if content_length.zero?
- strategy = parsers.fetch(content_mime_type) { return yield }
+ strategy = parsers.fetch(content_mime_type.symbol) { return yield }
begin
strategy.call(raw_post)
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 5427425ef7..316a9f08b7 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -403,6 +403,10 @@ module ActionDispatch
def commit_flash
end
+ def ssl?
+ super || scheme == 'wss'.freeze
+ end
+
private
def check_method(name)
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
diff --git a/actionpack/lib/action_dispatch/journey/backwards.rb b/actionpack/lib/action_dispatch/journey/backwards.rb
deleted file mode 100644
index 3bd20fdf81..0000000000
--- a/actionpack/lib/action_dispatch/journey/backwards.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module Rack # :nodoc:
- Mount = ActionDispatch::Journey::Router
- Mount::RouteSet = ActionDispatch::Journey::Router
- Mount::RegexpWithNamedGroups = ActionDispatch::Journey::Path::Pattern
-end
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 35c2b1b86e..cfd6681dd1 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -3,7 +3,7 @@ module ActionDispatch
class Route # :nodoc:
attr_reader :app, :path, :defaults, :name, :precedence
- attr_reader :constraints
+ attr_reader :constraints, :internal
alias :conditions :constraints
module VerbMatchers
@@ -55,7 +55,7 @@ module ActionDispatch
##
# +path+ is a path constraint.
# +constraints+ is a hash of constraints to be applied to this route.
- def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence)
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
@name = name
@app = app
@path = path
@@ -70,6 +70,7 @@ module ActionDispatch
@decorated_ast = nil
@precedence = precedence
@path_formatter = @path.build_formatter
+ @internal = internal
end
def ast
@@ -81,7 +82,7 @@ module ActionDispatch
end
def requirements # :nodoc:
- # needed for rails `rake routes`
+ # needed for rails `rails routes`
@defaults.merge(path.requirements).delete_if { |_,v|
/.+?/ == v
}
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index f649588520..06cdce1724 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -16,9 +16,6 @@ module ActionDispatch
class RoutingError < ::StandardError # :nodoc:
end
- # :nodoc:
- VERSION = '2.0.0'
-
attr_accessor :routes
def initialize(routes)
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index f80df78582..c782779b34 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -7,7 +7,16 @@ module ActionDispatch
define_callbacks :call
class << self
- delegate :to_prepare, :to_cleanup, :to => "ActionDispatch::Reloader"
+ def to_prepare(*args, &block)
+ ActiveSupport::Reloader.to_prepare(*args, &block)
+ end
+
+ def to_cleanup(*args, &block)
+ ActiveSupport::Reloader.to_complete(*args, &block)
+ end
+
+ deprecate to_prepare: 'use ActiveSupport::Reloader.to_prepare instead',
+ to_cleanup: 'use ActiveSupport::Reloader.to_complete instead'
def before(*args, &block)
set_callback(:call, :before, *args, &block)
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 3477aa8b29..f2f3150b56 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/hash/keys'
require 'active_support/key_generator'
require 'active_support/message_verifier'
require 'active_support/json'
+require 'rack/utils'
module ActionDispatch
class Request
@@ -337,7 +338,7 @@ module ActionDispatch
end
def to_header
- @cookies.map { |k,v| "#{k}=#{v}" }.join ';'
+ @cookies.map { |k,v| "#{escape(k)}=#{escape(v)}" }.join '; '
end
def handle_options(options) #:nodoc:
@@ -419,6 +420,10 @@ module ActionDispatch
private
+ def escape(string)
+ ::Rack::Utils.escape(string)
+ end
+
def make_set_cookie_header(header)
header = @set_cookies.inject(header) { |m, (k, v)|
if write_cookie?(v)
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index b55c937e0c..51a471fb23 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -156,15 +156,20 @@ module ActionDispatch
trace = wrapper.framework_trace if trace.empty?
ActiveSupport::Deprecation.silence do
- message = "\n#{exception.class} (#{exception.message}):\n"
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
- message << " " << trace.join("\n ")
- logger.fatal("#{message}\n\n")
+ 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
end
end
+ def log_array(logger, array)
+ array.map { |line| logger.fatal line }
+ end
+
def logger(request)
- request.logger || stderr_logger
+ request.logger || ActionView::Base.logger || stderr_logger
end
def stderr_logger
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 3b61824cc9..59edc66086 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -1,4 +1,3 @@
-require 'action_controller/metal/exceptions'
require 'active_support/core_ext/module/attribute_accessors'
require 'rack/utils'
diff --git a/actionpack/lib/action_dispatch/middleware/executor.rb b/actionpack/lib/action_dispatch/middleware/executor.rb
new file mode 100644
index 0000000000..06245b403b
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/executor.rb
@@ -0,0 +1,19 @@
+require 'rack/body_proxy'
+
+module ActionDispatch
+ class Executor
+ def initialize(app, executor)
+ @app, @executor = app, executor
+ end
+
+ def call(env)
+ state = @executor.run!
+ begin
+ response = @app.call(env)
+ returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! }
+ ensure
+ state.complete! unless returned
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/load_interlock.rb b/actionpack/lib/action_dispatch/middleware/load_interlock.rb
deleted file mode 100644
index 07f498319c..0000000000
--- a/actionpack/lib/action_dispatch/middleware/load_interlock.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'active_support/dependencies'
-require 'rack/body_proxy'
-
-module ActionDispatch
- class LoadInterlock
- def initialize(app)
- @app = app
- end
-
- def call(env)
- interlock = ActiveSupport::Dependencies.interlock
- interlock.start_running
- response = @app.call(env)
- body = Rack::BodyProxy.new(response[2]) { interlock.done_running }
- response[2] = body
- response
- ensure
- interlock.done_running unless body
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index c2a4f46e67..5841c978af 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -37,6 +37,7 @@ module ActionDispatch
# The +parsers+ argument can take Hash of parsers where key is identifying
# content mime type, and value is a lambda that is going to process data.
def self.new(app, parsers = {})
+ parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS.merge(parsers)
app
end
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
index af9a29eb07..112bde6596 100644
--- a/actionpack/lib/action_dispatch/middleware/reloader.rb
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -23,74 +23,32 @@ module ActionDispatch
# middleware stack, but are executed only when <tt>ActionDispatch::Reloader.prepare!</tt>
# or <tt>ActionDispatch::Reloader.cleanup!</tt> are called manually.
#
- class Reloader
- include ActiveSupport::Callbacks
- include ActiveSupport::Deprecation::Reporting
-
- define_callbacks :prepare
- define_callbacks :cleanup
-
- # Add a prepare callback. Prepare callbacks are run before each request, prior
- # to ActionDispatch::Callback's before callbacks.
+ class Reloader < Executor
def self.to_prepare(*args, &block)
- unless block_given?
- warn "to_prepare without a block is deprecated. Please use a block"
- end
- set_callback(:prepare, *args, &block)
+ ActiveSupport::Reloader.to_prepare(*args, &block)
end
- # Add a cleanup callback. Cleanup callbacks are run after each request is
- # complete (after #close is called on the response body).
def self.to_cleanup(*args, &block)
- unless block_given?
- warn "to_cleanup without a block is deprecated. Please use a block"
- end
- set_callback(:cleanup, *args, &block)
+ ActiveSupport::Reloader.to_complete(*args, &block)
end
- # Execute all prepare callbacks.
def self.prepare!
- new(nil).prepare!
+ default_reloader.prepare!
end
- # Execute all cleanup callbacks.
def self.cleanup!
- new(nil).cleanup!
- end
-
- def initialize(app, condition=nil)
- @app = app
- @condition = condition || lambda { true }
- @validated = true
+ default_reloader.reload!
end
- def call(env)
- @validated = @condition.call
- prepare!
-
- response = @app.call(env)
- response[2] = ::Rack::BodyProxy.new(response[2]) { cleanup! }
+ class << self
+ attr_accessor :default_reloader # :nodoc:
- response
- rescue Exception
- cleanup!
- raise
+ deprecate to_prepare: 'use ActiveSupport::Reloader.to_prepare instead',
+ to_cleanup: 'use ActiveSupport::Reloader.to_complete instead',
+ prepare!: 'use Rails.application.reloader.prepare! instead',
+ cleanup!: 'use Rails.application.reloader.reload! instead of cleanup + prepare'
end
- def prepare! #:nodoc:
- run_callbacks :prepare if validated?
- end
-
- def cleanup! #:nodoc:
- run_callbacks :cleanup if validated?
- ensure
- @validated = true
- end
-
- private
-
- def validated? #:nodoc:
- @validated
- end
+ self.default_reloader = ActiveSupport::Reloader
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index 735b5939dd..ab3077b308 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -23,7 +23,7 @@ module ActionDispatch
# preload lists is `18.weeks`.
# * `subdomains`: Set to `true` to tell the browser to apply these settings
# to all subdomains. This protects your cookies from interception by a
- # vulnerable site on a subdomain. Defaults to `false`.
+ # vulnerable site on a subdomain. Defaults to `true`.
# * `preload`: Advertise that this site may be included in browsers'
# preloaded HSTS lists. HSTS protects your site on every visit *except the
# first visit* since it hasn't seen your HSTS header yet. To close this
@@ -34,6 +34,10 @@ module ActionDispatch
# original HSTS directive until it expires. Instead, use the header to tell browsers to
# expire HSTS immediately. Setting `hsts: false` is a shortcut for
# `hsts: { expires: 0 }`.
+ #
+ # Requests can opt-out of redirection with `exclude`:
+ #
+ # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }
class SSL
# Default to 180 days, the low end for https://www.ssllabs.com/ssltest/
# and greater than the 18-week requirement for browser preload lists.
@@ -49,14 +53,26 @@ module ActionDispatch
if options[:host] || options[:port]
ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc
The `:host` and `:port` options are moving within `:redirect`:
- `config.ssl_options = { redirect: { host: …, port: … }}`.
+ `config.ssl_options = { redirect: { host: …, port: … } }`.
end_warning
@redirect = options.slice(:host, :port)
else
@redirect = redirect
end
+ @exclude = @redirect && @redirect[:exclude] || proc { !@redirect }
@secure_cookies = secure_cookies
+
+ if hsts != true && hsts != false && hsts[:subdomains].nil?
+ hsts[:subdomains] = false
+
+ ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc
+ In Rails 5.1, The `:subdomains` option of HSTS config will be treated as true if
+ unspecified. Set `config.ssl_options = { hsts: { subdomains: false } }` to opt out
+ of this behavior.
+ end_warning
+ end
+
@hsts_header = build_hsts_header(normalize_hsts_options(hsts))
end
@@ -69,7 +85,7 @@ module ActionDispatch
flag_cookies_as_secure! headers if @secure_cookies
end
else
- return redirect_to_https request if @redirect
+ return redirect_to_https request unless @exclude.call(request)
@app.call(env)
end
end
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index ddeea24bb3..e9e6a2e597 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -39,6 +39,8 @@ module ActionDispatch
config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
+ ActionDispatch::Reloader.default_reloader = app.reloader
+
ActionDispatch.test_app = app
end
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 79f9283f83..dcf800b215 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -159,7 +159,7 @@ module ActionDispatch
#
# controller 'geocode' do
# get 'geocode/:postalcode' => :show, constraints: {
- # postalcode: /# Postcode format
+ # postalcode: /# Postalcode format
# \d{5} #Prefix
# (-\d{4})? #Suffix
# /x
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 983f1daeb3..5d30a545a2 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -41,7 +41,7 @@ module ActionDispatch
end
def internal?
- controller.to_s =~ %r{\Arails/(info|mailers|welcome)}
+ internal
end
def engine?
@@ -51,7 +51,7 @@ module ActionDispatch
##
# This class is just used for displaying route information when someone
- # executes `rake routes` or looks at the RoutingError page.
+ # executes `rails routes` or looks at the RoutingError page.
# People should not use this class.
class RoutesInspector # :nodoc:
def initialize(routes)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index afbaa45d20..16b430c36e 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -107,6 +107,7 @@ module ActionDispatch
@ast = ast
@anchor = anchor
@via = via
+ @internal = options[:internal]
path_params = ast.find_all(&:symbol?).map(&:to_sym)
@@ -148,7 +149,8 @@ module ActionDispatch
required_defaults,
defaults,
request_method,
- precedence)
+ precedence,
+ @internal)
route
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 846b5fa1fc..85f202b823 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -289,7 +289,7 @@ module ActionDispatch
if last.permitted?
args.pop.to_h
else
- raise ArgumentError, "Generating an URL from non sanitized request parameters is insecure!"
+ raise ArgumentError, "Generating a URL from non sanitized request parameters is insecure!"
end
end
helper.call self, args, options
@@ -513,6 +513,21 @@ module ActionDispatch
route = @set.add_route(name, mapping)
named_routes[name] = route if name
+
+ if route.segment_keys.include?(:controller)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Using a dynamic :controller segment in a route is deprecated and
+ will be removed in Rails 5.1
+ MSG
+ end
+
+ if route.segment_keys.include?(:action)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Using a dynamic :action segment in a route is deprecated and
+ will be removed in Rails 5.1
+ MSG
+ end
+
route
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index f91679593e..28be189f93 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -173,7 +173,7 @@ module ActionDispatch
route_name)
when ActionController::Parameters
unless options.permitted?
- raise ArgumentError.new("Generating an URL from non sanitized request parameters is insecure!")
+ raise ArgumentError.new("Generating a URL from non sanitized request parameters is insecure!")
end
route_name = options.delete :use_route
_routes.url_for(options.to_h.symbolize_keys.
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index e7af27463c..44ad2c10d8 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -117,7 +117,7 @@ module ActionDispatch
# # Tests a route, providing a defaults hash
# assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
#
- # # Tests a route with a HTTP method
+ # # Tests a route with an HTTP method
# assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
def assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_recognizes(options, path, extras, message)
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index 778c5482d3..157f401f54 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -8,7 +8,7 @@ module ActionPack
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end