diff options
Diffstat (limited to 'actionpack/lib')
6 files changed, 49 insertions, 53 deletions
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 17379cf7ac..d275a854fd 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -50,6 +50,10 @@ module ActionController #:nodoc: config_accessor :request_forgery_protection_token self.request_forgery_protection_token ||= :authenticity_token + # Holds the class which implements the request forgery protection. + config_accessor :forgery_protection_strategy + self.forgery_protection_strategy = nil + # Controls whether request forgery protection is turned on or not. Turned off by default only in test mode. config_accessor :allow_forgery_protection self.allow_forgery_protection = true if allow_forgery_protection.nil? @@ -82,14 +86,14 @@ module ActionController #:nodoc: # * <tt>:reset_session</tt> - Resets the session. # * <tt>:null_session</tt> - Provides an empty session during request but doesn't reset it completely. Used as default if <tt>:with</tt> option is not specified. def protect_from_forgery(options = {}) - include protection_method_module(options[:with] || :null_session) + self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session) self.request_forgery_protection_token ||= :authenticity_token prepend_before_action :verify_authenticity_token, options end private - def protection_method_module(name) + def protection_method_class(name) ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify) rescue NameError raise ArgumentError, 'Invalid request forgery protection method, use :null_session, :exception, or :reset_session' @@ -97,17 +101,22 @@ module ActionController #:nodoc: end module ProtectionMethods - module NullSession - protected + class NullSession + def initialize(controller) + @controller = controller + end # This is the method that defines the application behavior when a request is found to be unverified. def handle_unverified_request + request = @controller.request request.session = NullSessionHash.new(request.env) request.env['action_dispatch.request.flash_hash'] = nil request.env['rack.session.options'] = { skip: true } request.env['action_dispatch.cookies'] = NullCookieJar.build(request) end + protected + class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc: def initialize(env) super(nil, env) @@ -135,16 +144,20 @@ module ActionController #:nodoc: end end - module ResetSession - protected + class ResetSession + def initialize(controller) + @controller = controller + end def handle_unverified_request - reset_session + @controller.reset_session end end - module Exception - protected + class Exception + def initialize(controller) + @controller = controller + end def handle_unverified_request raise ActionController::InvalidAuthenticityToken @@ -153,6 +166,10 @@ module ActionController #:nodoc: end protected + def handle_unverified_request + forgery_protection_strategy.new(self).handle_unverified_request + end + # The actual before_action that is used. Modify this to change how you handle unverified requests. def verify_authenticity_token unless verified_request? diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 7e720ca6f5..e4dcd3213f 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -191,9 +191,9 @@ module ActionController # # +:name+ passes it is a key of +params+ whose associated value is of type # +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+, - # +Date+, +Time+, +DateTime+, +StringIO+, +IO+, or - # +ActionDispatch::Http::UploadedFile+. Otherwise, the key +:name+ is - # filtered out. + # +Date+, +Time+, +DateTime+, +StringIO+, +IO+, + # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+. + # Otherwise, the key +:name+ is filtered out. # # You may declare that the parameter should be an array of permitted scalars # by mapping it to an empty array: @@ -374,6 +374,7 @@ module ActionController StringIO, IO, ActionDispatch::Http::UploadedFile, + Rack::Test::UploadedFile, ] def permitted_scalar?(value) diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 0898ad82dd..0fa1e9b859 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -13,10 +13,7 @@ module ActionDispatch end end - DEFAULT_PARSERS = { - Mime::XML => :xml_simple, - Mime::JSON => :json - } + DEFAULT_PARSERS = { Mime::JSON => :json } def initialize(app, parsers = {}) @app, @parsers = app, DEFAULT_PARSERS.merge(parsers) @@ -36,19 +33,13 @@ module ActionDispatch return false if request.content_length.zero? - mime_type = content_type_from_legacy_post_data_format_header(env) || - request.content_mime_type - - strategy = @parsers[mime_type] + strategy = @parsers[request.content_mime_type] return false unless strategy case strategy when Proc strategy.call(request.raw_post) - when :xml_simple, :xml_node - data = request.deep_munge(Hash.from_xml(request.body.read) || {}) - data.with_indifferent_access when :json data = ActiveSupport::JSON.decode(request.body) data = {:_json => data} unless data.is_a?(Hash) @@ -56,23 +47,12 @@ module ActionDispatch else false end - rescue Exception => e # YAML, XML or Ruby code block errors + rescue Exception => e # JSON or Ruby code block errors logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" raise ParseError.new(e.message, e) end - def content_type_from_legacy_post_data_format_header(env) - if x_post_format = env['HTTP_X_POST_DATA_FORMAT'] - case x_post_format.to_s.downcase - when 'yaml' then return Mime::YAML - when 'xml' then return Mime::XML - end - end - - nil - end - def logger(env) env['action_dispatch.logger'] || ActiveSupport::Logger.new($stderr) end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0a41ed0fcf..a8e225d61c 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -50,7 +50,6 @@ module ActionDispatch class Mapping #:nodoc: IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix, :format] ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z} - SHORTHAND_REGEX = %r{/[\w/]+$} WILDCARD_PATH = %r{\*([^/\)]+)\)?$} attr_reader :scope, :path, :options, :requirements, :conditions, :defaults @@ -111,17 +110,7 @@ module ActionDispatch @options[:controller] ||= /.+?/ end - if using_match_shorthand?(path_without_format, @options) - to_shorthand = @options[:to].blank? - @options[:to] ||= path_without_format.gsub(/\(.*\)/, "")[1..-1].sub(%r{/([^/]*)$}, '#\1') - end - - @options.merge!(default_controller_and_action(to_shorthand)) - end - - # match "account/overview" - def using_match_shorthand?(path, options) - path && (options[:to] || options[:action]).nil? && path =~ SHORTHAND_REGEX + @options.merge!(default_controller_and_action) end def normalize_format! @@ -214,7 +203,7 @@ module ActionDispatch Constraints.new(endpoint, blocks, @set.request_class) end - def default_controller_and_action(to_shorthand=nil) + def default_controller_and_action if to.respond_to?(:call) { } else @@ -227,7 +216,7 @@ module ActionDispatch controller ||= default_controller action ||= default_action - unless controller.is_a?(Regexp) || to_shorthand + unless controller.is_a?(Regexp) controller = [@scope[:module], controller].compact.join("/").presence end @@ -1383,6 +1372,11 @@ module ActionDispatch paths = [path] + rest end + path_without_format = path.to_s.sub(/\(\.:format\)$/, '') + if using_match_shorthand?(path_without_format, options) + options[:to] ||= path_without_format.gsub(%r{^/}, "").sub(%r{/([^/]*)$}, '#\1') + end + options[:anchor] = true unless options.key?(:anchor) if options[:on] && !VALID_ON_OPTIONS.include?(options[:on]) @@ -1393,6 +1387,10 @@ module ActionDispatch self end + def using_match_shorthand?(path, options) + path && (options[:to] || options[:action]).nil? && path =~ %r{/[\w/]+$} + end + def decomposed_match(path, options) # :nodoc: if on = options.delete(:on) send(on) { decomposed_match(path, options) } diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 49473dd129..377819a80c 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -560,19 +560,19 @@ module ActionView def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone) zone_options = "".html_safe - zones = model.all.dup + zones = model.all convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } } if priority_zones if priority_zones.is_a?(Regexp) - priority_zones = zones.select { |z| z =~ priority_zones } + priority_zones = zones.grep(priority_zones) end zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected) zone_options.safe_concat content_tag(:option, '-------------', :value => '', :disabled => 'disabled') zone_options.safe_concat "\n" - zones.reject! { |z| priority_zones.include?(z) } + zones = zones - priority_zones end zone_options.safe_concat options_for_select(convert_zones[zones], selected) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 86d9f94067..1adc8225f1 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -33,7 +33,7 @@ module ActionView # (by passing <tt>false</tt>). Remote forms may omit the embedded authenticity token # by setting <tt>config.action_view.embed_authenticity_token_in_remote_forms = false</tt>. # This is helpful when you're fragment-caching the form. Remote forms get the - # authenticity from the <tt>meta</tt> tag, so embedding is unnecessary unless you + # authenticity token from the <tt>meta</tt> tag, so embedding is unnecessary unless you # support browsers without JavaScript. # * A list of parameters to feed to the URL the form will be posted to. # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the |