diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
14 files changed, 145 insertions, 101 deletions
| diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 68ba1a81b5..980c658ab7 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,6 +1,13 @@  module ActionDispatch    module Http      module MimeNegotiation +      extend ActiveSupport::Concern + +      included do +        mattr_accessor :ignore_accept_header +        self.ignore_accept_header = false +      end +        # The MIME type of the HTTP request, such as Mime::XML.        #        # For backward compatibility, the post \format is extracted from the @@ -42,16 +49,14 @@ module ActionDispatch          formats.first        end -      BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ -        def formats -        accept = @env['HTTP_ACCEPT'] -          @env["action_dispatch.request.formats"] ||=            if parameters[:format]              Array(Mime[parameters[:format]]) -          elsif xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) +          elsif use_accept_header && valid_accept_header              accepts +          elsif xhr? +            [Mime::JS]            else              [Mime::HTML]            end @@ -87,6 +92,18 @@ module ActionDispatch          order.include?(Mime::ALL) ? formats.first : nil        end + +      protected + +      BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ + +      def valid_accept_header +        xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) +      end + +      def use_accept_header +        !self.class.ignore_accept_header +      end      end    end  end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index f07ac44f7a..ccb866f4f7 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -17,16 +17,17 @@ module ActionDispatch      include ActionDispatch::Http::Upload      include ActionDispatch::Http::URL -    LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze - -    %w[ AUTH_TYPE GATEWAY_INTERFACE +    LOCALHOST   = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze +    ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE          PATH_TRANSLATED REMOTE_HOST          REMOTE_IDENT REMOTE_USER REMOTE_ADDR          SERVER_NAME SERVER_PROTOCOL          HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING          HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM -        HTTP_NEGOTIATE HTTP_PRAGMA ].each do |env| +        HTTP_NEGOTIATE HTTP_PRAGMA ].freeze +       +    ENV_METHODS.each do |env|        class_eval <<-METHOD, __FILE__, __LINE__ + 1          def #{env.sub(/^HTTP_/n, '').downcase}            @env["#{env}"] diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 8e03a7879f..1f4f3ac0da 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -32,24 +32,35 @@ module ActionDispatch # :nodoc:    #      puts @response.body    #    end    #  end -  class Response < Rack::Response -    attr_accessor :request, :blank +  class Response +    attr_accessor :request, :header, :status +    attr_writer :sending_file -    attr_writer :header, :sending_file      alias_method :headers=, :header= +    alias_method :headers,  :header + +    delegate :[], :[]=, :to => :@header +    delegate :each, :to => :@body + +    # Sets the HTTP response's content MIME type. For example, in the controller +    # you could write this: +    # +    #  response.content_type = "text/plain" +    # +    # If a character set has been defined for this response (see charset=) then +    # the character set information will also be included in the content type +    # information. +    attr_accessor :charset, :content_type + +    CONTENT_TYPE = "Content-Type" + +    cattr_accessor(:default_charset) { "utf-8" }      module Setup        def initialize(status = 200, header = {}, body = []) -        @writer = lambda { |x| @body << x } -        @block = nil -        @length = 0 +        self.body, self.header, self.status = body, header, status -        @header = header -        self.body, self.status = body, status - -        @cookie = []          @sending_file = false -          @blank = false          if content_type = self["Content-Type"] @@ -62,6 +73,7 @@ module ActionDispatch # :nodoc:        end      end +    include Rack::Response::Helpers      include Setup      include ActionDispatch::Http::Cache::Response @@ -106,13 +118,29 @@ module ActionDispatch # :nodoc:      def body=(body)        @blank = true if body == EMPTY -      @body = body.respond_to?(:to_str) ? [body] : body + +      # Explicitly check for strings. This is *wrong* theoretically +      # but if we don't check this, the performance on string bodies +      # is bad on Ruby 1.8 (because strings responds to each then). +      @body = if body.respond_to?(:to_str) || !body.respond_to?(:each) +        [body] +      else +        body +      end      end      def body_parts        @body      end +    def set_cookie(key, value) +      ::Rack::Utils.set_cookie_header!(header, key, value) +    end + +    def delete_cookie(key, value={}) +      ::Rack::Utils.delete_cookie_header!(header, key, value) +    end +      def location        headers['Location']      end @@ -122,46 +150,21 @@ module ActionDispatch # :nodoc:        headers['Location'] = url      end -    # Sets the HTTP response's content MIME type. For example, in the controller -    # you could write this: -    # -    #  response.content_type = "text/plain" -    # -    # If a character set has been defined for this response (see charset=) then -    # the character set information will also be included in the content type -    # information. -    attr_accessor :charset, :content_type - -    CONTENT_TYPE = "Content-Type" - -    cattr_accessor(:default_charset) { "utf-8" } -      def to_a        assign_default_content_type_and_charset!        handle_conditional_get! -      self["Set-Cookie"] = self["Set-Cookie"].join("\n") if self["Set-Cookie"].respond_to?(:join) -      super -    end -    alias prepare! to_a +      @header["Set-Cookie"] = @header["Set-Cookie"].join("\n") if @header["Set-Cookie"].respond_to?(:join) -    def each(&callback) -      if @body.respond_to?(:call) -        @writer = lambda { |x| callback.call(x) } -        @body.call(self, self) +      if [204, 304].include?(@status) +        @header.delete "Content-Type" +        [@status, @header, []]        else -        @body.each { |part| callback.call(part.to_s) } +        [@status, @header, self]        end - -      @writer = callback -      @block.call(self) if @block -    end - -    def write(str) -      str = str.to_s -      @writer.call str -      str      end +    alias prepare! to_a +    alias to_ary   to_a # For implicit splat on 1.9.2      # Returns the response cookies, converted to a Hash of (name => value) pairs      # @@ -180,18 +183,18 @@ module ActionDispatch # :nodoc:        cookies      end -    private -      def assign_default_content_type_and_charset! -        return if headers[CONTENT_TYPE].present? +  private -        @content_type ||= Mime::HTML -        @charset      ||= self.class.default_charset +    def assign_default_content_type_and_charset! +      return if headers[CONTENT_TYPE].present? -        type = @content_type.to_s.dup -        type << "; charset=#{@charset}" unless @sending_file +      @content_type ||= Mime::HTML +      @charset      ||= self.class.default_charset -        headers[CONTENT_TYPE] = type -      end +      type = @content_type.to_s.dup +      type << "; charset=#{@charset}" unless @sending_file +      headers[CONTENT_TYPE] = type +    end    end  end diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index ac0fd9607d..d9c07d6ca3 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -165,7 +165,7 @@ module ActionDispatch        # such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt>        # in "www.rubyonrails.co.uk".        def subdomain(tld_length = @@tld_length) -        subdomains(tld_length) +        subdomains(tld_length).join(".")        end      end    end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 027ff7f8ac..2adbce031b 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -4,7 +4,7 @@ module ActionDispatch      # read a notice you put there or <tt>flash["notice"] = "hello"</tt>      # to put a new one.      def flash -      @env['action_dispatch.request.flash_hash'] ||= (session["flash"] || Flash::FlashHash.new) +      @env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)      end    end @@ -40,18 +40,16 @@ module ActionDispatch    #    # See docs on the FlashHash class for more details about the flash.    class Flash +    KEY = 'action_dispatch.request.flash_hash'.freeze +      class FlashNow #:nodoc: +      attr_accessor :flash +        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 @@ -79,11 +77,16 @@ module ActionDispatch          @used    = Set.new          @closed  = false          @flashes = {} +        @now     = nil        end -      attr_reader :closed -      alias :closed? :closed -      def close!; @closed = true end +      def initialize_copy(other) +        if other.now_is_loaded? +          @now = other.now.dup +          @now.flash = self +        end +        super +      end        def []=(k, v) #:nodoc:          raise ClosedError, :flash if closed? @@ -152,6 +155,10 @@ module ActionDispatch          @now ||= FlashNow.new(self)        end +      attr_reader :closed +      alias :closed? :closed +      def close!; @closed = true; end +        # Keeps either the entire current flash or a specific flash entry available for the next action:        #        #    flash.keep            # keeps the entire flash @@ -205,7 +212,12 @@ module ActionDispatch          self[:notice] = message        end -      private +      protected + +        def now_is_loaded? +          !!@now +        end +          # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods          #     use()               # marks the entire flash as used          #     use('msg')          # marks the "msg" entry as used @@ -231,13 +243,18 @@ module ActionDispatch        @app.call(env)      ensure        session    = env['rack.session'] || {} -      flash_hash = env['action_dispatch.request.flash_hash'] +      flash_hash = env[KEY]        if flash_hash -       if !flash_hash.empty? || session.key?('flash') -        session["flash"] = flash_hash -       end -       flash_hash.close! +        if !flash_hash.empty? || session.key?('flash') +          session["flash"] = flash_hash +          new_hash = flash_hash.dup +        else +          new_hash = flash_hash +        end + +        env[KEY] = new_hash +        new_hash.close!        end        if session.key?('flash') && session['flash'].empty? diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 9c9ccc62f5..8ebf870b95 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -59,7 +59,7 @@ module ActionDispatch        end        def set_session(env, sid, session_data, options) -        persistent_session_id!(session_data, sid) +        session_data.merge("session_id" => sid)        end        def set_cookie(env, session_id, cookie) diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index dbe3206808..c17c746096 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -50,7 +50,7 @@ module ActionDispatch          # Only this middleware cares about RoutingError. So, let's just raise          # it here.          if headers['X-Cascade'] == 'pass' -           raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}" +           raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"          end        rescue Exception => exception          raise exception if env['action_dispatch.show_exceptions'] == false @@ -116,7 +116,7 @@ module ActionDispatch        end        def render(status, body) -        [status, {'Content-Type' => 'text/html', 'Content-Length' => body.bytesize.to_s}, [body]] +        [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]        end        def public_path diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb index 348f7b86b8..404943d720 100644 --- a/actionpack/lib/action_dispatch/middleware/static.rb +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -2,10 +2,10 @@ require 'rack/utils'  module ActionDispatch    class FileHandler -    def initialize(root) +    def initialize(root, cache_control)        @root          = root.chomp('/')        @compiled_root = /^#{Regexp.escape(root)}/ -      @file_server   = ::Rack::File.new(@root) +      @file_server   = ::Rack::File.new(@root, cache_control)      end      def match?(path) @@ -35,18 +35,15 @@ module ActionDispatch    end    class Static -    FILE_METHODS = %w(GET HEAD).freeze - -    def initialize(app, path) +    def initialize(app, path, cache_control=nil)        @app = app -      @file_handler = FileHandler.new(path) +      @file_handler = FileHandler.new(path, cache_control)      end      def call(env) -      path   = env['PATH_INFO'].chomp('/') -      method = env['REQUEST_METHOD'] - -      if FILE_METHODS.include?(method) +      case env['REQUEST_METHOD'] +      when 'GET', 'HEAD' +        path = env['PATH_INFO'].chomp('/')          if match = @file_handler.match?(path)            env["PATH_INFO"] = match            return @file_handler.call(env) diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb index 97f7cf0bbe..0c5bafa666 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -24,7 +24,7 @@  <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>  <p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p> -<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env %></pre></div> +<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>  <h2 style="margin-top: 30px">Response</h2> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb index 2099fd069a..4b9d3141d5 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb @@ -1,7 +1,7 @@  <h1>    <%=h @exception.class.to_s %>    <% if @request.parameters['controller'] %> -    in <%=h @request.parameters['controller'].classify.pluralize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %> +    in <%=h @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>    <% end %>  </h1>  <pre><%=h @exception.message %></pre> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb index 6c32fb17b8..6e71fd7ddc 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -1,11 +1,13 @@ -<html xmlns="http://www.w3.org/1999/xhtml"> +<!DOCTYPE html> +<html lang="en">  <head> +  <meta charset="utf-8" />    <title>Action Controller: Exception caught</title>    <style>      body { background-color: #fff; color: #333; }      body, p, ol, ul, td { -      font-family: verdana, arial, helvetica, sans-serif; +      font-family: helvetica, verdana, arial, sans-serif;        font-size:   13px;        line-height: 18px;      } diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 0a3bd5fe40..f51cc3711b 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -9,10 +9,12 @@ module ActionDispatch      config.action_dispatch.show_exceptions = true      config.action_dispatch.best_standards_support = true      config.action_dispatch.tld_length = 1 +    config.action_dispatch.ignore_accept_header = false      config.action_dispatch.rack_cache = {:metastore => "rails:/", :entitystore => "rails:/", :verbose => true}      initializer "action_dispatch.configure" do |app|        ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length +      ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header      end    end  end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index b28f6c2297..97e8ccc9a5 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -3,6 +3,7 @@ require 'forwardable'  require 'active_support/core_ext/object/blank'  require 'active_support/core_ext/object/to_query'  require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/module/remove_method'  module ActionDispatch    module Routing @@ -160,7 +161,7 @@ module ActionDispatch              # We use module_eval to avoid leaks              @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 -              remove_method :#{selector} if method_defined?(:#{selector}) +              remove_possible_method :#{selector}                def #{selector}(*args)                  options = args.extract_options! @@ -194,7 +195,7 @@ module ActionDispatch              hash_access_method = hash_access_name(name, kind)              @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 -              remove_method :#{selector} if method_defined?(:#{selector}) +              remove_possible_method :#{selector}                def #{selector}(*args)                  url_for(#{hash_access_method}(*args))                end @@ -240,6 +241,11 @@ module ActionDispatch        end        def eval_block(block) +        if block.arity == 1 +          raise "You are using the old router DSL which has been removed in Rails 3.1. " << +            "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/ " << +            "or add the rails_legacy_mapper gem to your Gemfile" +        end          mapper = Mapper.new(self)          if default_scope            mapper.with_default_scope(default_scope, &block) @@ -275,8 +281,7 @@ module ActionDispatch        module MountedHelpers        end -      def mounted_helpers(name = :main_app) -        define_mounted_helper(name) if name +      def mounted_helpers          MountedHelpers        end diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 8a04cfa886..3335742d47 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -42,7 +42,7 @@ module ActionDispatch          elsif type.is_a?(Symbol) && @response.response_code == Rack::Utils::SYMBOL_TO_STATUS_CODE[type]            assert_block("") { true } # to count the assertion          else -          assert_block(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) { false } +          flunk(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code))          end        end | 
