Browse files

Merge tag 'v3.0.20' into 3-0-stable

tagging 3.0.20
  • Loading branch information...
2 parents 3f1cf6a + b875be0 commit 8cd2fed0c6412f277245e22affe1641eda9674b2 @willbryant committed Jan 29, 2013
Showing with 1,654 additions and 408 deletions.
  1. +1 −0 .gitignore
  2. +10 −1 .travis.yml
  3. +3 −3 Gemfile
  4. +1 −1 RAILS_VERSION
  5. +26 −0 actionmailer/CHANGELOG
  6. +1 −1 actionmailer/lib/action_mailer/version.rb
  7. +82 −0 actionpack/CHANGELOG
  8. +1 −1 actionpack/actionpack.gemspec
  9. +1 −1 actionpack/lib/action_controller/deprecated/base.rb
  10. +2 −2 actionpack/lib/action_controller/metal/http_authentication.rb
  11. +1 −1 actionpack/lib/action_controller/metal/redirecting.rb
  12. +1 −3 actionpack/lib/action_dispatch/http/filter_parameters.rb
  13. +22 −0 actionpack/lib/action_dispatch/http/request.rb
  14. +2 −2 actionpack/lib/action_dispatch/middleware/params_parser.rb
  15. +6 −0 actionpack/lib/action_dispatch/routing/route_set.rb
  16. +1 −1 actionpack/lib/action_dispatch/testing/assertions/response.rb
  17. +1 −1 actionpack/lib/action_pack/version.rb
  18. +1 −1 actionpack/lib/action_view/helpers/capture_helper.rb
  19. +3 −3 actionpack/lib/action_view/helpers/form_options_helper.rb
  20. +2 −2 actionpack/lib/action_view/helpers/form_tag_helper.rb
  21. +1 −1 actionpack/lib/action_view/helpers/sanitize_helper.rb
  22. +3 −3 actionpack/lib/action_view/helpers/text_helper.rb
  23. +11 −4 actionpack/lib/action_view/helpers/translation_helper.rb
  24. +5 −4 actionpack/lib/action_view/testing/resolvers.rb
  25. +6 −2 actionpack/test/controller/integration_test.rb
  26. +12 −12 actionpack/test/controller/new_base/render_rjs_test.rb
  27. +20 −0 actionpack/test/controller/redirect_test.rb
  28. +2 −2 actionpack/test/controller/render_test.rb
  29. +13 −0 actionpack/test/controller/webservice_test.rb
  30. +22 −0 actionpack/test/dispatch/request/json_params_parsing_test.rb
  31. +10 −1 actionpack/test/dispatch/request/query_string_parsing_test.rb
  32. +17 −0 actionpack/test/dispatch/request/xml_params_parsing_test.rb
  33. +17 −6 actionpack/test/template/asset_tag_helper_test.rb
  34. +5 −5 actionpack/test/template/erb_util_test.rb
  35. +15 −10 actionpack/test/template/form_options_helper_test.rb
  36. +7 −1 actionpack/test/template/form_tag_helper_test.rb
  37. +5 −5 actionpack/test/template/javascript_helper_test.rb
  38. +2 −2 actionpack/test/template/sanitize_helper_test.rb
  39. +10 −9 actionpack/test/template/template_test.rb
  40. +1 −10 actionpack/test/template/text_helper_test.rb
  41. +17 −1 actionpack/test/template/translation_helper_test.rb
  42. +5 −5 actionpack/test/template/url_helper_test.rb
  43. +32 −5 activemodel/CHANGELOG
  44. +1 −0 activemodel/lib/active_model/serializers/xml.rb
  45. +3 −1 activemodel/lib/active_model/validations/confirmation.rb
  46. +1 −1 activemodel/lib/active_model/version.rb
  47. +4 −0 activemodel/test/cases/serializeration/xml_serialization_test.rb
  48. +4 −0 activemodel/test/models/contact.rb
  49. +37 −0 activerecord/CHANGELOG
  50. +1 −1 activerecord/lib/active_record/aggregations.rb
  51. +1 −1 activerecord/lib/active_record/associations.rb
  52. +2 −2 activerecord/lib/active_record/associations/association_proxy.rb
  53. +18 −1 activerecord/lib/active_record/autosave_association.rb
  54. +5 −1 activerecord/lib/active_record/base.rb
  55. +25 −10 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  56. +9 −4 activerecord/lib/active_record/relation/predicate_builder.rb
  57. +1 −1 activerecord/lib/active_record/schema_dumper.rb
  58. +1 −1 activerecord/lib/active_record/version.rb
  59. +10 −0 activerecord/test/cases/adapters/mysql/schema_test.rb
  60. +4 −5 activerecord/test/cases/associations/has_many_associations_test.rb
  61. +3 −3 activerecord/test/cases/associations/join_model_test.rb
  62. +23 −3 activerecord/test/cases/autosave_association_test.rb
  63. +14 −2 activerecord/test/cases/finder_test.rb
  64. +1 −1 activerecord/test/cases/fixtures_test.rb
  65. +1 −1 activerecord/test/cases/helper.rb
  66. +2 −2 activerecord/test/cases/json_serialization_test.rb
  67. +9 −5 activerecord/test/cases/nested_attributes_test.rb
  68. +6 −5 activerecord/test/cases/persistence_test.rb
  69. +39 −0 activerecord/test/cases/relation/where_test.rb
  70. +10 −10 activerecord/test/cases/relations_test.rb
  71. +1 −1 activerecord/test/cases/timestamp_test.rb
  72. +1 −4 activerecord/test/cases/xml_serialization_test.rb
  73. +1 −1 activerecord/test/cases/yaml_serialization_test.rb
  74. +1 −1 activerecord/test/models/company.rb
  75. +2 −0 activerecord/test/models/face.rb
  76. +1 −1 activerecord/test/schema/mysql2_specific_schema.rb
  77. +1 −1 activerecord/test/schema/mysql_specific_schema.rb
  78. +18 −0 activeresource/CHANGELOG
  79. +1 −1 activeresource/lib/active_resource/version.rb
  80. +2 −2 activeresource/test/cases/base/schema_test.rb
  81. +1 −25 activeresource/test/cases/base_test.rb
  82. +0 −14 activeresource/test/cases/finder_test.rb
  83. +31 −0 activesupport/CHANGELOG
  84. +1 −1 activesupport/lib/active_support/core_ext/date_time/calculations.rb
  85. +25 −7 activesupport/lib/active_support/core_ext/hash/conversions.rb
  86. +0 −2 activesupport/lib/active_support/core_ext/module/deprecation.rb
  87. +56 −35 activesupport/lib/active_support/core_ext/string/output_safety.rb
  88. +6 −2 activesupport/lib/active_support/dependencies.rb
  89. +3 −3 activesupport/lib/active_support/gzip.rb
  90. +644 −0 activesupport/lib/active_support/json/backends/okjson.rb
  91. +1 −93 activesupport/lib/active_support/json/backends/yaml.rb
  92. +1 −1 activesupport/lib/active_support/json/decoding.rb
  93. +1 −1 activesupport/lib/active_support/multibyte/chars.rb
  94. +1 −1 activesupport/lib/active_support/test_case.rb
  95. +7 −4 activesupport/lib/active_support/testing/setup_and_teardown.rb
  96. +1 −1 activesupport/lib/active_support/version.rb
  97. +1 −1 activesupport/test/abstract_unit.rb
  98. +4 −9 activesupport/test/core_ext/date_ext_test.rb
  99. +24 −8 activesupport/test/core_ext/hash_ext_test.rb
  100. +17 −0 activesupport/test/core_ext/string_ext_test.rb
  101. +79 −0 activesupport/test/dependencies_test.rb
  102. +2 −2 activesupport/test/json/decoding_test.rb
  103. +42 −4 activesupport/test/safe_buffer_test.rb
  104. +4 −0 activesupport/test/test_case_test.rb
  105. +1 −2 activesupport/test/whiny_nil_test.rb
  106. +26 −0 railties/CHANGELOG
  107. +1 −1 railties/lib/rails/generators/rails/app/app_generator.rb
  108. +1 −1 railties/lib/rails/version.rb
  109. +1 −1 railties/test/generators/app_generator_test.rb
  110. +1 −1 railties/test/generators_test.rb
  111. +0 −2 railties/test/railties/plugin_test.rb
  112. +1 −1 version.rb
View
1 .gitignore
@@ -6,6 +6,7 @@ doc/rdoc
activemodel/doc
activeresource/doc
activerecord/doc
+activerecord/sqlnet.log
actionpack/doc
actionmailer/doc
activesupport/doc
View
11 .travis.yml
@@ -9,8 +9,17 @@ env:
- "GEM=ar:mysql"
- "GEM=ar:mysql2"
- "GEM=ar:sqlite3"
+ - "GEM=ar:postgresql"
notifications:
email: false
irc:
- - "irc.freenode.org#rails-contrib"
+ on_success: change
+ on_failure: always
+ channels:
+ - "irc.freenode.org#rails-contrib"
+ campfire:
+ on_success: change
+ on_failure: always
+ rooms:
+ - secure: "CGWvthGkBKNnTnk9YSmf9AXKoiRI33fCl5D3jU4nx3cOPu6kv2R9nMjt9EAo\nOuS4Q85qNSf4VNQ2cUPNiNYSWQ+XiTfivKvDUw/QW9r1FejYyeWarMsSBWA+\n0fADjF1M2dkDIVLgYPfwoXEv7l+j654F1KLKB69F0F/netwP9CQ="
bundler_args: --path vendor/bundle
View
6 Gemfile
@@ -3,7 +3,7 @@ source 'http://rubygems.org'
gemspec
gem "rake", ">= 0.8.7"
-gem "mocha", ">= 0.9.8"
+gem 'mocha', '>= 0.13.0', :require => false
group :doc do
gem "rdoc", "~> 3.4"
@@ -39,9 +39,9 @@ platforms :ruby do
gem "sqlite3", "~> 1.3.3"
group :db do
- gem "pg", ">= 0.9.0" unless ENV['TRAVIS'] # once pg is on travis this can be removed
+ gem "pg", ">= 0.9.0"
gem "mysql", ">= 2.8.1"
- gem "mysql2", "~> 0.2.13"
+ gem "mysql2", :git => "git://github.com/brianmario/mysql2.git", :branch => "0.2.x"
end
end
View
2 RAILS_VERSION
@@ -1 +1 @@
-3.0.10
+3.0.20
View
26 actionmailer/CHANGELOG
@@ -1,3 +1,29 @@
+## Rails 3.0.20 (unreleased)
+
+## Rails 3.0.19 (Jan 8, 2013)
+
+* No changes.
+
+## Rails 3.0.18 (Jan 2, 2013)
+
+* No changes.
+
+## Rails 3.0.17 (Aug 9, 2012)
+
+* No changes.
+
+## Rails 3.0.16 (Jul 26, 2012)
+
+* No changes.
+
+## Rails 3.0.14 (Jun 12, 2012)
+
+* No changes.
+
+* Rails 3.0.13 (May 31, 2012)
+
+* No changes.
+
*Rails 3.0.10 (August 16, 2011)*
*No changes.
View
2 actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 3
MINOR = 0
- TINY = 10
+ TINY = 20
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
View
82 actionpack/CHANGELOG
@@ -1,5 +1,87 @@
+## Rails 3.0.20 (unreleased)
+
+* Fixed JSON params parsing regression for non-object JSON content.
+
+## Rails 3.0.19 (Jan 8, 2013)
+
+* Strip nils from collections on JSON and XML posts. [CVE-2013-0155]
+
+## Rails 3.0.18 (Jan 2, 2013)
+
+* No changes.
+
+## Rails 3.0.17 (Aug 9, 2012)
+
+* There is an XSS vulnerability in the strip_tags helper in Ruby on Rails, the
+ helper doesn't correctly handle malformed html. As a result an attacker can
+ execute arbitrary javascript through the use of specially crafted malformed
+ html.
+
+ *Marek from Nethemba (www.nethemba.com) & Santiago Pastorino*
+
+* When an "include_blank" value is supplied to the `select_tag` helper, the "include_blank" value is not escaped. If untrusted data is not escaped, and is supplied as the prompt value, there is a potential for XSS attacks.
+ Vulnerable code will look something like this:
+ select_tag("name", options, :include_blank => UNTRUSTED_INPUT)
+
+ *Santiago Pastorino*
+
+## Rails 3.0.16 (Jul 26, 2012)
+
+* Do not convert digest auth strings to symbols. CVE-2012-3424
+
+## Rails 3.0.14 (Jun 12, 2012)
+
+* nil is removed from array parameter values
+
+ CVE-2012-2694
+
+* Rails 3.0.13 (May 31, 2012)
+
+* Strip null bytes from Location header
+
+* load the encoding converter to work around [ruby-core:41556] when switching
+ encodings
+
+* Avoid inspecting the whole route set, closes #1525
+
+* whitelist protocols for auto_link
+
+* Strip [nil] from parameters hash. Thanks to Ben Murphy for reporting this!
+ CVE-2012-2660
+
+*Rails 3.0.12 (unreleased)*
+
+* Fix using `tranlate` helper with a html translation which uses the `:count` option for
+ pluralization.
+
+ *Jon Leighton*
+
*Rails 3.0.11 (unreleased)*
+* Fix XSS security vulnerability in the `translate` helper method. When using interpolation
+ in combination with HTML-safe translations, the interpolated input would not get HTML
+ escaped. *GH 3664*
+
+ Before:
+
+ translate('foo_html', :something => '<script>') # => "...<script>..."
+
+ After:
+
+ translate('foo_html', :something => '<script>') # => "...&lt;script&gt;..."
+
+ *Sergey Nartimov*
+
+* Implement a workaround for a bug in ruby-1.9.3p0 where an error would be
+ raised while attempting to convert a template from one encoding to another.
+
+ Please see http://redmine.ruby-lang.org/issues/5564 for details of the bug.
+
+ The workaround is to load all conversions into memory ahead of time, and will
+ only happen if the ruby version is exactly 1.9.3p0. The hope is obviously
+ that the underlying problem will be resolved in the next patchlevel release
+ of 1.9.3.
+
* Fix assert_select_email to work on multipart and non-multipart emails as the method stopped working correctly in Rails 3.x due to changes in the new mail gem.
* Fix url_for when passed a hash to prevent additional options (eg. :host, :protocol) from being added to the hash after calling it.
View
2 actionpack/actionpack.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', version)
s.add_dependency('builder', '~> 2.1.2')
s.add_dependency('i18n', '~> 0.5.0')
- s.add_dependency('rack', '~> 1.2.1')
+ s.add_dependency('rack', '~> 1.2.5')
s.add_dependency('rack-test', '~> 0.5.7')
s.add_dependency('rack-mount', '~> 0.6.14')
s.add_dependency('tzinfo', '~> 0.3.23')
View
2 actionpack/lib/action_controller/deprecated/base.rb
@@ -8,7 +8,7 @@ def relative_url_root
"Please stop using it.", caller
end
- def relative_url_root=
+ def relative_url_root=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root= is ineffective. " <<
"Please stop using it.", caller
end
View
4 actionpack/lib/action_controller/metal/http_authentication.rb
@@ -217,9 +217,9 @@ def decode_credentials_header(request)
end
def decode_credentials(header)
- Hash[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
+ HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
key, value = pair.split('=', 2)
- [key.strip.to_sym, value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')]
+ [key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')]
end]
end
View
2 actionpack/lib/action_controller/metal/redirecting.rb
@@ -87,7 +87,7 @@ def _compute_redirect_to_location(options)
refer
else
url_for(options)
- end.gsub(/[\r\n]/, '')
+ end.gsub(/[\0\r\n]/, '')
end
end
end
View
4 actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -26,8 +26,6 @@ module Http
module FilterParameters
extend ActiveSupport::Concern
- @@parameter_filter_for = {}
-
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
@filtered_parameters ||= parameter_filter.filter(parameters)
@@ -54,7 +52,7 @@ def env_filter
end
def parameter_filter_for(filters)
- @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
+ ParameterFilter.new(filters)
end
KV_RE = '[^&;=]+'
View
22 actionpack/lib/action_dispatch/http/request.rb
@@ -257,5 +257,27 @@ def authorization
def local?
LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip }
end
+
+ # Remove nils from the params hash
+ def deep_munge(hash)
+ hash.each do |k, v|
+ case v
+ when Array
+ v.grep(Hash) { |x| deep_munge(x) }
+ v.compact!
+ hash[k] = nil if v.empty?
+ when Hash
+ deep_munge(v)
+ end
+ end
+
+ hash
+ end
+
+ protected
+
+ def parse_query(qs)
+ deep_munge(super)
+ end
end
end
View
4 actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -38,7 +38,7 @@ def parse_formatted_parameters(env)
when Proc
strategy.call(request.raw_post)
when :xml_simple, :xml_node
- data = Hash.from_xml(request.body.read) || {}
+ data = request.deep_munge(Hash.from_xml(request.body.read) || {})
request.body.rewind if request.body.respond_to?(:rewind)
data.with_indifferent_access
when :yaml
@@ -47,7 +47,7 @@ def parse_formatted_parameters(env)
data = ActiveSupport::JSON.decode(request.body)
request.body.rewind if request.body.respond_to?(:rewind)
data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
+ request.deep_munge(data).with_indifferent_access
else
false
end
View
6 actionpack/lib/action_dispatch/routing/route_set.rb
@@ -6,6 +6,12 @@
module ActionDispatch
module Routing
class RouteSet #:nodoc:
+ # Since the router holds references to many parts of the system
+ # like engines, controllers and the application itself, inspecting
+ # the route set can actually be really slow, therefore we default
+ # alias inspect to to_s.
+ alias inspect to_s
+
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
class Dispatcher #:nodoc:
View
2 actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -94,7 +94,7 @@ def normalize_argument_to_redirection(fragment)
refer
else
@controller.url_for(fragment)
- end.gsub(/[\r\n]/, '')
+ end.gsub(/[\0\r\n]/, '')
end
def validate_request!
View
2 actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack
module VERSION #:nodoc:
MAJOR = 3
MINOR = 0
- TINY = 10
+ TINY = 20
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
View
2 actionpack/lib/action_view/helpers/capture_helper.rb
@@ -179,7 +179,7 @@ def with_output_buffer(buf = nil) #:nodoc:
def flush_output_buffer #:nodoc:
if output_buffer && !output_buffer.empty?
response.body_parts << output_buffer
- self.output_buffer = output_buffer[0,0]
+ self.output_buffer = output_buffer.respond_to?(:clone_empty) ? output_buffer.clone_empty : output_buffer[0, 0]
nil
end
end
View
6 actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -596,13 +596,13 @@ def to_time_zone_select_tag(priority_zones, options, html_options)
private
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- option_tags = "<option value=\"\">#{html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
+ option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = "<option value=\"\">#{html_escape(prompt)}</option>\n" + option_tags
+ option_tags = content_tag('option', prompt, :value => '') + "\n" + option_tags
end
- option_tags.html_safe
+ option_tags
end
end
View
4 actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -100,9 +100,9 @@ def select_tag(name, option_tags = nil, options = {})
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
if blank = options.delete(:include_blank)
if blank.kind_of?(String)
- option_tags = "<option value=\"\">#{blank}</option>".html_safe + option_tags
+ option_tags = content_tag(:option, blank, :value => '').safe_concat(option_tags)
else
- option_tags = "<option value=\"\"></option>".html_safe + option_tags
+ option_tags = content_tag(:option, '', :value => '').safe_concat(option_tags)
end
end
content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
View
2 actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -81,7 +81,7 @@ def sanitize_css(style)
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
- self.class.full_sanitizer.sanitize(html).try(:html_safe)
+ self.class.full_sanitizer.sanitize(html)
end
# Strips all link tags from +text+ leaving just the link text.
View
6 actionpack/lib/action_view/helpers/text_helper.rb
@@ -462,7 +462,7 @@ def set_cycle(name, cycle_object)
end
AUTO_LINK_RE = %r{
- (?: ([\w+.:-]+:)// | www\. )
+ (?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs):)// | www\. )
[^\s<]+
}x
@@ -497,8 +497,8 @@ def auto_link_urls(text, html_options = {}, options = {})
link_text = block_given? ? yield(href) : href
href = 'http://' + href unless scheme
- sanitize = options[:sanitize] != false
- content_tag(:a, link_text, link_attributes.merge('href' => href), sanitize) + punctuation.reverse.join('')
+ sanitize_link = options[:sanitize] != false
+ content_tag(:a, link_text, link_attributes.merge('href' => href), sanitize_link) + punctuation.reverse.join('')
end
end
end
View
15 actionpack/lib/action_view/helpers/translation_helper.rb
@@ -45,11 +45,18 @@ module TranslationHelper
# you know what kind of output to expect when you call translate in a template.
def translate(key, options = {})
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
- translation = I18n.translate(scope_key_by_partial(key), options)
- if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
- translation.html_safe
+ if html_safe_translation_key?(key)
+ html_safe_options = options.dup
+ options.except(*I18n::RESERVED_KEYS).each do |name, value|
+ unless name == :count && value.is_a?(Numeric)
+ html_safe_options[name] = ERB::Util.html_escape(value.to_s)
+ end
+ end
+ translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
+
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
else
- translation
+ I18n.translate(scope_key_by_partial(key), options)
end
end
alias :t :translate
View
9 actionpack/lib/action_view/testing/resolvers.rb
@@ -22,10 +22,11 @@ def query(path, exts, formats)
end
templates = []
- @hash.select { |k,v| k =~ /^#{query}$/ }.each do |path, source|
- handler, format = extract_handler_and_format(path, formats)
- templates << Template.new(source, path, handler,
- :virtual_path => path, :format => format)
+ @hash.each do |_path, source|
+ next unless _path =~ /^#{query}$/
+ handler, format = extract_handler_and_format(_path, formats)
+ templates << Template.new(source, _path, handler,
+ :virtual_path => _path, :format => format)
end
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
View
8 actionpack/test/controller/integration_test.rb
@@ -296,8 +296,12 @@ def test_post
self.cookies['cookie_1'] = "sugar"
self.cookies['cookie_2'] = "oatmeal"
get '/cookie_monster'
- assert_equal "cookie_1=; path=/\ncookie_3=chocolate; path=/", headers["Set-Cookie"]
- assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies.to_hash)
+ _headers = headers["Set-Cookie"].split("\n")
+ assert _headers.include?("cookie_1=; path=/")
+ assert _headers.include?("cookie_3=chocolate; path=/")
+ assert_equal cookies.to_hash["cookie_1"], ""
+ assert_equal cookies.to_hash["cookie_2"], "oatmeal"
+ assert_equal cookies.to_hash["cookie_3"], "chocolate"
end
end
View
24 actionpack/test/controller/new_base/render_rjs_test.rb
@@ -4,18 +4,18 @@ module RenderRjs
class BasicController < ActionController::Base
layout "application", :only => :index_respond_to
- self.view_paths = [ActionView::FixtureResolver.new(
- "layouts/application.html.erb" => "",
- "render_rjs/basic/index.js.rjs" => "page[:customer].replace_html render(:partial => 'customer')",
- "render_rjs/basic/index_html.js.rjs" => "page[:customer].replace_html :partial => 'customer'",
- "render_rjs/basic/index_no_js.js.erb" => "<%= render(:partial => 'developer') %>",
- "render_rjs/basic/_customer.js.erb" => "JS Partial",
- "render_rjs/basic/_customer.html.erb" => "HTML Partial",
- "render_rjs/basic/_developer.html.erb" => "HTML Partial",
- "render_rjs/basic/index_locale.js.rjs" => "page[:customer].replace_html :partial => 'customer'",
- "render_rjs/basic/_customer.da.html.erb" => "Danish HTML Partial",
- "render_rjs/basic/_customer.da.js.erb" => "Danish JS Partial"
- )]
+ self.view_paths = [ActionView::FixtureResolver.new(ActiveSupport::OrderedHash[
+ "layouts/application.html.erb" , "",
+ "render_rjs/basic/index.js.rjs" , "page[:customer].replace_html render(:partial => 'customer')",
+ "render_rjs/basic/index_html.js.rjs" , "page[:customer].replace_html :partial => 'customer'",
+ "render_rjs/basic/index_no_js.js.erb" , "<%= render(:partial => 'developer') %>",
+ "render_rjs/basic/_customer.js.erb" , "JS Partial",
+ "render_rjs/basic/_customer.html.erb" , "HTML Partial",
+ "render_rjs/basic/_developer.html.erb" , "HTML Partial",
+ "render_rjs/basic/index_locale.js.rjs" , "page[:customer].replace_html :partial => 'customer'",
+ "render_rjs/basic/_customer.da.html.erb" , "Danish HTML Partial",
+ "render_rjs/basic/_customer.da.js.erb" , "Danish JS Partial"
+ ])]
def index
render
View
20 actionpack/test/controller/redirect_test.rb
@@ -99,6 +99,14 @@ def redirect_to_nil
redirect_to nil
end
+ def redirect_with_header_break
+ redirect_to "/lol\r\nwat"
+ end
+
+ def redirect_with_null_bytes
+ redirect_to "\000/lol\r\nwat"
+ end
+
def rescue_errors(e) raise e end
def rescue_action(e) raise end
@@ -118,6 +126,18 @@ def test_simple_redirect
assert_equal "http://test.host/redirect/hello_world", redirect_to_url
end
+ def test_redirect_with_header_break
+ get :redirect_with_header_break
+ assert_response :redirect
+ assert_equal "http://test.host/lolwat", redirect_to_url
+ end
+
+ def test_redirect_with_null_bytes
+ get :redirect_with_null_bytes
+ assert_response :redirect
+ assert_equal "http://test.host/lolwat", redirect_to_url
+ end
+
def test_redirect_with_no_status
get :simple_redirect
assert_response 302
View
4 actionpack/test/controller/render_test.rb
@@ -149,7 +149,7 @@ def render_text_hello_world
# :ported:
def render_text_hello_world_with_layout
- @variable_for_layout = ", I'm here!"
+ @variable_for_layout = ", I am here!"
render :text => "hello world", :layout => true
end
@@ -776,7 +776,7 @@ def test_render_text
# :ported:
def test_do_with_render_text_and_layout
get :render_text_hello_world_with_layout
- assert_equal "<html>hello world, I'm here!</html>", @response.body
+ assert_equal "<html>hello world, I am here!</html>", @response.body
end
# :ported:
View
13 actionpack/test/controller/webservice_test.rb
@@ -117,6 +117,19 @@ def test_post_xml_using_an_attributted_node_named_type
end
end
+ def test_post_xml_using_a_disallowed_type_attribute
+ $stderr = StringIO.new
+ with_test_route_set do
+ post '/', '<foo type="symbol">value</foo>', 'CONTENT_TYPE' => 'application/xml'
+ assert_response 500
+
+ post '/', '<foo type="yaml">value</foo>', 'CONTENT_TYPE' => 'application/xml'
+ assert_response 500
+ end
+ ensure
+ $stderr = STDERR
+ end
+
def test_register_and_use_yaml
with_test_route_set do
with_params_parsers Mime::YAML => Proc.new { |d| YAML.load(d) } do
View
22 actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -30,6 +30,21 @@ def teardown
)
end
+ test "nils are stripped from collections" do
+ assert_parses(
+ {"person" => nil},
+ "{\"person\":[null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ assert_parses(
+ {"person" => ['foo']},
+ "{\"person\":[\"foo\",null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ assert_parses(
+ {"person" => nil},
+ "{\"person\":[null, null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ end
+
test "logs error if parsing unsuccessful" do
with_test_routing do
begin
@@ -45,6 +60,13 @@ def teardown
end
end
+ test "parses json with non-object JSON content" do
+ assert_parses(
+ {"_json" => "string content" },
+ "\"string content\"", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ end
+
private
def assert_parses(expected, actual, headers = {})
with_test_routing do
View
11 actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -81,7 +81,16 @@ def teardown
end
test "query string without equal" do
- assert_parses({ "action" => nil }, "action")
+ assert_parses({"action" => nil}, "action")
+ assert_parses({"action" => {"foo" => nil}}, "action[foo]")
+ assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]")
+ assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => nil}}, "action[foo][]")
+ assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]")
+ end
+
+ def test_array_parses_without_nil
+ assert_parses({"action" => ['1']}, "action[]=1&action[]")
end
test "query string with empty key" do
View
17 actionpack/test/dispatch/request/xml_params_parsing_test.rb
@@ -29,6 +29,23 @@ def call(env)
assert_equal "<ok>bar</ok>", resp.body
end
+ def assert_parses(expected, xml)
+ with_test_routing do
+ post "/parse", xml, default_headers
+ assert_response :ok
+ assert_equal(expected, TestController.last_request_parameters)
+ end
+ end
+
+ test "nils are stripped from collections" do
+ assert_parses(
+ {"hash" => { "person" => nil} },
+ "<hash><person type=\"array\"><person nil=\"true\"/></person></hash>")
+ assert_parses(
+ {"hash" => { "person" => ['foo']} },
+ "<hash><person type=\"array\"><person>foo</person><person nil=\"true\"/></person>\n</hash>")
+ end
+
test "parses hash params" do
with_test_routing do
xml = "<person><name>David</name></person>"
View
23 actionpack/test/template/asset_tag_helper_test.rb
@@ -159,8 +159,9 @@ def url_for(*args)
%(image_tag("slash..png")) => %(<img alt="Slash." src="/images/slash..png" />),
%(image_tag(".pdf.png")) => %(<img alt=".pdf" src="/images/.pdf.png" />),
%(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="http://www.rubyonrails.com/images/rails.png" />),
- %(image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
- %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
+ %(image_tag("//www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="//www.rubyonrails.com/images/rails.png" />),
+ %(image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) => %(<img alt="Mouse" onmouseover="this.src=&#x27;/images/mouse_over.png&#x27;" onmouseout="this.src=&#x27;/images/mouse.png&#x27;" src="/images/mouse.png" />),
+ %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(<img alt="Mouse" onmouseover="this.src=&#x27;/images/mouse_over.png&#x27;" onmouseout="this.src=&#x27;/images/mouse.png&#x27;" src="/images/mouse.png" />),
%(image_tag("mouse.png", :alt => nil)) => %(<img src="/images/mouse.png" />)
}
@@ -1007,8 +1008,8 @@ def test_should_compute_proper_path
assert_dom_equal(%(/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='/collaboration/hieraki/images/mouse.png'" src="/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
- assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='/collaboration/hieraki/images/mouse2.png'" src="/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
+ assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src=&#x27;/collaboration/hieraki/images/mouse_over.png&#x27;" onmouseout="this.src=&#x27;/collaboration/hieraki/images/mouse.png&#x27;" src="/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
+ assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src=&#x27;/collaboration/hieraki/images/mouse_over2.png&#x27;" onmouseout="this.src=&#x27;/collaboration/hieraki/images/mouse2.png&#x27;" src="/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
end
def test_should_ignore_relative_root_path_on_complete_url
@@ -1021,8 +1022,18 @@ def test_should_compute_proper_path_with_asset_host
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='http://assets.example.com/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='http://assets.example.com/collaboration/hieraki/images/mouse.png'" src="http://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
- assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='http://assets.example.com/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='http://assets.example.com/collaboration/hieraki/images/mouse2.png'" src="http://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
+ assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src=&#x27;http://assets.example.com/collaboration/hieraki/images/mouse_over.png&#x27;" onmouseout="this.src=&#x27;http://assets.example.com/collaboration/hieraki/images/mouse.png&#x27;" src="http://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
+ assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src=&#x27;http://assets.example.com/collaboration/hieraki/images/mouse_over2.png&#x27;" onmouseout="this.src=&#x27;http://assets.example.com/collaboration/hieraki/images/mouse2.png&#x27;" src="http://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
+ end
+
+ def test_should_compute_proper_path_with_asset_host_and_default_protocol
+ @controller.config.asset_host = "assets.example.com"
+ @controller.config.default_asset_host_protocol = :request
+ assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
+ assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
+ assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
+ assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src=&#x27;gopher://assets.example.com/collaboration/hieraki/images/mouse_over.png&#x27;" onmouseout="this.src=&#x27;gopher://assets.example.com/collaboration/hieraki/images/mouse.png&#x27;" src="gopher://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
+ assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src=&#x27;gopher://assets.example.com/collaboration/hieraki/images/mouse_over2.png&#x27;" onmouseout="this.src=&#x27;gopher://assets.example.com/collaboration/hieraki/images/mouse2.png&#x27;" src="gopher://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
end
def test_should_ignore_asset_host_on_complete_url
View
10 actionpack/test/template/erb_util_test.rb
@@ -7,11 +7,11 @@ class ErbUtilTest < Test::Unit::TestCase
define_method "test_html_escape_#{expected.gsub(/\W/, '')}" do
assert_equal expected, html_escape(given)
end
+ end
- unless given == '"'
- define_method "test_json_escape_#{expected.gsub(/\W/, '')}" do
- assert_equal ERB::Util::JSON_ESCAPE[given], json_escape(given)
- end
+ ERB::Util::JSON_ESCAPE.each do |given, expected|
+ define_method "test_json_escape_#{expected.gsub(/\W/, '')}" do
+ assert_equal ERB::Util::JSON_ESCAPE[given], json_escape(given)
end
end
@@ -39,7 +39,7 @@ def test_html_escape_passes_html_escpe_unmodified
def test_rest_in_ascii
(0..127).to_a.map {|int| int.chr }.each do |chr|
- next if %w(& " < >).include?(chr)
+ next if %w(& " < > ').include?(chr)
assert_equal chr, html_escape(chr)
end
end
View
25 actionpack/test/template/form_options_helper_test.rb
@@ -432,7 +432,7 @@ def @post.to_param; 108; end
def test_select_under_fields_for_with_string_and_given_prompt
@post = Post.new
- options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>"
+ options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>".html_safe
output_buffer = fields_for :post, @post do |f|
concat f.select(:category, options, :prompt => 'The prompt')
@@ -536,6 +536,13 @@ def test_select_with_index_option
)
end
+ def test_select_escapes_options
+ assert_dom_equal(
+ '<select id="post_title" name="post[title]">&lt;script&gt;alert(1)&lt;/script&gt;</select>',
+ select('post', 'title', '<script>alert(1)</script>')
+ )
+ end
+
def test_select_with_selected_nil
@post = Post.new
@post.category = "<mus>"
@@ -880,7 +887,7 @@ def test_time_zone_select_with_default_time_zone_and_value
def test_options_for_select_with_element_attributes
assert_dom_equal(
- "<option value=\"&lt;Denmark&gt;\" class=\"bold\">&lt;Denmark&gt;</option>\n<option value=\"USA\" onclick=\"alert('Hello World');\">USA</option>\n<option value=\"Sweden\">Sweden</option>\n<option value=\"Germany\">Germany</option>",
+ "<option value=\"&lt;Denmark&gt;\" class=\"bold\">&lt;Denmark&gt;</option>\n<option value=\"USA\" onclick=\"alert(&#x27;Hello World&#x27;);\">USA</option>\n<option value=\"Sweden\">Sweden</option>\n<option value=\"Germany\">Germany</option>",
options_for_select([ [ "<Denmark>", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ])
)
end
@@ -914,17 +921,15 @@ def test_option_html_attributes_with_single_element_hash
end
def test_option_html_attributes_with_multiple_element_hash
- assert_dom_equal(
- " class=\"fancy\" onclick=\"alert('Hello World');\"",
- option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ])
- )
+ output = option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ])
+ assert output.include?(" class=\"fancy\"")
+ assert output.include?(" onclick=\"alert(&#x27;Hello World&#x27;);\"")
end
def test_option_html_attributes_with_multiple_hashes
- assert_dom_equal(
- " class=\"fancy\" onclick=\"alert('Hello World');\"",
- option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ])
- )
+ output = option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ])
+ assert output.include?(" class=\"fancy\"")
+ assert output.include?(" onclick=\"alert(&#x27;Hello World&#x27;);\"")
end
def test_option_html_attributes_with_special_characters
View
8 actionpack/test/template/form_tag_helper_test.rb
@@ -195,6 +195,12 @@ def test_select_tag_with_include_blank
assert_dom_equal expected, actual
end
+ def test_select_tag_escapes_include_blank
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :include_blank => "<script>alert(1337)</script>"
+ expected = %(<select id="places" name="places"><option value="">&lt;script&gt;alert(1337)&lt;/script&gt;</option><option>Home</option><option>Work</option><option>Pub</option></select>)
+ assert_dom_equal expected, actual
+ end
+
def test_select_tag_with_include_blank_with_string
actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :include_blank => "string"
expected = %(<select id="places" name="places"><option value="">string</option><option>Home</option><option>Work</option><option>Pub</option></select>)
@@ -361,7 +367,7 @@ def test_stringify_symbol_keys
def test_submit_tag
assert_dom_equal(
- %(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!')" type="submit" value="Save" />),
+ %(<input name='commit' data-disable-with="Saving..." onclick="alert(&#x27;hello!&#x27;)" type="submit" value="Save" />),
submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')")
)
end
View
10 actionpack/test/template/javascript_helper_test.rb
@@ -41,7 +41,7 @@ def test_escape_javascript_with_safebuffer
end
def test_button_to_function
- assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />),
+ assert_dom_equal %(<input type="button" onclick="alert(&#x27;Hello world!&#x27;);" value="Greeting" />),
button_to_function("Greeting", "alert('Hello world!')")
end
@@ -60,7 +60,7 @@ def test_button_to_function_with_rjs_block_and_options
end
def test_button_to_function_with_onclick
- assert_dom_equal "<input onclick=\"alert('Goodbye World :('); alert('Hello world!');\" type=\"button\" value=\"Greeting\" />",
+ assert_dom_equal "<input onclick=\"alert(&#x27;Goodbye World :(&#x27;); alert(&#x27;Hello world!&#x27;);\" type=\"button\" value=\"Greeting\" />",
button_to_function("Greeting", "alert('Hello world!')", :onclick => "alert('Goodbye World :(')")
end
@@ -70,12 +70,12 @@ def test_button_to_function_without_function
end
def test_link_to_function
- assert_dom_equal %(<a href="#" onclick="alert('Hello world!'); return false;">Greeting</a>),
+ assert_dom_equal %(<a href="#" onclick="alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')")
end
def test_link_to_function_with_existing_onclick
- assert_dom_equal %(<a href="#" onclick="confirm('Sanity!'); alert('Hello world!'); return false;">Greeting</a>),
+ assert_dom_equal %(<a href="#" onclick="confirm(&#x27;Sanity!&#x27;); alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')", :onclick => "confirm('Sanity!')")
end
@@ -94,7 +94,7 @@ def test_link_to_function_with_rjs_block_and_options
end
def test_link_to_function_with_href
- assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>),
+ assert_dom_equal %(<a href="http://example.com/" onclick="alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
end
View
4 actionpack/test/template/sanitize_helper_test.rb
@@ -42,9 +42,9 @@ def test_strip_tags
[nil, '', ' '].each do |blank|
stripped = strip_tags(blank)
assert_equal blank, stripped
- assert stripped.html_safe? unless blank.nil?
end
- assert strip_tags("<script>").html_safe?
+ assert_equal "", strip_tags("<script>")
+ assert_equal "something &lt;img onerror=alert(1337)", ERB::Util.html_escape(strip_tags("something <img onerror=alert(1337)"))
end
def test_sanitize_is_marked_safe
View
19 actionpack/test/template/template_test.rb
@@ -50,7 +50,7 @@ def test_basic_template
def test_locals
@template = new_template("<%= my_local %>")
- assert_equal "I'm a local", render(:my_local => "I'm a local")
+ assert_equal "I am a local", render(:my_local => "I am a local")
end
def test_restores_buffer
@@ -82,12 +82,11 @@ def test_no_magic_comment_word_with_utf_8
# is set to something other than UTF-8, we don't
# get any errors and get back a UTF-8 String.
def test_default_external_works
- Encoding.default_external = "ISO-8859-1"
- @template = new_template("hello \xFCmlat")
- assert_equal Encoding::UTF_8, render.encoding
- assert_equal "hello \u{fc}mlat", render
- ensure
- Encoding.default_external = "UTF-8"
+ with_external_encoding "ISO-8859-1" do
+ @template = new_template("hello \xFCmlat")
+ assert_equal Encoding::UTF_8, render.encoding
+ assert_equal "hello \u{fc}mlat", render
+ end
end
def test_encoding_can_be_specified_with_magic_comment
@@ -123,10 +122,12 @@ def test_error_when_template_isnt_valid_utf8
end
def with_external_encoding(encoding)
- old, Encoding.default_external = Encoding.default_external, encoding
+ old = Encoding.default_external
+ Encoding::Converter.new old, encoding if old != encoding
+ silence_warnings { Encoding.default_external = encoding }
yield
ensure
- Encoding.default_external = old
+ silence_warnings { Encoding.default_external = old }
end
def test_render_inline_safebuffer_should_not_raise_error
View
11 actionpack/test/template/text_helper_test.rb
@@ -311,7 +311,7 @@ def test_auto_link_parsing
http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007
http://www.mail-archive.com/rails@lists.rubyonrails.org/
http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
- http://en.wikipedia.org/wiki/Texas_hold'em
+ http://en.wikipedia.org/wiki/Texas_hold
https://www.google.com/doku.php?id=gps:resource:scs:start
http://connect.oraclecorp.com/search?search[q]=green+france&search[type]=Group
http://of.openfoundry.org/projects/492/download#4th.Release.3
@@ -452,15 +452,6 @@ def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false
def test_auto_link_other_protocols
ftp_raw = 'ftp://example.com/file.txt'
assert_equal %(Download #{generate_result(ftp_raw)}), auto_link("Download #{ftp_raw}")
-
- file_scheme = 'file:///home/username/RomeoAndJuliet.pdf'
- z39_scheme = 'z39.50r://host:696/db'
- chrome_scheme = 'chrome://package/section/path'
- view_source = 'view-source:http://en.wikipedia.org/wiki/URI_scheme'
- assert_equal generate_result(file_scheme), auto_link(file_scheme)
- assert_equal generate_result(z39_scheme), auto_link(z39_scheme)
- assert_equal generate_result(chrome_scheme), auto_link(chrome_scheme)
- assert_equal generate_result(view_source), auto_link(view_source)
end
def test_auto_link_already_linked
View
18 actionpack/test/template/translation_helper_test.rb
@@ -17,8 +17,13 @@ def setup
:hello => '<a>Hello World</a>',
:html => '<a>Hello World</a>',
:hello_html => '<a>Hello World</a>',
+ :interpolated_html => '<a>Hello %{word}</a>',
:array_html => %w(foo bar),
- :array => %w(foo bar)
+ :array => %w(foo bar),
+ :count_html => {
+ :one => '<a>One %{count}</a>',
+ :other => '<a>Other %{count}</a>'
+ }
}
)
@view = ::ActionView::Base.new(ActionController::Base.view_paths, {})
@@ -83,6 +88,17 @@ def test_translate_marks_translations_with_a_html_suffix_as_safe_html
assert translate(:'translations.hello_html').html_safe?
end
+ def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
+ assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>')
+ assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>"))
+ end
+
+ def test_translate_with_html_count
+ assert_equal '<a>One 1</a>', translate(:'translations.count_html', :count => 1)
+ assert_equal '<a>Other 2</a>', translate(:'translations.count_html', :count => 2)
+ assert_equal '<a>Other &lt;One&gt;</a>', translate(:'translations.count_html', :count => '<One>')
+ end
+
def test_translation_returning_an_array_ignores_html_suffix
assert_equal ["foo", "bar"], translate(:'translations.array_html')
end
View
10 actionpack/test/template/url_helper_test.rb
@@ -188,7 +188,7 @@ def test_link_with_nil_html_options
def test_link_tag_with_custom_onclick
link = link_to("Hello", "http://www.example.com", :onclick => "alert('yay!')")
- expected = %{<a href="http://www.example.com" onclick="alert('yay!')">Hello</a>}
+ expected = %{<a href="http://www.example.com" onclick="alert(&#x27;yay!&#x27;)">Hello</a>}
assert_dom_equal expected, link
end
@@ -198,12 +198,12 @@ def test_link_tag_with_javascript_confirm
link_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
)
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure, can you?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?")
+ "<a href=\"http://www.example.com\" data-confirm=\"You cant possibly be sure, can you?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :confirm => "You cant possibly be sure, can you?")
)
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-confirm=\"You can't possibly be sure,\n can you?\">Hello</a>",
- link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?")
+ "<a href=\"http://www.example.com\" data-confirm=\"You cant possibly be sure,\n can you?\">Hello</a>",
+ link_to("Hello", "http://www.example.com", :confirm => "You cant possibly be sure,\n can you?")
)
end
View
37 activemodel/CHANGELOG
@@ -1,3 +1,31 @@
+## Rails 3.0.20 (unreleased)
+
+* Fix XML serialization of methods that return nil to not be considered as YAML (GH #8853 and GH #492)
+
+## Rails 3.0.19 (Jan 8, 2013)
+
+* No changes.
+
+## Rails 3.0.18 (Jan 2, 2013)
+
+* No changes.
+
+## Rails 3.0.17 (Aug 9, 2012)
+
+* No changes.
+
+## Rails 3.0.16 (Jul 26, 2012)
+
+* No changes.
+
+## Rails 3.0.14 (Jun 12, 2012)
+
+* No changes.
+
+*Rails 3.0.13 (May 31, 2012)*
+
+* No changes.
+
*Rails 3.0.10 (August 16, 2011)*
*No changes.
@@ -75,11 +103,10 @@
It has a custom hook to define after_find that should really be in a
ActiveRecord::Observer subclass:
- def add_observer!(klass)
- klass.add_observer(self)
- klass.class_eval 'def after_find() end' unless
- klass.respond_to?(:after_find)
- end
+ def add_observer!(klass)
+ klass.add_observer(self)
+ klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
+ end
* Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH]
View
1 activemodel/lib/active_model/serializers/xml.rb
@@ -33,6 +33,7 @@ def decorations
protected
def compute_type
+ return if value.nil?
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
type ||= :string if value.respond_to?(:to_str)
type ||= :yaml
View
4 activemodel/lib/active_model/validations/confirmation.rb
@@ -10,7 +10,9 @@ def validate_each(record, attribute, value)
end
def setup(klass)
- klass.send(:attr_accessor, *attributes.map { |attribute| :"#{attribute}_confirmation" })
+ klass.send(:attr_accessor, *attributes.map do |attribute|
+ :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
+ end.compact)
end
end
View
2 activemodel/lib/active_model/version.rb
@@ -2,7 +2,7 @@ module ActiveModel
module VERSION #:nodoc:
MAJOR = 3
MINOR = 0
- TINY = 10
+ TINY = 20
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
View
4 activemodel/test/cases/serializeration/xml_serialization_test.rb
@@ -86,6 +86,10 @@ def setup
assert_match %r{<name>aaron stack</name>}, @contact.to_xml
end
+ test "should serialize nil" do
+ assert_match %r{<pseudonyms nil=\"true\"></pseudonyms>}, @contact.to_xml(:methods => :pseudonyms)
+ end
+
test "should serialize integer" do
assert_match %r{<age type="integer">25</age>}, @contact.to_xml
end
View
4 activemodel/test/models/contact.rb
@@ -16,6 +16,10 @@ def initialize(options = {})
options.each { |name, value| send("#{name}=", value) }
end
+ def pseudonyms
+ nil
+ end
+
def persisted?
id
end
View
37 activerecord/CHANGELOG
@@ -1,3 +1,40 @@
+## Rails 3.0.20 (unreleased)
+
+## Rails 3.0.19 (Jan 8, 2013)
+
+* Fix querying with an empty hash *Damien Mathieu* [CVE-2013-0155]
+
+## Rails 3.0.18 (Jan 2, 2013)
+
+* CVE-2012-5664 ensure that options are never taken from the first parameter
+
+## Rails 3.0.17 (Aug 9, 2012)
+
+* Fix type_to_sql with text and limit on mysql/mysql2 (GH #7252)
+
+## Rails 3.0.16 (Jul 26, 2012)
+
+* No changes.
+
+## Rails 3.0.14 (Jun 12, 2012)
+
+* protect against the nesting of hashes changing the
+ table context in the next call to build_from_hash. This fix
+ covers this case as well.
+
+ CVE-2012-2695
+
+* Rails 3.0.13 (May 31, 2012)
+
+* Bugfix circular reference while saving has_one relationship
+
+* Test for circular reference while saving has_one relationship
+
+* Fixed typo in composed_of example with Money#<=>
+
+* predicate builder should not recurse for determining where columns.
+ Thanks to Ben Murphy for reporting this! CVE-2012-2661
+
* Rails 3.0.11 (unreleased)
* Exceptions from database adapters should not lose their backtrace.
View
2 activerecord/lib/active_record/aggregations.rb
@@ -48,7 +48,7 @@ def clear_aggregation_cache #:nodoc:
#
# def <=>(other_money)
# if currency == other_money.currency
- # amount <=> amount
+ # amount <=> other_money.amount
# else
# amount <=> other_money.exchange_to(currency).amount
# end
View
2 activerecord/lib/active_record/associations.rb
@@ -1439,7 +1439,7 @@ def association_accessor_methods(reflection, association_proxy_class)
if association.nil? || force_reload
association = association_proxy_class.new(self, reflection)
- retval = force_reload ? reflection.klass.uncached { association.reload } : association.load
+ retval = force_reload ? reflection.klass.uncached { association.reload } : association._load
if retval.nil? and association_proxy_class == BelongsToAssociation
association_instance_set(reflection.name, nil)
return nil
View
4 activerecord/lib/active_record/associations/association_proxy.rb
@@ -113,15 +113,15 @@ def reset
end
# Loads the \target if not already loaded. Returns +self+ if the \target is present.
- def load
+ def _load
load_target unless loaded?
self unless @target.nil?
end
# Reloads the \target and returns +self+ on success.
def reload
reset
- load
+ _load
end
# Has the \target been already \loaded?
View
19 activerecord/lib/active_record/autosave_association.rb
@@ -140,6 +140,23 @@ def #{type}(name, options = {})
CODE
end
+ def define_non_cyclic_method(name, reflection, &block)
+ define_method(name) do |*args|
+ result = true; @_already_called ||= {}
+ # Loop prevention for validation of associations
+ unless @_already_called[[name, reflection.name]]
+ begin
+ @_already_called[[name, reflection.name]]=true
+ result = instance_eval(&block)
+ ensure
+ @_already_called[[name, reflection.name]]=false
+ end
+ end
+
+ result
+ end
+ end
+
# Adds validation and save callbacks for the association as specified by
# the +reflection+.
#
@@ -169,7 +186,7 @@ def add_autosave_association_callbacks(reflection)
define_method(save_method) { save_has_one_association(reflection) }
after_save save_method
else
- define_method(save_method) { save_belongs_to_association(reflection) }
+ define_non_cyclic_method(save_method, reflection) { save_belongs_to_association(reflection) }
before_save save_method
end
end
View
6 activerecord/lib/active_record/base.rb
@@ -988,7 +988,11 @@ def method_missing(method_id, *arguments, &block)
attribute_names = match.attribute_names
super unless all_attributes_exists?(attribute_names)
if match.finder?
- options = arguments.extract_options!
+ options = if arguments.length > attribute_names.size
+ arguments.extract_options!
+ else
+ {}
+ end
relation = options.any? ? construct_finder_arel(options, current_scoped_methods) : scoped
relation.send :find_by_attributes, match, attribute_names, *arguments
elsif match.instantiator?
View
35 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -404,7 +404,11 @@ def collation
def tables(name = nil, database = nil) #:nodoc:
tables = []
- result = execute(["SHOW TABLES", database].compact.join(' IN '), name)
+
+ sql = "SHOW TABLES "
+ sql << "IN #{quote_table_name(database)} " if database
+
+ result = execute(sql, 'SCHEMA')
result.each { |field| tables << field[0] }
result.free
tables
@@ -518,15 +522,26 @@ def rename_column(table_name, column_name, new_column_name) #:nodoc:
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
- return super unless type.to_s == 'integer'
-
- case limit
- when 1; 'tinyint'
- when 2; 'smallint'
- when 3; 'mediumint'
- when nil, 4, 11; 'int(11)' # compatibility with MySQL default
- when 5..8; 'bigint'
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ case type.to_s
+ when 'integer'
+ case limit
+ when 1; 'tinyint'
+ when 2; 'smallint'
+ when 3; 'mediumint'
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
+ when 5..8; 'bigint'
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ end
+ when 'text'
+ case limit
+ when 0..0xff; 'tinytext'
+ when nil, 0x100..0xffff; 'text'
+ when 0x10000..0xffffff; 'mediumtext'
+ when 0x1000000..0xffffffff; 'longtext'
+ else raise(ActiveRecordError, "No text type has character length #{limit}")
+ end
+ else
+ super
end
end
View
13 activerecord/lib/active_record/relation/predicate_builder.rb
@@ -5,17 +5,22 @@ def initialize(engine)
@engine = engine
end
- def build_from_hash(attributes, default_table)
+ def build_from_hash(attributes, default_table, allow_table_name = true)
predicates = attributes.map do |column, value|
table = default_table
- if value.is_a?(Hash)
+ if allow_table_name && value.is_a?(Hash)
table = Arel::Table.new(column, :engine => @engine)
- build_from_hash(value, table)
+
+ if value.empty?
+ '1 = 2'
+ else
+ build_from_hash(value, table, false)
+ end
else
column = column.to_s
- if column.include?('.')
+ if allow_table_name && column.include?('.')
table_name, column = column.split('.', 2)
table = Arel::Table.new(table_name, :engine => @engine)
end
View
2 activerecord/lib/active_record/schema_dumper.rb
@@ -40,7 +40,7 @@ def initialize(connection)
def header(stream)
define_params = @version ? ":version => #{@version}" : ""
- if stream.respond_to?(:external_encoding)
+ if stream.respond_to?(:external_encoding) && stream.external_encoding
stream.puts "# encoding: #{stream.external_encoding.name}"
end
View
2 activerecord/lib/active_record/version.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 3
MINOR = 0
- TINY = 10
+ TINY = 20
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
View
10 activerecord/test/cases/adapters/mysql/schema_test.rb
@@ -19,6 +19,16 @@ def self.name; 'Post'; end
end
end
+ def test_tables_quoting
+ begin
+ @connection.tables(nil, "foo-bar")
+ flunk
+ rescue => e
+ # assertion for *quoted* database properly
+ assert_match(/database 'foo-bar'/, e.inspect)
+ end
+ end
+
def test_schema
assert @omgpost.find(:first)
end
View
9 activerecord/test/cases/associations/has_many_associations_test.rb
@@ -669,7 +669,7 @@ def test_clearing_an_association_collection
end
def test_clearing_updates_counter_cache
- topic = Topic.first
+ topic = Topic.order(:id).first
topic.replies.clear
topic.reload
@@ -749,14 +749,14 @@ def test_dependent_association_respects_optional_hash_conditions_on_delete
end
def test_delete_all_association_with_primary_key_deletes_correct_records
- firm = Firm.find(:first)
+ firm = Firm.order(:id).first
# break the vanilla firm_id foreign key
assert_equal 2, firm.clients.count
firm.clients.first.update_attribute(:firm_id, nil)
assert_equal 1, firm.clients(true).count
assert_equal 1, firm.clients_using_primary_key_with_delete_all.count
old_record = firm.clients_using_primary_key_with_delete_all.first
- firm = Firm.find(:first)
+ firm = Firm.order(:id).first
firm.destroy
assert_nil Client.find_by_id(old_record.id)
end
@@ -922,13 +922,12 @@ def test_depends_and_nullify
core = companies(:rails_core)
assert_equal accounts(:rails_core_account), core.account
- assert_equal companies(:leetsoft, :jadedpixel), core.companies
+ assert_equal companies(:leetsoft, :jadedpixel), core.companies.order(:id)
core.destroy
assert_nil accounts(:rails_core_account).reload.firm_id
assert_nil companies(:leetsoft).reload.client_of
assert_nil companies(:jadedpixel).reload.client_of
-
assert_equal num_accounts, Account.count
end
View
6 activerecord/test/cases/associations/join_model_test.rb
@@ -384,7 +384,7 @@ def test_has_many_through_has_many_find_by_id
end
def test_has_many_through_polymorphic_has_one
- assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).taggings
+ assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).taggings.order('taggings.id')
end
def test_has_many_through_polymorphic_has_many
@@ -441,7 +441,7 @@ def test_add_to_self_referential_has_many_through
end
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
- author = Author.find(:first)
+ author = Author.order(:id).first
assert_present author.comments
assert_blank author.nonexistant_comments
end
@@ -634,7 +634,7 @@ def test_preload_polymorphic_has_many_through
end
def test_preload_polymorph_many_types
- taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
+ taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel'], :order => 'id'
assert_no_queries do
taggings.first.taggable.id
taggings[1].taggable.id
View
26 activerecord/test/cases/autosave_association_test.rb
@@ -3,8 +3,10 @@
require 'models/company'
require 'models/customer'
require 'models/developer'
+require 'models/face'
require 'models/invoice'
require 'models/line_item'
+require 'models/man'
require 'models/order'
require 'models/parrot'
require 'models/person'
@@ -590,7 +592,9 @@ def test_should_skip_validation_on_a_child_association_if_marked_for_destruction
def test_a_child_marked_for_destruction_should_not_be_destroyed_twice
@pirate.ship.mark_for_destruction
assert @pirate.save
- @pirate.ship.expects(:destroy).never
+ class << @pirate.ship
+ def destroy; raise "Should not be called" end
+ end
assert @pirate.save
end
@@ -635,7 +639,9 @@ def test_should_skip_validation_on_a_parent_association_if_marked_for_destructio
def test_a_parent_marked_for_destruction_should_not_be_destroyed_twice
@ship.pirate.mark_for_destruction
assert @ship.save
- @ship.pirate.expects(:destroy).never
+ class << @ship.pirate
+ def destroy; raise "Should not be called" end
+ end
assert @ship.save
end
@@ -703,7 +709,11 @@ def save(*args)
children.each { |child| child.mark_for_destruction }
assert @pirate.save
- children.each { |child| child.expects(:destroy).never }
+ children.each { |child|
+ class << child
+ def destroy; raise "Should not be called" end
+ end
+ }
assert @pirate.save
end
@@ -880,6 +890,16 @@ def test_should_not_load_the_associated_model
end
end
+class TestAutosaveInverseAssociationOnAHasOneAssociation < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def test_should_save_the_inverse_association_model
+ man = Man.new
+ man.build_face
+ man.face.save
+ end
+end
+
class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
self.use_transactional_fixtures = false
View
16 activerecord/test/cases/finder_test.rb
@@ -65,6 +65,18 @@ def test_find_or_create_by
class FinderTest < ActiveRecord::TestCase
fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations
+ def test_find_by_id_with_hash
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Post.find_by_id(:limit => 1)
+ end
+ end
+
+ def test_find_by_title_and_id_with_hash
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Post.find_by_title_and_id('foo', :limit => 1)
+ end
+ end
+
def test_find
assert_equal(topics(:first).title, Topic.find(1).title)
end
@@ -103,8 +115,8 @@ def test_exists_returns_true_with_one_record_and_no_args
def test_exists_with_nil_arg
assert !Topic.exists?(nil)
assert Topic.exists?
- assert !Topic.first.replies.exists?(nil)
- assert Topic.first.replies.exists?
+ assert !Topic.order(:id).first.replies.exists?(nil)
+ assert Topic.order(:id).first.replies.exists?
end
def test_does_not_exist_with_empty_table_and_no_args_given
View
2 activerecord/test/cases/fixtures_test.rb
@@ -48,7 +48,7 @@ def test_clean_fixtures
def test_broken_yaml_exception
badyaml = Tempfile.new ['foo', '.yml']
- badyaml.write 'a: !ruby.yaml.org,2002:str |\nfoo'
+ badyaml.write 'a: : '
badyaml.flush
dir = File.dirname badyaml.path
View
2 activerecord/test/cases/helper.rb
@@ -4,7 +4,7 @@
require 'test/unit'
require 'stringio'
-require 'mocha'
+require 'mocha/setup'
require 'active_record'
require 'active_support/dependencies'
View
4 activerecord/test/cases/json_serialization_test.rb