diff options
Diffstat (limited to 'actionpack/lib')
135 files changed, 785 insertions, 433 deletions
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 8bd965b198..0477e7f1c9 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "action_pack" require "active_support/rails" require "active_support/i18n" diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index e6170228d9..d6ee84b87b 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController module AssetPaths #:nodoc: extend ActiveSupport::Concern diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index bca850c0c0..a312af6715 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -1,4 +1,6 @@ -require_relative "error" +# frozen_string_literal: true + +require "abstract_controller/error" require "active_support/configurable" require "active_support/descendants_tracker" require "active_support/core_ext/module/anonymous" @@ -178,8 +180,6 @@ module AbstractController # # ==== Parameters # * <tt>name</tt> - The name of an action to be tested - # - # :api: private def action_method?(name) self.class.action_methods.include?(name) end diff --git a/actionpack/lib/abstract_controller/caching.rb b/actionpack/lib/abstract_controller/caching.rb index 30e3d4426c..ce6b757c3c 100644 --- a/actionpack/lib/abstract_controller/caching.rb +++ b/actionpack/lib/abstract_controller/caching.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController module Caching extend ActiveSupport::Concern diff --git a/actionpack/lib/abstract_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb index 14e4a82523..f99b0830b2 100644 --- a/actionpack/lib/abstract_controller/caching/fragments.rb +++ b/actionpack/lib/abstract_controller/caching/fragments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController module Caching # Fragment caching is used for caching various blocks within diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index e4400e8704..146d17cf40 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController # = Abstract Controller Callbacks # @@ -33,8 +35,8 @@ module AbstractController skip_after_callbacks_if_terminated: true end - # Override AbstractController::Base's process_action to run the - # process_action callbacks around the normal behavior. + # Override <tt>AbstractController::Base#process_action</tt> to run the + # <tt>process_action</tt> callbacks around the normal behavior. def process_action(*args) run_callbacks(:process_action) do super diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb index 40ae5aa1ca..297ec5ca40 100644 --- a/actionpack/lib/abstract_controller/collector.rb +++ b/actionpack/lib/abstract_controller/collector.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "action_dispatch/http/mime_type" module AbstractController diff --git a/actionpack/lib/abstract_controller/error.rb b/actionpack/lib/abstract_controller/error.rb index 7fafce4dd4..89a54f072e 100644 --- a/actionpack/lib/abstract_controller/error.rb +++ b/actionpack/lib/abstract_controller/error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController class Error < StandardError #:nodoc: end diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index 2e50637c39..35b462bc92 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/dependencies" module AbstractController diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb index c31ea6c5b5..8d0acc1b5c 100644 --- a/actionpack/lib/abstract_controller/logger.rb +++ b/actionpack/lib/abstract_controller/logger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/benchmarkable" module AbstractController diff --git a/actionpack/lib/abstract_controller/railties/routes_helpers.rb b/actionpack/lib/abstract_controller/railties/routes_helpers.rb index 14b574e322..b6e5631a4e 100644 --- a/actionpack/lib/abstract_controller/railties/routes_helpers.rb +++ b/actionpack/lib/abstract_controller/railties/routes_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController module Railties module RoutesHelpers diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 1c87739d42..8ba2b25552 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,4 +1,6 @@ -require_relative "error" +# frozen_string_literal: true + +require "abstract_controller/error" require "action_view" require "action_view/view_paths" require "set" @@ -18,7 +20,6 @@ module AbstractController # Normalizes arguments, options and then delegates render_to_body and # sticks the result in <tt>self.response_body</tt>. - # :api: public def render(*args, &block) options = _normalize_render(*args, &block) rendered_body = render_to_body(options) @@ -40,19 +41,16 @@ module AbstractController # (as ActionController extends it to be anything that # responds to the method each), this method needs to be # overridden in order to still return a string. - # :api: plugin def render_to_string(*args, &block) options = _normalize_render(*args, &block) render_to_body(options) end # Performs the actual template rendering. - # :api: public def render_to_body(options = {}) end - # Returns Content-Type of rendered content - # :api: public + # Returns Content-Type of rendered content. def rendered_format Mime[:text] end @@ -63,7 +61,6 @@ module AbstractController # This method should return a hash with assigns. # You can overwrite this configuration per controller. - # :api: public def view_assigns protected_vars = _protected_ivars variables = instance_variables @@ -74,11 +71,11 @@ module AbstractController } end + private # Normalize args by converting <tt>render "foo"</tt> to # <tt>render :action => "foo"</tt> and <tt>render "foo/bar"</tt> to # <tt>render :file => "foo/bar"</tt>. - # :api: plugin - def _normalize_args(action = nil, options = {}) + def _normalize_args(action = nil, options = {}) # :doc: if action.respond_to?(:permitted?) if action.permitted? action @@ -93,20 +90,17 @@ module AbstractController end # Normalize options. - # :api: plugin - def _normalize_options(options) + def _normalize_options(options) # :doc: options end # Process extra options. - # :api: plugin - def _process_options(options) + def _process_options(options) # :doc: options end # Process the rendered format. - # :api: private - def _process_format(format) + def _process_format(format) # :nodoc: end def _process_variant(options) @@ -119,8 +113,7 @@ module AbstractController end # Normalize args and options. - # :api: private - def _normalize_render(*args, &block) + def _normalize_render(*args, &block) # :nodoc: options = _normalize_args(*args, &block) _process_variant(options) _normalize_options(options) diff --git a/actionpack/lib/abstract_controller/translation.rb b/actionpack/lib/abstract_controller/translation.rb index e4ac95df50..666e154e4c 100644 --- a/actionpack/lib/abstract_controller/translation.rb +++ b/actionpack/lib/abstract_controller/translation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController module Translation # Delegates to <tt>I18n.translate</tt>. Also aliased as <tt>t</tt>. diff --git a/actionpack/lib/abstract_controller/url_for.rb b/actionpack/lib/abstract_controller/url_for.rb index 72d07b0927..bd74c27d3b 100644 --- a/actionpack/lib/abstract_controller/url_for.rb +++ b/actionpack/lib/abstract_controller/url_for.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AbstractController # Includes +url_for+ into the host class (e.g. an abstract controller or mailer). The class # has to provide a +RouteSet+ by implementing the <tt>_routes</tt> methods. Otherwise, an diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 4e2d67954f..bd19b8cd5d 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "active_support/rails" require "abstract_controller" require "action_dispatch" -require_relative "action_controller/metal/live" -require_relative "action_controller/metal/strong_parameters" +require "action_controller/metal/live" +require "action_controller/metal/strong_parameters" module ActionController extend ActiveSupport::Autoload diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb index 2bfa65021d..b192e496de 100644 --- a/actionpack/lib/action_controller/api.rb +++ b/actionpack/lib/action_controller/api.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "action_view" require "action_controller" -require_relative "log_subscriber" +require "action_controller/log_subscriber" module ActionController # API Controller is a lightweight version of <tt>ActionController::Base</tt>, diff --git a/actionpack/lib/action_controller/api/api_rendering.rb b/actionpack/lib/action_controller/api/api_rendering.rb index 3a08d28c39..aca5265313 100644 --- a/actionpack/lib/action_controller/api/api_rendering.rb +++ b/actionpack/lib/action_controller/api/api_rendering.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module ApiRendering extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 6e195fa359..b73269871b 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "action_view" -require_relative "log_subscriber" -require_relative "metal/params_wrapper" +require "action_controller/log_subscriber" +require "action_controller/metal/params_wrapper" module ActionController # Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 954265ad97..97775d1dc8 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + 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. diff --git a/actionpack/lib/action_controller/form_builder.rb b/actionpack/lib/action_controller/form_builder.rb index f2656ca894..09d2ac1837 100644 --- a/actionpack/lib/action_controller/form_builder.rb +++ b/actionpack/lib/action_controller/form_builder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # Override the default form builder for all views rendered by this # controller and any of its descendants. Accepts a subclass of diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index 5d75393897..14f41eb55f 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController class LogSubscriber < ActiveSupport::LogSubscriber INTERNAL_PARAMS = %w(controller action format _method only_path) diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 96c708f45a..457884ea08 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/array/extract_options" require "action_dispatch/middleware/stack" require "action_dispatch/http/request" diff --git a/actionpack/lib/action_controller/metal/basic_implicit_render.rb b/actionpack/lib/action_controller/metal/basic_implicit_render.rb index cef65a362c..2dc990f303 100644 --- a/actionpack/lib/action_controller/metal/basic_implicit_render.rb +++ b/actionpack/lib/action_controller/metal/basic_implicit_render.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module BasicImplicitRender # :nodoc: def send_action(method, *args) diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index 0525252c7c..06b6a95ff8 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/keys" module ActionController @@ -226,7 +228,7 @@ module ActionController # expires_in 3.hours, public: true, must_revalidate: true # # This method will overwrite an existing Cache-Control header. - # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. + # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. # # The method will also ensure an HTTP Date header for client compatibility. def expires_in(seconds, options = {}) diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb index 44925641a1..ff46966693 100644 --- a/actionpack/lib/action_controller/metal/cookies.rb +++ b/actionpack/lib/action_controller/metal/cookies.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController #:nodoc: module Cookies extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb index 3dbdd4a1b6..5a82ccf668 100644 --- a/actionpack/lib/action_controller/metal/data_streaming.rb +++ b/actionpack/lib/action_controller/metal/data_streaming.rb @@ -1,4 +1,6 @@ -require_relative "exceptions" +# frozen_string_literal: true + +require "action_controller/metal/exceptions" module ActionController #:nodoc: # Methods for sending arbitrary data and for streaming files to the browser, @@ -54,14 +56,14 @@ module ActionController #:nodoc: # # Read about the other Content-* HTTP headers if you'd like to # provide the user with more information (such as Content-Description) in - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11. + # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11. # # Also be aware that the document may be cached by proxies and browsers. # The Pragma and Cache-Control headers declare how the file may be cached # by intermediaries. They default to require clients to validate with # the server before releasing cached responses. See - # http://www.mnot.net/cache_docs/ for an overview of web caching and - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 + # https://www.mnot.net/cache_docs/ for an overview of web caching and + # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 # for the Cache-Control header spec. def send_file(path, options = {}) #:doc: raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path) @@ -111,10 +113,10 @@ module ActionController #:nodoc: def send_file_headers!(options) type_provided = options.has_key?(:type) - self.content_type = DEFAULT_SEND_FILE_TYPE + content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE) + self.content_type = content_type response.sending_file = true - content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE) raise ArgumentError, ":type option required" if content_type.nil? if content_type.is_a?(Symbol) diff --git a/actionpack/lib/action_controller/metal/etag_with_flash.rb b/actionpack/lib/action_controller/metal/etag_with_flash.rb index 7bd338bd7c..38899e2f16 100644 --- a/actionpack/lib/action_controller/metal/etag_with_flash.rb +++ b/actionpack/lib/action_controller/metal/etag_with_flash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # When you're using the flash, it's generally used as a conditional on the view. # This means the content of the view depends on the flash. Which in turn means diff --git a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb index 69c3979a0e..640c75536e 100644 --- a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb +++ b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # When our views change, they should bubble up into HTTP cache freshness # and bust browser caches. So the template digest for the current action diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index 175dd9eb9e..a65857d6ef 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController class ActionControllerError < StandardError #:nodoc: end @@ -32,9 +34,6 @@ module ActionController class NotImplemented < MethodNotAllowed #:nodoc: end - class UnknownController < ActionControllerError #:nodoc: - end - class MissingFile < ActionControllerError #:nodoc: end diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb index 24d1097ebe..5115c2fadf 100644 --- a/actionpack/lib/action_controller/metal/flash.rb +++ b/actionpack/lib/action_controller/metal/flash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController #:nodoc: module Flash extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb index 73e67573ca..0ba1f9f783 100644 --- a/actionpack/lib/action_controller/metal/force_ssl.rb +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/except" require "active_support/core_ext/hash/slice" diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb index 0c50894bce..bac9bc5e5f 100644 --- a/actionpack/lib/action_controller/metal/head.rb +++ b/actionpack/lib/action_controller/metal/head.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module Head # Returns a response that has no content (merely headers). The options diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 913a4b9a04..22c84e440b 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # The \Rails framework provides a large number of helpers for working with assets, dates, forms, # numbers and model objects, to name a few. These helpers are available to all templates diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index d8bc895265..0c8132684a 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "base64" require "active_support/security_utils" @@ -246,7 +248,7 @@ module ActionController def decode_credentials(header) ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, "").split(",").map do |pair| key, value = pair.split("=", 2) - [key.strip, value.to_s.gsub(/^"|"$/, "").delete('\'')] + [key.strip, value.to_s.gsub(/^"|"$/, "").delete("'")] end] end @@ -475,7 +477,7 @@ module ActionController # This removes the <tt>"</tt> characters wrapping the value. def rewrite_param_values(array_params) - array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, "" } + array_params.each { |param| (param[1] || "".dup).gsub! %r/^"|"$/, "" } end # This method takes an authorization body and splits up the key-value diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index eeb27f99f4..ac0c127cdc 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # Handles implicit rendering for a controller action that does not # explicitly respond with +render+, +respond_to+, +redirect+, or +head+. diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index 2485d27cec..be9449629f 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "benchmark" require "abstract_controller/logger" @@ -81,16 +83,13 @@ module ActionController # def cleanup_view_runtime # super - time_taken_in_something_expensive # end - # - # :api: plugin - def cleanup_view_runtime + def cleanup_view_runtime # :doc: yield end # Every time after an action is processed, this method is invoked # with the payload, so you can add more information. - # :api: plugin - def append_info_to_payload(payload) + def append_info_to_payload(payload) # :doc: payload[:view_runtime] = view_runtime end @@ -98,7 +97,6 @@ module ActionController # A hook which allows other frameworks to log what happened during # controller process action. This method should return an array # with the messages to be added. - # :api: plugin def log_process_action(payload) #:nodoc: messages, view_runtime = [], payload[:view_runtime] messages << ("Views: %.1fms" % view_runtime.to_f) if view_runtime diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index a607ee2309..2f4c8fb83c 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "action_dispatch/http/response" require "delegate" require "active_support/json" @@ -295,7 +297,7 @@ module ActionController return unless logger logger.fatal do - message = "\n#{exception.class} (#{exception.message}):\n" + message = "\n#{exception.class} (#{exception.message}):\n".dup message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) message << " " << exception.backtrace.join("\n ") "#{message}\n\n" diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 96bd548268..2233b93406 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_controller/collector" module ActionController #:nodoc: diff --git a/actionpack/lib/action_controller/metal/parameter_encoding.rb b/actionpack/lib/action_controller/metal/parameter_encoding.rb index ecc691619e..7a45732d31 100644 --- a/actionpack/lib/action_controller/metal/parameter_encoding.rb +++ b/actionpack/lib/action_controller/metal/parameter_encoding.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # Specify binary encoding for parameters for a given action. module ParameterEncoding diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 818af549eb..a678377d4f 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/slice" require "active_support/core_ext/hash/except" require "active_support/core_ext/module/anonymous" @@ -110,6 +112,14 @@ module ActionController else self.include = m.attribute_names end + + if m.respond_to?(:nested_attributes_options) && m.nested_attributes_options.keys.any? + self.include += m.nested_attributes_options.keys.map do |key| + key.to_s.concat("_attributes") + end + end + + self.include end end end diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index fdfe82f96b..8de57f9199 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module Redirecting extend ActiveSupport::Concern @@ -29,7 +31,7 @@ module ActionController # redirect_to post_url(@post), status: 301 # redirect_to action: 'atom', status: 302 # - # The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an + # The status code can either be a standard {HTTP Status code}[https://www.iana.org/assignments/http-status-codes] as an # integer, or a symbol representing the downcased, underscored and symbolized description. # Note that the status code must be a 3xx HTTP code, or redirection will not occur. # @@ -77,15 +79,18 @@ module ActionController # redirect_back fallback_location: "/images/screenshot.jpg" # redirect_back fallback_location: posts_url # redirect_back fallback_location: proc { edit_post_url(@post) } + # redirect_back fallback_location: '/', allow_other_host: false + # + # ==== Options + # * <tt>:fallback_location</tt> - The default fallback location that will be used on missing `Referer` header. + # * <tt>:allow_other_host</tt> - Allows or disallow redirection to the host that is different to the current host # - # All options that can be passed to <tt>redirect_to</tt> are accepted as + # All other options that can be passed to <tt>redirect_to</tt> are accepted as # options and the behavior is identical. - def redirect_back(fallback_location:, **args) - if referer = request.headers["Referer"] - redirect_to referer, **args - else - redirect_to fallback_location, **args - end + def redirect_back(fallback_location:, allow_other_host: true, **args) + referer = request.headers["Referer"] + redirect_to_referer = referer && (allow_other_host || _url_host_allowed?(referer)) + redirect_to redirect_to_referer ? referer : fallback_location, **args end def _compute_redirect_to_location(request, options) #:nodoc: @@ -93,7 +98,7 @@ module ActionController # The scheme name consist of a letter followed by any combination of # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") # characters; and is terminated by a colon (":"). - # See http://tools.ietf.org/html/rfc3986#section-3.1 + # See https://tools.ietf.org/html/rfc3986#section-3.1 # The protocol relative scheme starts with a double slash "//". when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i options @@ -118,5 +123,11 @@ module ActionController 302 end end + + def _url_host_allowed?(url) + URI(url.to_s).host == request.host + rescue ArgumentError, URI::Error + false + end end end diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 23c21b0501..b81d3ef539 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" module ActionController @@ -83,7 +85,7 @@ module ActionController def self.remove(key) RENDERERS.delete(key.to_sym) method_name = _render_with_renderer_method_name(key) - remove_method(method_name) if method_defined?(method_name) + remove_possible_method(method_name) end def self._render_with_renderer_method_name(key) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 67f207afc2..6d181e6456 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/string/filters" +# frozen_string_literal: true module ActionController module Rendering @@ -40,7 +40,7 @@ module ActionController def render_to_string(*) result = super if result.respond_to?(:each) - string = "" + string = "".dup result.each { |r| string << r } string else diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 027dae60fa..bd133f24a1 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "rack/session/abstract/id" -require_relative "exceptions" +require "action_controller/metal/exceptions" require "active_support/security_utils" module ActionController #:nodoc: @@ -20,7 +22,7 @@ module ActionController #:nodoc: # Since HTML and JavaScript requests are typically made from the browser, we # need to ensure to verify request authenticity for the web browser. We can # use session-oriented authentication for these types of requests, by using - # the `protect_from_forgery` method in our controllers. + # the <tt>protect_from_forgery</tt> method in our controllers. # # GET requests are not protected since they don't have side effects like writing # to the database and don't leak sensitive information. JavaScript requests are @@ -246,6 +248,7 @@ module ActionController #:nodoc: "If you know what you're doing, go ahead and disable forgery " \ "protection on this action to permit cross-origin JavaScript embedding." private_constant :CROSS_ORIGIN_JAVASCRIPT_WARNING + # :startdoc: # If `verify_authenticity_token` was run (indicating that we have # forgery protection enabled for this request) then also verify that diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb index 25757938f5..44f7fb7a07 100644 --- a/actionpack/lib/action_controller/metal/rescue.rb +++ b/actionpack/lib/action_controller/metal/rescue.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + module ActionController #:nodoc: - # This module is responsible for providing `rescue_from` helpers + # This module is responsible for providing +rescue_from+ helpers # to controllers and configuring when detailed exceptions must be # shown. module Rescue @@ -8,8 +10,8 @@ module ActionController #:nodoc: # Override this method if you want to customize when detailed # exceptions must be shown. This method is only called when - # consider_all_requests_local is false. By default, it returns - # false, but someone may set it to `request.local?` so local + # +consider_all_requests_local+ is +false+. By default, it returns + # +false+, but someone may set it to <tt>request.local?</tt> so local # requests in production still show the detailed exception pages. def show_detailed_exceptions? false diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 58cf60ad2a..0b1598bf1b 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rack/chunked" module ActionController #:nodoc: diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index a1b8b7cd6e..ef7c4c4c16 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/indifferent_access" require "active_support/core_ext/hash/transform_values" require "active_support/core_ext/array/wrap" @@ -673,10 +675,10 @@ module ActionController self end - # Deletes and returns a key-value pair from +Parameters+ whose key is equal - # to key. If the key is not found, returns the default value. If the - # optional code block is given and the key is not found, pass in the key - # and return the result of block. + # Deletes a key-value pair from +Parameters+ and returns the value. If + # +key+ is not found, returns +nil+ (or, with optional code block, yields + # +key+ and returns the result). Cf. +#extract!+, which returns the + # corresponding +ActionController::Parameters+ object. def delete(key, &block) convert_value_to_parameters(@parameters.delete(key, &block)) end diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index 9bb416178a..6e8a95040f 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module Testing extend ActiveSupport::Concern @@ -10,11 +12,5 @@ module ActionController self.params = nil end end - - module ClassMethods - def before_filters - _process_action_callbacks.find_all { |x| x.kind == :before }.map(&:name) - end - end end end diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 21ed5b4ec8..84dbb59a63 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing # the <tt>_routes</tt> method. Otherwise, an exception will be raised. diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 1c1cd58732..7d42f5d931 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "rails" require "action_controller" require "action_dispatch/railtie" require "abstract_controller/railties/routes_helpers" -require_relative "railties/helpers" +require "action_controller/railties/helpers" require "action_view/railtie" module ActionController @@ -22,7 +24,7 @@ module ActionController initializer "action_controller.parameters_config" do |app| options = app.config.action_controller - ActiveSupport.on_load(:action_controller) do + ActiveSupport.on_load(:action_controller, run_once: true) do ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false } if app.config.action_controller[:always_permitted_parameters] ActionController::Parameters.always_permitted_parameters = @@ -77,5 +79,11 @@ module ActionController end end end + + initializer "action_controller.eager_load_actions" do + ActiveSupport.on_load(:after_initialize) do + ActionController::Metal.descendants.each(&:action_methods) if config.eager_load + end + end end end diff --git a/actionpack/lib/action_controller/railties/helpers.rb b/actionpack/lib/action_controller/railties/helpers.rb index 3985c6b273..fa746fa9e8 100644 --- a/actionpack/lib/action_controller/railties/helpers.rb +++ b/actionpack/lib/action_controller/railties/helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module Railties module Helpers diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb index cbb719d8b2..49c5b782f0 100644 --- a/actionpack/lib/action_controller/renderer.rb +++ b/actionpack/lib/action_controller/renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/keys" module ActionController diff --git a/actionpack/lib/action_controller/template_assertions.rb b/actionpack/lib/action_controller/template_assertions.rb index 0179f4afcd..dd83c1a283 100644 --- a/actionpack/lib/action_controller/template_assertions.rb +++ b/actionpack/lib/action_controller/template_assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController module TemplateAssertions def assert_template(options = {}, message = nil) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 9d8240e46d..4b408750a4 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + require "rack/session/abstract/id" require "active_support/core_ext/hash/conversions" require "active_support/core_ext/object/to_query" require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/redefine_method" require "active_support/core_ext/hash/keys" require "active_support/testing/constant_lookup" -require_relative "template_assertions" +require "action_controller/template_assertions" require "rails-dom-testing" module ActionController @@ -17,7 +20,7 @@ module ActionController # the database on the main thread, so they could open a txn, then the # controller thread will open a new connection and try to access data # that's only visible to the main thread's txn. This is the problem in #23483. - remove_method :new_controller_thread + silence_redefinition_of_method :new_controller_thread def new_controller_thread # :nodoc: yield end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 303790e96d..34937f3229 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- # Copyright (c) 2004-2017 David Heinemeier Hansson # diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index 985e0fb972..3328ce17a0 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Http module Cache @@ -95,7 +97,7 @@ module ActionDispatch # support strong ETags and will ignore weak ETags entirely. # # Weak ETags are what we almost always need, so they're the default. - # Check out `#strong_etag=` to provide a strong ETag validator. + # Check out #strong_etag= to provide a strong ETag validator. def etag=(weak_validators) self.weak_etag = weak_validators end @@ -164,19 +166,23 @@ module ActionDispatch @cache_control = cache_control_headers end - def handle_conditional_get! - if etag? || last_modified? || !@cache_control.empty? - set_conditional_cache_control!(@cache_control) - end - 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 - def set_conditional_cache_control!(cache_control) + def handle_conditional_get! + # Normally default cache control setting is handled by ETag + # middleware. But, if an etag is already set, the middleware + # defaults to `no-cache` unless a default `Cache-Control` value is + # previously set. So, set a default one here. + if (etag? || last_modified?) && !self._cache_control + self._cache_control = DEFAULT_CACHE_CONTROL + end + end + + def merge_and_normalize_cache_control!(cache_control) control = {} cc_headers = cache_control_headers if extras = cc_headers.delete(:extras) @@ -189,7 +195,7 @@ module ActionDispatch control.merge! cache_control if control.empty? - self._cache_control = DEFAULT_CACHE_CONTROL + # Let middleware handle default behavior elsif control[:no_cache] self._cache_control = NO_CACHE if control[:extras] diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index eb6761d067..ec86b8bc47 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -1,4 +1,6 @@ -require_relative "parameter_filter" +# frozen_string_literal: true + +require "action_dispatch/http/parameter_filter" module ActionDispatch module Http @@ -7,7 +9,7 @@ module ActionDispatch # 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 + # sub-hashes is passed to it, where the value or the key can be replaced using # String#replace or similar method. # # env["action_dispatch.parameter_filter"] = [:password] @@ -46,7 +48,7 @@ module ActionDispatch @filtered_env ||= env_filter.filter(@env) end - # Reconstructed a path with all sensitive GET parameters replaced. + # Reconstructs a path with all sensitive GET parameters replaced. def filtered_path @filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}" end diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb index fc3c44582a..25394fe5dd 100644 --- a/actionpack/lib/action_dispatch/http/filter_redirect.rb +++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Http module FilterRedirect diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb index 3c03976f03..c3c2a9d8c5 100644 --- a/actionpack/lib/action_dispatch/http/headers.rb +++ b/actionpack/lib/action_dispatch/http/headers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Http # Provides access to the request's HTTP headers from the environment. diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 5994a01c78..d7435fa8df 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/module/attribute_accessors" module ActionDispatch @@ -10,9 +12,6 @@ module ActionDispatch end # The MIME type of the HTTP request, such as Mime[:xml]. - # - # For backward compatibility, the post \format is extracted from the - # X-Post-Data-Format HTTP header if present. def content_mime_type fetch_header("action_dispatch.request.content_type") do |k| v = if get_header("CONTENT_TYPE") =~ /^([^,\;]*)/ diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 5a0f661d99..d2b2106845 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # -*- frozen-string-literal: true -*- require "singleton" @@ -337,4 +339,4 @@ module Mime end end -require_relative "mime_types" +require "action_dispatch/http/mime_types" diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 8b04174f1f..f8e6fca36d 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Build list of Mime types for HTTP responses -# http://www.iana.org/assignments/media-types/ +# https://www.iana.org/assignments/media-types/ Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml ) Mime::Type.register "text/plain", :text, [], %w(txt) @@ -26,7 +28,7 @@ Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml ), %w(yml yaml) Mime::Type.register "multipart/form-data", :multipart_form Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form -# http://www.ietf.org/rfc/rfc4627.txt +# https://www.ietf.org/rfc/rfc4627.txt # http://www.json.org/JSONRequest.html Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest ) diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb index 1d2b4b902b..1d58964862 100644 --- a/actionpack/lib/action_dispatch/http/parameter_filter.rb +++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/object/duplicable" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 7c585dbe68..8d7431fd6b 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Http module Parameters @@ -55,7 +57,7 @@ module ActionDispatch query_parameters.dup end params.merge!(path_parameters) - params = set_binary_encoding(params) + params = set_binary_encoding(params, params[:controller], params[:action]) set_header("action_dispatch.request.parameters", params) params end @@ -64,6 +66,7 @@ module ActionDispatch def path_parameters=(parameters) #:nodoc: delete_header("action_dispatch.request.parameters") + parameters = set_binary_encoding(parameters, parameters[:controller], parameters[:action]) # If any of the path parameters has an invalid encoding then # raise since it's likely to trigger errors further on. Request::Utils.check_param_encoding(parameters) @@ -83,9 +86,10 @@ module ActionDispatch private - def set_binary_encoding(params) - action = params[:action] - if binary_params_for?(action) + def set_binary_encoding(params, controller, action) + return params unless controller && controller.valid_encoding? + + if binary_params_for?(controller, action) ActionDispatch::Request::Utils.each_param_value(params) do |param| param.force_encoding ::Encoding::ASCII_8BIT end @@ -93,8 +97,8 @@ module ActionDispatch params end - def binary_params_for?(action) - controller_class.binary_params_for?(action) + def binary_params_for?(controller, action) + controller_class_for(controller).binary_params_for?(action) rescue NameError false end @@ -119,9 +123,4 @@ module ActionDispatch end end end - - module ParamsParser - include ActiveSupport::Deprecation::DeprecatedConstantAccessor - deprecate_constant "ParseError", "ActionDispatch::Http::Parameters::ParseError" - end end diff --git a/actionpack/lib/action_dispatch/http/rack_cache.rb b/actionpack/lib/action_dispatch/http/rack_cache.rb index 003ae4029d..3e2d01aea3 100644 --- a/actionpack/lib/action_dispatch/http/rack_cache.rb +++ b/actionpack/lib/action_dispatch/http/rack_cache.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rack/cache" require "rack/cache/context" require "active_support/cache" diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index fd986d88e7..d631281e4b 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -3,15 +3,15 @@ require "stringio" require "active_support/inflector" -require_relative "headers" +require "action_dispatch/http/headers" require "action_controller/metal/exceptions" require "rack/request" -require_relative "cache" -require_relative "mime_negotiation" -require_relative "parameters" -require_relative "filter_parameters" -require_relative "upload" -require_relative "url" +require "action_dispatch/http/cache" +require "action_dispatch/http/mime_negotiation" +require "action_dispatch/http/parameters" +require "action_dispatch/http/filter_parameters" +require "action_dispatch/http/upload" +require "action_dispatch/http/url" require "active_support/core_ext/array/conversions" module ActionDispatch @@ -76,10 +76,13 @@ module ActionDispatch def controller_class params = path_parameters + params[:action] ||= "index" + controller_class_for(params[:controller]) + end - if params.key?(:controller) - controller_param = params[:controller].underscore - params[:action] ||= "index" + def controller_class_for(name) + if name + controller_param = name.underscore const_name = "#{controller_param.camelize}Controller" ActiveSupport::Dependencies.constantize(const_name) else @@ -95,14 +98,14 @@ module ActionDispatch end # List of HTTP request methods from the following RFCs: - # Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt) - # HTTP Extensions for Distributed Authoring -- WEBDAV (http://www.ietf.org/rfc/rfc2518.txt) - # Versioning Extensions to WebDAV (http://www.ietf.org/rfc/rfc3253.txt) - # Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt) - # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt) - # Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt) - # Calendar Extensions to WebDAV (http://www.ietf.org/rfc/rfc4791.txt) - # PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt) + # Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt) + # HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt) + # Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt) + # Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt) + # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt) + # Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt) + # Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt) + # PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt) RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT) RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK) RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY) @@ -196,6 +199,23 @@ module ActionDispatch @headers ||= Http::Headers.new(self) end + # Early Hints is an HTTP/2 status code that indicates hints to help a client start + # making preparations for processing the final response. + # + # If the env contains +rack.early_hints+ then the server accepts HTTP2 push for Link headers. + # + # The +send_early_hints+ method accepts a hash of links as follows: + # + # send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload") + # + # If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the + # Early Hints headers are included by default if supported. + def send_early_hints(links) + return unless env["rack.early_hints"] + + env["rack.early_hints"].call(links) + end + # Returns a +String+ with the last requested path including their params. # # # get '/foo' @@ -300,7 +320,7 @@ module ActionDispatch # variable is already set, wrap it in a StringIO. def body if raw_post = get_header("RAW_POST_DATA") - raw_post.force_encoding(Encoding::BINARY) + raw_post = raw_post.dup.force_encoding(Encoding::BINARY) StringIO.new(raw_post) else body_stream diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index eab663e2e0..7e50cb6d23 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "active_support/core_ext/module/attribute_accessors" -require_relative "filter_redirect" -require_relative "cache" +require "action_dispatch/http/filter_redirect" +require "action_dispatch/http/cache" require "monitor" module ActionDispatch # :nodoc: @@ -252,16 +254,15 @@ module ActionDispatch # :nodoc: end # Sets the HTTP character set. In case of +nil+ parameter - # it sets the charset to utf-8. + # it sets the charset to +default_charset+. # # response.charset = 'utf-16' # => 'utf-16' # response.charset = nil # => 'utf-8' def charset=(charset) - header_info = parsed_content_type_header + content_type = parsed_content_type_header.mime_type if false == charset - set_header CONTENT_TYPE, header_info.mime_type + set_content_type content_type, nil else - content_type = header_info.mime_type set_content_type content_type, charset || self.class.default_charset end end @@ -432,6 +433,7 @@ module ActionDispatch # :nodoc: def before_committed return if committed? assign_default_content_type_and_charset! + merge_and_normalize_cache_control!(@cache_control) handle_conditional_get! handle_no_content! end diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index 225272d66e..0b162dc7f1 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Http # Models uploaded files. diff --git a/actionpack/lib/action_dispatch/journey.rb b/actionpack/lib/action_dispatch/journey.rb index 222cbf4584..2852efa6ae 100644 --- a/actionpack/lib/action_dispatch/journey.rb +++ b/actionpack/lib/action_dispatch/journey.rb @@ -1,5 +1,7 @@ -require_relative "journey/router" -require_relative "journey/gtg/builder" -require_relative "journey/gtg/simulator" -require_relative "journey/nfa/builder" -require_relative "journey/nfa/simulator" +# frozen_string_literal: true + +require "action_dispatch/journey/router" +require "action_dispatch/journey/gtg/builder" +require "action_dispatch/journey/gtg/simulator" +require "action_dispatch/journey/nfa/builder" +require "action_dispatch/journey/nfa/simulator" diff --git a/actionpack/lib/action_dispatch/journey/gtg/builder.rb b/actionpack/lib/action_dispatch/journey/gtg/builder.rb index b1132ef17c..44c31053cb 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/builder.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/builder.rb @@ -1,4 +1,6 @@ -require_relative "transition_table" +# frozen_string_literal: true + +require "action_dispatch/journey/gtg/transition_table" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb index 62f052ced6..2ee4f5c30c 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "strscan" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index 278e4f0e11..ea647e051a 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -1,4 +1,6 @@ -require_relative "../nfa/dot" +# frozen_string_literal: true + +require "action_dispatch/journey/nfa/dot" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nfa/builder.rb b/actionpack/lib/action_dispatch/journey/nfa/builder.rb index 5b628d8cef..d22302e101 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/builder.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/builder.rb @@ -1,5 +1,7 @@ -require_relative "transition_table" -require_relative "../gtg/transition_table" +# frozen_string_literal: true + +require "action_dispatch/journey/nfa/transition_table" +require "action_dispatch/journey/gtg/transition_table" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nfa/dot.rb b/actionpack/lib/action_dispatch/journey/nfa/dot.rb index 8119e5d9da..bdb78d8d48 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/dot.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/dot.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Journey # :nodoc: module NFA # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb index 324d0eed15..8efe48d91c 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "strscan" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb index d18243545b..fe55861507 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb @@ -1,4 +1,6 @@ -require_relative "dot" +# frozen_string_literal: true + +require "action_dispatch/journey/nfa/dot" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb index 97acad6995..08b931a3cd 100644 --- a/actionpack/lib/action_dispatch/journey/nodes/node.rb +++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb @@ -1,4 +1,6 @@ -require_relative "../visitors" +# frozen_string_literal: true + +require "action_dispatch/journey/visitors" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/parser.rb b/actionpack/lib/action_dispatch/journey/parser.rb index 6ddfe96098..e002755bcf 100644 --- a/actionpack/lib/action_dispatch/journey/parser.rb +++ b/actionpack/lib/action_dispatch/journey/parser.rb @@ -8,7 +8,7 @@ require 'racc/parser.rb' # :stopdoc: -require_relative "parser_extras" +require "action_dispatch/journey/parser_extras" module ActionDispatch module Journey class Parser < Racc::Parser diff --git a/actionpack/lib/action_dispatch/journey/parser.y b/actionpack/lib/action_dispatch/journey/parser.y index 850c84ea1a..f9b1a7a958 100644 --- a/actionpack/lib/action_dispatch/journey/parser.y +++ b/actionpack/lib/action_dispatch/journey/parser.y @@ -47,4 +47,4 @@ end ---- header # :stopdoc: -require_relative "parser_extras" +require "action_dispatch/journey/parser_extras" diff --git a/actionpack/lib/action_dispatch/journey/parser_extras.rb b/actionpack/lib/action_dispatch/journey/parser_extras.rb index d26f0e121f..18ec6c9b9b 100644 --- a/actionpack/lib/action_dispatch/journey/parser_extras.rb +++ b/actionpack/lib/action_dispatch/journey/parser_extras.rb @@ -1,5 +1,7 @@ -require_relative "scanner" -require_relative "nodes/node" +# frozen_string_literal: true + +require "action_dispatch/journey/scanner" +require "action_dispatch/journey/nodes/node" module ActionDispatch # :stopdoc: diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb index cf0108ec32..2d85a89a56 100644 --- a/actionpack/lib/action_dispatch/journey/path/pattern.rb +++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Journey # :nodoc: module Path # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index 0acbac1d9d..8165709a3d 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch # :stopdoc: module Journey diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index 85f4aade55..30af3ff930 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -1,14 +1,16 @@ -require_relative "router/utils" -require_relative "routes" -require_relative "formatter" +# frozen_string_literal: true + +require "action_dispatch/journey/router/utils" +require "action_dispatch/journey/routes" +require "action_dispatch/journey/formatter" before = $-w $-w = false -require_relative "parser" +require "action_dispatch/journey/parser" $-w = before -require_relative "route" -require_relative "path/pattern" +require "action_dispatch/journey/route" +require "action_dispatch/journey/path/pattern" module ActionDispatch module Journey # :nodoc: @@ -41,6 +43,10 @@ module ActionDispatch req.path_info = "/" + req.path_info unless req.path_info.start_with? "/" end + parameters = route.defaults.merge parameters.transform_values { |val| + val.dup.force_encoding(::Encoding::UTF_8) + } + req.path_parameters = set_params.merge parameters status, headers, body = route.app.serve(req) @@ -55,7 +61,7 @@ module ActionDispatch return [status, headers, body] end - return [404, { "X-Cascade" => "pass" }, ["Not Found"]] + [404, { "X-Cascade" => "pass" }, ["Not Found"]] end def recognize(rails_req) @@ -65,6 +71,7 @@ module ActionDispatch rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1') end + parameters = route.defaults.merge parameters yield(route, parameters) end end @@ -117,7 +124,7 @@ module ActionDispatch routes.map! { |r| match_data = r.path.match(req.path_info) - path_parameters = r.defaults.dup + path_parameters = {} match_data.names.zip(match_data.captures) { |name, val| path_parameters[name.to_sym] = Utils.unescape_uri(val) if val } diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb index 3336036a03..df3f79a407 100644 --- a/actionpack/lib/action_dispatch/journey/router/utils.rb +++ b/actionpack/lib/action_dispatch/journey/router/utils.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Journey # :nodoc: class Router # :nodoc: @@ -13,7 +15,7 @@ module ActionDispatch # normalize_path("") # => "/" # normalize_path("/%ab") # => "/%AB" def self.normalize_path(path) - path ||= '' + path ||= "" encoding = path.encoding path = "/#{path}".dup path.squeeze!("/".freeze) @@ -25,7 +27,7 @@ module ActionDispatch end # URI path and fragment escaping - # http://tools.ietf.org/html/rfc3986 + # https://tools.ietf.org/html/rfc3986 class UriEncoder # :nodoc: ENCODE = "%%%02X".freeze US_ASCII = Encoding::US_ASCII diff --git a/actionpack/lib/action_dispatch/journey/routes.rb b/actionpack/lib/action_dispatch/journey/routes.rb index f7b009109e..639c063495 100644 --- a/actionpack/lib/action_dispatch/journey/routes.rb +++ b/actionpack/lib/action_dispatch/journey/routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Journey # :nodoc: # The Routing table. Contains all routes for a system. Routes can be diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index ff129cf96a..5b2ad36dd5 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch # Provides callbacks to be executed before and after dispatching the request. class Callbacks diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 533925ebe1..86a070c6ad 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/keys" require "active_support/key_generator" require "active_support/message_verifier" @@ -47,6 +49,18 @@ module ActionDispatch get_header Cookies::AUTHENTICATED_ENCRYPTED_COOKIE_SALT end + def use_authenticated_cookie_encryption + get_header Cookies::USE_AUTHENTICATED_COOKIE_ENCRYPTION + end + + def encrypted_cookie_cipher + get_header Cookies::ENCRYPTED_COOKIE_CIPHER + end + + def signed_cookie_digest + get_header Cookies::SIGNED_COOKIE_DIGEST + end + def secret_token get_header Cookies::SECRET_TOKEN end @@ -62,6 +76,11 @@ module ActionDispatch def cookies_digest get_header Cookies::COOKIES_DIGEST end + + def cookies_rotations + get_header Cookies::COOKIES_ROTATIONS + end + # :startdoc: end @@ -81,16 +100,17 @@ module ActionDispatch # cookies[:lat_lon] = JSON.generate([47.68, -122.37]) # # # Sets a cookie that expires in 1 hour. - # cookies[:login] = { value: "XJ-122", expires: 1.hour.from_now } + # cookies[:login] = { value: "XJ-122", expires: 1.hour } + # + # # Sets a cookie that expires at a specific time. + # cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) } # # # Sets a signed cookie, which prevents users from tampering with its value. - # # The cookie is signed by your app's `secrets.secret_key_base` value. # # It can be read using the signed method `cookies.signed[:name]` # cookies.signed[:user_id] = current_user.id # # # Sets an encrypted cookie value before sending it to the client which # # prevent users from reading and tampering with its value. - # # The cookie is signed by your app's `secrets.secret_key_base` value. # # It can be read using the encrypted method `cookies.encrypted[:name]` # cookies.encrypted[:discount] = 45 # @@ -98,7 +118,7 @@ module ActionDispatch # cookies.permanent[:login] = "XJ-122" # # # You can also chain these methods: - # cookies.permanent.signed[:login] = "XJ-122" + # cookies.signed.permanent[:login] = "XJ-122" # # Examples of reading: # @@ -116,7 +136,7 @@ module ActionDispatch # # cookies[:name] = { # value: 'a yummy cookie', - # expires: 1.year.from_now, + # expires: 1.year, # domain: 'domain.com' # } # @@ -142,7 +162,7 @@ module ActionDispatch # * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly # set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD. # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 1. - # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object. + # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time or ActiveSupport::Duration object. # * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers. # Default is +false+. # * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or @@ -154,10 +174,14 @@ module ActionDispatch 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 # Cookies can typically store 4096 bytes. MAX_COOKIE_SIZE = 4096 @@ -186,10 +210,10 @@ module ActionDispatch # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed # cookie was tampered with by the user (or a 3rd party), +nil+ will be returned. # - # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set, + # If +secret_key_base+ and +secrets.secret_token+ (deprecated) are both set, # legacy cookies signed with the old key generator will be transparently upgraded. # - # This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+. + # This jar requires that you set a suitable secret for the verification on your app's +secret_key_base+. # # Example: # @@ -198,40 +222,28 @@ module ActionDispatch # # cookies.signed[:discount] # => 45 def signed - @signed ||= - if upgrade_legacy_signed_cookies? - UpgradeLegacySignedCookieJar.new(self) - else - SignedCookieJar.new(self) - end + @signed ||= SignedKeyRotatingCookieJar.new(self) end # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read. # If the cookie was tampered with by the user (or a 3rd party), +nil+ will be returned. # - # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set, + # If +secret_key_base+ and +secrets.secret_token+ (deprecated) are both set, # legacy cookies signed with the old key generator will be transparently upgraded. # # If +config.action_dispatch.encrypted_cookie_salt+ and +config.action_dispatch.encrypted_signed_cookie_salt+ # are both set, legacy cookies encrypted with HMAC AES-256-CBC will be transparently upgraded. # - # This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+. + # This jar requires that you set a suitable secret for the verification on your app's +secret_key_base+. # # Example: # # cookies.encrypted[:discount] = 45 - # # => Set-Cookie: discount=ZS9ZZ1R4cG1pcUJ1bm80anhQang3dz09LS1mbDZDSU5scGdOT3ltQ2dTdlhSdWpRPT0%3D--ab54663c9f4e3bc340c790d6d2b71e92f5b60315; path=/ + # # => Set-Cookie: discount=DIQ7fw==--K3n//8vvnSbGq9dA--7Xh91HfLpwzbj1czhBiwOg==; path=/ # # cookies.encrypted[:discount] # => 45 def encrypted - @encrypted ||= - if upgrade_legacy_signed_cookies? - UpgradeLegacyEncryptedCookieJar.new(self) - elsif upgrade_legacy_hmac_aes_cbc_cookies? - UpgradeLegacyHmacAesCbcCookieJar.new(self) - else - EncryptedCookieJar.new(self) - end + @encrypted ||= EncryptedKeyRotatingCookieJar.new(self) end # Returns the +signed+ or +encrypted+ jar, preferring +encrypted+ if +secret_key_base+ is set. @@ -252,34 +264,18 @@ module ActionDispatch end def upgrade_legacy_hmac_aes_cbc_cookies? - request.secret_key_base.present? && - request.authenticated_encrypted_cookie_salt.present? && - request.encrypted_signed_cookie_salt.present? && - request.encrypted_cookie_salt.present? + request.secret_key_base.present? && + request.encrypted_signed_cookie_salt.present? && + request.encrypted_cookie_salt.present? && + request.use_authenticated_cookie_encryption end - end - # Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream - # to the Message{Encryptor,Verifier} allows us to handle the - # (de)serialization step within the cookie jar, which gives us the - # opportunity to detect and migrate legacy cookies. - module VerifyAndUpgradeLegacySignedMessage # :nodoc: - def initialize(*args) - super - @legacy_verifier = ActiveSupport::MessageVerifier.new(request.secret_token, serializer: ActiveSupport::MessageEncryptor::NullSerializer) - end - - def verify_and_upgrade_legacy_signed_message(name, signed_message) - deserialize(name, @legacy_verifier.verify(signed_message)).tap do |value| - self[name] = { value: value } + def encrypted_cookie_cipher + request.encrypted_cookie_cipher || "aes-256-gcm" end - rescue ActiveSupport::MessageVerifier::InvalidSignature - nil - end - private - def parse(name, signed_message) - super || verify_and_upgrade_legacy_signed_message(name, signed_message) + def signed_cookie_digest + request.signed_cookie_digest || "SHA1" end end @@ -358,7 +354,11 @@ module ActionDispatch @cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; " end - def handle_options(options) #:nodoc: + def handle_options(options) # :nodoc: + if options[:expires].respond_to?(:from_now) + options[:expires] = options[:expires].from_now + end + options[:path] ||= "/" if options[:domain] == :all || options[:domain] == "all" @@ -486,6 +486,14 @@ module ActionDispatch def request; @parent_jar.request; end private + def expiry_options(options) + if options[:expires].respond_to?(:from_now) + { expires_in: options[:expires] } + else + { expires_at: options[:expires] } + end + end + def parse(name, data); data; end def commit(options); end end @@ -509,6 +517,7 @@ module ActionDispatch module SerializedCookieJars # :nodoc: MARSHAL_SIGNATURE = "\x04\x08".freeze + SERIALIZER = ActiveSupport::MessageEncryptor::NullSerializer protected def needs_migration?(value) @@ -519,12 +528,16 @@ module ActionDispatch serializer.dump(value) end - def deserialize(name, value) + def deserialize(name) + rotate = false + value = yield -> { rotate = true } + if value - if needs_migration?(value) - Marshal.load(value).tap do |v| - self[name] = { value: v } - end + case + when needs_migration?(value) + self[name] = Marshal.load(value) + when rotate + self[name] = serializer.load(value) else serializer.load(value) end @@ -546,104 +559,97 @@ module ActionDispatch def digest request.cookies_digest || "SHA1" end - - def key_generator - request.key_generator - end end - class SignedCookieJar < AbstractCookieJar # :nodoc: + class SignedKeyRotatingCookieJar < AbstractCookieJar # :nodoc: include SerializedCookieJars def initialize(parent_jar) super - secret = key_generator.generate_key(request.signed_cookie_salt) - @verifier = ActiveSupport::MessageVerifier.new(secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) + + secret = request.key_generator.generate_key(request.signed_cookie_salt) + @verifier = ActiveSupport::MessageVerifier.new(secret, digest: signed_cookie_digest, serializer: SERIALIZER) + + request.cookies_rotations.signed.each do |*secrets, **options| + @verifier.rotate(*secrets, serializer: SERIALIZER, **options) + end + + if upgrade_legacy_signed_cookies? + @verifier.rotate request.secret_token, serializer: SERIALIZER + end end private def parse(name, signed_message) - deserialize name, @verifier.verified(signed_message) + deserialize(name) do |rotate| + @verifier.verified(signed_message, on_rotation: rotate) + end end def commit(options) - options[:value] = @verifier.generate(serialize(options[:value])) + options[:value] = @verifier.generate(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end end - # UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if - # secrets.secret_token and secrets.secret_key_base are both set. It reads - # legacy cookies signed with the old dummy key generator and signs and - # re-saves them using the new key generator to provide a smooth upgrade path. - class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc: - include VerifyAndUpgradeLegacySignedMessage - end - - class EncryptedCookieJar < AbstractCookieJar # :nodoc: + class EncryptedKeyRotatingCookieJar < AbstractCookieJar # :nodoc: include SerializedCookieJars def initialize(parent_jar) super - if ActiveSupport::LegacyKeyGenerator === key_generator - raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " \ - "Read the upgrade documentation to learn more about this new config option." + if request.use_authenticated_cookie_encryption + key_len = ActiveSupport::MessageEncryptor.key_len(encrypted_cookie_cipher) + secret = request.key_generator.generate_key(request.authenticated_encrypted_cookie_salt, key_len) + @encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: encrypted_cookie_cipher, serializer: SERIALIZER) + else + key_len = ActiveSupport::MessageEncryptor.key_len("aes-256-cbc") + secret = request.key_generator.generate_key(request.encrypted_cookie_salt, key_len) + sign_secret = request.key_generator.generate_key(request.encrypted_signed_cookie_salt) + @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, cipher: "aes-256-cbc", serializer: SERIALIZER) + end + + request.cookies_rotations.encrypted.each do |*secrets, **options| + @encryptor.rotate(*secrets, serializer: SERIALIZER, **options) end - cipher = "aes-256-gcm" - key_len = ActiveSupport::MessageEncryptor.key_len(cipher) - secret = key_generator.generate_key(request.authenticated_encrypted_cookie_salt || "")[0, key_len] + if upgrade_legacy_hmac_aes_cbc_cookies? + legacy_cipher = "aes-256-cbc" + secret = request.key_generator.generate_key(request.encrypted_cookie_salt, ActiveSupport::MessageEncryptor.key_len(legacy_cipher)) + sign_secret = request.key_generator.generate_key(request.encrypted_signed_cookie_salt) - @encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: ActiveSupport::MessageEncryptor::NullSerializer) + @encryptor.rotate(secret, sign_secret, cipher: legacy_cipher, digest: digest, serializer: SERIALIZER) + end + + if upgrade_legacy_signed_cookies? + @legacy_verifier = ActiveSupport::MessageVerifier.new(request.secret_token, digest: digest, serializer: SERIALIZER) + end end private def parse(name, encrypted_message) - deserialize name, @encryptor.decrypt_and_verify(encrypted_message) - rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage - nil + deserialize(name) do |rotate| + @encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate) + end + rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature + parse_legacy_signed_message(name, encrypted_message) end def commit(options) - options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value])) + options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end - end - - # UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore - # instead of EncryptedCookieJar if secrets.secret_token and secrets.secret_key_base - # are both set. It reads legacy cookies signed with the old dummy key generator and - # encrypts and re-saves them using the new key generator to provide a smooth upgrade path. - class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc: - include VerifyAndUpgradeLegacySignedMessage - end - - # UpgradeLegacyHmacAesCbcCookieJar is used by ActionDispatch::Session::CookieStore - # to upgrade cookies encrypted with AES-256-CBC with HMAC to AES-256-GCM - class UpgradeLegacyHmacAesCbcCookieJar < EncryptedCookieJar - def initialize(parent_jar) - super - secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len] - sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "") - - @legacy_encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, cipher: "aes-256-cbc", digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) - end + def parse_legacy_signed_message(name, legacy_signed_message) + if defined?(@legacy_verifier) + deserialize(name) do |rotate| + rotate.call - def decrypt_and_verify_legacy_encrypted_message(name, signed_message) - deserialize(name, @legacy_encryptor.decrypt_and_verify(signed_message)).tap do |value| - self[name] = { value: value } - end - rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage - nil - end - - private - def parse(name, signed_message) - super || decrypt_and_verify_legacy_encrypted_message(name, signed_message) + @legacy_verifier.verified(legacy_signed_message) + end + end end end diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 3006cd97ce..511306eb0e 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative "../http/request" -require_relative "exception_wrapper" -require_relative "../routing/inspector" +require "action_dispatch/http/request" +require "action_dispatch/middleware/exception_wrapper" +require "action_dispatch/routing/inspector" require "action_view" require "action_view/base" diff --git a/actionpack/lib/action_dispatch/middleware/debug_locks.rb b/actionpack/lib/action_dispatch/middleware/debug_locks.rb index 74b952528e..03760438f7 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_locks.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_locks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch # This middleware can be used to diagnose deadlocks in the autoload interlock. # @@ -41,7 +43,7 @@ module ActionDispatch private def render_details(req) - threads = ActiveSupport::Dependencies.interlock.raw_state do |threads| + threads = ActiveSupport::Dependencies.interlock.raw_state do |raw_threads| # The Interlock itself comes to a complete halt as long as this block # is executing. That gives us a more consistent picture of everything, # but creates a pretty strong Observer Effect. @@ -51,29 +53,29 @@ module ActionDispatch # strictly diagnostic tool (to be used when something has gone wrong), # and not for any sort of general monitoring. - threads.each.with_index do |(thread, info), idx| + raw_threads.each.with_index do |(thread, info), idx| info[:index] = idx info[:backtrace] = thread.backtrace end - threads + raw_threads end str = threads.map do |thread, info| if info[:exclusive] - lock_state = "Exclusive" + lock_state = "Exclusive".dup elsif info[:sharing] > 0 - lock_state = "Sharing" + lock_state = "Sharing".dup lock_state << " x#{info[:sharing]}" if info[:sharing] > 1 else - lock_state = "No lock" + lock_state = "No lock".dup end if info[:waiting] lock_state << " (yielded share)" end - msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n" + msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n".dup if info[:sleeper] msg << " Waiting in #{info[:sleeper]}" diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 08b4541d24..4f69abfa6f 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + 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 index 3d43f97a2b..129b18d3d9 100644 --- a/actionpack/lib/action_dispatch/middleware/executor.rb +++ b/actionpack/lib/action_dispatch/middleware/executor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rack/body_proxy" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 6b29ce63ba..3e11846778 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/keys" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb index 46f0f675b9..3feb3a19f3 100644 --- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + module ActionDispatch # When called, this middleware renders an error page. By default if an HTML - # response is expected it will render static error pages from the `/public` + # response is expected it will render static error pages from the <tt>/public</tt> # directory. For example when this middleware receives a 500 response it will - # render the template found in `/public/500.html`. + # render the template found in <tt>/public/500.html</tt>. # If an internationalized locale is set, this middleware will attempt to render - # the template in `/public/500.<locale>.html`. If an internationalized template - # is not found it will fall back on `/public/500.html`. + # the template in <tt>/public/500.<locale>.html</tt>. If an internationalized template + # is not found it will fall back on <tt>/public/500.html</tt>. # # When a request with a content type other than HTML is made, this middleware # will attempt to convert error information into the appropriate response type. diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb index 6d64b1424b..8bb3ba7504 100644 --- a/actionpack/lib/action_dispatch/middleware/reloader.rb +++ b/actionpack/lib/action_dispatch/middleware/reloader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch # ActionDispatch::Reloader wraps the request with callbacks provided by ActiveSupport::Reloader # callbacks, intended to assist with code reloading during development. diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb index 53d5a4918c..35158f9062 100644 --- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb +++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "ipaddr" module ActionDispatch @@ -10,7 +12,7 @@ module ActionDispatch # by @gingerlime. A more detailed explanation of the algorithm is given # at GetIp#calculate_ip. # - # Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2] + # Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2] # requires. Some Rack servers simply drop preceding headers, and only report # the value that was {given in the last header}[http://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers]. # If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn) @@ -29,7 +31,7 @@ module ActionDispatch # The default trusted IPs list simply includes IP addresses that are # guaranteed by the IP specification to be private addresses. Those will # not be the ultimate client IP in production, and so are discarded. See - # http://en.wikipedia.org/wiki/Private_network for details. + # https://en.wikipedia.org/wiki/Private_network for details. TRUSTED_PROXIES = [ "127.0.0.1", # localhost IPv4 "::1", # localhost IPv6 diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb index 1925ffd9dd..805d3f2148 100644 --- a/actionpack/lib/action_dispatch/middleware/request_id.rb +++ b/actionpack/lib/action_dispatch/middleware/request_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "securerandom" require "active_support/core_ext/string/access" diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 31979fa576..5b0be96223 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "rack/utils" require "rack/request" require "rack/session/abstract/id" -require_relative "../cookies" -require_relative "../../request/session" +require "action_dispatch/middleware/cookies" +require "action_dispatch/request/session" module ActionDispatch module Session diff --git a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb index 4babeb6354..a6d965a644 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb @@ -1,4 +1,6 @@ -require_relative "abstract_store" +# frozen_string_literal: true + +require "action_dispatch/middleware/session/abstract_store" module ActionDispatch module Session diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 496f221617..4ea96196d3 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/keys" -require_relative "abstract_store" +require "action_dispatch/middleware/session/abstract_store" require "rack/session/cookie" module ActionDispatch @@ -19,39 +21,25 @@ module ActionDispatch # knowing your app's secret key, but can easily read their +user_id+. This # was the default for Rails 3 apps. # - # If you have secret_key_base set, your cookies will be encrypted. This + # Your cookies will be encrypted using your apps secret_key_base. This # goes a step further than signed cookies in that encrypted cookies cannot # be altered or read by users. This is the default starting in Rails 4. # - # If you have both secret_token and secret_key_base set, your cookies will - # be encrypted, and signed cookies generated by Rails 3 will be - # transparently read and encrypted to provide a smooth upgrade path. - # - # Configure your session store in config/initializers/session_store.rb: + # Configure your session store in <tt>config/initializers/session_store.rb</tt>: # # Rails.application.config.session_store :cookie_store, key: '_your_app_session' # - # Configure your secret key in config/secrets.yml: - # - # development: - # secret_key_base: 'secret key' - # - # To generate a secret key for an existing application, run `rails secret`. + # By default, your secret key base is derived from your application name in + # the test and development environments. In all other environments, it is stored + # encrypted in the <tt>config/credentials.yml.enc</tt> file. # - # If you are upgrading an existing Rails 3 app, you should leave your - # existing secret_token in place and simply add the new secret_key_base. - # Note that you should wait to set secret_key_base until you have 100% of - # your userbase on Rails 4 and are reasonably sure you will not need to - # rollback to Rails 3. This is because cookies signed based on the new - # secret_key_base in Rails 4 are not backwards compatible with Rails 3. - # You are free to leave your existing secret_token in place, not set the - # new secret_key_base, and ignore the deprecation warnings until you are - # reasonably sure that your upgrade is otherwise complete. Additionally, - # you should take care to make sure you are not relying on the ability to - # decode signed cookies generated by your app in external applications or - # JavaScript before upgrading. + # If your application was not updated to Rails 5.2 defaults, the secret_key_base + # will be found in the old <tt>config/secrets.yml</tt> file. # - # Note that changing the secret key will invalidate all existing sessions! + # Note that changing your secret_key_base will invalidate all existing session. + # Additionally, you should take care to make sure you are not relying on the + # ability to decode signed cookies generated by your app in external + # applications or JavaScript before changing it. # # Because CookieStore extends Rack::Session::Abstract::Persisted, many of the # options described there can be used to customize the session cookie that diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb index bc2b1c9b12..914df3a2b1 100644 --- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb @@ -1,4 +1,6 @@ -require_relative "abstract_store" +# frozen_string_literal: true + +require "action_dispatch/middleware/session/abstract_store" begin require "rack/session/dalli" rescue LoadError => e diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index db84ff48e9..3c88afd4d3 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -1,5 +1,7 @@ -require_relative "../http/request" -require_relative "exception_wrapper" +# frozen_string_literal: true + +require "action_dispatch/http/request" +require "action_dispatch/middleware/exception_wrapper" module ActionDispatch # This middleware rescues any exception returned by the application diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index fb2bfbb41e..ef633aadc6 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -1,47 +1,52 @@ # frozen_string_literal: true module ActionDispatch - # This middleware is added to the stack when `config.force_ssl = true`, and is passed - # the options set in `config.ssl_options`. It does three jobs to enforce secure HTTP + # This middleware is added to the stack when <tt>config.force_ssl = true</tt>, and is passed + # the options set in +config.ssl_options+. It does three jobs to enforce secure HTTP # requests: # - # 1. TLS redirect: Permanently redirects http:// requests to https:// - # with the same URL host, path, etc. Enabled by default. Set `config.ssl_options` - # to modify the destination URL - # (e.g. `redirect: { host: "secure.widgets.com", port: 8080 }`), or set - # `redirect: false` to disable this feature. + # 1. <b>TLS redirect</b>: Permanently redirects +http://+ requests to +https://+ + # with the same URL host, path, etc. Enabled by default. Set +config.ssl_options+ + # to modify the destination URL + # (e.g. <tt>redirect: { host: "secure.widgets.com", port: 8080 }</tt>), or set + # <tt>redirect: false</tt> to disable this feature. # - # 2. Secure cookies: Sets the `secure` flag on cookies to tell browsers they - # mustn't be sent along with http:// requests. Enabled by default. Set - # `config.ssl_options` with `secure_cookies: false` to disable this feature. + # Requests can opt-out of redirection with +exclude+: # - # 3. HTTP Strict Transport Security (HSTS): Tells the browser to remember - # this site as TLS-only and automatically redirect non-TLS requests. - # Enabled by default. Configure `config.ssl_options` with `hsts: false` to disable. + # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } } # - # Set `config.ssl_options` with `hsts: { … }` to configure HSTS: - # * `expires`: How long, in seconds, these settings will stick. The minimum - # required to qualify for browser preload lists is `18.weeks`. Defaults to - # `180.days` (recommended). - # * `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 `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 - # gap, browser vendors include a baked-in list of HSTS-enabled sites. - # Go to https://hstspreload.appspot.com to submit your site for inclusion. - # Defaults to `false`. + # 2. <b>Secure cookies</b>: Sets the +secure+ flag on cookies to tell browsers they + # must not be sent along with +http://+ requests. Enabled by default. Set + # +config.ssl_options+ with <tt>secure_cookies: false</tt> to disable this feature. # - # To turn off HSTS, omitting the header is not enough. Browsers will remember the - # 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 }`. + # 3. <b>HTTP Strict Transport Security (HSTS)</b>: Tells the browser to remember + # this site as TLS-only and automatically redirect non-TLS requests. + # Enabled by default. Configure +config.ssl_options+ with <tt>hsts: false</tt> to disable. # - # Requests can opt-out of redirection with `exclude`: + # Set +config.ssl_options+ with <tt>hsts: { ... }</tt> to configure HSTS: # - # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } } + # * +expires+: How long, in seconds, these settings will stick. The minimum + # required to qualify for browser preload lists is 18 weeks. Defaults to + # 180 days (recommended). + # + # * +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 +true+. + # + # * +preload+: Advertise that this site may be included in browsers' + # preloaded HSTS lists. HSTS protects your site on every visit <i>except the + # first visit</i> since it hasn't seen your HSTS header yet. To close this + # gap, browser vendors include a baked-in list of HSTS-enabled sites. + # Go to https://hstspreload.org to submit your site for inclusion. + # Defaults to +false+. + # + # To turn off HSTS, omitting the header is not enough. Browsers will remember the + # original HSTS directive until it expires. Instead, use the header to tell browsers to + # expire HSTS immediately. Setting <tt>hsts: false</tt> is a shortcut for + # <tt>hsts: { expires: 0 }</tt>. class SSL + # :stopdoc: + # Default to 180 days, the low end for https://www.ssllabs.com/ssltest/ # and greater than the 18-week requirement for browser preload lists. HSTS_EXPIRES_IN = 15552000 @@ -94,7 +99,7 @@ module ActionDispatch end end - # http://tools.ietf.org/html/rfc6797#section-6.1 + # https://tools.ietf.org/html/rfc6797#section-6.1 def build_hsts_header(hsts) value = "max-age=#{hsts[:expires].to_i}".dup value << "; includeSubDomains" if hsts[:subdomains] diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 6949b31e75..b82f8aa3a3 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/inflector/methods" require "active_support/dependencies" diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb index e0509f56f4..39ea25bdfc 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -106,6 +106,7 @@ .line { padding-left: 10px; + white-space: pre; } .line:hover { diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb index 2d21ae63f5..1fa0691303 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb @@ -17,6 +17,10 @@ line-height: 15px; } + #route_table thead tr.bottom th input#search { + -webkit-appearance: textfield; + } + #route_table tbody tr { border-bottom: 1px solid #ddd; } diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 7662e164b8..855f2ffa47 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -1,4 +1,7 @@ +# frozen_string_literal: true + require "action_dispatch" +require "active_support/messages/rotation_configuration" module ActionDispatch class Railtie < Rails::Railtie # :nodoc: @@ -16,6 +19,7 @@ module ActionDispatch config.action_dispatch.signed_cookie_salt = "signed cookie" config.action_dispatch.encrypted_cookie_salt = "encrypted cookie" config.action_dispatch.encrypted_signed_cookie_salt = "signed encrypted cookie" + config.action_dispatch.authenticated_encrypted_cookie_salt = "authenticated encrypted cookie" config.action_dispatch.use_authenticated_cookie_encryption = false config.action_dispatch.perform_deep_munge = true @@ -25,6 +29,8 @@ module ActionDispatch "X-Content-Type-Options" => "nosniff" } + config.action_dispatch.cookies_rotations = ActiveSupport::Messages::RotationConfiguration.new + config.eager_load_namespaces << ActionDispatch initializer "action_dispatch.configure" do |app| @@ -37,8 +43,6 @@ module ActionDispatch ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses) ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates) - config.action_dispatch.authenticated_encrypted_cookie_salt = "authenticated encrypted cookie" if config.action_dispatch.use_authenticated_cookie_encryption - 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 diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 3547a8604f..d86d0b10c2 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rack/session/abstract/id" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb index 4f79c4c21e..0ae464082d 100644 --- a/actionpack/lib/action_dispatch/request/utils.rb +++ b/actionpack/lib/action_dispatch/request/utils.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch class Request class Utils # :nodoc: @@ -32,7 +34,7 @@ module ActionDispatch unless params.valid_encoding? # Raise Rack::Utils::InvalidParameterError for consistency with Rack. # ActionDispatch::Request#GET will re-raise as a BadRequest error. - raise Rack::Utils::InvalidParameterError, "Non UTF-8 value: #{params}" + raise Rack::Utils::InvalidParameterError, "Invalid encoding for parameter: #{params.scrub}" end end end diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 87dd1eba38..72f7407c6e 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/string/filters" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/routing/endpoint.rb b/actionpack/lib/action_dispatch/routing/endpoint.rb index 88aa13c3e8..24dced1efd 100644 --- a/actionpack/lib/action_dispatch/routing/endpoint.rb +++ b/actionpack/lib/action_dispatch/routing/endpoint.rb @@ -1,10 +1,14 @@ +# frozen_string_literal: true + module ActionDispatch module Routing class Endpoint # :nodoc: - def dispatcher?; false; end - def redirect?; false; end - def matches?(req); true; end - def app; self; end + def dispatcher?; false; end + def redirect?; false; end + def engine?; rack_app.respond_to?(:routes); end + def matches?(req); true; end + def app; self; end + def rack_app; app; end end end end diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index 9aa4b92df2..a2205569b4 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "delegate" require "active_support/core_ext/string/strip" @@ -13,7 +15,7 @@ module ActionDispatch end def rack_app - app.app + app.rack_app end def path @@ -45,7 +47,7 @@ module ActionDispatch end def engine? - rack_app.respond_to?(:routes) + app.engine? end end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index eaa0e12b67..ded42adee9 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -4,8 +4,8 @@ require "active_support/core_ext/hash/slice" require "active_support/core_ext/enumerable" require "active_support/core_ext/array/extract_options" require "active_support/core_ext/regexp" -require_relative "redirection" -require_relative "endpoint" +require "action_dispatch/routing/redirection" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -473,7 +473,17 @@ module ActionDispatch # <tt>params[<:param>]</tt>. # In your router: # - # resources :user, param: :name + # resources :users, param: :name + # + # The +users+ resource here will have the following routes generated for it: + # + # GET /users(.:format) + # POST /users(.:format) + # GET /users/new(.:format) + # GET /users/:name/edit(.:format) + # GET /users/:name(.:format) + # PATCH/PUT /users/:name(.:format) + # DELETE /users/:name(.:format) # # You can override <tt>ActiveRecord::Base#to_param</tt> of a related # model to construct a URL: @@ -484,8 +494,8 @@ module ActionDispatch # end # end # - # user = User.find_by(name: 'Phusion') - # user_path(user) # => "/users/Phusion" + # user = User.find_by(name: 'Phusion') + # user_path(user) # => "/users/Phusion" # # [:path] # The path prefix for the routes. @@ -658,6 +668,11 @@ module ActionDispatch script_namer = ->(options) do prefix_options = options.slice(*_route.segment_keys) prefix_options[:relative_url_root] = "".freeze + + if options[:_recall] + prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys)) + end + # We must actually delete prefix segment keys to avoid passing them to next url_for. _route.segment_keys.each { |k| options.delete(k) } _routes.url_helpers.send("#{name}_path", prefix_options) @@ -1260,7 +1275,7 @@ module ActionDispatch # POST /profile # # === Options - # Takes same options as +resources+. + # Takes same options as resources[rdoc-ref:#resources] def resource(*resources, &block) options = resources.extract_options!.dup @@ -1325,7 +1340,7 @@ module ActionDispatch # DELETE /photos/:photo_id/comments/:id # # === Options - # Takes same options as <tt>Base#match</tt> as well as: + # Takes same options as match[rdoc-ref:Base#match] as well as: # # [:path_names] # Allows you to change the segment component of the +edit+ and +new+ actions. @@ -1846,7 +1861,7 @@ module ActionDispatch path_types.fetch(String, []).each do |_path| route_options = options.dup if _path && option_path - raise ArgumentError, "Ambiguous route definition. Both :path and the route path where specified as strings." + raise ArgumentError, "Ambiguous route definition. Both :path and the route path were specified as strings." end to = get_to_from_path(_path, to, route_options[:action]) decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints) diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index e89ea8b21d..6da869c0c2 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Routing # Polymorphic URL helpers are methods for smart resolution to a named route call when diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index 6396b5031d..143a4b3d62 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -1,9 +1,11 @@ -require_relative "../http/request" +# frozen_string_literal: true + +require "action_dispatch/http/request" require "active_support/core_ext/uri" require "active_support/core_ext/array/extract_options" require "rack/utils" require "action_controller/metal/exceptions" -require_relative "endpoint" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -140,7 +142,7 @@ module ActionDispatch # get "/stories" => redirect("/posts") # # This will redirect the user, while ignoring certain parts of the request, including query string, etc. - # `/stories`, `/stories?foo=bar`, etc all redirect to `/posts`. + # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, etc all redirect to <tt>/posts</tt>. # # You can also use interpolation in the supplied redirect argument: # @@ -173,8 +175,8 @@ module ActionDispatch # get '/stories', to: redirect(path: '/posts') # # This will redirect the user, while changing only the specified parts of the request, - # for example the `path` option in the last example. - # `/stories`, `/stories?foo=bar`, redirect to `/posts` and `/posts?foo=bar` respectively. + # for example the +path+ option in the last example. + # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, redirect to <tt>/posts</tt> and <tt>/posts?foo=bar</tt> respectively. # # Finally, an object which responds to call can be supplied to redirect, allowing you to reuse # common redirect routes. The call method must accept two arguments, params and request, and return diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 357eaec572..987e709f6f 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -1,13 +1,14 @@ # frozen_string_literal: true -require_relative "../journey" +require "action_dispatch/journey" require "active_support/core_ext/object/to_query" require "active_support/core_ext/hash/slice" +require "active_support/core_ext/module/redefine_method" require "active_support/core_ext/module/remove_method" require "active_support/core_ext/array/extract_options" require "action_controller/metal/exceptions" -require_relative "../http/request" -require_relative "endpoint" +require "action_dispatch/http/request" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -546,7 +547,7 @@ module ActionDispatch # plus a singleton class method called _routes ... included do - singleton_class.send(:redefine_method, :_routes) { routes } + redefine_singleton_method(:_routes) { routes } end # And an instance method _routes. Note that @@ -583,14 +584,14 @@ module ActionDispatch 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.2. + will be removed in Rails 6.0. 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.2. + will be removed in Rails 6.0. MSG end @@ -841,6 +842,10 @@ module ActionDispatch end req = make_request(env) + recognize_path_with_request(req, path, extras) + end + + def recognize_path_with_request(req, path, extras) @router.recognize(req) do |route, params| params.merge!(extras) params.each do |key, value| @@ -859,6 +864,9 @@ module ActionDispatch end return req.path_parameters + elsif app.matches?(req) && app.engine? + path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras) + return path_parameters end end diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb index 7a6c2e95d8..587a72729c 100644 --- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb +++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/array/extract_options" module ActionDispatch @@ -31,7 +33,14 @@ module ActionDispatch def #{method}(*args) options = args.extract_options! options = url_options.merge((options || {}).symbolize_keys) - options.reverse_merge!(script_name: @script_namer.call(options)) if @script_namer + + if @script_namer + options[:script_name] = merge_script_names( + options[:script_name], + @script_namer.call(options) + ) + end + args << options @helpers.#{method}(*args) end @@ -41,6 +50,20 @@ module ActionDispatch super end end + + # Keeps the part of the script name provided by the global + # context via ENV["SCRIPT_NAME"], which `mount` doesn't know + # about since it depends on the specific request, but use our + # script name resolver for the mount point dependent part. + def merge_script_names(previous_script_name, new_script_name) + return new_script_name unless previous_script_name + + resolved_parts = new_script_name.count("/") + previous_parts = previous_script_name.count("/") + context_parts = previous_parts - resolved_parts + 1 + + (previous_script_name.split("/").slice(0, context_parts).join("/")) + new_script_name + end end end end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index a9bdefa775..3ae533dd37 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Routing # In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse @@ -107,7 +109,7 @@ module ActionDispatch end # Hook overridden in controller to add request information - # with `default_url_options`. Application logic should not + # with +default_url_options+. Application logic should not # go into url_options. def url_options default_url_options diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb index 23ce8d5a92..7246e01cff 100644 --- a/actionpack/lib/action_dispatch/system_test_case.rb +++ b/actionpack/lib/action_dispatch/system_test_case.rb @@ -1,11 +1,15 @@ +# frozen_string_literal: true + +gem "capybara", "~> 2.15" + require "capybara/dsl" require "capybara/minitest" require "action_controller" -require_relative "system_testing/driver" -require_relative "system_testing/server" -require_relative "system_testing/test_helpers/screenshot_helper" -require_relative "system_testing/test_helpers/setup_and_teardown" -require_relative "system_testing/test_helpers/undef_methods" +require "action_dispatch/system_testing/driver" +require "action_dispatch/system_testing/server" +require "action_dispatch/system_testing/test_helpers/screenshot_helper" +require "action_dispatch/system_testing/test_helpers/setup_and_teardown" +require "action_dispatch/system_testing/test_helpers/undef_methods" module ActionDispatch # = System Testing @@ -119,12 +123,16 @@ module ActionDispatch # # driven_by :selenium, using: :firefox # + # driven_by :selenium, using: :headless_chrome + # # driven_by :selenium, screen_size: [800, 800] def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}) self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options) end driven_by :selenium + + ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self) end SystemTestCase.start_application diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb index 81e6f0fc80..2687772b4b 100644 --- a/actionpack/lib/action_dispatch/system_testing/driver.rb +++ b/actionpack/lib/action_dispatch/system_testing/driver.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting class Driver # :nodoc: @@ -29,8 +31,24 @@ module ActionDispatch end end + def browser_options + if @browser == :headless_chrome + browser_options = Selenium::WebDriver::Chrome::Options.new + browser_options.args << "--headless" + browser_options.args << "--disable-gpu" + + @options.merge(options: browser_options) + else + @options + end + end + + def browser + @browser == :headless_chrome ? :chrome : @browser + end + def register_selenium(app) - Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver| + Capybara::Selenium::Driver.new(app, { browser: browser }.merge(browser_options)).tap do |driver| driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) end end @@ -41,7 +59,7 @@ module ActionDispatch def register_webkit(app) Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver| - driver.resize_window(*@screen_size) + driver.resize_window_to(driver.current_window_handle, *@screen_size) end end diff --git a/actionpack/lib/action_dispatch/system_testing/server.rb b/actionpack/lib/action_dispatch/system_testing/server.rb index 89ca6944d9..8f1b6725b1 100644 --- a/actionpack/lib/action_dispatch/system_testing/server.rb +++ b/actionpack/lib/action_dispatch/system_testing/server.rb @@ -1,4 +1,4 @@ -require "rack/handler/puma" +# frozen_string_literal: true module ActionDispatch module SystemTesting @@ -10,29 +10,17 @@ module ActionDispatch self.silence_puma = false def run - register setup end private - def register - Capybara.register_server :rails_puma do |app, port, host| - Rack::Handler::Puma.run( - app, - Port: port, - Threads: "0:1", - Silent: self.class.silence_puma - ) - end - end - def setup set_server set_port end def set_server - Capybara.server = :rails_puma + Capybara.server = :puma, { Silent: self.class.silence_puma } end def set_port diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb index 859d68e475..6c337cdc31 100644 --- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting module TestHelpers @@ -14,12 +16,12 @@ module ActionDispatch # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to # control the output. Possible values are: # * [+inline+ (default)] display the screenshot in the terminal using the - # iTerm image protocol (http://iterm2.com/documentation-images.html). + # iTerm image protocol (https://iterm2.com/documentation-images.html). # * [+simple+] only display the screenshot path. # This is the default value if the +CI+ environment variables # is defined. # * [+artifact+] display the screenshot in the terminal, using the terminal - # artifact format (http://buildkite.github.io/terminal/inline-images/). + # artifact format (https://buildkite.github.io/terminal/inline-images/). def take_screenshot save_image puts display_image @@ -42,11 +44,15 @@ module ActionDispatch end def image_path - "tmp/screenshots/#{image_name}.png" + @image_path ||= absolute_image_path.relative_path_from(Pathname.pwd).to_s + end + + def absolute_image_path + Rails.root.join("tmp/screenshots/#{image_name}.png") end def save_image - page.save_screenshot(Rails.root.join(image_path)) + page.save_screenshot(absolute_image_path) end def output_type @@ -63,14 +69,14 @@ module ActionDispatch end def display_image - message = "[Screenshot]: #{image_path}\n" + message = "[Screenshot]: #{image_path}\n".dup case output_type when "artifact" - message << "\e]1338;url=artifact://#{image_path}\a\n" + message << "\e]1338;url=artifact://#{absolute_image_path}\a\n" when "inline" - name = inline_base64(File.basename(image_path)) - image = inline_base64(File.read(image_path)) + name = inline_base64(File.basename(absolute_image_path)) + image = inline_base64(File.read(absolute_image_path)) message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n" end 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 f03f0d4299..ffa85f4e14 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 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting module TestHelpers diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb index 2d3f4662d7..d64be3b3d9 100644 --- a/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting module TestHelpers @@ -12,7 +14,7 @@ module ActionDispatch def method_missing(method, *args, &block) if METHODS.include?(method) - raise NoMethodError + raise NoMethodError, "System tests cannot make direct requests via ##{method}; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information." else super end diff --git a/actionpack/lib/action_dispatch/testing/assertion_response.rb b/actionpack/lib/action_dispatch/testing/assertion_response.rb index c37726957e..dc019db6ac 100644 --- a/actionpack/lib/action_dispatch/testing/assertion_response.rb +++ b/actionpack/lib/action_dispatch/testing/assertion_response.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch # This is a class that abstracts away an asserted response. It purposely # does not inherit from Response because it doesn't need it. That means it diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index 4ea18d671d..08c2969685 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails-dom-testing" module ActionDispatch diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 749f2eab57..98b1965d22 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch module Assertions # A small suite of assertions that test responses from \Rails applications. diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 8645df4370..5390581139 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "uri" require "active_support/core_ext/hash/indifferent_access" require "active_support/core_ext/string/access" diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index beba4e3c36..7171b6942c 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "stringio" require "uri" require "active_support/core_ext/kernel/singleton_class" @@ -5,43 +7,43 @@ require "active_support/core_ext/object/try" require "rack/test" require "minitest" -require_relative "request_encoder" +require "action_dispatch/testing/request_encoder" module ActionDispatch module Integration #:nodoc: module RequestHelpers - # Performs a GET request with the given parameters. See +#process+ for more - # details. + # Performs a GET request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def get(path, **args) process(:get, path, **args) end - # Performs a POST request with the given parameters. See +#process+ for more - # details. + # Performs a POST request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def post(path, **args) process(:post, path, **args) end - # Performs a PATCH request with the given parameters. See +#process+ for more - # details. + # Performs a PATCH request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def patch(path, **args) process(:patch, path, **args) end - # Performs a PUT request with the given parameters. See +#process+ for more - # details. + # Performs a PUT request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def put(path, **args) process(:put, path, **args) end - # Performs a DELETE request with the given parameters. See +#process+ for - # more details. + # Performs a DELETE request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def delete(path, **args) process(:delete, path, **args) end - # Performs a HEAD request with the given parameters. See +#process+ for more - # details. + # Performs a HEAD request with the given parameters. See ActionDispatch::Integration::Session#process + # for more details. def head(path, *args) process(:head, path, *args) end diff --git a/actionpack/lib/action_dispatch/testing/request_encoder.rb b/actionpack/lib/action_dispatch/testing/request_encoder.rb index 8c27e9ecb7..01246b7a2e 100644 --- a/actionpack/lib/action_dispatch/testing/request_encoder.rb +++ b/actionpack/lib/action_dispatch/testing/request_encoder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionDispatch class RequestEncoder # :nodoc: class IdentityEncoder diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index 8061ac2e3b..8ac50c730d 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -1,5 +1,7 @@ -require_relative "../middleware/cookies" -require_relative "../middleware/flash" +# frozen_string_literal: true + +require "action_dispatch/middleware/cookies" +require "action_dispatch/middleware/flash" module ActionDispatch module TestProcess diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index ec949c869b..6c5b7af50e 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/indifferent_access" require "rack/utils" @@ -9,7 +11,7 @@ module ActionDispatch "HTTP_USER_AGENT" => "Rails Testing", ) - # Create a new test request with default `env` values. + # Create a new test request with default +env+ values. def self.create(env = {}) env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application env["rack.request.cookie_hash"] ||= {}.with_indifferent_access diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 2a1a9ffce9..1e6b21f235 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -1,4 +1,6 @@ -require_relative "request_encoder" +# frozen_string_literal: true + +require "action_dispatch/testing/request_encoder" module ActionDispatch # Integration test methods such as ActionDispatch::Integration::Session#get @@ -18,13 +20,31 @@ module ActionDispatch end # Was the response successful? - alias_method :success?, :successful? + def success? + ActiveSupport::Deprecation.warn(<<-MSG.squish) + The success? predicate is deprecated and will be removed in Rails 6.0. + Please use successful? as provided by Rack::Response::Helpers. + MSG + successful? + end # Was the URL not found? - alias_method :missing?, :not_found? + def missing? + ActiveSupport::Deprecation.warn(<<-MSG.squish) + The missing? predicate is deprecated and will be removed in Rails 6.0. + Please use not_found? as provided by Rack::Response::Helpers. + MSG + not_found? + end # Was there a server-side error? - alias_method :error?, :server_error? + def error? + ActiveSupport::Deprecation.warn(<<-MSG.squish) + The error? predicate is deprecated and will be removed in Rails 6.0. + Please use server_error? as provided by Rack::Response::Helpers. + MSG + server_error? + end def parsed_body @parsed_body ||= @response_parser.call(body) diff --git a/actionpack/lib/action_pack.rb b/actionpack/lib/action_pack.rb index 6a74baff09..95fdd3affb 100644 --- a/actionpack/lib/action_pack.rb +++ b/actionpack/lib/action_pack.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- # Copyright (c) 2004-2017 David Heinemeier Hansson # @@ -21,4 +23,4 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require_relative "action_pack/version" +require "action_pack/version" diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb index fddc3033d5..28bc153f4d 100644 --- a/actionpack/lib/action_pack/gem_version.rb +++ b/actionpack/lib/action_pack/gem_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionPack # Returns the version of the currently loaded Action Pack as a <tt>Gem::Version</tt> def self.gem_version diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 3d96158431..fd039fe140 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "gem_version" module ActionPack |