aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/middleware
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/middleware')
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb35
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb24
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb76
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb24
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb58
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb8
8 files changed, 165 insertions, 72 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 0bb950d1cc..1bb2ad7f67 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -1,32 +1,14 @@
+require 'active_support/core_ext/module/delegation'
+
module ActionDispatch
# Provide callbacks to be executed before and after the request dispatch.
- #
- # It also provides a to_prepare callback, which is performed in all requests
- # in development by only once in production and notification callback for async
- # operations.
- #
class Callbacks
include ActiveSupport::Callbacks
define_callbacks :call, :rescuable => true
- define_callbacks :prepare, :scope => :name
- # Add a preparation callback. Preparation callbacks are run before every
- # request in development mode, and before the first request in production mode.
- #
- # If a symbol with a block is given, the symbol is used as an identifier.
- # That allows to_prepare to be called again with the same identifier to
- # replace the existing callback. Passing an identifier is a suggested
- # practice if the code adding a preparation block may be reloaded.
- def self.to_prepare(*args, &block)
- first_arg = args.first
- if first_arg.is_a?(Symbol) && block_given?
- remove_method :"__#{first_arg}" if method_defined?(:"__#{first_arg}")
- define_method :"__#{first_arg}", &block
- set_callback(:prepare, :"__#{first_arg}")
- else
- set_callback(:prepare, *args, &block)
- end
+ class << self
+ delegate :to_prepare, :to_cleanup, :to => "ActionDispatch::Reloader"
end
def self.before(*args, &block)
@@ -37,14 +19,13 @@ module ActionDispatch
set_callback(:call, :after, *args, &block)
end
- def initialize(app, prepare_each_request = false)
- @app, @prepare_each_request = app, prepare_each_request
- _run_prepare_callbacks
+ def initialize(app, unused = nil)
+ ActiveSupport::Deprecation.warn "Passing a second argument to ActionDispatch::Callbacks.new is deprecated." unless unused.nil?
+ @app = app
end
def call(env)
- _run_call_callbacks do
- _run_prepare_callbacks if @prepare_each_request
+ run_callbacks :call do
@app.call(env)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index b0a4e3d949..7ac608f0a8 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -90,17 +90,14 @@ module ActionDispatch
# **.**, ***.** style TLDs like co.uk or com.au
#
# www.example.co.uk gives:
- # $1 => example
- # $2 => co.uk
+ # $& => example.co.uk
#
# example.com gives:
- # $1 => example
- # $2 => com
+ # $& => example.com
#
# lots.of.subdomains.example.local gives:
- # $1 => example
- # $2 => local
- DOMAIN_REGEXP = /([^.]*)\.([^.]*|..\...|...\...)$/
+ # $& => example.local
+ DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
def self.build(request)
secret = request.env[TOKEN_KEY]
@@ -131,8 +128,17 @@ module ActionDispatch
options[:path] ||= "/"
if options[:domain] == :all
- @host =~ DOMAIN_REGEXP
- options[:domain] = ".#{$1}.#{$2}"
+ # if there is a provided tld length then we use it otherwise default domain regexp
+ domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
+
+ # if host is not ip and matches domain regexp
+ # (ip confirms to domain regexp so we explicitly check for ip)
+ options[:domain] = if (@host !~ /^[\d.]+$/) && (@host =~ domain_regexp)
+ ".#{$&}"
+ end
+ elsif options[:domain].is_a? Array
+ # if host matches one of the supplied domains without a dot in front of it
+ options[:domain] = options[:domain].find {|domain| @host.include? domain[/^\.?(.*)$/, 1] }
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
new file mode 100644
index 0000000000..29289a76b4
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -0,0 +1,76 @@
+module ActionDispatch
+ # ActionDispatch::Reloader provides prepare and cleanup callbacks,
+ # intended to assist with code reloading during development.
+ #
+ # Prepare callbacks are run before each request, and cleanup callbacks
+ # after each request. In this respect they are analogs of ActionDispatch::Callback's
+ # before and after callbacks. However, cleanup callbacks are not called until the
+ # request is fully complete -- that is, after #close has been called on
+ # the response body. This is important for streaming responses such as the
+ # following:
+ #
+ # self.response_body = lambda { |response, output|
+ # # code here which refers to application models
+ # }
+ #
+ # Cleanup callbacks will not be called until after the response_body lambda
+ # is evaluated, ensuring that it can refer to application models and other
+ # classes before they are unloaded.
+ #
+ # By default, ActionDispatch::Reloader is included in the middleware stack
+ # only in the development environment; specifically, when config.cache_classes
+ # is false. Callbacks may be registered even when it is not included in the
+ # middleware stack, but are executed only when +ActionDispatch::Reloader.prepare!+
+ # or +ActionDispatch::Reloader.cleanup!+ are called manually.
+ #
+ class Reloader
+ include ActiveSupport::Callbacks
+
+ define_callbacks :prepare, :scope => :name
+ define_callbacks :cleanup, :scope => :name
+
+ # Add a prepare callback. Prepare callbacks are run before each request, prior
+ # to ActionDispatch::Callback's before callbacks.
+ def self.to_prepare(*args, &block)
+ set_callback(:prepare, *args, &block)
+ end
+
+ # Add a cleanup callback. Cleanup callbacks are run after each request is
+ # complete (after #close is called on the response body).
+ def self.to_cleanup(*args, &block)
+ set_callback(:cleanup, *args, &block)
+ end
+
+ # Execute all prepare callbacks.
+ def self.prepare!
+ new(nil).run_callbacks :prepare
+ end
+
+ # Execute all cleanup callbacks.
+ def self.cleanup!
+ new(nil).run_callbacks :cleanup
+ end
+
+ def initialize(app)
+ @app = app
+ end
+
+ module CleanupOnClose
+ def close
+ super if defined?(super)
+ ensure
+ ActionDispatch::Reloader.cleanup!
+ end
+ end
+
+ def call(env)
+ run_callbacks :prepare
+ response = @app.call(env)
+ response[2].extend(CleanupOnClose)
+ response
+ rescue Exception
+ run_callbacks :cleanup
+ raise
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 71e736ce9f..dbe3206808 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -43,20 +43,20 @@ module ActionDispatch
end
def call(env)
- status, headers, body = @app.call(env)
-
- # Only this middleware cares about RoutingError. So, let's just raise
- # it here.
- # TODO: refactor this middleware to handle the X-Cascade scenario without
- # having to raise an exception.
- if headers['X-Cascade'] == 'pass'
- raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
+ begin
+ status, headers, body = @app.call(env)
+ exception = nil
+
+ # 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}"
+ end
+ rescue Exception => exception
+ raise exception if env['action_dispatch.show_exceptions'] == false
end
- [status, headers, body]
- rescue Exception => exception
- raise exception if env['action_dispatch.show_exceptions'] == false
- render_exception(env, exception)
+ exception ? render_exception(env, exception) : [status, headers, body]
end
private
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index e3cd779756..a4308f528c 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -2,17 +2,26 @@ require "active_support/inflector/methods"
require "active_support/dependencies"
module ActionDispatch
- class MiddlewareStack < Array
+ class MiddlewareStack
class Middleware
- attr_reader :args, :block
+ attr_reader :args, :block, :name, :classcache
def initialize(klass_or_name, *args, &block)
- @ref = ActiveSupport::Dependencies::Reference.new(klass_or_name)
+ @klass = nil
+
+ if klass_or_name.respond_to?(:name)
+ @klass = klass_or_name
+ @name = @klass.name
+ else
+ @name = klass_or_name.to_s
+ end
+
+ @classcache = ActiveSupport::Dependencies::Reference
@args, @block = args, block
end
def klass
- @ref.get
+ @klass || classcache[@name]
end
def ==(middleware)
@@ -22,7 +31,7 @@ module ActionDispatch
when Class
klass == middleware
else
- normalize(@ref.name) == normalize(middleware)
+ normalize(@name) == normalize(middleware)
end
end
@@ -41,18 +50,39 @@ module ActionDispatch
end
end
- # Use this instead of super to work around a warning.
- alias :array_initialize :initialize
+ include Enumerable
+
+ attr_accessor :middlewares
def initialize(*args)
- array_initialize(*args)
+ @middlewares = []
yield(self) if block_given?
end
+ def each
+ @middlewares.each { |x| yield x }
+ end
+
+ def size
+ middlewares.size
+ end
+
+ def last
+ middlewares.last
+ end
+
+ def [](i)
+ middlewares[i]
+ end
+
+ def initialize_copy(other)
+ self.middlewares = other.middlewares.dup
+ end
+
def insert(index, *args, &block)
index = assert_index(index, :before)
middleware = self.class::Middleware.new(*args, &block)
- super(index, middleware)
+ middlewares.insert(index, middleware)
end
alias_method :insert_before, :insert
@@ -67,21 +97,25 @@ module ActionDispatch
delete(target)
end
+ def delete(target)
+ middlewares.delete target
+ end
+
def use(*args, &block)
middleware = self.class::Middleware.new(*args, &block)
- push(middleware)
+ middlewares.push(middleware)
end
def build(app = nil, &block)
app ||= block
raise "MiddlewareStack#build requires an app" unless app
- reverse.inject(app) { |a, e| e.build(a) }
+ middlewares.reverse.inject(app) { |a, e| e.build(a) }
end
protected
def assert_index(index, where)
- i = index.is_a?(Integer) ? index : self.index(index)
+ i = index.is_a?(Integer) ? index : middlewares.index(index)
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
i
end
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 913b899e20..c57f694c4d 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -3,10 +3,10 @@ require 'rack/utils'
module ActionDispatch
class FileHandler
def initialize(at, root)
- @at, @root = at.chomp('/'), root.chomp('/')
- @compiled_at = (Regexp.compile(/^#{Regexp.escape(at)}/) unless @at.blank?)
- @compiled_root = Regexp.compile(/^#{Regexp.escape(root)}/)
- @file_server = ::Rack::File.new(@root)
+ @at, @root = at.chomp('/'), root.chomp('/')
+ @compiled_at = @at.blank? ? nil : /^#{Regexp.escape(at)}/
+ @compiled_root = /^#{Regexp.escape(root)}/
+ @file_server = ::Rack::File.new(@root)
end
def match?(path)
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
index bd6ffbab5d..50d8ca9484 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
@@ -6,5 +6,5 @@
</h1>
<pre><%=h @exception.message %></pre>
-<%= render :file => "rescues/_trace.erb" %>
-<%= render :file => "rescues/_request_and_response.erb" %>
+<%= render :template => "rescues/_trace" %>
+<%= render :template => "rescues/_request_and_response" %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb
index 02fa18211d..c658559be9 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb
@@ -13,9 +13,5 @@
<p><%=h @exception.sub_template_message %></p>
-<% @real_exception = @exception
- @exception = @exception.original_exception || @exception %>
-<%= render :file => "rescues/_trace.erb" %>
-<% @exception = @real_exception %>
-
-<%= render :file => "rescues/_request_and_response.erb" %>
+<%= render :template => "rescues/_trace" %>
+<%= render :template => "rescues/_request_and_response" %>