Merge pull request #40457 from HParker/specify-per-param-encoding
add ability to set per param encoding
This commit is contained in:
commit
c9ddceab6d
@ -135,7 +135,7 @@ def self.make_response!(request)
|
||||
end
|
||||
end
|
||||
|
||||
def self.binary_params_for?(action) # :nodoc:
|
||||
def self.custom_encoding_for(action, param) # :nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
|
@ -12,11 +12,11 @@ def inherited(klass) # :nodoc:
|
||||
end
|
||||
|
||||
def setup_param_encode # :nodoc:
|
||||
@_parameter_encodings = {}
|
||||
@_parameter_encodings = Hash.new { |h, k| h[k] = {} }
|
||||
end
|
||||
|
||||
def binary_params_for?(action) # :nodoc:
|
||||
@_parameter_encodings[action.to_s]
|
||||
def custom_encoding_for(action, param) # :nodoc:
|
||||
@_parameter_encodings[action.to_s][param.to_s]
|
||||
end
|
||||
|
||||
# Specify that a given action's parameters should all be encoded as
|
||||
@ -44,7 +44,35 @@ def binary_params_for?(action) # :nodoc:
|
||||
# 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
|
||||
@_parameter_encodings[action.to_s] = Hash.new { Encoding::ASCII_8BIT }
|
||||
end
|
||||
|
||||
# Specify the encoding for a a parameter on an action
|
||||
# ASCII-8BIT (it "skips" the encoding default of UTF-8).
|
||||
#
|
||||
# For example, a controller would use it like this:
|
||||
#
|
||||
# class RepositoryController < ActionController::Base
|
||||
# param_encoding :show, :file_path, Encoding::ASCII_8BIT
|
||||
#
|
||||
# def show
|
||||
# @repo = Repository.find_by_filesystem_path params[:file_path]
|
||||
#
|
||||
# # `repo_name` is guaranteed to be UTF-8, but was ASCII-8BIT, so
|
||||
# # tag it as such
|
||||
# @repo_name = params[:repo_name].force_encoding 'UTF-8'
|
||||
# end
|
||||
#
|
||||
# def index
|
||||
# @repositories = Repository.all
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# The file_path parameter on the show action would be 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 param_encoding(action, param, encoding)
|
||||
@_parameter_encodings[action.to_s][param.to_s] = encoding
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -76,7 +76,7 @@ def commit_cookie_jar! # :nodoc:
|
||||
PASS_NOT_FOUND = Class.new { # :nodoc:
|
||||
def self.action(_); self; end
|
||||
def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
|
||||
def self.binary_params_for?(action); false; end
|
||||
def self.custom_encoding_for(action, param); nil; end
|
||||
}
|
||||
|
||||
def controller_class
|
||||
|
@ -42,7 +42,7 @@ def self.check_param_encoding(params)
|
||||
end
|
||||
|
||||
def self.set_binary_encoding(request, params, controller, action)
|
||||
BinaryParamEncoder.encode(request, params, controller, action)
|
||||
CustomParamEncoder.encode(request, params, controller, action)
|
||||
end
|
||||
|
||||
class ParamEncoder # :nodoc:
|
||||
@ -78,23 +78,25 @@ def self.handle_array(params)
|
||||
end
|
||||
end
|
||||
|
||||
class BinaryParamEncoder # :nodoc:
|
||||
class CustomParamEncoder # :nodoc:
|
||||
def self.encode(request, params, controller, action)
|
||||
return params unless controller && controller.valid_encoding?
|
||||
|
||||
if binary_params_for?(request, controller, action)
|
||||
ActionDispatch::Request::Utils.each_param_value(params.except(:controller, :action)) do |param|
|
||||
param.force_encoding ::Encoding::ASCII_8BIT
|
||||
params.except(:controller, :action).each do |key, value|
|
||||
# next if key == :controller || key == :action
|
||||
ActionDispatch::Request::Utils.each_param_value(value) do |param|
|
||||
if desired_encoding = custom_encoding_for(request, controller, action, key)
|
||||
param.force_encoding(desired_encoding)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
params
|
||||
end
|
||||
|
||||
def self.binary_params_for?(request, controller, action)
|
||||
request.controller_class_for(controller).binary_params_for?(action)
|
||||
def self.custom_encoding_for(request, controller, action, param)
|
||||
request.controller_class_for(controller).custom_encoding_for(action, param)
|
||||
rescue MissingController
|
||||
false
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -4,12 +4,10 @@
|
||||
|
||||
class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
|
||||
class TestController < ActionController::Base
|
||||
skip_parameter_encoding("parse_binary")
|
||||
|
||||
class << self
|
||||
attr_accessor :last_request_parameters, :last_parameters
|
||||
|
||||
def binary_params_for?(action)
|
||||
action == "parse_binary"
|
||||
end
|
||||
end
|
||||
|
||||
def parse_binary
|
||||
|
@ -4559,9 +4559,7 @@ def app; APP end
|
||||
|
||||
class TestInvalidUrls < ActionDispatch::IntegrationTest
|
||||
class FooController < ActionController::Base
|
||||
def self.binary_params_for?(action)
|
||||
action == "show"
|
||||
end
|
||||
param_encoding :show, :id, Encoding::ASCII_8BIT
|
||||
|
||||
def show
|
||||
render plain: "foo#show"
|
||||
@ -4595,7 +4593,7 @@ def show
|
||||
end
|
||||
end
|
||||
|
||||
test "params encoded with binary_params_for? are treated as ASCII 8bit" do
|
||||
test "params param_encoding uses ASCII 8bit" do
|
||||
with_routing do |set|
|
||||
set.draw do
|
||||
get "/foo/show(/:id)", to: "test_invalid_urls/foo#show"
|
||||
|
Loading…
Reference in New Issue
Block a user