mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Document and update API for skip_parameter_encoding
This commit changes `parameter_encoding` to `skip_parameter_encoding`. `skip_parameter_encoding` will set encoding on all parameters to ASCII-8BIT for a given action on a particular controller. This allows the controller to handle data when the encoding of that data is unknown, for example file systems or truly binary parameters.
This commit is contained in:
parent
85b2a3ea2f
commit
2eb0a6630a
6 changed files with 52 additions and 54 deletions
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
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 "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" }
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue