aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md17
-rw-r--r--actionpack/lib/abstract_controller.rb6
-rw-r--r--actionpack/lib/abstract_controller/caching.rb62
-rw-r--r--actionpack/lib/abstract_controller/caching/fragments.rb (renamed from actionpack/lib/action_controller/caching/fragments.rb)11
-rw-r--r--actionpack/lib/action_controller.rb10
-rw-r--r--actionpack/lib/action_controller/caching.rb67
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb3
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb21
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb5
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb1
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb26
-rw-r--r--actionpack/lib/action_dispatch/routing.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb4
-rw-r--r--actionpack/lib/action_pack/gem_version.rb2
-rw-r--r--actionpack/test/controller/caching_test.rb21
-rw-r--r--actionpack/test/controller/force_ssl_test.rb9
-rw-r--r--actionpack/test/controller/integration_test.rb2
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb16
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb124
-rw-r--r--actionpack/test/controller/webservice_test.rb2
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb28
-rw-r--r--actionpack/test/dispatch/request/session_test.rb10
-rw-r--r--actionpack/test/dispatch/routing/inspector_test.rb23
-rw-r--r--actionpack/test/dispatch/session/abstract_store_test.rb16
-rw-r--r--actionpack/test/dispatch/session/cache_store_test.rb29
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb34
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb31
-rw-r--r--actionpack/test/dispatch/session/test_session_test.rb7
-rw-r--r--actionpack/test/fixtures/collection_cache/index.html.erb2
33 files changed, 429 insertions, 176 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index d473ab427d..da96aef98b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,14 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Update session to have indifferent access across multiple requests.
+
+ session[:deep][:hash] = "Magic"
+
+ session[:deep][:hash] == "Magic"
+ session[:deep]["hash"] == "Magic"
+
+ *Tom Prats*
+
* Add application/gzip as a default mime type.
*Mehmet Emin İNAÇ*
@@ -37,13 +48,13 @@
end
end
```
-
+
Passing `as: :json` to integration test request helpers will set the format,
content type and encode the parameters as JSON.
-
+
Then on the response side, `parsed_body` will parse the body according to the
content type the response has.
-
+
Currently JSON is the only supported MIME type. Add your own with
`ActionDispatch::IntegrationTest.register_encoder`.
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 56c4033387..1e57cbaac4 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -6,6 +6,7 @@ module AbstractController
extend ActiveSupport::Autoload
autoload :Base
+ autoload :Caching
autoload :Callbacks
autoload :Collector
autoload :DoubleRenderError, "abstract_controller/rendering"
@@ -15,4 +16,9 @@ module AbstractController
autoload :Translation
autoload :AssetPaths
autoload :UrlFor
+
+ def self.eager_load!
+ super
+ AbstractController::Caching.eager_load!
+ end
end
diff --git a/actionpack/lib/abstract_controller/caching.rb b/actionpack/lib/abstract_controller/caching.rb
new file mode 100644
index 0000000000..0dea50889a
--- /dev/null
+++ b/actionpack/lib/abstract_controller/caching.rb
@@ -0,0 +1,62 @@
+module AbstractController
+ module Caching
+ extend ActiveSupport::Concern
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Fragments
+ end
+
+ module ConfigMethods
+ def cache_store
+ config.cache_store
+ end
+
+ def cache_store=(store)
+ config.cache_store = ActiveSupport::Cache.lookup_store(store)
+ end
+
+ private
+ def cache_configured?
+ perform_caching && cache_store
+ end
+ end
+
+ include ConfigMethods
+ include AbstractController::Caching::Fragments
+
+ included do
+ extend ConfigMethods
+
+ config_accessor :default_static_extension
+ self.default_static_extension ||= '.html'
+
+ config_accessor :perform_caching
+ self.perform_caching = true if perform_caching.nil?
+
+ class_attribute :_view_cache_dependencies
+ self._view_cache_dependencies = []
+ helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ end
+
+ module ClassMethods
+ def view_cache_dependency(&dependency)
+ self._view_cache_dependencies += [dependency]
+ end
+ end
+
+ def view_cache_dependencies
+ self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
+ end
+
+ protected
+ # Convenience accessor.
+ def cache(key, options = {}, &block)
+ if cache_configured?
+ cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
+ else
+ yield
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb
index b9ad51a9cf..3257a731ed 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/abstract_controller/caching/fragments.rb
@@ -1,4 +1,4 @@
-module ActionController
+module AbstractController
module Caching
# Fragment caching is used for caching various blocks within
# views without caching the entire action as a whole. This is
@@ -135,13 +135,8 @@ module ActionController
end
def instrument_fragment_cache(name, key) # :nodoc:
- payload = {
- controller: controller_name,
- action: action_name,
- key: key
- }
-
- ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
+ payload = instrument_payload(key)
+ ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", payload) { yield }
end
end
end
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 40f33a9de0..62f5905205 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -9,12 +9,15 @@ module ActionController
autoload :API
autoload :Base
- autoload :Caching
autoload :Metal
autoload :Middleware
autoload :Renderer
autoload :FormBuilder
+ eager_autoload do
+ autoload :Caching
+ end
+
autoload_under "metal" do
autoload :ConditionalGet
autoload :Cookies
@@ -47,11 +50,6 @@ module ActionController
autoload :TestCase, 'action_controller/test_case'
autoload :TemplateAssertions, 'action_controller/test_case'
-
- def self.eager_load!
- super
- ActionController::Caching.eager_load!
- end
end
# Common Active Support usage in Action Controller
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 0b8fa2ea09..a9a8508abc 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -1,6 +1,3 @@
-require 'fileutils'
-require 'uri'
-
module ActionController
# \Caching is a cheap way of speeding up slow applications by keeping the result of
# calculations, renderings, and database calls around for subsequent requests.
@@ -23,65 +20,25 @@ module ActionController
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
# config.action_controller.cache_store = MyOwnStore.new('parameter')
module Caching
- extend ActiveSupport::Concern
extend ActiveSupport::Autoload
-
- eager_autoload do
- autoload :Fragments
- end
-
- module ConfigMethods
- def cache_store
- config.cache_store
- end
-
- def cache_store=(store)
- config.cache_store = ActiveSupport::Cache.lookup_store(store)
- end
-
- private
- def cache_configured?
- perform_caching && cache_store
- end
- end
-
- include AbstractController::Callbacks
-
- include ConfigMethods
- include Fragments
+ extend ActiveSupport::Concern
included do
- extend ConfigMethods
-
- config_accessor :default_static_extension
- self.default_static_extension ||= '.html'
-
- config_accessor :perform_caching
- self.perform_caching = true if perform_caching.nil?
-
- class_attribute :_view_cache_dependencies
- self._view_cache_dependencies = []
- helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ include AbstractController::Caching
end
- module ClassMethods
- def view_cache_dependency(&dependency)
- self._view_cache_dependencies += [dependency]
- end
- end
+ private
- def view_cache_dependencies
- self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
- end
+ def instrument_payload(key)
+ {
+ controller: controller_name,
+ action: action_name,
+ key: key
+ }
+ end
- protected
- # Convenience accessor.
- def cache(key, options = {}, &block)
- if cache_configured?
- cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
- else
- yield
- end
+ def instrument_name
+ "action_controller"
end
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 6586985ff5..b2f0b382b9 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -379,7 +379,8 @@ module ActionController #:nodoc:
def xor_byte_strings(s1, s2)
s2_bytes = s2.bytes
- s1.bytes.map.with_index { |c1, i| c1 ^ s2_bytes[i] }.pack('c*')
+ s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
+ s2_bytes.pack('C*')
end
# The form's authenticity parameter. Override to provide your own.
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 25ec3cf5b6..a01110d474 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -579,7 +579,7 @@ module ActionController
end
def inspect
- "<#{self.class} #{@parameters}>"
+ "<#{self.class} #{@parameters} permitted: #{@permitted}>"
end
def method_missing(method_sym, *args, &block)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 0c4b661214..6548ce326b 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -52,7 +52,7 @@ module ActionController
self.session = session
self.session_options = TestSession::DEFAULT_OPTIONS
@custom_param_parsers = {
- Mime[:xml] => lambda { |raw_post| Hash.from_xml(raw_post)['hash'] }
+ xml: lambda { |raw_post| Hash.from_xml(raw_post)['hash'] }
}
end
@@ -105,7 +105,7 @@ module ActionController
when :url_encoded_form
data = non_path_parameters.to_query
else
- @custom_param_parsers[content_mime_type] = ->(_) { non_path_parameters }
+ @custom_param_parsers[content_mime_type.symbol] = ->(_) { non_path_parameters }
data = non_path_parameters.to_query
end
end
@@ -176,7 +176,7 @@ module ActionController
def initialize(session = {})
super(nil, nil)
@id = SecureRandom.hex(16)
- @data = stringify_keys(session)
+ @data = session.with_indifferent_access
@loaded = true
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index cca7376ffa..ff5031d7d5 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -1,22 +1,31 @@
module ActionDispatch
module Http
module Parameters
+ extend ActiveSupport::Concern
+
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
DEFAULT_PARSERS = {
- Mime[:json] => lambda { |raw_post|
+ Mime[:json].symbol => -> (raw_post) {
data = ActiveSupport::JSON.decode(raw_post)
data.is_a?(Hash) ? data : {:_json => data}
}
}
- def self.included(klass)
- class << klass
- attr_accessor :parameter_parsers
+ included do
+ class << self
+ attr_reader :parameter_parsers
end
- klass.parameter_parsers = DEFAULT_PARSERS
+ self.parameter_parsers = DEFAULT_PARSERS
end
+
+ module ClassMethods
+ def parameter_parsers=(parsers) # :nodoc:
+ @parameter_parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
+ end
+ end
+
# Returns both GET and POST \parameters in a single hash.
def parameters
params = get_header("action_dispatch.request.parameters")
@@ -51,7 +60,7 @@ module ActionDispatch
def parse_formatted_parameters(parsers)
return yield if content_length.zero?
- strategy = parsers.fetch(content_mime_type) { return yield }
+ strategy = parsers.fetch(content_mime_type.symbol) { return yield }
begin
strategy.call(raw_post)
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 5427425ef7..316a9f08b7 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -403,6 +403,10 @@ module ActionDispatch
def commit_flash
end
+ def ssl?
+ super || scheme == 'wss'.freeze
+ end
+
private
def check_method(name)
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 35c2b1b86e..fee08fc3db 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -3,7 +3,7 @@ module ActionDispatch
class Route # :nodoc:
attr_reader :app, :path, :defaults, :name, :precedence
- attr_reader :constraints
+ attr_reader :constraints, :internal
alias :conditions :constraints
module VerbMatchers
@@ -55,7 +55,7 @@ module ActionDispatch
##
# +path+ is a path constraint.
# +constraints+ is a hash of constraints to be applied to this route.
- def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence)
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
@name = name
@app = app
@path = path
@@ -70,6 +70,7 @@ module ActionDispatch
@decorated_ast = nil
@precedence = precedence
@path_formatter = @path.build_formatter
+ @internal = internal
end
def ast
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index c2a4f46e67..5841c978af 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -37,6 +37,7 @@ module ActionDispatch
# The +parsers+ argument can take Hash of parsers where key is identifying
# content mime type, and value is a lambda that is going to process data.
def self.new(app, parsers = {})
+ parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS.merge(parsers)
app
end
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index 42890225fa..38d0da3e67 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -9,7 +9,7 @@ module ActionDispatch
# Singleton object used to determine if an optional param wasn't specified
Unspecified = Object.new
-
+
# Creates a session hash, merging the properties of the previous session if any
def self.create(store, req, default_options)
session_was = find req
@@ -61,7 +61,7 @@ module ActionDispatch
def initialize(by, req)
@by = by
@req = req
- @delegate = {}
+ @delegate = {}.with_indifferent_access
@loaded = false
@exists = nil # we haven't checked yet
end
@@ -88,13 +88,13 @@ module ActionDispatch
# nil if the given key is not found in the session.
def [](key)
load_for_read!
- @delegate[key.to_s]
+ @delegate[key]
end
# Returns true if the session has the given key or false.
def has_key?(key)
load_for_read!
- @delegate.key?(key.to_s)
+ @delegate.key?(key)
end
alias :key? :has_key?
alias :include? :has_key?
@@ -112,7 +112,7 @@ module ActionDispatch
# Writes given value to given key of the session.
def []=(key, value)
load_for_write!
- @delegate[key.to_s] = value
+ @delegate[key] = value
end
# Clears the session.
@@ -139,13 +139,13 @@ module ActionDispatch
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
def update(hash)
load_for_write!
- @delegate.update stringify_keys(hash)
+ @delegate.update hash
end
# Deletes given key from the session.
def delete(key)
load_for_write!
- @delegate.delete key.to_s
+ @delegate.delete key
end
# Returns value of the given key from the session, or raises +KeyError+
@@ -165,9 +165,9 @@ module ActionDispatch
def fetch(key, default=Unspecified, &block)
load_for_read!
if default == Unspecified
- @delegate.fetch(key.to_s, &block)
+ @delegate.fetch(key, &block)
else
- @delegate.fetch(key.to_s, default, &block)
+ @delegate.fetch(key, default, &block)
end
end
@@ -211,15 +211,9 @@ module ActionDispatch
def load!
id, session = @by.load_session @req
options[:id] = id
- @delegate.replace(stringify_keys(session))
+ @delegate.replace(session)
@loaded = true
end
-
- def stringify_keys(other)
- other.each_with_object({}) { |(key, value), hash|
- hash[key.to_s] = value
- }
- end
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 79f9283f83..dcf800b215 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -159,7 +159,7 @@ module ActionDispatch
#
# controller 'geocode' do
# get 'geocode/:postalcode' => :show, constraints: {
- # postalcode: /# Postcode format
+ # postalcode: /# Postalcode format
# \d{5} #Prefix
# (-\d{4})? #Suffix
# /x
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 983f1daeb3..6f651a5689 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -41,7 +41,7 @@ module ActionDispatch
end
def internal?
- controller.to_s =~ %r{\Arails/(info|mailers|welcome)}
+ internal
end
def engine?
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index afbaa45d20..16b430c36e 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -107,6 +107,7 @@ module ActionDispatch
@ast = ast
@anchor = anchor
@via = via
+ @internal = options[:internal]
path_params = ast.find_all(&:symbol?).map(&:to_sym)
@@ -148,7 +149,8 @@ module ActionDispatch
required_defaults,
defaults,
request_method,
- precedence)
+ precedence,
+ @internal)
route
end
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index 778c5482d3..157f401f54 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -8,7 +8,7 @@ module ActionPack
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 7556f984f2..754ac144cc 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -381,19 +381,14 @@ class CollectionCacheController < ActionController::Base
render 'index'
end
- def index_explicit_render
+ def index_explicit_render_in_controller
@customers = [Customer.new('david', 1)]
- render partial: 'customers/customer', collection: @customers
+ render partial: 'customers/customer', collection: @customers, cached: true
end
def index_with_comment
@customers = [Customer.new('david', 1)]
- render partial: 'customers/commented_customer', collection: @customers, as: :customer
- end
-
- def index_with_callable_cache_key
- @customers = [Customer.new('david', 1)]
- render @customers, cache: -> customer { 'cached_david' }
+ render partial: 'customers/commented_customer', collection: @customers, as: :customer, cached: true
end
end
@@ -404,7 +399,7 @@ class AutomaticCollectionCacheTest < ActionController::TestCase
@controller.perform_caching = true
@controller.partial_rendered_times = 0
@controller.cache_store = ActiveSupport::Cache::MemoryStore.new
- ActionView::PartialRenderer.collection_cache = @controller.cache_store
+ ActionView::PartialRenderer.collection_cache = ActiveSupport::Cache::MemoryStore.new
end
def test_collection_fetches_cached_views
@@ -427,7 +422,7 @@ class AutomaticCollectionCacheTest < ActionController::TestCase
end
def test_explicit_render_call_with_options
- get :index_explicit_render
+ get :index_explicit_render_in_controller
assert_select ':root', "david, 1"
end
@@ -440,12 +435,6 @@ class AutomaticCollectionCacheTest < ActionController::TestCase
assert_equal 1, @controller.partial_rendered_times
end
- def test_caching_with_callable_cache_key
- get :index_with_callable_cache_key
- assert_customer_cached 'cached_david', 'david, 1'
- assert_customer_cached 'david/1', 'david, 1'
- end
-
private
def assert_customer_cached(key, content)
assert_match content,
diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb
index 22f1cc7c22..03a9c9ae78 100644
--- a/actionpack/test/controller/force_ssl_test.rb
+++ b/actionpack/test/controller/force_ssl_test.rb
@@ -322,3 +322,12 @@ class RedirectToSSLTest < ActionController::TestCase
assert_equal 'ihaz', response.body
end
end
+
+class ForceSSLControllerLevelTest < ActionController::TestCase
+ def test_no_redirect_websocket_ssl_request
+ request.env['rack.url_scheme'] = 'wss'
+ request.env['Upgrade'] = 'websocket'
+ get :cheeseburger
+ assert_response 200
+ end
+end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index ea50f05f4d..6277407ff7 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -390,7 +390,7 @@ class IntegrationTestUsesCorrectClass < ActionDispatch::IntegrationTest
reset!
%w( get post head patch put delete ).each do |verb|
- assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
+ assert_nothing_raised { __send__(verb, '/') }
end
end
end
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index 4ef5bed30d..cea265f9ab 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -4,6 +4,8 @@ require 'active_support/core_ext/hash/transform_values'
class ParametersAccessorsTest < ActiveSupport::TestCase
setup do
+ ActionController::Parameters.permit_all_parameters = false
+
@params = ActionController::Parameters.new(
person: {
age: '32',
@@ -176,12 +178,20 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert(@params != false)
end
- test "inspect shows both class name and parameters" do
+ test "inspect shows both class name, parameters and permitted flag" do
assert_equal(
'<ActionController::Parameters {"person"=>{"age"=>"32", '\
- '"name"=>{"first"=>"David", "last"=>"Heinemeier Hansson"}, ' \
- '"addresses"=>[{"city"=>"Chicago", "state"=>"Illinois"}]}}>',
+ '"name"=>{"first"=>"David", "last"=>"Heinemeier Hansson"}, ' \
+ '"addresses"=>[{"city"=>"Chicago", "state"=>"Illinois"}]}} permitted: false>',
@params.inspect
)
end
+
+ test "inspect prints updated permitted flag in the output" do
+ assert_match(/permitted: false/, @params.inspect)
+
+ @params.permit!
+
+ assert_match(/permitted: true/, @params.inspect)
+ end
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 1984ad8825..f7dcbc1984 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -133,7 +133,11 @@ class PerFormTokensController < ActionController::Base
self.per_form_csrf_tokens = true
def index
- render inline: "<%= form_tag (params[:form_path] || '/per_form_tokens/post_one'), method: (params[:form_method] || :post) %>"
+ render inline: "<%= form_tag (params[:form_path] || '/per_form_tokens/post_one'), method: params[:form_method] %>"
+ end
+
+ def button_to
+ render inline: "<%= button_to 'Button', (params[:form_path] || '/per_form_tokens/post_one'), method: params[:form_method] %>"
end
def post_one
@@ -652,15 +656,9 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_accepts_token_for_correct_path_and_method
get :index
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
- actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
- expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
- assert_equal expected, actual
+ assert_matches_session_token_on_server form_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one'
@@ -673,15 +671,9 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_rejects_token_for_incorrect_path
get :index
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
- actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
- expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
- assert_equal expected, actual
+ assert_matches_session_token_on_server form_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_two'
@@ -693,15 +685,9 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_rejects_token_for_incorrect_method
get :index
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
- actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
- expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
- assert_equal expected, actual
+ assert_matches_session_token_on_server form_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one'
@@ -710,6 +696,50 @@ class PerFormTokensControllerTest < ActionController::TestCase
end
end
+ def test_rejects_token_for_incorrect_method_button_to
+ get :button_to, params: { form_method: 'delete' }
+
+ form_token = assert_presence_and_fetch_form_csrf_token
+
+ assert_matches_session_token_on_server form_token, 'delete'
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ patch :post_one, params: { custom_authenticity_token: form_token }
+ end
+ end
+
+ test "Accepts proper token for implicit post method on button_to tag" do
+ get :button_to
+
+ form_token = assert_presence_and_fetch_form_csrf_token
+
+ assert_matches_session_token_on_server form_token, 'post'
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_nothing_raised do
+ post :post_one, params: { custom_authenticity_token: form_token }
+ end
+ end
+
+ %w{delete post patch}.each do |verb|
+ test "Accepts proper token for #{verb} method on button_to tag" do
+ get :button_to, params: { form_method: verb }
+
+ form_token = assert_presence_and_fetch_form_csrf_token
+
+ assert_matches_session_token_on_server form_token, verb
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_nothing_raised do
+ send verb, :post_one, params: { custom_authenticity_token: form_token }
+ end
+ end
+ end
+
def test_accepts_global_csrf_token
get :index
@@ -726,15 +756,9 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_ignores_params
get :index, params: {form_path: '/per_form_tokens/post_one?foo=bar'}
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
- actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
- expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
- assert_equal expected, actual
+ assert_matches_session_token_on_server form_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one?foo=baz'
@@ -747,11 +771,7 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_ignores_trailing_slash_during_generation
get :index, params: {form_path: '/per_form_tokens/post_one/'}
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one'
@@ -764,11 +784,7 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_ignores_trailing_slash_during_validation
get :index
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
+ form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one/'
@@ -781,12 +797,7 @@ class PerFormTokensControllerTest < ActionController::TestCase
def test_method_is_case_insensitive
get :index, params: {form_method: "POST"}
- form_token = nil
- assert_select 'input[name=custom_authenticity_token]' do |elts|
- form_token = elts.first['value']
- assert_not_nil form_token
- end
-
+ form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env['PATH_INFO'] = '/per_form_tokens/post_one/'
assert_nothing_raised do
@@ -794,4 +805,19 @@ class PerFormTokensControllerTest < ActionController::TestCase
end
assert_response :success
end
+
+ private
+ def assert_presence_and_fetch_form_csrf_token
+ assert_select 'input[name="custom_authenticity_token"]' do |input|
+ form_csrf_token = input.first['value']
+ assert_not_nil form_csrf_token
+ return form_csrf_token
+ end
+ end
+
+ def assert_matches_session_token_on_server(form_token, method = 'post')
+ actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
+ expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', method)
+ assert_equal expected, actual
+ end
end
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index 6d377c4691..daf17558aa 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -99,7 +99,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest
def test_parsing_json_doesnot_rescue_exception
req = Class.new(ActionDispatch::Request) do
def params_parsers
- { Mime[:json] => Proc.new { |data| raise Interrupt } }
+ { json: Proc.new { |data| raise Interrupt } }
end
def content_length; get_header('rack.input').length; end
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index 64801bff39..3655c7f570 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -150,6 +150,34 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest
)
end
+ test "parses json params after custom json mime type registered" do
+ begin
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w(application/vnd.api+json)
+ assert_parses(
+ {"user" => {"username" => "meinac"}, "username" => "meinac"},
+ "{\"username\": \"meinac\"}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ ensure
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
+ end
+ end
+
+ test "parses json params after custom json mime type registered with synonym" do
+ begin
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w(application/vnd.api+json)
+ assert_parses(
+ {"user" => {"username" => "meinac"}, "username" => "meinac"},
+ "{\"username\": \"meinac\"}", { 'CONTENT_TYPE' => 'application/vnd.api+json' }
+ )
+ ensure
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
+ end
+ end
+
private
def assert_parses(expected, actual, headers = {})
with_test_routing(UsersController) do
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 7dcbcc5c21..3433d82791 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -105,6 +105,16 @@ module ActionDispatch
end
end
+ def test_indifferent_access
+ s = Session.create(store, req, {})
+
+ s[:one] = { test: "deep" }
+ s[:two] = { "test" => "deep" }
+
+ assert_equal 'deep', s[:one]["test"]
+ assert_equal 'deep', s[:two][:test]
+ end
+
private
def store
Class.new {
diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb
index f72a87b994..fd85cc6e9f 100644
--- a/actionpack/test/dispatch/routing/inspector_test.rb
+++ b/actionpack/test/dispatch/routing/inspector_test.rb
@@ -389,6 +389,29 @@ module ActionDispatch
], output
end
+ def test_displaying_routes_for_internal_engines
+ engine = Class.new(Rails::Engine) do
+ def self.inspect
+ "Blog::Engine"
+ end
+ end
+ engine.routes.draw do
+ get '/cart', to: 'cart#show'
+ post '/cart', to: 'cart#create'
+ patch '/cart', to: 'cart#update'
+ end
+
+ output = draw do
+ get '/custom/assets', to: 'custom_assets#show'
+ mount engine => "/blog", as: "blog", internal: true
+ end
+
+ assert_equal [
+ " Prefix Verb URI Pattern Controller#Action",
+ "custom_assets GET /custom/assets(.:format) custom_assets#show",
+ ], output
+ end
+
end
end
end
diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb
index d38d1bbce6..c9ce5cad42 100644
--- a/actionpack/test/dispatch/session/abstract_store_test.rb
+++ b/actionpack/test/dispatch/session/abstract_store_test.rb
@@ -46,6 +46,22 @@ module ActionDispatch
assert_equal session.to_hash, session1.to_hash
end
+ def test_previous_session_has_indifferent_access
+ env = {}
+ as = MemoryStore.new app
+ as.call(env)
+
+ assert @env
+ session = Request::Session.find ActionDispatch::Request.new @env
+ session[:foo] = { bar: "baz" }
+
+ as.call(@env)
+ session = Request::Session.find ActionDispatch::Request.new @env
+
+ assert_equal session[:foo][:bar], "baz"
+ assert_equal session[:foo]["bar"], "baz"
+ end
+
private
def app(&block)
@env = nil
diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb
index dbb996973d..b911392cf1 100644
--- a/actionpack/test/dispatch/session/cache_store_test.rb
+++ b/actionpack/test/dispatch/session/cache_store_test.rb
@@ -12,6 +12,11 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
head :ok
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ head :ok
+ end
+
def set_serialized_session_value
session[:foo] = SessionAutoloadTest::Foo.new
head :ok
@@ -21,6 +26,14 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "#{request.session.id}"
end
@@ -160,6 +173,22 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_deep_session_value_with_symbol'
+ assert_response :success
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_response :success
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ end
+
private
def with_test_route_set
with_routing do |set|
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index f07e215e3a..71402b021a 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -24,10 +24,23 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
render plain: Rack::Utils.escape(Verifier.generate(session.to_hash))
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ render plain: Rack::Utils.escape(Verifier.generate(session.to_hash))
+ end
+
def get_session_value
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "id: #{request.session.id}"
end
@@ -81,6 +94,15 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_session_indifferent_access
+ with_test_route_set do
+ cookies[SessionKey] = SignedBar
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: "bar"', response.body
+ end
+ end
+
def test_getting_session_id
with_test_route_set do
cookies[SessionKey] = SignedBar
@@ -332,6 +354,18 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+
+ get '/get_deep_session_value_with_symbol'
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ end
+
private
# Overwrite get to send SessionSecret in env hash
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 3fed9bad4f..2e6b42856f 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -13,6 +13,11 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
head :ok
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ head :ok
+ end
+
def set_serialized_session_value
session[:foo] = SessionAutoloadTest::Foo.new
head :ok
@@ -22,6 +27,14 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "#{request.session.id}"
end
@@ -179,6 +192,24 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
rescue Dalli::RingError => ex
skip ex.message, ex.backtrace
end
+
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_deep_session_value_with_symbol'
+ assert_response :success
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_response :success
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
+ end
rescue LoadError, RuntimeError, Dalli::DalliError
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
end
diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb
index 3e61d123e3..332c2ae3c8 100644
--- a/actionpack/test/dispatch/session/test_session_test.rb
+++ b/actionpack/test/dispatch/session/test_session_test.rb
@@ -60,4 +60,11 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase
session = ActionController::TestSession.new(one: '1')
assert_equal(2, session.fetch('2') { |key| key.to_i })
end
+
+ def test_fetch_returns_indifferent_access
+ session = ActionController::TestSession.new(three: { two: '1' })
+ three = session.fetch(:three)
+ assert_equal('1', three[:two])
+ assert_equal('1', three["two"])
+ end
end
diff --git a/actionpack/test/fixtures/collection_cache/index.html.erb b/actionpack/test/fixtures/collection_cache/index.html.erb
index 521b1450df..853e501ab4 100644
--- a/actionpack/test/fixtures/collection_cache/index.html.erb
+++ b/actionpack/test/fixtures/collection_cache/index.html.erb
@@ -1 +1 @@
-<%= render @customers %> \ No newline at end of file
+<%= render partial: 'customers/customer', collection: @customers, cached: true %>