diff options
author | wycats <wycats@gmail.com> | 2010-06-27 21:12:10 -0700 |
---|---|---|
committer | wycats <wycats@gmail.com> | 2010-06-27 21:13:55 -0700 |
commit | 25215d7285db10e2c04d903f251b791342e4dd6a (patch) | |
tree | dd9e3f755aaef1e328d142967db216183f7db610 /actionpack/lib | |
parent | 06b0d6e5cdcfab8d49bcf559008f1753f3e7853c (diff) | |
download | rails-25215d7285db10e2c04d903f251b791342e4dd6a.tar.gz rails-25215d7285db10e2c04d903f251b791342e4dd6a.tar.bz2 rails-25215d7285db10e2c04d903f251b791342e4dd6a.zip |
Fix several known web encoding issues:
* Specify accept-charset on all forms. All recent browsers,
as well as IE5+, will use the encoding specified for form
parameters
* Unfortunately, IE5+ will not look at accept-charset unless
at least one character in the form's values is not in the
page's charset. Since the user can override the default
charset (which Rails sets to UTF-8), we provide a hidden
input containing a unicode character, forcing IE to look
at the accept-charset.
* Now that the vast majority of web input is UTF-8, we set
the inbound parameters to UTF-8. This will eliminate many
cases of incompatible encodings between ASCII-8BIT and
UTF-8.
* You can safely ignore params[:_snowman_]
TODO:
* Validate inbound text to confirm it is UTF-8
* Combine the whole_form implementations in form_helper_test
and form_tag_helper_test
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameters.rb | 31 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_tag_helper.rb | 15 |
2 files changed, 42 insertions, 4 deletions
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 0a37bd7fc1..add8cab2ab 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -6,7 +6,11 @@ module ActionDispatch module Parameters # Returns both GET and POST \parameters in a single hash. def parameters - @env["action_dispatch.request.parameters"] ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access + @env["action_dispatch.request.parameters"] ||= begin + params = request_parameters.merge(query_parameters) + params.merge!(path_parameters) + encode_params(params).with_indifferent_access + end end alias :params :parameters @@ -32,6 +36,31 @@ module ActionDispatch end private + + # TODO: Validate that the characters are UTF-8. If they aren't, + # you'll get a weird error down the road, but our form handling + # should really prevent that from happening + def encode_params(params) + return params unless "ruby".encoding_aware? + + if params.is_a?(String) + return params.force_encoding("UTF-8").encode! + elsif !params.is_a?(Hash) + return params + end + + params.each do |k, v| + case v + when Hash + encode_params(v) + when Array + v.map! {|el| encode_params(el) } + else + encode_params(v) + end + end + end + # Convert nested Hash to HashWithIndifferentAccess def normalize_parameters(value) case value diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index ea491b2db8..0e9cb2349f 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -530,22 +530,31 @@ module ActionView returning options.stringify_keys do |html_options| html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart") html_options["action"] = url_for(url_for_options, *parameters_for_url) + html_options["accept-encoding"] = "UTF-8" html_options["data-remote"] = true if html_options.delete("remote") end end def extra_tags_for_form(html_options) - case method = html_options.delete("method").to_s + snowman_tag = tag(:input, :type => "hidden", + :name => "_snowman_", :value => "☃") + + method = html_options.delete("method").to_s + + method_tag = case method when /^get$/i # must be case-insensitive, but can't use downcase as might be nil html_options["method"] = "get" '' when /^post$/i, "", nil html_options["method"] = "post" - protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0;display:inline') : '' + token_tag else html_options["method"] = "post" - content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0;display:inline') + tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag end + + tags = snowman_tag << method_tag + content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline') end def form_tag_html(html_options) |