aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG33
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb17
-rw-r--r--actionpack/lib/action_view/helpers/controller_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionpack/lib/sprockets/railtie.rb71
-rw-r--r--actionpack/test/abstract/abstract_controller_test.rb2
-rw-r--r--actionpack/test/abstract/callbacks_test.rb2
-rw-r--r--actionpack/test/abstract/layouts_test.rb12
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb3
-rw-r--r--actionpack/test/controller/caching_test.rb4
-rw-r--r--actionpack/test/controller/content_type_test.rb1
-rw-r--r--actionpack/test/controller/test_test.rb1
-rw-r--r--actionpack/test/controller/url_for_test.rb4
-rw-r--r--actionpack/test/controller/webservice_test.rb4
-rw-r--r--actionpack/test/template/erb_util_test.rb10
-rw-r--r--actionpack/test/template/form_helper_test.rb4
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb4
-rw-r--r--actionpack/test/template/javascript_helper_test.rb9
-rw-r--r--actionpack/test/template/number_helper_test.rb7
21 files changed, 131 insertions, 75 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 479e8246c5..1965906df9 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -21,6 +21,39 @@
*Rails 3.1.0 (unreleased)*
+* json_escape will now return a SafeBuffer string if it receives SafeBuffer string [tenderlove]
+
+* Make sure escape_js returns SafeBuffer string if it receives SafeBuffer string [Prem Sichanugrist]
+
+* Fix escape_js to work correctly with the new SafeBuffer restriction [Paul Gallagher]
+
+* Brought back alternative convention for namespaced models in i18n [thoefer]
+
+ Now the key can be either "namespace.model" or "namespace/model" until further deprecation.
+
+* It is prohibited to perform a in-place SafeBuffer mutation [tenderlove]
+
+ The old behavior of SafeBuffer allowed you to mutate string in place via
+ method like `sub!`. These methods can add unsafe strings to a safe buffer,
+ and the safe buffer will continue to be marked as safe.
+
+ An example problem would be something like this:
+
+ <%= link_to('hello world', @user).sub!(/hello/, params[:xss]) %>
+
+ In the above example, an untrusted string (`params[:xss]`) is added to the
+ safe buffer returned by `link_to`, and the untrusted content is successfully
+ sent to the client without being escaped. To prevent this from happening
+ `sub!` and other similar methods will now raise an exception when they are called on a safe buffer.
+
+ In addition to the in-place versions, some of the versions of these methods which return a copy of the string will incorrectly mark strings as safe. For example:
+
+ <%= link_to('hello world', @user).sub(/hello/, params[:xss]) %>
+
+ The new versions will now ensure that *all* strings returned by these methods on safe buffers are marked unsafe.
+
+ You can read more about this change in http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2e516e7acc96c4fb
+
* Added 'ActionView::Helpers::FormHelper.fields_for_with_index', similar to fields_for but allows to have access to the current iteration index [Jorge Bejar]
* Warn if we cannot verify CSRF token authenticity [José Valim]
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index ec76d1da1e..70ea419e81 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -49,6 +49,9 @@ module ActionDispatch
class Mapping #:nodoc:
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]
+ ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
+ SHORTHAND_REGEX = %r{^/[\w/]+$}
+ WILDCARD_PATH = %r{\*([^/]+)$}
def initialize(set, scope, path, options)
@set, @scope = set, scope
@@ -77,18 +80,18 @@ module ActionDispatch
# segment_keys.include?(k.to_s) || k == :controller
next unless Regexp === requirement && !constraints[name]
- if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
+ if requirement.source =~ ANCHOR_CHARACTERS_REGEX
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
end
if requirement.multiline?
raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
end
end
- end
+ end
# match "account/overview"
def using_match_shorthand?(path, options)
- path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
+ path && options.except(:via, :anchor, :to, :as).empty? && path =~ SHORTHAND_REGEX
end
def normalize_path(path)
@@ -107,7 +110,7 @@ module ActionDispatch
# Add a constraint for wildcard route to make it non-greedy and match the
# optional format part of the route by default
- if path.match(/\*([^\/]+)$/) && @options[:format] != false
+ if path.match(WILDCARD_PATH) && @options[:format] != false
@options.reverse_merge!(:"#{$1}" => /.+?/)
end
@@ -1102,9 +1105,9 @@ module ActionDispatch
#
# The +comments+ resource here will have the following routes generated for it:
#
- # post_comments GET /sekret/posts/:post_id/comments(.:format)
- # post_comments POST /sekret/posts/:post_id/comments(.:format)
- # new_post_comment GET /sekret/posts/:post_id/comments/new(.:format)
+ # post_comments GET /posts/:post_id/comments(.:format)
+ # post_comments POST /posts/:post_id/comments(.:format)
+ # new_post_comment GET /posts/:post_id/comments/new(.:format)
# edit_comment GET /sekret/comments/:id/edit(.:format)
# comment GET /sekret/comments/:id(.:format)
# comment PUT /sekret/comments/:id(.:format)
diff --git a/actionpack/lib/action_view/helpers/controller_helper.rb b/actionpack/lib/action_view/helpers/controller_helper.rb
index db59bca159..1a583e62ae 100644
--- a/actionpack/lib/action_view/helpers/controller_helper.rb
+++ b/actionpack/lib/action_view/helpers/controller_helper.rb
@@ -20,4 +20,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index a91e86f4db..72bc4510b5 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -597,6 +597,12 @@ module ActionView
number_field_tag(name, value, options.stringify_keys.update("type" => "range"))
end
+ # Creates the hidden UTF8 enforcer tag. Override this method in a helper
+ # to customize the tag.
+ def utf8_enforcer_tag
+ tag(:input, :type => "hidden", :name => "utf8", :value => "&#x2713;".html_safe)
+ end
+
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
options.stringify_keys.tap do |html_options|
@@ -611,9 +617,6 @@ module ActionView
end
def extra_tags_for_form(html_options)
- snowman_tag = tag(:input, :type => "hidden",
- :name => "utf8", :value => "&#x2713;".html_safe)
-
authenticity_token = html_options.delete("authenticity_token")
method = html_options.delete("method").to_s
@@ -629,7 +632,7 @@ module ActionView
tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
end
- tags = snowman_tag << method_tag
+ tags = utf8_enforcer_tag << method_tag
content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline')
end
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index d7228bab67..4484390fde 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -18,7 +18,8 @@ module ActionView
# $('some_element').replaceWith('<%=j render 'some/element_template' %>');
def escape_javascript(javascript)
if javascript
- javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
+ result = javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] }
+ javascript.html_safe? ? result.html_safe : result
else
''
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 4dafb7739a..fe0288521f 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -211,7 +211,7 @@ module ActionView
defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
options = options.reverse_merge(defaults)
- parts = number.to_s.split('.')
+ parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
parts.join(options[:separator]).html_safe
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index 7b8a7ad3bb..4b497d142d 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -46,43 +46,48 @@ module Sprockets
end
protected
+ def asset_environment(app)
+ require "sprockets"
- def asset_environment(app)
- require "sprockets"
- assets = app.config.assets
- env = Sprockets::Environment.new(app.root.to_s)
- env.static_root = File.join(app.root.join("public"), assets.prefix)
- env.paths.concat assets.paths
- env.logger = Rails.logger
- env.js_compressor = expand_js_compressor(assets.js_compressor) if assets.compress
- env.css_compressor = expand_css_compressor(assets.css_compressor) if assets.compress
- env
- end
+ assets = app.config.assets
+
+ env = Sprockets::Environment.new(app.root.to_s)
+
+ env.static_root = File.join(app.root.join("public"), assets.prefix)
+ env.paths.concat assets.paths
+
+ env.logger = Rails.logger
+
+ env.js_compressor = expand_js_compressor(assets.js_compressor)
+ env.css_compressor = expand_css_compressor(assets.css_compressor)
- def expand_js_compressor(sym)
- case sym
- when :closure
- require 'closure-compiler'
- Closure::Compiler.new
- when :uglifier
- require 'uglifier'
- Uglifier.new
- when :yui
- require 'yui/compressor'
- YUI::JavaScriptCompressor.new
- else
- sym
+ env
end
- end
- def expand_css_compressor(sym)
- case sym
- when :yui
- require 'yui/compressor'
- YUI::CssCompressor.new
- else
- sym
+ def expand_js_compressor(sym)
+ case sym
+ when :closure
+ require 'closure-compiler'
+ Closure::Compiler.new
+ when :uglifier
+ require 'uglifier'
+ Uglifier.new
+ when :yui
+ require 'yui/compressor'
+ YUI::JavaScriptCompressor.new
+ else
+ sym
+ end
+ end
+
+ def expand_css_compressor(sym)
+ case sym
+ when :yui
+ require 'yui/compressor'
+ YUI::CssCompressor.new
+ else
+ sym
+ end
end
- end
end
end
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 53712a60ec..5823e64637 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -181,7 +181,7 @@ module AbstractController
class TestLayouts < ActiveSupport::TestCase
test "layouts are included" do
controller = Me4.new
- result = controller.process(:index)
+ controller.process(:index)
assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", controller.response_body
end
end
diff --git a/actionpack/test/abstract/callbacks_test.rb b/actionpack/test/abstract/callbacks_test.rb
index 3bdde86291..5d1a703c55 100644
--- a/actionpack/test/abstract/callbacks_test.rb
+++ b/actionpack/test/abstract/callbacks_test.rb
@@ -131,7 +131,7 @@ module AbstractController
end
def authenticate
- @list = []
+ @list ||= []
@authenticated = "true"
end
end
diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb
index 5ed6aa68b5..86208899f8 100644
--- a/actionpack/test/abstract/layouts_test.rb
+++ b/actionpack/test/abstract/layouts_test.rb
@@ -87,18 +87,6 @@ module AbstractControllerTests
end
end
- class WithSymbolReturningString < Base
- layout :no_hello
-
- def index
- render :template => ActionView::Template::Text.new("Hello missing symbol!")
- end
- private
- def no_hello
- nil
- end
- end
-
class WithSymbolReturningNil < Base
layout :nilz
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 7f3d943bba..a714e8bbcc 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -100,9 +100,6 @@ class AssertResponseWithUnexpectedErrorController < ActionController::Base
end
end
-class UserController < ActionController::Base
-end
-
module Admin
class InnerModuleController < ActionController::Base
def index
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 82c2c23607..da3314fe6d 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -127,7 +127,7 @@ class PageCachingTest < ActionController::TestCase
assert_equal 'I am xml', @response.body
end
- def test_should_cache_with_trailing_slash_on_url
+ def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
@controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
end
@@ -141,7 +141,7 @@ class PageCachingTest < ActionController::TestCase
[:ok, :no_content, :found, :not_found].each do |status|
[:get, :post, :put, :delete].each do |method|
- unless method == :get and status == :ok
+ unless method == :get && status == :ok
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
send(method, status)
assert_response status
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index b12c798302..d51882066d 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -74,6 +74,7 @@ class ContentTypeTest < ActionController::TestCase
get :render_defaults
assert_equal "utf-16", @response.charset
assert_equal Mime::HTML, @response.content_type
+ ensure
OldContentTypeController.default_charset = "utf-8"
end
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index f48b73b63a..6265e78030 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -612,7 +612,6 @@ XML
send(method, :test_remote_addr)
assert false, "expected RuntimeError, got nothing"
rescue RuntimeError => error
- assert true
assert_match(%r{@#{variable} is nil}, error.message)
rescue => error
assert false, "expected RuntimeError, got #{error.class}"
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 3f3d6dcc2f..484e996f31 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -293,8 +293,8 @@ module AbstractController
first_class.default_url_options[:host] = first_host
second_class.default_url_options[:host] = second_host
- assert_equal first_class.default_url_options[:host], first_host
- assert_equal second_class.default_url_options[:host], second_host
+ assert_equal first_host, first_class.default_url_options[:host]
+ assert_equal second_host, second_class.default_url_options[:host]
end
def test_with_stringified_keys
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index 621fb79915..ae8588cbb0 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -30,7 +30,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest
def test_check_parameters
with_test_route_set do
get "/"
- assert_blank @controller.response.body
+ assert_equal '', @controller.response.body
end
end
@@ -162,7 +162,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest
def test_use_xml_ximple_with_empty_request
with_test_route_set do
assert_nothing_raised { post "/", "", {'CONTENT_TYPE' => 'application/xml'} }
- assert_blank @controller.response.body
+ assert_equal '', @controller.response.body
end
end
diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb
index 30f6d1a213..790ab1c74c 100644
--- a/actionpack/test/template/erb_util_test.rb
+++ b/actionpack/test/template/erb_util_test.rb
@@ -16,6 +16,16 @@ class ErbUtilTest < Test::Unit::TestCase
end
end
+ def test_json_escape_returns_unsafe_strings_when_passed_unsafe_strings
+ value = json_escape("asdf")
+ assert !value.html_safe?
+ end
+
+ def test_json_escape_returns_safe_strings_when_passed_safe_strings
+ value = json_escape("asdf".html_safe)
+ assert value.html_safe?
+ end
+
def test_html_escape_is_html_safe
escaped = h("<p>")
assert_equal "&lt;p&gt;", escaped
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 5296556fe6..0507045ad2 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -1890,7 +1890,7 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
- def snowman(method = nil)
+ def hidden_fields(method = nil)
txt = %{<div style="margin:0;padding:0;display:inline">}
txt << %{<input name="utf8" type="hidden" value="&#x2713;" />}
if method && !method.to_s.in?(['get', 'post'])
@@ -1918,7 +1918,7 @@ class FormHelperTest < ActionView::TestCase
method = options
end
- form_text(action, id, html_class, remote, multipart, method) + snowman(method) + contents + "</form>"
+ form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "</form>"
end
def test_default_form_builder
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index f95308b847..979251bfd1 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -9,7 +9,7 @@ class FormTagHelperTest < ActionView::TestCase
@controller = BasicController.new
end
- def snowman(options = {})
+ def hidden_fields(options = {})
method = options[:method]
txt = %{<div style="margin:0;padding:0;display:inline">}
@@ -34,7 +34,7 @@ class FormTagHelperTest < ActionView::TestCase
end
def whole_form(action = "http://www.example.com", options = {})
- out = form_text(action, options) + snowman(options)
+ out = form_text(action, options) + hidden_fields(options)
if block_given?
out << yield << "</form>"
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index 538e0e9874..dd8b7b7cd5 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -30,6 +30,15 @@ class JavaScriptHelperTest < ActionView::TestCase
assert_equal %(dont <\\/close> tags), j(%(dont </close> tags))
end
+ def test_escape_javascript_with_safebuffer
+ given = %('quoted' "double-quoted" new-line:\n </closed>)
+ expect = %(\\'quoted\\' \\"double-quoted\\" new-line:\\n <\\/closed>)
+ assert_equal expect, escape_javascript(given)
+ assert_equal expect, escape_javascript(ActiveSupport::SafeBuffer.new(given))
+ assert_instance_of String, escape_javascript(given)
+ assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given))
+ end
+
def test_button_to_function
assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />),
button_to_function("Greeting", "alert('Hello world!')")
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index 0104c20bc7..0e3475d98b 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -283,33 +283,40 @@ class NumberHelperTest < ActionView::TestCase
assert number_to_human(1).html_safe?
assert !number_to_human("<script></script>").html_safe?
assert number_to_human("asdf".html_safe).html_safe?
+ assert number_to_human("1".html_safe).html_safe?
assert number_to_human_size(1).html_safe?
assert number_to_human_size(1000000).html_safe?
assert !number_to_human_size("<script></script>").html_safe?
assert number_to_human_size("asdf".html_safe).html_safe?
+ assert number_to_human_size("1".html_safe).html_safe?
assert number_with_precision(1, :strip_insignificant_zeros => false).html_safe?
assert number_with_precision(1, :strip_insignificant_zeros => true).html_safe?
assert !number_with_precision("<script></script>").html_safe?
assert number_with_precision("asdf".html_safe).html_safe?
+ assert number_with_precision("1".html_safe).html_safe?
assert number_to_currency(1).html_safe?
assert !number_to_currency("<script></script>").html_safe?
assert number_to_currency("asdf".html_safe).html_safe?
+ assert number_to_currency("1".html_safe).html_safe?
assert number_to_percentage(1).html_safe?
assert !number_to_percentage("<script></script>").html_safe?
assert number_to_percentage("asdf".html_safe).html_safe?
+ assert number_to_percentage("1".html_safe).html_safe?
assert number_to_phone(1).html_safe?
assert_equal "&lt;script&gt;&lt;/script&gt;", number_to_phone("<script></script>")
assert number_to_phone("<script></script>").html_safe?
assert number_to_phone("asdf".html_safe).html_safe?
+ assert number_to_phone("1".html_safe).html_safe?
assert number_with_delimiter(1).html_safe?
assert !number_with_delimiter("<script></script>").html_safe?
assert number_with_delimiter("asdf".html_safe).html_safe?
+ assert number_with_delimiter("1".html_safe).html_safe?
end
def test_number_helpers_should_raise_error_if_invalid_when_specified