diff options
Diffstat (limited to 'actionpack/lib/action_controller')
6 files changed, 83 insertions, 24 deletions
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index e920a33765..b1acca2435 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -54,9 +54,9 @@ module ActionController end def deep_munge(event) - message = "Value for params[:#{event.payload[:keys].join('][:')}] was set"\ - "to nil, because it was one of [], [null] or [null, null, ...]."\ - "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation"\ + message = "Value for params[:#{event.payload[:keys].join('][:')}] was set "\ + "to nil, because it was one of [], [null] or [null, null, ...]. "\ + "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation "\ "for more information."\ debug(message) diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index fdf4ef293d..41b997a755 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -107,8 +107,11 @@ module ActionController end class Buffer < ActionDispatch::Response::Buffer #:nodoc: + include MonitorMixin + def initialize(response) - @error_callback = nil + @error_callback = lambda { true } + @cv = new_cond super(response, SizedQueue.new(10)) end @@ -122,14 +125,25 @@ module ActionController end def each + @response.sending! while str = @buf.pop yield str end + @response.sent! end def close - super - @buf.push nil + synchronize do + super + @buf.push nil + @cv.broadcast + end + end + + def await_close + synchronize do + @cv.wait_until { @closed } + end end def on_error(&block) @@ -165,12 +179,20 @@ module ActionController end end - def commit! - headers.freeze + private + + def before_committed super + jar = request.cookie_jar + # The response can be committed multiple times + jar.write self unless committed? end - private + def before_sending + super + request.cookie_jar.commit! + headers.freeze + end def build_buffer(response, body) buf = Live::Buffer.new response @@ -191,6 +213,7 @@ module ActionController t1 = Thread.current locals = t1.keys.map { |key| [key, t1[key]] } + error = nil # This processes the action in a child thread. It lets us return the # response code and headers back up the rack stack, and still process # the body in parallel with sending data to the client @@ -205,8 +228,9 @@ module ActionController begin super(name) rescue => e - @_response.status = 500 unless @_response.committed? - @_response.status = 400 if e.class == ActionController::BadRequest + unless @_response.committed? + error = e + end begin @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html @_response.stream.call_on_error @@ -222,6 +246,7 @@ module ActionController } @_response.await_commit + raise error if error end def log_error(exception) diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb index e1bee9e60c..bdf6e88699 100644 --- a/actionpack/lib/action_controller/metal/rack_delegation.rb +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -5,8 +5,8 @@ module ActionController module RackDelegation extend ActiveSupport::Concern - delegate :headers, :status=, :location=, :content_type=, :no_content_type=, - :status, :location, :content_type, :no_content_type, :to => "@_response" + delegate :headers, :status=, :location=, :content_type=, + :status, :location, :content_type, :to => "@_response" def dispatch(action, request) set_response!(request) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 3c4ef596c7..93e7d6954c 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -45,9 +45,7 @@ module ActionController def _process_format(format, options = {}) super - if options[:body] - self.headers.delete "Content-Type" - elsif options[:plain] + if options[:plain] self.content_type = Mime::TEXT else self.content_type ||= format.to_s diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index c88074d4c6..e3b1f5ae7c 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -68,6 +68,10 @@ module ActionController #:nodoc: config_accessor :allow_forgery_protection self.allow_forgery_protection = true if allow_forgery_protection.nil? + # Controls whether a CSRF failure logs a warning. On by default. + config_accessor :log_warning_on_csrf_failure + self.log_warning_on_csrf_failure = true + helper_method :form_authenticity_token helper_method :protect_against_forgery? end @@ -193,7 +197,9 @@ module ActionController #:nodoc: mark_for_same_origin_verification! if !verified_request? - logger.warn "Can't verify CSRF token authenticity" if logger + if logger && log_warning_on_csrf_failure + logger.warn "Can't verify CSRF token authenticity" + end handle_unverified_request end end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 8650b75400..e9166d8747 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -258,6 +258,29 @@ module ActionController end end + class LiveTestResponse < Live::Response + def recycle! + @body = nil + initialize + end + + def body + @body ||= super + end + + # Was the response successful? + alias_method :success?, :successful? + + # Was the URL not found? + alias_method :missing?, :not_found? + + # Were we redirected? + alias_method :redirect?, :redirection? + + # Was there a server-side error? + alias_method :error?, :server_error? + end + # Methods #destroy and #load! are overridden to avoid calling methods on the # @store object, which does not exist for the TestSession class. class TestSession < Rack::Session::Abstract::SessionHash #:nodoc: @@ -572,7 +595,9 @@ module ActionController @controller.process(name) if cookies = @request.env['action_dispatch.cookies'] - cookies.write(@response) + unless @response.committed? + cookies.write(@response) + end end @response.prepare! @@ -583,13 +608,14 @@ module ActionController end def setup_controller_request_and_response - @request = build_request - @response = build_response - @response.request = @request - @controller = nil unless defined? @controller + response_klass = TestResponse + if klass = self.class.controller_class + if klass < ActionController::Live + response_klass = LiveTestResponse + end unless @controller begin @controller = klass.new @@ -599,6 +625,10 @@ module ActionController end end + @request = build_request + @response = build_response response_klass + @response.request = @request + if @controller @controller.request = @request @controller.params = {} @@ -609,8 +639,8 @@ module ActionController TestRequest.new end - def build_response - TestResponse.new + def build_response(klass) + klass.new end included do |