diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
7 files changed, 103 insertions, 24 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/closed_error.rb b/actionpack/lib/action_dispatch/middleware/closed_error.rb new file mode 100644 index 0000000000..0a4db47f4b --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/closed_error.rb @@ -0,0 +1,7 @@ +module ActionDispatch +  class ClosedError < StandardError #:nodoc: +    def initialize(kind) +      super "Cannot modify #{kind} because it was closed. This means it was already streamed back to the client or converted to HTTP headers." +    end +  end +end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 7ac608f0a8..24ebb8fed7 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -83,7 +83,7 @@ module ActionDispatch      # Raised when storing more than 4K of session data.      class CookieOverflow < StandardError; end -    class CookieJar < Hash #:nodoc: +    class CookieJar #:nodoc:        # This regular expression is used to split the levels of a domain.        # The top level domain can be any string without a period or @@ -115,13 +115,22 @@ module ActionDispatch          @delete_cookies = {}          @host = host          @secure = secure - -        super() +        @closed = false +        @cookies = {}        end +      attr_reader :closed +      alias :closed? :closed +      def close!; @closed = true end +        # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.        def [](name) -        super(name.to_s) +        @cookies[name.to_s] +      end + +      def update(other_hash) +        @cookies.update other_hash +        self        end        def handle_options(options) #:nodoc: @@ -145,6 +154,7 @@ module ActionDispatch        # Sets the cookie named +name+. The second argument may be the very cookie        # value, or a hash of options as documented above.        def []=(key, options) +        raise ClosedError, :cookies if closed?          if options.is_a?(Hash)            options.symbolize_keys!            value = options[:value] @@ -153,7 +163,7 @@ module ActionDispatch            options = { :value => value }          end -        value = super(key.to_s, value) +        value = @cookies[key.to_s] = value          handle_options(options) @@ -170,7 +180,7 @@ module ActionDispatch          handle_options(options) -        value = super(key.to_s) +        value = @cookies.delete(key.to_s)          @delete_cookies[key] = options          value        end @@ -225,6 +235,7 @@ module ActionDispatch        end        def []=(key, options) +        raise ClosedError, :cookies if closed?          if options.is_a?(Hash)            options.symbolize_keys!          else @@ -263,6 +274,7 @@ module ActionDispatch        end        def []=(key, options) +        raise ClosedError, :cookies if closed?          if options.is_a?(Hash)            options.symbolize_keys!            options[:value] = @verifier.generate(options[:value]) @@ -305,6 +317,7 @@ module ActionDispatch      end      def call(env) +      cookie_jar = nil        status, headers, body = @app.call(env)        if cookie_jar = env['action_dispatch.cookies'] @@ -315,6 +328,9 @@ module ActionDispatch        end        [status, headers, body] +    ensure +      cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar +      cookie_jar.close!      end    end  end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 21aeeb217a..027ff7f8ac 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -43,9 +43,15 @@ module ActionDispatch      class FlashNow #:nodoc:        def initialize(flash)          @flash = flash +        @closed = false        end +      attr_reader :closed +      alias :closed? :closed +      def close!; @closed = true end +        def []=(k, v) +        raise ClosedError, :flash if closed?          @flash[k] = v          @flash.discard(k)          v @@ -66,27 +72,70 @@ module ActionDispatch        end      end -    class FlashHash < Hash +    class FlashHash +      include Enumerable +        def initialize #:nodoc: -        super -        @used = Set.new +        @used    = Set.new +        @closed  = false +        @flashes = {}        end +      attr_reader :closed +      alias :closed? :closed +      def close!; @closed = true end +        def []=(k, v) #:nodoc: +        raise ClosedError, :flash if closed?          keep(k) -        super +        @flashes[k] = v +      end + +      def [](k) +        @flashes[k]        end        def update(h) #:nodoc:          h.keys.each { |k| keep(k) } -        super +        @flashes.update h +        self +      end + +      def keys +        @flashes.keys +      end + +      def key?(name) +        @flashes.key? name +      end + +      def delete(key) +        @flashes.delete key +        self +      end + +      def to_hash +        @flashes.dup +      end + +      def empty? +        @flashes.empty? +      end + +      def clear +        @flashes.clear +      end + +      def each(&block) +        @flashes.each(&block)        end        alias :merge! :update        def replace(h) #:nodoc:          @used = Set.new -        super +        @flashes.replace h +        self        end        # Sets a flash that will not be available to the next action, only to the current. @@ -100,7 +149,7 @@ module ActionDispatch        #        # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.        def now -        FlashNow.new(self) +        @now ||= FlashNow.new(self)        end        # Keeps either the entire current flash or a specific flash entry available for the next action: @@ -184,8 +233,11 @@ module ActionDispatch        session    = env['rack.session'] || {}        flash_hash = env['action_dispatch.request.flash_hash'] -      if flash_hash && (!flash_hash.empty? || session.key?('flash')) +      if flash_hash +       if !flash_hash.empty? || session.key?('flash')          session["flash"] = flash_hash +       end +       flash_hash.close!        end        if session.key?('flash') && session['flash'].empty? diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 35be0b3a27..13aef18ee1 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,6 +1,7 @@  require 'erb'  require 'active_support/core_ext/hash/except'  require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/object/inclusion'  require 'active_support/inflector'  require 'action_dispatch/routing/redirection' @@ -1345,11 +1346,11 @@ module ActionDispatch            end            def resource_scope? #:nodoc: -            [:resource, :resources].include?(@scope[:scope_level]) +            @scope[:scope_level].among?(:resource, :resources)            end            def resource_method_scope? #:nodoc: -            [:collection, :member, :new].include?(@scope[:scope_level]) +            @scope[:scope_level].among?(:collection, :member, :new)            end            def with_exclusive_scope diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 77a15f3e97..16a6b93ce8 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/inclusion' +  module ActionDispatch    module Assertions      # A small suite of assertions that test responses from \Rails applications. @@ -33,7 +35,7 @@ module ActionDispatch        def assert_response(type, message = nil)          validate_request! -        if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") +        if type.among?(:success, :missing, :redirect, :error) && @response.send("#{type}?")            assert_block("") { true } # to count the assertion          elsif type.is_a?(Fixnum) && @response.response_code == type            assert_block("") { true } # to count the assertion diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2b862fb7d6..f41d3e5ddb 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,4 +1,5 @@  require 'action_controller/vendor/html-scanner' +require 'active_support/core_ext/object/inclusion'  #--  # Copyright (c) 2006 Assaf Arkin (http://labnotes.org) @@ -441,7 +442,7 @@ module ActionDispatch          if matches            assert_block("") { true } # to count the assertion -          if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type) +          if block_given? && !rjs_type.among?(:remove, :show, :hide, :toggle)              begin                @selected ||= nil                in_scope, @selected = @selected, matches diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 4706112a06..174babb9aa 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,6 +1,7 @@  require 'stringio'  require 'uri'  require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/core_ext/object/inclusion'  require 'active_support/core_ext/object/try'  require 'rack/test'  require 'test/unit/assertions' @@ -243,7 +244,8 @@ module ActionDispatch          end          # Performs the actual request. -        def process(method, path, parameters = nil, rack_environment = nil) +        def process(method, path, parameters = nil, env = nil) +          env ||= {}            if path =~ %r{://}              location = URI.parse(path)              https! URI::HTTPS === location if location.scheme @@ -259,7 +261,7 @@ module ActionDispatch            hostname, port = host.split(':') -          env = { +          default_env = {              :method => method,              :params => parameters, @@ -277,9 +279,7 @@ module ActionDispatch            session = Rack::Test::Session.new(_mock_session) -          (rack_environment || {}).each do |key, value| -            env[key] = value -          end +          env.reverse_merge!(default_env)            # NOTE: rack-test v0.5 doesn't build a default uri correctly            # Make sure requested path is always a full uri @@ -321,7 +321,7 @@ module ActionDispatch          define_method(method) do |*args|            reset! unless integration_session            # reset the html_document variable, but only for new get/post calls -          @html_document = nil unless %w(cookies assigns).include?(method) +          @html_document = nil unless method.among?("cookies", "assigns")            integration_session.__send__(method, *args).tap do              copy_session_variables!            end  | 
