aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal.rb4
-rw-r--r--actionpack/lib/action_controller/metal/parameter_encoding.rb35
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb15
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb2
-rw-r--r--actionpack/lib/action_dispatch/request/utils.rb11
-rw-r--r--actionpack/test/controller/parameter_encoding_test.rb39
6 files changed, 52 insertions, 54 deletions
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index ed93a2f09c..9dab7aeef4 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -139,8 +139,8 @@ module ActionController
end
end
- def self.encoding_for_param(action, param) # :nodoc:
- ::Encoding::UTF_8
+ def self.binary_params_for?(action) # :nodoc:
+ false
end
# Delegates to the class' <tt>controller_name</tt>
diff --git a/actionpack/lib/action_controller/metal/parameter_encoding.rb b/actionpack/lib/action_controller/metal/parameter_encoding.rb
index c457fd0d06..8b2c414a5f 100644
--- a/actionpack/lib/action_controller/metal/parameter_encoding.rb
+++ b/actionpack/lib/action_controller/metal/parameter_encoding.rb
@@ -1,5 +1,5 @@
module ActionController
- # Allows encoding to be specified per parameter per action.
+ # Specify binary encoding for parameters for a given action.
module ParameterEncoding
extend ActiveSupport::Concern
@@ -13,17 +13,32 @@ module ActionController
@_parameter_encodings = {}
end
- def encoding_for_param(action, param) # :nodoc:
- if @_parameter_encodings[action.to_s] && @_parameter_encodings[action.to_s][param.to_s]
- @_parameter_encodings[action.to_s][param.to_s]
- else
- super
- end
+ def binary_params_for?(action) # :nodoc:
+ @_parameter_encodings[action.to_s]
end
- def parameter_encoding(action, param_name, encoding)
- @_parameter_encodings[action.to_s] ||= {}
- @_parameter_encodings[action.to_s][param_name.to_s] = encoding
+ # Specify that a given action's parameters should all be encoded as
+ # ASCII-8BIT (it "skips" the encoding default of UTF-8).
+ #
+ # For example, a controller would use it like this:
+ #
+ # class RepositoryController < ActionController::Base
+ # skip_parameter_encoding :show
+ #
+ # def show
+ # @repo = Repository.find_by_filesystem_path params[:file_path]
+ # end
+ #
+ # def index
+ # @repositories = Repository.all
+ # end
+ # end
+ #
+ # The show action in the above controller would have all parameter values
+ # encoded as ASCII-8BIT. This is useful in the case where an application
+ # must handle data but encoding of the data is unknown, like file system data.
+ def skip_parameter_encoding(action)
+ @_parameter_encodings[action.to_s] = true
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index ddd15b748b..ad4aadacf5 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -45,7 +45,7 @@ module ActionDispatch
query_parameters.dup
end
params.merge!(path_parameters)
- params = set_custom_encoding(params)
+ params = set_binary_encoding(params)
set_header("action_dispatch.request.parameters", params)
params
end
@@ -73,21 +73,16 @@ module ActionDispatch
private
- def set_custom_encoding(params)
+ def set_binary_encoding(params)
action = params[:action]
- params.each do |k, v|
- if v.is_a?(String) && v.encoding != encoding_template(action, k)
- params[k] = v.force_encoding(encoding_template(action, k))
+ if controller_class.binary_params_for?(action)
+ ActionDispatch::Request::Utils.each_param_value(params) do |param|
+ param.force_encoding ::Encoding::ASCII_8BIT
end
end
-
params
end
- def encoding_template(action, param)
- controller_class.encoding_for_param(action, param)
- end
-
def parse_formatted_parameters(parsers)
return yield if content_length.zero? || content_mime_type.nil?
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 9986d6e1e9..a886358399 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -69,7 +69,7 @@ module ActionDispatch
PASS_NOT_FOUND = Class.new { # :nodoc:
def self.action(_); self; end
def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
- def self.encoding_for_param(action, param); ::Encoding::UTF_8; end
+ def self.binary_params_for?(action); false; end
}
def controller_class
diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb
index 282bdbd2be..01bc871e5f 100644
--- a/actionpack/lib/action_dispatch/request/utils.rb
+++ b/actionpack/lib/action_dispatch/request/utils.rb
@@ -4,6 +4,17 @@ module ActionDispatch
mattr_accessor :perform_deep_munge
self.perform_deep_munge = true
+ def self.each_param_value(params, &block)
+ case params
+ when Array
+ params.each { |element| each_param_value(element, &block) }
+ when Hash
+ params.each_value { |value| each_param_value(value, &block) }
+ when String
+ block.call params
+ end
+ end
+
def self.normalize_encode_params(params)
if perform_deep_munge
NoNilParamEncoder.normalize_encode_params params
diff --git a/actionpack/test/controller/parameter_encoding_test.rb b/actionpack/test/controller/parameter_encoding_test.rb
index 7840b4f5c4..234d0bddd1 100644
--- a/actionpack/test/controller/parameter_encoding_test.rb
+++ b/actionpack/test/controller/parameter_encoding_test.rb
@@ -1,9 +1,8 @@
require "abstract_unit"
class ParameterEncodingController < ActionController::Base
- parameter_encoding :test_bar, :bar, Encoding::ASCII_8BIT
- parameter_encoding :test_baz, :baz, Encoding::ISO_8859_1
- parameter_encoding :test_baz_to_ascii, :baz, Encoding::ASCII_8BIT
+ skip_parameter_encoding :test_bar
+ skip_parameter_encoding :test_all_values_encoding
def test_foo
render body: params[:foo].encoding
@@ -13,16 +12,8 @@ class ParameterEncodingController < ActionController::Base
render body: params[:bar].encoding
end
- def test_baz
- render body: params[:baz].encoding
- end
-
- def test_no_change_to_baz
- render body: params[:baz].encoding
- end
-
- def test_baz_to_ascii
- render body: params[:baz].encoding
+ def test_all_values_encoding
+ render body: ::JSON.dump(params.values.map(&:encoding).map(&:name))
end
end
@@ -36,32 +27,18 @@ class ParameterEncodingTest < ActionController::TestCase
assert_equal "UTF-8", @response.body
end
- test "properly transcodes ASCII_8BIT parameters into declared encodings" do
+ test "properly encodes ASCII_8BIT parameters into binary" do
post :test_bar, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
assert_response :success
assert_equal "ASCII-8BIT", @response.body
end
- test "properly transcodes ISO_8859_1 parameters into declared encodings" do
- post :test_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
-
- assert_response :success
- assert_equal "ISO-8859-1", @response.body
- end
-
- test "does not transcode parameters when not specified" do
- post :test_no_change_to_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
+ test "properly encodes all ASCII_8BIT parameters into binary" do
+ post :test_all_values_encoding, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
assert_response :success
- assert_equal "UTF-8", @response.body
- end
-
- test "respects different encoding declarations for a param per action" do
- post :test_baz_to_ascii, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
-
- assert_response :success
- assert_equal "ASCII-8BIT", @response.body
+ assert_equal ["ASCII-8BIT"], JSON.parse(@response.body).uniq
end
test "does not raise an error when passed a param declared as ASCII-8BIT that contains invalid bytes" do