diff --git a/.gitignore b/.gitignore index 1c94c4b0f8..da296e7e11 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,4 @@ railties/guides/output actionpack/bin vendor/gems/ */vendor/gems/ -bin/ railties/tmp diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 38aaa6146e..11cd812695 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -39,6 +39,7 @@ module ActionDispatch autoload :Rescue, 'action_dispatch/middleware/rescue' autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions' autoload :Static, 'action_dispatch/middleware/static' + autoload :StringCoercion, 'action_dispatch/middleware/string_coercion' autoload :Assertions, 'action_dispatch/testing/assertions' autoload :Integration, 'action_dispatch/testing/integration' diff --git a/actionpack/lib/action_dispatch/middleware/string_coercion.rb b/actionpack/lib/action_dispatch/middleware/string_coercion.rb new file mode 100644 index 0000000000..232e947835 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/string_coercion.rb @@ -0,0 +1,29 @@ +module ActionDispatch + class StringCoercion + class UglyBody < ActiveSupport::BasicObject + def initialize(body) + @body = body + end + + def each + @body.each do |part| + yield part.to_s + end + end + + private + def method_missing(*args, &block) + @body.__send__(*args, &block) + end + end + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + [status, headers, UglyBody.new(body)] + end + end +end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 1214d608a4..4820f00aa1 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -93,6 +93,7 @@ end class ActionController::IntegrationTest < ActiveSupport::TestCase def self.build_app(routes = nil) ActionDispatch::MiddlewareStack.new { |middleware| + middleware.use "ActionDispatch::StringCoercion" middleware.use "ActionDispatch::ShowExceptions" middleware.use "ActionDispatch::Callbacks" middleware.use "ActionDispatch::ParamsParser" diff --git a/actionpack/test/dispatch/string_coercion_test.rb b/actionpack/test/dispatch/string_coercion_test.rb new file mode 100644 index 0000000000..d79b17b932 --- /dev/null +++ b/actionpack/test/dispatch/string_coercion_test.rb @@ -0,0 +1,40 @@ +require 'abstract_unit' + +class StringCoercionTest < ActiveSupport::TestCase + test "body responds to each" do + original_body = [] + body = ActionDispatch::StringCoercion::UglyBody.new(original_body) + + assert original_body.respond_to?(:each) + assert body.respond_to?(:each) + end + + test "body responds to to_path" do + original_body = [] + def original_body.to_path; end + body = ActionDispatch::StringCoercion::UglyBody.new(original_body) + + assert original_body.respond_to?(:to_path) + assert body.respond_to?(:to_path) + end + + test "body does not responds to to_path" do + original_body = [] + body = ActionDispatch::StringCoercion::UglyBody.new(original_body) + + assert !original_body.respond_to?(:to_path) + assert !body.respond_to?(:to_path) + end + + test "calls to_s on body parts" do + app = lambda { |env| + [200, {'Content-Type' => 'html'}, [1, 2, 3]] + } + app = ActionDispatch::StringCoercion.new(app) + parts = [] + status, headers, body = app.call({}) + body.each { |part| parts << part } + + assert_equal %w( 1 2 3 ), parts + end +end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index 74e080a23d..fcdc09ff08 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -26,6 +26,8 @@ module ActiveSupport end def verify(signed_message) + raise InvalidSignature if signed_message.blank? + data, digest = signed_message.split("--") if secure_compare(digest, generate_digest(data)) Marshal.load(ActiveSupport::Base64.decode64(data)) diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 4f8837ba4e..e6370bc3db 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -18,6 +18,11 @@ class MessageVerifierTest < Test::Unit::TestCase assert_equal @data, @verifier.verify(message) end + def test_missing_signature_raises + assert_not_verified(nil) + assert_not_verified("") + end + def test_tampered_data_raises data, hash = @verifier.generate(@data).split("--") assert_not_verified("#{data.reverse}--#{hash}") diff --git a/railties/lib/rails/initializer.rb b/railties/lib/rails/initializer.rb index 2d63ac4d39..c2d6e1609f 100644 --- a/railties/lib/rails/initializer.rb +++ b/railties/lib/rails/initializer.rb @@ -271,6 +271,7 @@ module Rails configuration.middleware.use(ActionDispatch::ParamsParser) configuration.middleware.use(::Rack::MethodOverride) configuration.middleware.use(::Rack::Head) + configuration.middleware.use(ActionDispatch::StringCoercion) end end