Merge commit 'mainstream/master'
Conflicts: actionpack/lib/action_controller/base/mime_responds.rb
This commit is contained in:
commit
7324e46a3f
4
Rakefile
4
Rakefile
@ -15,9 +15,11 @@ task :default => :test
|
||||
%w(test isolated_test rdoc pgem package release).each do |task_name|
|
||||
desc "Run #{task_name} task for all projects"
|
||||
task task_name do
|
||||
errors = []
|
||||
PROJECTS.each do |project|
|
||||
system %(cd #{project} && #{env} #{$0} #{task_name})
|
||||
system(%(cd #{project} && #{env} #{$0} #{task_name})) || errors << project
|
||||
end
|
||||
fail("Errors in #{errors.join(', ')}") unless errors.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
require File.dirname(__FILE__) + '/abstract_unit'
|
||||
require 'abstract_unit'
|
||||
require 'action_mailer/adv_attr_accessor'
|
||||
|
||||
class AdvAttrTest < Test::Unit::TestCase
|
||||
@ -15,6 +15,4 @@ def test_adv_attr
|
||||
|
||||
assert_raise(ArgumentError) {bob.name 'x', 'y'}
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
@ -1,5 +1,12 @@
|
||||
*Edge*
|
||||
|
||||
* Change integration test helpers to accept Rack environment instead of just HTTP Headers [Pratik Naik]
|
||||
|
||||
Before : get '/path', {}, 'Accept' => 'text/javascript'
|
||||
After : get '/path', {}, 'HTTP_ACCEPT' => 'text/javascript'
|
||||
|
||||
* Instead of checking Rails.env.test? in Failsafe middleware, check env["rails.raise_exceptions"] [Bryan Helmkamp]
|
||||
|
||||
* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes]
|
||||
|
||||
|
||||
|
@ -22,14 +22,15 @@ task :default => [ :test ]
|
||||
# Run the unit tests
|
||||
|
||||
desc "Run all unit tests"
|
||||
task :test => [:test_action_pack, :test_active_record_integration, :test_new_base]
|
||||
task :test => [:test_action_pack, :test_active_record_integration, :test_new_base, :test_new_base_on_old_tests]
|
||||
|
||||
test_lib_dirs = [ENV["NEW"] ? "test/new_base" : "test", "test/lib"]
|
||||
Rake::TestTask.new(:test_action_pack) do |t|
|
||||
t.libs << "test"
|
||||
t.libs.concat test_lib_dirs
|
||||
|
||||
# make sure we include the tests in alphabetical order as on some systems
|
||||
# this will not happen automatically and the tests (as a whole) will error
|
||||
t.test_files = Dir.glob( "test/{controller,dispatch,template}/**/*_test.rb" ).sort
|
||||
t.test_files = Dir.glob( "test/{controller,dispatch,template,html-scanner}/**/*_test.rb" ).sort
|
||||
|
||||
t.verbose = true
|
||||
#t.warning = true
|
||||
@ -37,24 +38,46 @@ end
|
||||
task :isolated_test do
|
||||
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
|
||||
Dir.glob("test/{controller,dispatch,template}/**/*_test.rb").all? do |file|
|
||||
system(ruby, '-Ilib:test', file)
|
||||
system(ruby, "-Ilib:#{test_lib_dirs * ':'}", file)
|
||||
end or raise "Failures"
|
||||
end
|
||||
|
||||
desc 'ActiveRecord Integration Tests'
|
||||
Rake::TestTask.new(:test_active_record_integration) do |t|
|
||||
t.libs << "test"
|
||||
t.libs.concat test_lib_dirs
|
||||
t.test_files = Dir.glob("test/activerecord/*_test.rb")
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'New Controller Tests'
|
||||
Rake::TestTask.new(:test_new_base) do |t|
|
||||
t.libs << "test"
|
||||
t.libs << "test/new_base" << "test/lib"
|
||||
t.test_files = Dir.glob("test/{abstract_controller,new_base}/*_test.rb")
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Old Controller Tests on New Base'
|
||||
Rake::TestTask.new(:test_new_base_on_old_tests) do |t|
|
||||
t.libs << "test/new_base" << "test/lib"
|
||||
# layout
|
||||
# Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort +
|
||||
|
||||
# ==== Not ported
|
||||
# * filters
|
||||
# * integration
|
||||
# * test
|
||||
# * view_paths
|
||||
t.test_files = %w(
|
||||
action_pack_assertions addresses_render assert_select
|
||||
base benchmark caching capture content_type cookie dispatcher
|
||||
filter_params flash helper http_basic_authentication
|
||||
http_digest_authentication layout logging mime_responds
|
||||
record_identifier redirect render render_js render_json
|
||||
render_other render_xml request_forgery_protection rescue
|
||||
resources routing selector send_file url_rewriter verification webservice
|
||||
).map { |name| "test/controller/#{name}_test.rb" }
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
# Genereate the RDoc documentation
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
# Pass NEW=1 to run with the new Base
|
||||
ENV['RAILS_ENV'] ||= 'production'
|
||||
ENV['NO_RELOAD'] ||= '1'
|
||||
|
||||
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
||||
require 'action_controller'
|
||||
require 'action_controller/new_base' if ENV['NEW']
|
||||
@ -9,26 +13,30 @@ def index
|
||||
end
|
||||
end
|
||||
|
||||
n = (ENV['N'] || 10000).to_i
|
||||
input = StringIO.new('')
|
||||
|
||||
def call_index(controller, input, n)
|
||||
n.times do
|
||||
controller.action(:index).call({ 'rack.input' => input })
|
||||
class Runner
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
puts controller.name
|
||||
status, headers, body = controller.action(:index).call({ 'rack.input' => input })
|
||||
|
||||
puts status
|
||||
puts headers.to_yaml
|
||||
puts '---'
|
||||
body.each do |part|
|
||||
puts part
|
||||
def call(env)
|
||||
env['n'].to_i.times { @app.call(env) }
|
||||
@app.call(env).tap { |response| report(env, response) }
|
||||
end
|
||||
|
||||
def report(env, response)
|
||||
out = env['rack.errors']
|
||||
out.puts response[0], response[1].to_yaml, '---'
|
||||
response[2].each { |part| out.puts part }
|
||||
out.puts '---'
|
||||
end
|
||||
puts '---'
|
||||
end
|
||||
|
||||
elapsed = Benchmark.realtime { call_index BaseController, input, n }
|
||||
n = (ENV['N'] || 1000).to_i
|
||||
input = StringIO.new('')
|
||||
|
||||
puts "%dms elapsed, %d requests/sec" % [1000 * elapsed, n / elapsed]
|
||||
elapsed = Benchmark.realtime do
|
||||
Runner.new(BaseController.action(:index)).
|
||||
call('n' => n, 'rack.input' => input, 'rack.errors' => $stdout)
|
||||
end
|
||||
puts "%dms elapsed, %d req/sec, %.2f msec/req" %
|
||||
[1000 * elapsed, n / elapsed, 1000 * elapsed / n]
|
||||
|
@ -66,6 +66,7 @@ def self.load_all!
|
||||
autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
|
||||
autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
|
||||
autoload :Verification, 'action_controller/base/verification'
|
||||
autoload :FilterParameterLogging, 'action_controller/base/filter_parameter_logging'
|
||||
|
||||
module Assertions
|
||||
autoload :DomAssertions, 'action_controller/testing/assertions/dom'
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
module AbstractController
|
||||
autoload :Base, "action_controller/abstract/base"
|
||||
autoload :Benchmarker, "action_controller/abstract/benchmarker"
|
||||
autoload :Callbacks, "action_controller/abstract/callbacks"
|
||||
autoload :Helpers, "action_controller/abstract/helpers"
|
||||
autoload :Layouts, "action_controller/abstract/layouts"
|
||||
|
@ -68,11 +68,11 @@ def initialize
|
||||
self.response_obj = {}
|
||||
end
|
||||
|
||||
def process(action_name)
|
||||
@_action_name = action_name = action_name.to_s
|
||||
def process(action)
|
||||
@_action_name = action_name = action.to_s
|
||||
|
||||
unless action_name = method_for_action(action_name)
|
||||
raise ActionNotFound, "The action '#{action_name}' could not be found"
|
||||
raise ActionNotFound, "The action '#{action}' could not be found"
|
||||
end
|
||||
|
||||
process_action(action_name)
|
||||
|
28
actionpack/lib/action_controller/abstract/benchmarker.rb
Normal file
28
actionpack/lib/action_controller/abstract/benchmarker.rb
Normal file
@ -0,0 +1,28 @@
|
||||
module AbstractController
|
||||
module Benchmarker
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
depends_on Logger
|
||||
|
||||
module ClassMethods
|
||||
def benchmark(title, log_level = ::Logger::DEBUG, use_silence = true)
|
||||
if logger && logger.level >= log_level
|
||||
result = nil
|
||||
ms = Benchmark.ms { result = use_silence ? silence { yield } : yield }
|
||||
logger.add(log_level, "#{title} (#{('%.1f' % ms)}ms)")
|
||||
result
|
||||
else
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
# Silences the logger for the duration of the block.
|
||||
def silence
|
||||
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
|
||||
yield
|
||||
ensure
|
||||
logger.level = old_logger_level if logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -36,6 +36,17 @@ def #{filter}_filter(*names, &blk)
|
||||
process_action_callback(:#{filter}, name, options)
|
||||
end
|
||||
end
|
||||
|
||||
def skip_#{filter}_filter(*names, &blk)
|
||||
options = names.last.is_a?(Hash) ? names.pop : {}
|
||||
_normalize_callback_options(options)
|
||||
names.push(blk) if block_given?
|
||||
names.each do |name|
|
||||
skip_process_action_callback(:#{filter}, name, options)
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :append_#{filter}_filter, :#{filter}_filter
|
||||
RUBY_EVAL
|
||||
end
|
||||
end
|
||||
|
@ -24,11 +24,30 @@ def inherited(klass)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
|
||||
# Makes all the (instance) methods in the helper module available to templates rendered through this controller.
|
||||
# See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
|
||||
# available to the templates.
|
||||
def add_template_helper(mod)
|
||||
master_helper_module.module_eval { include mod }
|
||||
end
|
||||
|
||||
|
||||
# Declare a controller method as a helper. For example, the following
|
||||
# makes the +current_user+ controller method available to the view:
|
||||
# class ApplicationController < ActionController::Base
|
||||
# helper_method :current_user, :logged_in?
|
||||
#
|
||||
# def current_user
|
||||
# @current_user ||= User.find_by_id(session[:user])
|
||||
# end
|
||||
#
|
||||
# def logged_in?
|
||||
# current_user != nil
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# In a view:
|
||||
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
||||
def helper_method(*meths)
|
||||
meths.flatten.each do |meth|
|
||||
master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
|
||||
@ -39,14 +58,14 @@ def #{meth}(*args, &blk)
|
||||
end
|
||||
end
|
||||
|
||||
def helper(*args, &blk)
|
||||
def helper(*args, &block)
|
||||
args.flatten.each do |arg|
|
||||
case arg
|
||||
when Module
|
||||
add_template_helper(arg)
|
||||
end
|
||||
end
|
||||
master_helper_module.module_eval(&blk) if block_given?
|
||||
master_helper_module.module_eval(&block) if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -4,11 +4,19 @@ module Layouts
|
||||
|
||||
depends_on Renderer
|
||||
|
||||
included do
|
||||
extlib_inheritable_accessor :_layout_conditions
|
||||
self._layout_conditions = {}
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def layout(layout)
|
||||
def layout(layout, conditions = {})
|
||||
unless [String, Symbol, FalseClass, NilClass].include?(layout.class)
|
||||
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
|
||||
end
|
||||
|
||||
conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
|
||||
self._layout_conditions = conditions
|
||||
|
||||
@_layout = layout || false # Converts nil to false
|
||||
_write_layout_method
|
||||
@ -31,15 +39,15 @@ def _implied_layout_name
|
||||
def _write_layout_method
|
||||
case @_layout
|
||||
when String
|
||||
self.class_eval %{def _layout() #{@_layout.inspect} end}
|
||||
self.class_eval %{def _layout(details) #{@_layout.inspect} end}
|
||||
when Symbol
|
||||
self.class_eval %{def _layout() #{@_layout} end}
|
||||
self.class_eval %{def _layout(details) #{@_layout} end}
|
||||
when false
|
||||
self.class_eval %{def _layout() end}
|
||||
self.class_eval %{def _layout(details) end}
|
||||
else
|
||||
self.class_eval %{
|
||||
def _layout
|
||||
if view_paths.find_by_parts?("#{_implied_layout_name}", {:formats => formats}, "layouts")
|
||||
def _layout(details)
|
||||
if view_paths.find_by_parts?("#{_implied_layout_name}", details, "layouts")
|
||||
"#{_implied_layout_name}"
|
||||
else
|
||||
super
|
||||
@ -49,38 +57,50 @@ def _layout
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def _render_template(template, options)
|
||||
_action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _layout() end # This will be overwritten
|
||||
def _layout(details) end # This will be overwritten
|
||||
|
||||
# :api: plugin
|
||||
# ====
|
||||
# Override this to mutate the inbound layout name
|
||||
def _layout_for_name(name)
|
||||
def _layout_for_name(name, details = {:formats => formats})
|
||||
unless [String, FalseClass, NilClass].include?(name.class)
|
||||
raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}"
|
||||
end
|
||||
|
||||
name && view_paths.find_by_parts(name, {:formats => formats}, "layouts")
|
||||
name && view_paths.find_by_parts(name, details, _layout_prefix(name))
|
||||
end
|
||||
|
||||
# TODO: Decide if this is the best hook point for the feature
|
||||
def _layout_prefix(name)
|
||||
"layouts"
|
||||
end
|
||||
|
||||
def _default_layout(require_layout = false)
|
||||
if require_layout && !_layout
|
||||
def _default_layout(require_layout = false, details = {:formats => formats})
|
||||
if require_layout && _action_has_layout? && !_layout(details)
|
||||
raise ArgumentError,
|
||||
"There was no default layout for #{self.class} in #{view_paths.inspect}"
|
||||
end
|
||||
|
||||
begin
|
||||
layout = _layout_for_name(_layout)
|
||||
_layout_for_name(_layout(details), details) if _action_has_layout?
|
||||
rescue NameError => e
|
||||
raise NoMethodError,
|
||||
"You specified #{@_layout.inspect} as the layout, but no such method was found"
|
||||
end
|
||||
end
|
||||
|
||||
def _action_has_layout?
|
||||
conditions = _layout_conditions
|
||||
if only = conditions[:only]
|
||||
only.include?(action_name)
|
||||
elsif except = conditions[:except]
|
||||
!except.include?(action_name)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,4 +1,5 @@
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
require 'active_support/core_ext/logger'
|
||||
|
||||
module AbstractController
|
||||
module Logger
|
||||
|
@ -33,16 +33,12 @@ def render(*args)
|
||||
#
|
||||
# :api: plugin
|
||||
def render_to_body(options = {})
|
||||
name = options[:_template_name] || action_name
|
||||
|
||||
# TODO: Refactor so we can just use the normal template logic for this
|
||||
if options[:_partial_object]
|
||||
_action_view._render_partial_from_controller(options)
|
||||
else
|
||||
options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats},
|
||||
options[:_prefix], options[:_partial])
|
||||
|
||||
_render_template(options[:_template], options)
|
||||
else
|
||||
_determine_template(options)
|
||||
_render_template(options)
|
||||
end
|
||||
end
|
||||
|
||||
@ -56,8 +52,8 @@ def render_to_string(options = {})
|
||||
AbstractController::Renderer.body_to_s(render_to_body(options))
|
||||
end
|
||||
|
||||
def _render_template(template, options)
|
||||
_action_view._render_template_from_controller(template, nil, options, options[:_partial])
|
||||
def _render_template(options)
|
||||
_action_view._render_template_from_controller(options[:_template], options[:_layout], options, options[:_partial])
|
||||
end
|
||||
|
||||
def view_paths() _view_paths end
|
||||
@ -74,6 +70,16 @@ def self.body_to_s(body)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _determine_template(options)
|
||||
name = (options[:_template_name] || action_name).to_s
|
||||
|
||||
options[:_template] ||= view_paths.find_by_parts(
|
||||
name, { :formats => formats }, options[:_prefix], options[:_partial]
|
||||
)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
def append_view_path(path)
|
||||
|
@ -242,7 +242,6 @@ class Base
|
||||
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
|
||||
# and images to a dedicated asset server away from the main web server. Example:
|
||||
# ActionController::Base.asset_host = "http://assets.example.com"
|
||||
@@asset_host = ""
|
||||
cattr_accessor :asset_host
|
||||
|
||||
# All requests are considered local by default, so everyone will be exposed to detailed debugging screens on errors.
|
||||
@ -368,9 +367,8 @@ def session
|
||||
attr_reader :template
|
||||
|
||||
def action(name, env)
|
||||
# HACK: For global rescue to have access to the original request and response
|
||||
request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
|
||||
response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
|
||||
request = ActionDispatch::Request.new(env)
|
||||
response = ActionDispatch::Response.new
|
||||
self.action_name = name && name.to_s
|
||||
process(request, response).to_a
|
||||
end
|
||||
@ -449,55 +447,6 @@ def append_view_path(path)
|
||||
@view_paths = superclass.view_paths.dup if @view_paths.nil?
|
||||
@view_paths.push(*path)
|
||||
end
|
||||
|
||||
# Replace sensitive parameter data from the request log.
|
||||
# Filters parameters that have any of the arguments as a substring.
|
||||
# Looks in all subhashes of the param hash for keys to filter.
|
||||
# If a block is given, each key and value of the parameter hash and all
|
||||
# subhashes is passed to it, the value or key
|
||||
# can be replaced using String#replace or similar method.
|
||||
#
|
||||
# Examples:
|
||||
# filter_parameter_logging
|
||||
# => Does nothing, just slows the logging process down
|
||||
#
|
||||
# filter_parameter_logging :password
|
||||
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
||||
#
|
||||
# filter_parameter_logging :foo, "bar"
|
||||
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
||||
#
|
||||
# filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
|
||||
# => reverses the value to all keys matching /secret/i
|
||||
#
|
||||
# filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
|
||||
# => reverses the value to all keys matching /secret/i, and
|
||||
# replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
||||
def filter_parameter_logging(*filter_words, &block)
|
||||
parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
|
||||
|
||||
define_method(:filter_parameters) do |unfiltered_parameters|
|
||||
filtered_parameters = {}
|
||||
|
||||
unfiltered_parameters.each do |key, value|
|
||||
if key =~ parameter_filter
|
||||
filtered_parameters[key] = '[FILTERED]'
|
||||
elsif value.is_a?(Hash)
|
||||
filtered_parameters[key] = filter_parameters(value)
|
||||
elsif block_given?
|
||||
key = key.dup
|
||||
value = value.dup if value
|
||||
yield key, value
|
||||
filtered_parameters[key] = value
|
||||
else
|
||||
filtered_parameters[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
filtered_parameters
|
||||
end
|
||||
protected :filter_parameters
|
||||
end
|
||||
|
||||
@@exempt_from_layout = [ActionView::TemplateHandlers::RJS]
|
||||
|
||||
@ -854,13 +803,6 @@ def log_processing_for_request_id
|
||||
logger.info(request_id)
|
||||
end
|
||||
|
||||
def log_processing_for_parameters
|
||||
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
|
||||
parameters = parameters.except!(:controller, :action, :format, :_method)
|
||||
|
||||
logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
|
||||
end
|
||||
|
||||
def default_render #:nodoc:
|
||||
render
|
||||
end
|
||||
@ -934,7 +876,7 @@ def process_cleanup
|
||||
[ Filters, Layout, Renderer, Redirector, Responder, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
|
||||
Cookies, Caching, Verification, Streaming, SessionManagement,
|
||||
HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, RecordIdentifier,
|
||||
RequestForgeryProtection, Translation
|
||||
RequestForgeryProtection, Translation, FilterParameterLogging
|
||||
].each do |mod|
|
||||
include mod
|
||||
end
|
||||
|
@ -21,7 +21,7 @@ module ClassMethods
|
||||
# easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
|
||||
# will only be conducted if the log level is low enough.
|
||||
def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
|
||||
if logger && logger.level == log_level
|
||||
if logger && logger.level >= log_level
|
||||
result = nil
|
||||
ms = Benchmark.ms { result = use_silence ? silence { yield } : yield }
|
||||
logger.add(log_level, "#{title} (#{('%.1f' % ms)}ms)")
|
||||
|
@ -571,12 +571,7 @@ def skip_filter(*filters)
|
||||
|
||||
# Returns an array of Filter objects for this controller.
|
||||
def filter_chain
|
||||
if chain = read_inheritable_attribute('filter_chain')
|
||||
return chain
|
||||
else
|
||||
write_inheritable_attribute('filter_chain', FilterChain.new)
|
||||
return filter_chain
|
||||
end
|
||||
read_inheritable_attribute('filter_chain') || write_inheritable_attribute('filter_chain', FilterChain.new)
|
||||
end
|
||||
|
||||
# Returns all the before filters for this class and all its ancestors.
|
||||
|
@ -26,9 +26,18 @@ module ActionController #:nodoc:
|
||||
#
|
||||
# See docs on the FlashHash class for more details about the flash.
|
||||
module Flash
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
include InstanceMethods
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
depends_on Session if defined?(ActionController::Http)
|
||||
|
||||
included do
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
if defined?(ActionController::Http)
|
||||
include InstanceMethodsForNewBase
|
||||
else
|
||||
include InstanceMethodsForBase
|
||||
|
||||
alias_method_chain :perform_action, :flash
|
||||
alias_method_chain :reset_session, :flash
|
||||
end
|
||||
@ -135,29 +144,50 @@ def use(k=nil, v=true)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods #:nodoc:
|
||||
module InstanceMethodsForBase #:nodoc:
|
||||
protected
|
||||
def perform_action_with_flash
|
||||
perform_action_without_flash
|
||||
remove_instance_variable(:@_flash) if defined? @_flash
|
||||
end
|
||||
|
||||
def reset_session_with_flash
|
||||
reset_session_without_flash
|
||||
remove_instance_variable(:@_flash) if defined? @_flash
|
||||
end
|
||||
def perform_action_with_flash
|
||||
perform_action_without_flash
|
||||
remove_instance_variable(:@_flash) if defined?(@_flash)
|
||||
end
|
||||
|
||||
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
|
||||
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
|
||||
# to put a new one.
|
||||
def flash #:doc:
|
||||
unless defined? @_flash
|
||||
@_flash = session["flash"] ||= FlashHash.new
|
||||
@_flash.sweep
|
||||
end
|
||||
def reset_session_with_flash
|
||||
reset_session_without_flash
|
||||
remove_instance_variable(:@_flash) if defined?(@_flash)
|
||||
end
|
||||
end
|
||||
|
||||
@_flash
|
||||
end
|
||||
module InstanceMethodsForNewBase #:nodoc:
|
||||
protected
|
||||
|
||||
def reset_session
|
||||
super
|
||||
remove_flash_instance_variable
|
||||
end
|
||||
|
||||
def process_action(method_name)
|
||||
super
|
||||
remove_flash_instance_variable
|
||||
end
|
||||
|
||||
def remove_flash_instance_variable
|
||||
remove_instance_variable(:@_flash) if defined?(@_flash)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
|
||||
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
|
||||
# to put a new one.
|
||||
def flash #:doc:
|
||||
unless defined?(@_flash)
|
||||
@_flash = session["flash"] ||= FlashHash.new
|
||||
@_flash.sweep
|
||||
end
|
||||
|
||||
@_flash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,97 @@
|
||||
module ActionController
|
||||
module FilterParameterLogging
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
if defined?(ActionController::Http)
|
||||
depends_on AbstractController::Logger
|
||||
end
|
||||
|
||||
included do
|
||||
if defined?(ActionController::Http)
|
||||
include InstanceMethodsForNewBase
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Replace sensitive parameter data from the request log.
|
||||
# Filters parameters that have any of the arguments as a substring.
|
||||
# Looks in all subhashes of the param hash for keys to filter.
|
||||
# If a block is given, each key and value of the parameter hash and all
|
||||
# subhashes is passed to it, the value or key
|
||||
# can be replaced using String#replace or similar method.
|
||||
#
|
||||
# Examples:
|
||||
# filter_parameter_logging
|
||||
# => Does nothing, just slows the logging process down
|
||||
#
|
||||
# filter_parameter_logging :password
|
||||
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
||||
#
|
||||
# filter_parameter_logging :foo, "bar"
|
||||
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
||||
#
|
||||
# filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
|
||||
# => reverses the value to all keys matching /secret/i
|
||||
#
|
||||
# filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
|
||||
# => reverses the value to all keys matching /secret/i, and
|
||||
# replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
||||
def filter_parameter_logging(*filter_words, &block)
|
||||
parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
|
||||
|
||||
define_method(:filter_parameters) do |unfiltered_parameters|
|
||||
filtered_parameters = {}
|
||||
|
||||
unfiltered_parameters.each do |key, value|
|
||||
if key =~ parameter_filter
|
||||
filtered_parameters[key] = '[FILTERED]'
|
||||
elsif value.is_a?(Hash)
|
||||
filtered_parameters[key] = filter_parameters(value)
|
||||
elsif block_given?
|
||||
key = key.dup
|
||||
value = value.dup if value
|
||||
yield key, value
|
||||
filtered_parameters[key] = value
|
||||
else
|
||||
filtered_parameters[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
filtered_parameters
|
||||
end
|
||||
protected :filter_parameters
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethodsForNewBase
|
||||
# TODO : Fix the order of information inside such that it's exactly same as the old base
|
||||
def process(*)
|
||||
ret = super
|
||||
|
||||
if logger
|
||||
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
|
||||
parameters = parameters.except!(:controller, :action, :format, :_method, :only_path)
|
||||
|
||||
unless parameters.empty?
|
||||
# TODO : Move DelayedLog to AS
|
||||
log = AbstractController::Logger::DelayedLog.new { " Parameters: #{parameters.inspect}" }
|
||||
logger.info(log)
|
||||
end
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# TODO : This method is not needed for the new base
|
||||
def log_processing_for_parameters
|
||||
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
|
||||
parameters = parameters.except!(:controller, :action, :format, :_method)
|
||||
|
||||
logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
|
||||
end
|
||||
end
|
||||
end
|
@ -3,23 +3,19 @@
|
||||
# FIXME: helper { ... } is broken on Ruby 1.9
|
||||
module ActionController #:nodoc:
|
||||
module Helpers #:nodoc:
|
||||
def self.included(base)
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
included do
|
||||
# Initialize the base module to aggregate its helpers.
|
||||
base.class_inheritable_accessor :master_helper_module
|
||||
base.master_helper_module = Module.new
|
||||
class_inheritable_accessor :master_helper_module
|
||||
self.master_helper_module = Module.new
|
||||
|
||||
# Set the default directory for helpers
|
||||
base.class_inheritable_accessor :helpers_dir
|
||||
base.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
|
||||
class_inheritable_accessor :helpers_dir
|
||||
self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
|
||||
|
||||
# Extend base with class methods to declare helpers.
|
||||
base.extend(ClassMethods)
|
||||
|
||||
base.class_eval do
|
||||
# Wrap inherited to create a new master helper module for subclasses.
|
||||
class << self
|
||||
alias_method_chain :inherited, :helper
|
||||
end
|
||||
class << self
|
||||
alias_method_chain :inherited, :helper
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -194,9 +194,10 @@ def validate_digest_response(request, realm, &password_procedure)
|
||||
|
||||
if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
|
||||
password = password_procedure.call(credentials[:username])
|
||||
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
|
||||
|
||||
[true, false].any? do |password_is_ha1|
|
||||
expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1)
|
||||
expected = expected_response(method, request.env['REQUEST_URI'], credentials, password, password_is_ha1)
|
||||
expected == credentials[:response]
|
||||
end
|
||||
end
|
||||
|
@ -1,123 +1,103 @@
|
||||
module ActionController #:nodoc:
|
||||
module MimeResponds #:nodoc:
|
||||
def self.included(base)
|
||||
base.module_eval do
|
||||
include ActionController::MimeResponds::InstanceMethods
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Without web-service support, an action which collects the data for displaying a list of people
|
||||
# might look something like this:
|
||||
#
|
||||
# def index
|
||||
# @people = Person.find(:all)
|
||||
# end
|
||||
#
|
||||
# Here's the same action, with web-service support baked in:
|
||||
#
|
||||
# def index
|
||||
# @people = Person.find(:all)
|
||||
#
|
||||
# respond_to do |format|
|
||||
# format.html
|
||||
# format.xml { render :xml => @people.to_xml }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# What that says is, "if the client wants HTML in response to this action, just respond as we
|
||||
# would have before, but if the client wants XML, return them the list of people in XML format."
|
||||
# (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
|
||||
#
|
||||
# Supposing you have an action that adds a new person, optionally creating their company
|
||||
# (by name) if it does not already exist, without web-services, it might look like this:
|
||||
#
|
||||
# def create
|
||||
# @company = Company.find_or_create_by_name(params[:company][:name])
|
||||
# @person = @company.people.create(params[:person])
|
||||
#
|
||||
# redirect_to(person_list_url)
|
||||
# end
|
||||
#
|
||||
# Here's the same action, with web-service support baked in:
|
||||
#
|
||||
# def create
|
||||
# company = params[:person].delete(:company)
|
||||
# @company = Company.find_or_create_by_name(company[:name])
|
||||
# @person = @company.people.create(params[:person])
|
||||
#
|
||||
# respond_to do |format|
|
||||
# format.html { redirect_to(person_list_url) }
|
||||
# format.js
|
||||
# format.xml { render :xml => @person.to_xml(:include => @company) }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# If the client wants HTML, we just redirect them back to the person list. If they want Javascript
|
||||
# (format.js), then it is an RJS request and we render the RJS template associated with this action.
|
||||
# Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
|
||||
# include the person's company in the rendered XML, so you get something like this:
|
||||
#
|
||||
# <person>
|
||||
# <id>...</id>
|
||||
# ...
|
||||
# <company>
|
||||
# <id>...</id>
|
||||
# <name>...</name>
|
||||
# ...
|
||||
# </company>
|
||||
# </person>
|
||||
#
|
||||
# Note, however, the extra bit at the top of that action:
|
||||
#
|
||||
# company = params[:person].delete(:company)
|
||||
# @company = Company.find_or_create_by_name(company[:name])
|
||||
#
|
||||
# This is because the incoming XML document (if a web-service request is in process) can only contain a
|
||||
# single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
|
||||
#
|
||||
# person[name]=...&person[company][name]=...&...
|
||||
#
|
||||
# And, like this (xml-encoded):
|
||||
#
|
||||
# <person>
|
||||
# <name>...</name>
|
||||
# <company>
|
||||
# <name>...</name>
|
||||
# </company>
|
||||
# </person>
|
||||
#
|
||||
# In other words, we make the request so that it operates on a single entity's person. Then, in the action,
|
||||
# we extract the company data from the request, find or create the company, and then create the new person
|
||||
# with the remaining data.
|
||||
#
|
||||
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
|
||||
# in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
|
||||
# and accept Rails' defaults, life will be much easier.
|
||||
#
|
||||
# Further more, you may call the #any method on the block's object in order to run the same code for different responses.
|
||||
# def index
|
||||
#
|
||||
# respond_to do |format|
|
||||
# format.html { @people = People.all(:limit => 10) }
|
||||
# format.any(:xml, :atom) { @people = People.all }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# This will limit the @people variable to 10 people records if we're requesting HTML, but will list all the
|
||||
# people for any xml or atom request.
|
||||
#
|
||||
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
|
||||
# environment.rb as follows.
|
||||
#
|
||||
# Mime::Type.register "image/jpg", :jpg
|
||||
def respond_to(*types, &block)
|
||||
raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
|
||||
block ||= lambda { |responder| types.each { |type| responder.send(type) } }
|
||||
responder = Responder.new(self)
|
||||
block.call(responder)
|
||||
responder.respond
|
||||
end
|
||||
# Without web-service support, an action which collects the data for displaying a list of people
|
||||
# might look something like this:
|
||||
#
|
||||
# def index
|
||||
# @people = Person.find(:all)
|
||||
# end
|
||||
#
|
||||
# Here's the same action, with web-service support baked in:
|
||||
#
|
||||
# def index
|
||||
# @people = Person.find(:all)
|
||||
#
|
||||
# respond_to do |format|
|
||||
# format.html
|
||||
# format.xml { render :xml => @people.to_xml }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# What that says is, "if the client wants HTML in response to this action, just respond as we
|
||||
# would have before, but if the client wants XML, return them the list of people in XML format."
|
||||
# (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
|
||||
#
|
||||
# Supposing you have an action that adds a new person, optionally creating their company
|
||||
# (by name) if it does not already exist, without web-services, it might look like this:
|
||||
#
|
||||
# def create
|
||||
# @company = Company.find_or_create_by_name(params[:company][:name])
|
||||
# @person = @company.people.create(params[:person])
|
||||
#
|
||||
# redirect_to(person_list_url)
|
||||
# end
|
||||
#
|
||||
# Here's the same action, with web-service support baked in:
|
||||
#
|
||||
# def create
|
||||
# company = params[:person].delete(:company)
|
||||
# @company = Company.find_or_create_by_name(company[:name])
|
||||
# @person = @company.people.create(params[:person])
|
||||
#
|
||||
# respond_to do |format|
|
||||
# format.html { redirect_to(person_list_url) }
|
||||
# format.js
|
||||
# format.xml { render :xml => @person.to_xml(:include => @company) }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# If the client wants HTML, we just redirect them back to the person list. If they want Javascript
|
||||
# (format.js), then it is an RJS request and we render the RJS template associated with this action.
|
||||
# Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
|
||||
# include the person's company in the rendered XML, so you get something like this:
|
||||
#
|
||||
# <person>
|
||||
# <id>...</id>
|
||||
# ...
|
||||
# <company>
|
||||
# <id>...</id>
|
||||
# <name>...</name>
|
||||
# ...
|
||||
# </company>
|
||||
# </person>
|
||||
#
|
||||
# Note, however, the extra bit at the top of that action:
|
||||
#
|
||||
# company = params[:person].delete(:company)
|
||||
# @company = Company.find_or_create_by_name(company[:name])
|
||||
#
|
||||
# This is because the incoming XML document (if a web-service request is in process) can only contain a
|
||||
# single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
|
||||
#
|
||||
# person[name]=...&person[company][name]=...&...
|
||||
#
|
||||
# And, like this (xml-encoded):
|
||||
#
|
||||
# <person>
|
||||
# <name>...</name>
|
||||
# <company>
|
||||
# <name>...</name>
|
||||
# </company>
|
||||
# </person>
|
||||
#
|
||||
# In other words, we make the request so that it operates on a single entity's person. Then, in the action,
|
||||
# we extract the company data from the request, find or create the company, and then create the new person
|
||||
# with the remaining data.
|
||||
#
|
||||
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
|
||||
# in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
|
||||
# and accept Rails' defaults, life will be much easier.
|
||||
#
|
||||
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
|
||||
# environment.rb as follows.
|
||||
#
|
||||
# Mime::Type.register "image/jpg", :jpg
|
||||
def respond_to(*types, &block)
|
||||
raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
|
||||
block ||= lambda { |responder| types.each { |type| responder.send(type) } }
|
||||
responder = Responder.new(self)
|
||||
block.call(responder)
|
||||
responder.respond
|
||||
end
|
||||
|
||||
class Responder #:nodoc:
|
||||
@ -139,8 +119,14 @@ def custom(mime_type, &block)
|
||||
@order << mime_type
|
||||
|
||||
@responses[mime_type] ||= Proc.new do
|
||||
# TODO: Remove this when new base is merged in
|
||||
if defined?(Http)
|
||||
@controller.formats = [mime_type.to_sym]
|
||||
end
|
||||
|
||||
@controller.template.formats = [mime_type.to_sym]
|
||||
@response.content_type = mime_type.to_s
|
||||
|
||||
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
|
||||
end
|
||||
end
|
||||
|
@ -3,12 +3,26 @@ class InvalidAuthenticityToken < ActionControllerError #:nodoc:
|
||||
end
|
||||
|
||||
module RequestForgeryProtection
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
helper_method :form_authenticity_token
|
||||
helper_method :protect_against_forgery?
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
if defined?(ActionController::Http)
|
||||
depends_on AbstractController::Helpers, Session
|
||||
end
|
||||
|
||||
included do
|
||||
if defined?(ActionController::Http)
|
||||
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
|
||||
# sets it to <tt>:authenticity_token</tt> by default.
|
||||
cattr_accessor :request_forgery_protection_token
|
||||
|
||||
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
|
||||
class_inheritable_accessor :allow_forgery_protection
|
||||
self.allow_forgery_protection = true
|
||||
end
|
||||
base.extend(ClassMethods)
|
||||
|
||||
helper_method :form_authenticity_token
|
||||
helper_method :protect_against_forgery?
|
||||
end
|
||||
|
||||
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a
|
||||
|
@ -2,6 +2,13 @@ module ActionController #:nodoc:
|
||||
# Methods for sending arbitrary data and for streaming files to the browser,
|
||||
# instead of rendering.
|
||||
module Streaming
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
if defined?(ActionController::Http)
|
||||
depends_on ActionController::Renderer
|
||||
end
|
||||
|
||||
DEFAULT_SEND_FILE_OPTIONS = {
|
||||
:type => 'application/octet-stream'.freeze,
|
||||
:disposition => 'attachment'.freeze,
|
||||
@ -88,6 +95,7 @@ def send_file(path, options = {}) #:doc:
|
||||
head options[:status], X_SENDFILE_HEADER => path
|
||||
else
|
||||
if options[:stream]
|
||||
# TODO : Make render :text => proc {} work with the new base
|
||||
render :status => options[:status], :text => Proc.new { |response, output|
|
||||
logger.info "Streaming file #{path}" unless logger.nil?
|
||||
len = options[:buffer_size] || 4096
|
||||
|
@ -1,7 +1,10 @@
|
||||
module ActionController #:nodoc:
|
||||
module Verification #:nodoc:
|
||||
def self.included(base) #:nodoc:
|
||||
base.extend(ClassMethods)
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
# TODO : Remove the defined? check when new base is the main base
|
||||
if defined?(ActionController::Http)
|
||||
depends_on AbstractController::Callbacks, Session, Flash, Renderer
|
||||
end
|
||||
|
||||
# This module provides a class-level method for specifying that certain
|
||||
@ -102,7 +105,7 @@ def prereqs_invalid?(options) # :nodoc:
|
||||
end
|
||||
|
||||
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
|
||||
[*options[:params] ].find { |v| params[v].nil? } ||
|
||||
[*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
|
||||
[*options[:session]].find { |v| session[v].nil? } ||
|
||||
[*options[:flash] ].find { |v| flash[v].nil? }
|
||||
end
|
||||
|
@ -24,31 +24,31 @@ module ActionController #:nodoc:
|
||||
# ActionController::Base.cache_store = :mem_cache_store, "localhost"
|
||||
# ActionController::Base.cache_store = MyOwnStore.new("parameter")
|
||||
module Caching
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
autoload :Actions, 'action_controller/caching/actions'
|
||||
autoload :Fragments, 'action_controller/caching/fragments'
|
||||
autoload :Pages, 'action_controller/caching/pages'
|
||||
autoload :Sweeper, 'action_controller/caching/sweeping'
|
||||
autoload :Sweeping, 'action_controller/caching/sweeping'
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
base.class_eval do
|
||||
@@cache_store = nil
|
||||
cattr_reader :cache_store
|
||||
included do
|
||||
@@cache_store = nil
|
||||
cattr_reader :cache_store
|
||||
|
||||
# Defines the storage option for cached fragments
|
||||
def self.cache_store=(store_option)
|
||||
@@cache_store = ActiveSupport::Cache.lookup_store(store_option)
|
||||
end
|
||||
# Defines the storage option for cached fragments
|
||||
def self.cache_store=(store_option)
|
||||
@@cache_store = ActiveSupport::Cache.lookup_store(store_option)
|
||||
end
|
||||
|
||||
include Pages, Actions, Fragments
|
||||
include Sweeping if defined?(ActiveRecord)
|
||||
include Pages, Actions, Fragments
|
||||
include Sweeping if defined?(ActiveRecord)
|
||||
|
||||
@@perform_caching = true
|
||||
cattr_accessor :perform_caching
|
||||
@@perform_caching = true
|
||||
cattr_accessor :perform_caching
|
||||
|
||||
def self.cache_configured?
|
||||
perform_caching && cache_store
|
||||
end
|
||||
def self.cache_configured?
|
||||
perform_caching && cache_store
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -61,8 +61,14 @@ def caches_action(*actions)
|
||||
filter_options = { :only => actions, :if => options.delete(:if), :unless => options.delete(:unless) }
|
||||
|
||||
cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options)
|
||||
around_filter(filter_options) do |controller, action|
|
||||
cache_filter.filter(controller, action)
|
||||
|
||||
# TODO: Remove this once new base is swapped in.
|
||||
if defined?(Http)
|
||||
around_filter cache_filter, filter_options
|
||||
else
|
||||
around_filter(filter_options) do |controller, action|
|
||||
cache_filter.filter(controller, action)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -85,14 +91,22 @@ def initialize(options, &block)
|
||||
@options = options
|
||||
end
|
||||
|
||||
# TODO: Remove once New Base is merged
|
||||
def filter(controller, action)
|
||||
should_continue = before(controller)
|
||||
action.call if should_continue
|
||||
after(controller)
|
||||
end
|
||||
|
||||
def around_process_action(controller)
|
||||
should_continue = before(controller)
|
||||
yield if should_continue
|
||||
after(controller)
|
||||
end
|
||||
|
||||
def before(controller)
|
||||
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options.slice(:cache_path)))
|
||||
|
||||
if cache = controller.read_fragment(cache_path.path, @options[:store_options])
|
||||
controller.rendered_action_cache = true
|
||||
set_content_type!(controller, cache_path.extension)
|
||||
@ -129,7 +143,9 @@ def cache_layout?
|
||||
end
|
||||
|
||||
def content_for_layout(controller)
|
||||
controller.template.layout && controller.template.instance_variable_get('@cached_content_for_layout')
|
||||
# TODO: Remove this when new base is merged in
|
||||
template = controller.respond_to?(:template) ? controller.template : controller._action_view
|
||||
template.layout && template.instance_variable_get('@cached_content_for_layout')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,46 +1,11 @@
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
|
||||
module ActionController
|
||||
# Dispatches requests to the appropriate controller and takes care of
|
||||
# reloading the app after each request when Dependencies.load? is true.
|
||||
class Dispatcher
|
||||
class << self
|
||||
def define_dispatcher_callbacks(cache_classes)
|
||||
unless cache_classes
|
||||
# Development mode callbacks
|
||||
before_dispatch :reload_application
|
||||
after_dispatch :cleanup_application
|
||||
|
||||
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
|
||||
end
|
||||
|
||||
after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush)
|
||||
|
||||
to_prepare do
|
||||
I18n.reload!
|
||||
end
|
||||
end
|
||||
|
||||
# Add a preparation callback. Preparation callbacks are run before every
|
||||
# request in development mode, and before the first request in production
|
||||
# mode.
|
||||
#
|
||||
# An optional identifier may be supplied for the callback. If provided,
|
||||
# to_prepare may 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 to_prepare(identifier = nil, &block)
|
||||
@prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
|
||||
callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
|
||||
@prepare_dispatch_callbacks.replace_or_append!(callback)
|
||||
end
|
||||
|
||||
def run_prepare_callbacks
|
||||
new.send :run_callbacks, :prepare_dispatch
|
||||
end
|
||||
end
|
||||
cattr_accessor :prepare_each_request
|
||||
self.prepare_each_request = false
|
||||
|
||||
cattr_accessor :router
|
||||
self.router = Routing::Routes
|
||||
@ -51,37 +16,50 @@ def run_prepare_callbacks
|
||||
middleware.instance_eval(File.read(middlewares), middlewares, 1)
|
||||
end
|
||||
|
||||
include ActiveSupport::Callbacks
|
||||
define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch
|
||||
class << self
|
||||
def define_dispatcher_callbacks(cache_classes)
|
||||
unless cache_classes
|
||||
# Run prepare callbacks before every request in development mode
|
||||
self.prepare_each_request = true
|
||||
|
||||
def initialize
|
||||
@app = @@middleware.build(@@router)
|
||||
freeze
|
||||
end
|
||||
# Development mode callbacks
|
||||
ActionDispatch::Callbacks.before_dispatch do |app|
|
||||
ActionController::Dispatcher.router.reload
|
||||
end
|
||||
|
||||
def call(env)
|
||||
run_callbacks :before_dispatch
|
||||
@app.call(env)
|
||||
ensure
|
||||
run_callbacks :after_dispatch, :enumerator => :reverse_each
|
||||
end
|
||||
ActionDispatch::Callbacks.after_dispatch do
|
||||
# Cleanup the application before processing the current request.
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
ActiveSupport::Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
end
|
||||
|
||||
def reload_application
|
||||
# Run prepare callbacks before every request in development mode
|
||||
run_callbacks :prepare_dispatch
|
||||
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
|
||||
end
|
||||
|
||||
@@router.reload
|
||||
end
|
||||
if defined?(ActiveRecord)
|
||||
to_prepare(:activerecord_instantiate_observers) do
|
||||
ActiveRecord::Base.instantiate_observers
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_application
|
||||
# Cleanup the application before processing the current request.
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
ActiveSupport::Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
end
|
||||
if Base.logger && Base.logger.respond_to?(:flush)
|
||||
after_dispatch do
|
||||
Base.logger.flush
|
||||
end
|
||||
end
|
||||
|
||||
def flush_logger
|
||||
Base.logger.flush
|
||||
to_prepare do
|
||||
I18n.reload!
|
||||
end
|
||||
end
|
||||
|
||||
delegate :to_prepare, :prepare_dispatch, :before_dispatch, :after_dispatch,
|
||||
:to => ActionDispatch::Callbacks
|
||||
|
||||
def new
|
||||
@@middleware.build(@@router)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,8 +2,8 @@
|
||||
!ActionController::Base.allow_concurrency
|
||||
}
|
||||
|
||||
use "ActionDispatch::Failsafe"
|
||||
use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local }
|
||||
use "ActionDispatch::Callbacks", lambda { ActionController::Dispatcher.prepare_each_request }
|
||||
use "ActionDispatch::Rescue", lambda {
|
||||
controller = (::ApplicationController rescue ActionController::Base)
|
||||
# TODO: Replace with controller.action(:_rescue_action)
|
||||
|
@ -7,13 +7,19 @@ module ActionController
|
||||
autoload :Rails2Compatibility, "action_controller/new_base/compatibility"
|
||||
autoload :Redirector, "action_controller/new_base/redirector"
|
||||
autoload :Renderer, "action_controller/new_base/renderer"
|
||||
autoload :RenderOptions, "action_controller/new_base/render_options"
|
||||
autoload :Renderers, "action_controller/new_base/render_options"
|
||||
autoload :Rescue, "action_controller/new_base/rescuable"
|
||||
autoload :Testing, "action_controller/new_base/testing"
|
||||
autoload :UrlFor, "action_controller/new_base/url_for"
|
||||
|
||||
autoload :Session, "action_controller/new_base/session"
|
||||
autoload :Helpers, "action_controller/new_base/helpers"
|
||||
|
||||
# Ported modules
|
||||
# require 'action_controller/routing'
|
||||
autoload :Caching, 'action_controller/caching'
|
||||
autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
|
||||
autoload :MimeResponds, 'action_controller/base/mime_responds'
|
||||
autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
|
||||
autoload :RecordIdentifier, 'action_controller/record_identifier'
|
||||
autoload :Resources, 'action_controller/routing/resources'
|
||||
@ -21,9 +27,18 @@ module ActionController
|
||||
autoload :TestCase, 'action_controller/testing/test_case'
|
||||
autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
|
||||
autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
|
||||
|
||||
|
||||
autoload :Verification, 'action_controller/base/verification'
|
||||
autoload :Flash, 'action_controller/base/chained/flash'
|
||||
autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
|
||||
autoload :Streaming, 'action_controller/base/streaming'
|
||||
autoload :HttpAuthentication, 'action_controller/base/http_authentication'
|
||||
autoload :FilterParameterLogging, 'action_controller/base/filter_parameter_logging'
|
||||
autoload :Translation, 'action_controller/translation'
|
||||
autoload :Cookies, 'action_controller/base/cookies'
|
||||
|
||||
require 'action_controller/routing'
|
||||
end
|
||||
|
||||
require 'action_dispatch'
|
||||
require 'action_view'
|
||||
require 'action_view'
|
||||
|
@ -2,41 +2,56 @@ module ActionController
|
||||
class Base < Http
|
||||
abstract!
|
||||
|
||||
include AbstractController::Benchmarker
|
||||
include AbstractController::Callbacks
|
||||
include AbstractController::Helpers
|
||||
include AbstractController::Logger
|
||||
|
||||
|
||||
include ActionController::Helpers
|
||||
include ActionController::HideActions
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirector
|
||||
include ActionController::Renderer
|
||||
include ActionController::Renderers::All
|
||||
include ActionController::Layouts
|
||||
include ActionController::ConditionalGet
|
||||
|
||||
# Legacy modules
|
||||
include SessionManagement
|
||||
include ActionDispatch::StatusCodes
|
||||
include ActionController::Caching
|
||||
include ActionController::MimeResponds
|
||||
|
||||
# Rails 2.x compatibility
|
||||
include ActionController::Rails2Compatibility
|
||||
|
||||
include ActionController::Cookies
|
||||
include ActionController::Session
|
||||
include ActionController::Flash
|
||||
include ActionController::Verification
|
||||
include ActionController::RequestForgeryProtection
|
||||
include ActionController::Streaming
|
||||
include ActionController::HttpAuthentication::Basic::ControllerMethods
|
||||
include ActionController::HttpAuthentication::Digest::ControllerMethods
|
||||
include ActionController::FilterParameterLogging
|
||||
include ActionController::Translation
|
||||
|
||||
# TODO: Extract into its own module
|
||||
# This should be moved together with other normalizing behavior
|
||||
module ImplicitRender
|
||||
def process_action(method_name)
|
||||
ret = super
|
||||
render if response_body.nil?
|
||||
default_render if response_body.nil?
|
||||
ret
|
||||
end
|
||||
|
||||
def _implicit_render
|
||||
def default_render
|
||||
render
|
||||
end
|
||||
|
||||
def method_for_action(action_name)
|
||||
super || begin
|
||||
if view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
|
||||
"_implicit_render"
|
||||
"default_render"
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -61,7 +76,7 @@ def self.app_loaded!
|
||||
end
|
||||
end
|
||||
|
||||
def render_to_body(action = nil, options = {})
|
||||
def _normalize_options(action = nil, options = {}, &blk)
|
||||
if action.is_a?(Hash)
|
||||
options, action = action, nil
|
||||
elsif action.is_a?(String) || action.is_a?(Symbol)
|
||||
@ -78,11 +93,25 @@ def render_to_body(action = nil, options = {})
|
||||
if options.key?(:action) && options[:action].to_s.index("/")
|
||||
options[:template] = options.delete(:action)
|
||||
end
|
||||
|
||||
# options = {:template => options.to_s} if options.is_a?(String) || options.is_a?(Symbol)
|
||||
super(options) || " "
|
||||
|
||||
if options[:status]
|
||||
options[:status] = interpret_status(options[:status]).to_i
|
||||
end
|
||||
|
||||
options[:update] = blk if block_given?
|
||||
options
|
||||
end
|
||||
|
||||
|
||||
def render(action = nil, options = {}, &blk)
|
||||
options = _normalize_options(action, options, &blk)
|
||||
super(options)
|
||||
end
|
||||
|
||||
def render_to_string(action = nil, options = {}, &blk)
|
||||
options = _normalize_options(action, options, &blk)
|
||||
super(options)
|
||||
end
|
||||
|
||||
# Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
|
||||
#
|
||||
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
|
||||
@ -140,4 +169,4 @@ def redirect_to(options = {}, response_status = {}) #:doc:
|
||||
super(url, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,10 @@
|
||||
module ActionController
|
||||
module Rails2Compatibility
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
|
||||
class ::ActionController::ActionControllerError < StandardError #:nodoc:
|
||||
end
|
||||
|
||||
# Temporary hax
|
||||
included do
|
||||
::ActionController::UnknownAction = ::AbstractController::ActionNotFound
|
||||
@ -53,10 +56,23 @@ module Rails2Compatibility
|
||||
|
||||
cattr_accessor :consider_all_requests_local
|
||||
self.consider_all_requests_local = true
|
||||
|
||||
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
|
||||
# and images to a dedicated asset server away from the main web server. Example:
|
||||
# ActionController::Base.asset_host = "http://assets.example.com"
|
||||
cattr_accessor :asset_host
|
||||
end
|
||||
|
||||
# For old tests
|
||||
def initialize_template_class(*) end
|
||||
def assign_shortcuts(*) end
|
||||
|
||||
# TODO: Remove this after we flip
|
||||
def template
|
||||
_action_view
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def protect_from_forgery() end
|
||||
def consider_all_requests_local() end
|
||||
def rescue_action(env)
|
||||
raise env["action_dispatch.rescue.exception"]
|
||||
@ -80,7 +96,9 @@ def render_to_body(options)
|
||||
|
||||
options[:text] = nil if options[:nothing] == true
|
||||
|
||||
super
|
||||
body = super
|
||||
body = [' '] if body.blank?
|
||||
body
|
||||
end
|
||||
|
||||
def _handle_method_missing
|
||||
@ -91,10 +109,12 @@ def method_for_action(action_name)
|
||||
super || (respond_to?(:method_missing) && "_handle_method_missing")
|
||||
end
|
||||
|
||||
def _layout_for_name(name)
|
||||
name &&= name.sub(%r{^/?layouts/}, '')
|
||||
super
|
||||
def _layout_prefix(name)
|
||||
super unless name =~ /\blayouts/
|
||||
end
|
||||
|
||||
def performed?
|
||||
response_body
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -57,7 +57,7 @@ def head(*args)
|
||||
raise ArgumentError, "too few arguments to head"
|
||||
end
|
||||
options = args.extract_options!
|
||||
status = interpret_status(args.shift || options.delete(:status) || :ok)
|
||||
status = args.shift || options.delete(:status) || :ok
|
||||
|
||||
options.each do |key, value|
|
||||
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
|
||||
|
130
actionpack/lib/action_controller/new_base/helpers.rb
Normal file
130
actionpack/lib/action_controller/new_base/helpers.rb
Normal file
@ -0,0 +1,130 @@
|
||||
require 'active_support/core_ext/load_error'
|
||||
require 'active_support/core_ext/name_error'
|
||||
require 'active_support/dependencies'
|
||||
|
||||
module ActionController
|
||||
module Helpers
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
depends_on AbstractController::Helpers
|
||||
|
||||
included do
|
||||
# Set the default directory for helpers
|
||||
class_inheritable_accessor :helpers_dir
|
||||
self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def inherited(klass)
|
||||
klass.__send__ :default_helper_module!
|
||||
super
|
||||
end
|
||||
|
||||
# The +helper+ class method can take a series of helper module names, a block, or both.
|
||||
#
|
||||
# * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>.
|
||||
# * <tt>&block</tt>: A block defining helper methods.
|
||||
#
|
||||
# ==== Examples
|
||||
# When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
|
||||
# and include the module in the template class. The second form illustrates how to include custom helpers
|
||||
# when working with namespaced controllers, or other cases where the file containing the helper definition is not
|
||||
# in one of Rails' standard load paths:
|
||||
# helper :foo # => requires 'foo_helper' and includes FooHelper
|
||||
# helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
|
||||
#
|
||||
# When the argument is a module it will be included directly in the template class.
|
||||
# helper FooHelper # => includes FooHelper
|
||||
#
|
||||
# When the argument is the symbol <tt>:all</tt>, the controller will include all helpers beneath
|
||||
# <tt>ActionController::Base.helpers_dir</tt> (defaults to <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT).
|
||||
# helper :all
|
||||
#
|
||||
# Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
|
||||
# to the template.
|
||||
# # One line
|
||||
# helper { def hello() "Hello, world!" end }
|
||||
# # Multi-line
|
||||
# helper do
|
||||
# def foo(bar)
|
||||
# "#{bar} is the very best"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
|
||||
# +symbols+, +strings+, +modules+ and blocks.
|
||||
# helper(:three, BlindHelper) { def mice() 'mice' end }
|
||||
#
|
||||
def helper(*args, &block)
|
||||
args.flatten.each do |arg|
|
||||
case arg
|
||||
when :all
|
||||
helper all_application_helpers
|
||||
when String, Symbol
|
||||
file_name = arg.to_s.underscore + '_helper'
|
||||
class_name = file_name.camelize
|
||||
|
||||
begin
|
||||
require_dependency(file_name)
|
||||
rescue LoadError => load_error
|
||||
requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
|
||||
if requiree == file_name
|
||||
msg = "Missing helper file helpers/#{file_name}.rb"
|
||||
raise LoadError.new(msg).copy_blame!(load_error)
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
super class_name.constantize
|
||||
else
|
||||
super args
|
||||
end
|
||||
end
|
||||
|
||||
# Evaluate block in template class if given.
|
||||
master_helper_module.module_eval(&block) if block_given?
|
||||
end
|
||||
|
||||
# Declares helper accessors for controller attributes. For example, the
|
||||
# following adds new +name+ and <tt>name=</tt> instance methods to a
|
||||
# controller and makes them available to the view:
|
||||
# helper_attr :name
|
||||
# attr_accessor :name
|
||||
def helper_attr(*attrs)
|
||||
attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
|
||||
end
|
||||
|
||||
# Provides a proxy to access helpers methods from outside the view.
|
||||
def helpers
|
||||
unless @helper_proxy
|
||||
@helper_proxy = ActionView::Base.new
|
||||
@helper_proxy.extend master_helper_module
|
||||
else
|
||||
@helper_proxy
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_helper_module!
|
||||
unless name.blank?
|
||||
module_name = name.sub(/Controller$|$/, 'Helper')
|
||||
module_path = module_name.split('::').map { |m| m.underscore }.join('/')
|
||||
require_dependency module_path
|
||||
helper module_name.constantize
|
||||
end
|
||||
rescue MissingSourceFile => e
|
||||
raise unless e.is_missing? module_path
|
||||
rescue NameError => e
|
||||
raise unless e.missing_name? module_name
|
||||
end
|
||||
|
||||
# Extract helper names from files in app/helpers/**/*.rb
|
||||
def all_application_helpers
|
||||
extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/
|
||||
Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
|
||||
end
|
||||
end # ClassMethods
|
||||
end
|
||||
end
|
@ -37,7 +37,7 @@ def self.call(env)
|
||||
end
|
||||
|
||||
delegate :headers, :to => "@_response"
|
||||
|
||||
|
||||
def params
|
||||
@_params ||= @_request.parameters
|
||||
end
|
||||
@ -60,7 +60,6 @@ def self.action(name)
|
||||
|
||||
# :api: private
|
||||
def to_rack
|
||||
@_response.body = response_body
|
||||
@_response.prepare!
|
||||
@_response.to_a
|
||||
end
|
||||
|
@ -11,23 +11,20 @@ def _implied_layout_name
|
||||
end
|
||||
end
|
||||
|
||||
def render_to_body(options)
|
||||
# render :text => ..., :layout => ...
|
||||
# or
|
||||
# render :anything_else
|
||||
if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout)
|
||||
options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _determine_template(options)
|
||||
super
|
||||
if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout)
|
||||
options[:_layout] = _layout_for_option(options.key?(:layout) ? options[:layout] : :none, options[:_template].details)
|
||||
end
|
||||
end
|
||||
|
||||
def _layout_for_option(name)
|
||||
def _layout_for_option(name, details)
|
||||
case name
|
||||
when String then _layout_for_name(name)
|
||||
when true then _default_layout(true)
|
||||
when String then _layout_for_name(name, details)
|
||||
when true then _default_layout(true, details)
|
||||
when :none then _default_layout(false, details)
|
||||
when false, nil then nil
|
||||
else
|
||||
raise ArgumentError,
|
||||
|
107
actionpack/lib/action_controller/new_base/render_options.rb
Normal file
107
actionpack/lib/action_controller/new_base/render_options.rb
Normal file
@ -0,0 +1,107 @@
|
||||
module ActionController
|
||||
module RenderOptions
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
included do
|
||||
extlib_inheritable_accessor :_renderers
|
||||
self._renderers = []
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def _write_render_options
|
||||
renderers = _renderers.map do |r|
|
||||
<<-RUBY_EVAL
|
||||
if options.key?(:#{r})
|
||||
_process_options(options)
|
||||
return _render_#{r}(options[:#{r}], options)
|
||||
end
|
||||
RUBY_EVAL
|
||||
end
|
||||
|
||||
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
||||
def _handle_render_options(options)
|
||||
#{renderers.join}
|
||||
end
|
||||
RUBY_EVAL
|
||||
end
|
||||
|
||||
def _add_render_option(name)
|
||||
_renderers << name
|
||||
_write_render_options
|
||||
end
|
||||
end
|
||||
|
||||
def render_to_body(options)
|
||||
_handle_render_options(options) || super
|
||||
end
|
||||
end
|
||||
|
||||
module RenderOption
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
included do
|
||||
extend ActiveSupport::DependencyModule
|
||||
depends_on ::ActionController::RenderOptions
|
||||
|
||||
def self.register_renderer(name)
|
||||
included { _add_render_option(name) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Renderers
|
||||
module Json
|
||||
include RenderOption
|
||||
register_renderer :json
|
||||
|
||||
def _render_json(json, options)
|
||||
json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str)
|
||||
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
|
||||
response.content_type ||= Mime::JSON
|
||||
self.response_body = json
|
||||
end
|
||||
end
|
||||
|
||||
module Js
|
||||
include RenderOption
|
||||
register_renderer :js
|
||||
|
||||
def _render_js(js, options)
|
||||
response.content_type ||= Mime::JS
|
||||
self.response_body = js
|
||||
end
|
||||
end
|
||||
|
||||
module Xml
|
||||
include RenderOption
|
||||
register_renderer :xml
|
||||
|
||||
def _render_xml(xml, options)
|
||||
response.content_type ||= Mime::XML
|
||||
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
|
||||
end
|
||||
end
|
||||
|
||||
module Rjs
|
||||
include RenderOption
|
||||
register_renderer :update
|
||||
|
||||
def _render_update(proc, options)
|
||||
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(_action_view, &proc)
|
||||
response.content_type = Mime::JS
|
||||
self.response_body = generator.to_s
|
||||
end
|
||||
end
|
||||
|
||||
module All
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
included do
|
||||
include ::ActionController::Renderers::Json
|
||||
include ::ActionController::Renderers::Js
|
||||
include ::ActionController::Renderers::Xml
|
||||
include ::ActionController::Renderers::Rjs
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -4,17 +4,45 @@ module Renderer
|
||||
|
||||
depends_on AbstractController::Renderer
|
||||
|
||||
def initialize(*)
|
||||
self.formats = [:html]
|
||||
def process_action(*)
|
||||
self.formats = request.formats.map {|x| x.to_sym}
|
||||
super
|
||||
end
|
||||
|
||||
def response_body=(body)
|
||||
response.body = body if response
|
||||
super
|
||||
end
|
||||
|
||||
def render(options)
|
||||
super
|
||||
options[:_template] ||= _action_view._partial
|
||||
response.content_type ||= begin
|
||||
mime = options[:_template].mime_type
|
||||
formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first)
|
||||
end
|
||||
response_body
|
||||
end
|
||||
|
||||
def render_to_body(options)
|
||||
_process_options(options)
|
||||
|
||||
if options.key?(:partial)
|
||||
_render_partial(options[:partial], options)
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _prefix
|
||||
controller_path
|
||||
end
|
||||
|
||||
def _determine_template(options)
|
||||
if options.key?(:text)
|
||||
options[:_template] = ActionView::TextTemplate.new(_text(options))
|
||||
template = nil
|
||||
options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
|
||||
elsif options.key?(:inline)
|
||||
handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
|
||||
template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
|
||||
@ -23,35 +51,14 @@ def render_to_body(options)
|
||||
options[:_template_name] = options[:template]
|
||||
elsif options.key?(:file)
|
||||
options[:_template_name] = options[:file]
|
||||
elsif options.key?(:partial)
|
||||
_render_partial(options[:partial], options)
|
||||
else
|
||||
elsif !options.key?(:partial)
|
||||
options[:_template_name] = (options[:action] || action_name).to_s
|
||||
options[:_prefix] = _prefix
|
||||
end
|
||||
|
||||
ret = super(options)
|
||||
|
||||
options[:_template] ||= _action_view._partial
|
||||
response.content_type ||= options[:_template].mime_type
|
||||
ret
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _prefix
|
||||
controller_path
|
||||
end
|
||||
|
||||
def _text(options)
|
||||
text = options[:text]
|
||||
|
||||
case text
|
||||
when nil then " "
|
||||
else text.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def _render_partial(partial, options)
|
||||
case partial
|
||||
when true
|
||||
@ -68,9 +75,10 @@ def _render_partial(partial, options)
|
||||
end
|
||||
|
||||
def _process_options(options)
|
||||
status, content_type = options.values_at(:status, :content_type)
|
||||
response.status = status.to_i if status
|
||||
status, content_type, location = options.values_at(:status, :content_type, :location)
|
||||
response.status = status if status
|
||||
response.content_type = content_type if content_type
|
||||
response.headers["Location"] = url_for(location) if location
|
||||
end
|
||||
end
|
||||
end
|
||||
|
11
actionpack/lib/action_controller/new_base/session.rb
Normal file
11
actionpack/lib/action_controller/new_base/session.rb
Normal file
@ -0,0 +1,11 @@
|
||||
module ActionController
|
||||
module Session
|
||||
def session
|
||||
@_request.session
|
||||
end
|
||||
|
||||
def reset_session
|
||||
@_request.reset_session
|
||||
end
|
||||
end
|
||||
end
|
@ -1,13 +1,13 @@
|
||||
module ActionController
|
||||
module Testing
|
||||
|
||||
|
||||
# OMG MEGA HAX
|
||||
def process_with_test(request, response)
|
||||
def process_with_new_base_test(request, response)
|
||||
@_request = request
|
||||
@_response = response
|
||||
@_response.request = request
|
||||
ret = process(request.parameters[:action])
|
||||
@_response.body = self.response_body || " "
|
||||
@_response.body ||= self.response_body
|
||||
@_response.prepare!
|
||||
set_test_assigns
|
||||
ret
|
||||
@ -20,6 +20,11 @@ def set_test_assigns
|
||||
@assigns[name] = value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# TODO : Rewrite tests using controller.headers= to use Rack env
|
||||
def headers=(new_headers)
|
||||
@_response ||= ActionDispatch::Response.new
|
||||
@_response.headers.replace(new_headers)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,10 @@
|
||||
module ActionController
|
||||
module UrlFor
|
||||
def process_action(*)
|
||||
initialize_current_url
|
||||
super
|
||||
end
|
||||
|
||||
def initialize_current_url
|
||||
@url = UrlRewriter.new(request, params.clone)
|
||||
end
|
||||
|
@ -2,6 +2,9 @@
|
||||
require 'uri'
|
||||
require 'active_support/test_case'
|
||||
|
||||
require 'rack/mock_session'
|
||||
require 'rack/test/cookie_jar'
|
||||
|
||||
module ActionController
|
||||
module Integration #:nodoc:
|
||||
module RequestHelpers
|
||||
@ -62,8 +65,8 @@ def head(path, parameters = nil, headers = nil)
|
||||
# with 'HTTP_' if not already.
|
||||
def xml_http_request(request_method, path, parameters = nil, headers = nil)
|
||||
headers ||= {}
|
||||
headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||
headers['Accept'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
||||
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
||||
process(request_method, path, parameters, headers)
|
||||
end
|
||||
alias xhr :xml_http_request
|
||||
@ -121,6 +124,8 @@ def delete_via_redirect(path, parameters = nil, headers = nil)
|
||||
# IntegrationTest#open_session, rather than instantiating
|
||||
# Integration::Session directly.
|
||||
class Session
|
||||
DEFAULT_HOST = "www.example.com"
|
||||
|
||||
include Test::Unit::Assertions
|
||||
include ActionDispatch::Assertions
|
||||
include ActionController::TestProcess
|
||||
@ -145,7 +150,9 @@ class Session
|
||||
|
||||
# A map of the cookies returned by the last response, and which will be
|
||||
# sent with the next request.
|
||||
attr_reader :cookies
|
||||
def cookies
|
||||
@mock_session.cookie_jar
|
||||
end
|
||||
|
||||
# A reference to the controller instance used by the last request.
|
||||
attr_reader :controller
|
||||
@ -172,11 +179,11 @@ def initialize(app = nil)
|
||||
# session.reset!
|
||||
def reset!
|
||||
@https = false
|
||||
@cookies = {}
|
||||
@mock_session = Rack::MockSession.new(@app, DEFAULT_HOST)
|
||||
@controller = @request = @response = nil
|
||||
@request_count = 0
|
||||
|
||||
self.host = "www.example.com"
|
||||
self.host = DEFAULT_HOST
|
||||
self.remote_addr = "127.0.0.1"
|
||||
self.accept = "text/xml,application/xml,application/xhtml+xml," +
|
||||
"text/html;q=0.9,text/plain;q=0.8,image/png," +
|
||||
@ -227,8 +234,9 @@ def url_for(options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Performs the actual request.
|
||||
def process(method, path, parameters = nil, headers = nil)
|
||||
def process(method, path, parameters = nil, rack_environment = nil)
|
||||
if path =~ %r{://}
|
||||
location = URI.parse(path)
|
||||
https! URI::HTTPS === location if location.scheme
|
||||
@ -242,8 +250,6 @@ def process(method, path, parameters = nil, headers = nil)
|
||||
end
|
||||
end
|
||||
|
||||
ActionController::Base.clear_last_instantiation!
|
||||
|
||||
opts = {
|
||||
:method => method,
|
||||
:params => parameters,
|
||||
@ -258,34 +264,23 @@ def process(method, path, parameters = nil, headers = nil)
|
||||
"HTTP_HOST" => host,
|
||||
"REMOTE_ADDR" => remote_addr,
|
||||
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
||||
"HTTP_ACCEPT" => accept,
|
||||
"HTTP_COOKIE" => cookies.inject("") { |string, (name, value)|
|
||||
string << "#{name}=#{value}; "
|
||||
}
|
||||
"HTTP_ACCEPT" => accept
|
||||
}
|
||||
env = Rack::MockRequest.env_for(path, opts)
|
||||
|
||||
(headers || {}).each do |key, value|
|
||||
key = key.to_s.upcase.gsub(/-/, "_")
|
||||
key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/
|
||||
(rack_environment || {}).each do |key, value|
|
||||
env[key] = value
|
||||
end
|
||||
|
||||
app = Rack::Lint.new(@app)
|
||||
status, headers, body = app.call(env)
|
||||
mock_response = ::Rack::MockResponse.new(status, headers, body)
|
||||
@controller = ActionController::Base.capture_instantiation do
|
||||
@mock_session.request(URI.parse(path), env)
|
||||
end
|
||||
|
||||
@request_count += 1
|
||||
@request = ActionDispatch::Request.new(env)
|
||||
@response = ActionDispatch::TestResponse.from_response(mock_response)
|
||||
|
||||
@cookies.merge!(@response.cookies)
|
||||
@response = ActionDispatch::TestResponse.from_response(@mock_session.last_response)
|
||||
@html_document = nil
|
||||
|
||||
if @controller = ActionController::Base.last_instantiation
|
||||
@controller.send(:set_test_assigns)
|
||||
end
|
||||
|
||||
return response.status
|
||||
end
|
||||
|
||||
@ -306,11 +301,10 @@ def generic_url_rewriter
|
||||
# A module used to extend ActionController::Base, so that integration tests
|
||||
# can capture the controller used to satisfy a request.
|
||||
module ControllerCapture #:nodoc:
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
base.class_eval do
|
||||
alias_method_chain :initialize, :capture
|
||||
end
|
||||
extend ActiveSupport::DependencyModule
|
||||
|
||||
included do
|
||||
alias_method_chain :initialize, :capture
|
||||
end
|
||||
|
||||
def initialize_with_capture(*args)
|
||||
@ -321,8 +315,10 @@ def initialize_with_capture(*args)
|
||||
module ClassMethods #:nodoc:
|
||||
mattr_accessor :last_instantiation
|
||||
|
||||
def clear_last_instantiation!
|
||||
def capture_instantiation
|
||||
self.last_instantiation = nil
|
||||
yield
|
||||
return last_instantiation
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -41,6 +41,7 @@ def assign_parameters(controller_path, action, parameters)
|
||||
end
|
||||
|
||||
def recycle!
|
||||
@formats = nil
|
||||
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
|
||||
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
|
||||
@env['action_dispatch.request.query_parameters'] = {}
|
||||
@ -132,9 +133,6 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
|
||||
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
|
||||
build_request_uri(action, parameters)
|
||||
|
||||
@request.env["action_controller.rescue.request"] = @request
|
||||
@request.env["action_controller.rescue.response"] = @response
|
||||
|
||||
Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
|
||||
|
||||
env = @request.env
|
||||
|
@ -40,6 +40,8 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
|
||||
@request.recycle!
|
||||
@response.recycle!
|
||||
@controller.response_body = nil
|
||||
@controller.formats = nil
|
||||
@controller.params = nil
|
||||
|
||||
@html_document = nil
|
||||
@request.env['REQUEST_METHOD'] = http_method
|
||||
@ -53,7 +55,8 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
|
||||
@controller.request = @request
|
||||
@controller.params.merge!(parameters)
|
||||
# Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
|
||||
@controller.process_with_test(@request, @response)
|
||||
@controller.process_with_new_base_test(@request, @response)
|
||||
@response
|
||||
end
|
||||
|
||||
def build_request_uri(action, parameters)
|
||||
|
@ -73,7 +73,7 @@ class WhiteListSanitizer < Sanitizer
|
||||
|
||||
# Specifies the default Set of tags that the #sanitize helper will allow unscathed.
|
||||
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
|
||||
acronym a img blockquote del ins))
|
||||
|
||||
# Specifies the default Set of html attributes that the #sanitize helper will leave
|
||||
|
@ -27,23 +27,26 @@
|
||||
|
||||
begin
|
||||
gem 'rack', '~> 1.1.pre'
|
||||
rescue Gem::LoadError
|
||||
rescue Gem::LoadError, ArgumentError
|
||||
$:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-1.1.pre"
|
||||
end
|
||||
|
||||
require 'rack'
|
||||
|
||||
$:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-test"
|
||||
|
||||
module ActionDispatch
|
||||
autoload :Request, 'action_dispatch/http/request'
|
||||
autoload :Response, 'action_dispatch/http/response'
|
||||
autoload :StatusCodes, 'action_dispatch/http/status_codes'
|
||||
|
||||
autoload :Failsafe, 'action_dispatch/middleware/failsafe'
|
||||
autoload :Callbacks, 'action_dispatch/middleware/callbacks'
|
||||
autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
|
||||
autoload :Rescue, 'action_dispatch/middleware/rescue'
|
||||
autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions'
|
||||
autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
|
||||
|
||||
autoload :HTML, 'action_controller/vendor/html-scanner'
|
||||
autoload :Assertions, 'action_dispatch/testing/assertions'
|
||||
autoload :TestRequest, 'action_dispatch/testing/test_request'
|
||||
autoload :TestResponse, 'action_dispatch/testing/test_response'
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
module Mime
|
||||
SET = []
|
||||
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
|
||||
EXTENSION_LOOKUP = {}
|
||||
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
|
||||
|
||||
def self.[](type)
|
||||
|
@ -1,9 +1,9 @@
|
||||
# Build list of Mime types for HTTP responses
|
||||
# http://www.iana.org/assignments/media-types/
|
||||
|
||||
Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
|
||||
Mime::Type.register "*/*", :all
|
||||
Mime::Type.register "text/plain", :text, [], %w(txt)
|
||||
Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
|
||||
Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
|
||||
Mime::Type.register "text/css", :css
|
||||
Mime::Type.register "text/calendar", :ics
|
||||
|
@ -3,7 +3,9 @@
|
||||
require 'strscan'
|
||||
|
||||
require 'active_support/memoizable'
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/hash/indifferent_access'
|
||||
require 'active_support/core_ext/object/tap'
|
||||
|
||||
module ActionDispatch
|
||||
class Request < Rack::Request
|
||||
@ -173,9 +175,21 @@ def format(view_path = [])
|
||||
|
||||
def formats
|
||||
if ActionController::Base.use_accept_header
|
||||
Array(Mime[parameters[:format]] || accepts)
|
||||
if param = parameters[:format]
|
||||
Array.wrap(Mime[param])
|
||||
else
|
||||
accepts.dup
|
||||
end.tap do |ret|
|
||||
if defined?(ActionController::Http)
|
||||
if ret == ONLY_ALL
|
||||
ret.replace Mime::SET
|
||||
elsif all = ret.index(Mime::ALL)
|
||||
ret.delete_at(all) && ret.insert(all, *Mime::SET)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
[format]
|
||||
[format] + Mime::SET
|
||||
end
|
||||
end
|
||||
|
||||
|
40
actionpack/lib/action_dispatch/middleware/callbacks.rb
Normal file
40
actionpack/lib/action_dispatch/middleware/callbacks.rb
Normal file
@ -0,0 +1,40 @@
|
||||
module ActionDispatch
|
||||
class Callbacks
|
||||
include ActiveSupport::Callbacks
|
||||
define_callbacks :prepare, :before, :after
|
||||
|
||||
class << self
|
||||
# DEPRECATED
|
||||
alias_method :prepare_dispatch, :prepare
|
||||
alias_method :before_dispatch, :before
|
||||
alias_method :after_dispatch, :after
|
||||
end
|
||||
|
||||
# Add a preparation callback. Preparation callbacks are run before every
|
||||
# request in development mode, and before the first request in production
|
||||
# mode.
|
||||
#
|
||||
# An optional identifier may be supplied for the callback. If provided,
|
||||
# to_prepare may 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(identifier = nil, &block)
|
||||
@prepare_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
|
||||
callback = ActiveSupport::Callbacks::Callback.new(:prepare, block, :identifier => identifier)
|
||||
@prepare_callbacks.replace_or_append!(callback)
|
||||
end
|
||||
|
||||
def initialize(app, prepare_each_request = false)
|
||||
@app, @prepare_each_request = app, prepare_each_request
|
||||
run_callbacks :prepare
|
||||
end
|
||||
|
||||
def call(env)
|
||||
run_callbacks :before
|
||||
run_callbacks :prepare if @prepare_each_request
|
||||
@app.call(env)
|
||||
ensure
|
||||
run_callbacks :after, :enumerator => :reverse_each
|
||||
end
|
||||
end
|
||||
end
|
@ -1,52 +0,0 @@
|
||||
module ActionDispatch
|
||||
class Failsafe
|
||||
cattr_accessor :error_file_path
|
||||
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
rescue Exception => exception
|
||||
# Reraise exception in test environment
|
||||
if defined?(Rails) && Rails.env.test?
|
||||
raise exception
|
||||
else
|
||||
failsafe_response(exception)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def failsafe_response(exception)
|
||||
log_failsafe_exception(exception)
|
||||
[500, {'Content-Type' => 'text/html'}, failsafe_response_body]
|
||||
rescue Exception => failsafe_error # Logger or IO errors
|
||||
$stderr.puts "Error during failsafe response: #{failsafe_error}"
|
||||
end
|
||||
|
||||
def failsafe_response_body
|
||||
error_path = "#{self.class.error_file_path}/500.html"
|
||||
if File.exist?(error_path)
|
||||
[File.read(error_path)]
|
||||
else
|
||||
["<html><body><h1>500 Internal Server Error</h1></body></html>"]
|
||||
end
|
||||
end
|
||||
|
||||
def log_failsafe_exception(exception)
|
||||
message = "/!\\ FAILSAFE /!\\ #{Time.now}\n Status: 500 Internal Server Error\n"
|
||||
message << " #{exception}\n #{exception.backtrace.join("\n ")}" if exception
|
||||
failsafe_logger.fatal(message)
|
||||
end
|
||||
|
||||
def failsafe_logger
|
||||
if defined?(Rails) && Rails.logger
|
||||
Rails.logger
|
||||
else
|
||||
Logger.new($stderr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -32,16 +32,14 @@ def parse_formatted_parameters(env)
|
||||
when Proc
|
||||
strategy.call(request.raw_post)
|
||||
when :xml_simple, :xml_node
|
||||
body = request.raw_post
|
||||
body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
|
||||
request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
|
||||
when :yaml
|
||||
YAML.load(request.raw_post)
|
||||
YAML.load(request.body)
|
||||
when :json
|
||||
body = request.raw_post
|
||||
if body.blank?
|
||||
if request.body.size == 0
|
||||
{}
|
||||
else
|
||||
data = ActiveSupport::JSON.decode(body)
|
||||
data = ActiveSupport::JSON.decode(request.body)
|
||||
data = {:_json => data} unless data.is_a?(Hash)
|
||||
data.with_indifferent_access
|
||||
end
|
||||
|
@ -4,8 +4,11 @@ class ShowExceptions
|
||||
|
||||
LOCALHOST = '127.0.0.1'.freeze
|
||||
|
||||
DEFAULT_RESCUE_RESPONSE = :internal_server_error
|
||||
DEFAULT_RESCUE_RESPONSES = {
|
||||
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
|
||||
|
||||
cattr_accessor :rescue_responses
|
||||
@@rescue_responses = Hash.new(:internal_server_error)
|
||||
@@rescue_responses.update({
|
||||
'ActionController::RoutingError' => :not_found,
|
||||
'ActionController::UnknownAction' => :not_found,
|
||||
'ActiveRecord::RecordNotFound' => :not_found,
|
||||
@ -15,25 +18,19 @@ class ShowExceptions
|
||||
'ActionController::MethodNotAllowed' => :method_not_allowed,
|
||||
'ActionController::NotImplemented' => :not_implemented,
|
||||
'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
|
||||
}
|
||||
})
|
||||
|
||||
DEFAULT_RESCUE_TEMPLATE = 'diagnostics'
|
||||
DEFAULT_RESCUE_TEMPLATES = {
|
||||
cattr_accessor :rescue_templates
|
||||
@@rescue_templates = Hash.new('diagnostics')
|
||||
@@rescue_templates.update({
|
||||
'ActionView::MissingTemplate' => 'missing_template',
|
||||
'ActionController::RoutingError' => 'routing_error',
|
||||
'ActionController::UnknownAction' => 'unknown_action',
|
||||
'ActionView::TemplateError' => 'template_error'
|
||||
}
|
||||
})
|
||||
|
||||
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
|
||||
|
||||
cattr_accessor :rescue_responses
|
||||
@@rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE)
|
||||
@@rescue_responses.update DEFAULT_RESCUE_RESPONSES
|
||||
|
||||
cattr_accessor :rescue_templates
|
||||
@@rescue_templates = Hash.new(DEFAULT_RESCUE_TEMPLATE)
|
||||
@@rescue_templates.update DEFAULT_RESCUE_TEMPLATES
|
||||
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
|
||||
['<html><body><h1>500 Internal Server Error</h1></body></html>']]
|
||||
|
||||
def initialize(app, consider_all_requests_local = false)
|
||||
@app = app
|
||||
@ -43,34 +40,35 @@ def initialize(app, consider_all_requests_local = false)
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
rescue Exception => exception
|
||||
raise exception if env['rack.test']
|
||||
|
||||
log_error(exception) if logger
|
||||
|
||||
request = Request.new(env)
|
||||
if @consider_all_requests_local || local_request?(request)
|
||||
rescue_action_locally(request, exception)
|
||||
else
|
||||
rescue_action_in_public(exception)
|
||||
end
|
||||
raise exception if env['action_dispatch.show_exceptions'] == false
|
||||
render_exception(env, exception)
|
||||
end
|
||||
|
||||
private
|
||||
def render_exception(env, exception)
|
||||
log_error(exception)
|
||||
|
||||
request = Request.new(env)
|
||||
if @consider_all_requests_local || local_request?(request)
|
||||
rescue_action_locally(request, exception)
|
||||
else
|
||||
rescue_action_in_public(exception)
|
||||
end
|
||||
rescue Exception => failsafe_error
|
||||
$stderr.puts "Error during failsafe response: #{failsafe_error}"
|
||||
FAILSAFE_RESPONSE
|
||||
end
|
||||
|
||||
# Render detailed diagnostics for unhandled exceptions rescued from
|
||||
# a controller action.
|
||||
def rescue_action_locally(request, exception)
|
||||
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
|
||||
:template => template,
|
||||
:request => request,
|
||||
:exception => exception
|
||||
)
|
||||
file = "rescues/#{@@rescue_templates[exception.class.name]}.erb"
|
||||
body = template.render(:file => file, :layout => 'rescues/layout.erb')
|
||||
|
||||
headers = {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}
|
||||
status = status_code(exception)
|
||||
|
||||
[status, headers, body]
|
||||
render(status_code(exception), body)
|
||||
end
|
||||
|
||||
# Attempts to render a static error page based on the
|
||||
@ -86,11 +84,11 @@ def rescue_action_in_public(exception)
|
||||
path = "#{public_path}/#{status}.html"
|
||||
|
||||
if locale_path && File.exist?(locale_path)
|
||||
render_public_file(status, locale_path)
|
||||
render(status, File.read(locale_path))
|
||||
elsif File.exist?(path)
|
||||
render_public_file(status, path)
|
||||
render(status, File.read(path))
|
||||
else
|
||||
[status, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]
|
||||
render(status, '')
|
||||
end
|
||||
end
|
||||
|
||||
@ -99,24 +97,21 @@ def local_request?(request)
|
||||
request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST
|
||||
end
|
||||
|
||||
def render_public_file(status, path)
|
||||
body = File.read(path)
|
||||
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, body]
|
||||
end
|
||||
|
||||
def status_code(exception)
|
||||
interpret_status(@@rescue_responses[exception.class.name]).to_i
|
||||
end
|
||||
|
||||
def public_path
|
||||
if defined?(Rails)
|
||||
Rails.public_path
|
||||
else
|
||||
"public"
|
||||
end
|
||||
def render(status, body)
|
||||
[status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, [body]]
|
||||
end
|
||||
|
||||
def log_error(exception) #:doc:
|
||||
def public_path
|
||||
defined?(Rails.public_path) ? Rails.public_path : 'public_path'
|
||||
end
|
||||
|
||||
def log_error(exception)
|
||||
return unless logger
|
||||
|
||||
ActiveSupport::Deprecation.silence do
|
||||
if ActionView::TemplateError === exception
|
||||
logger.fatal(exception.to_s)
|
||||
@ -136,9 +131,7 @@ def clean_backtrace(exception)
|
||||
end
|
||||
|
||||
def logger
|
||||
if defined?(Rails.logger)
|
||||
Rails.logger
|
||||
end
|
||||
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
50
actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb
vendored
Normal file
50
actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
module Rack
|
||||
|
||||
class MockSession
|
||||
attr_writer :cookie_jar
|
||||
attr_reader :last_response
|
||||
|
||||
def initialize(app, default_host = Rack::Test::DEFAULT_HOST)
|
||||
@app = app
|
||||
@default_host = default_host
|
||||
end
|
||||
|
||||
def clear_cookies
|
||||
@cookie_jar = Rack::Test::CookieJar.new([], @default_host)
|
||||
end
|
||||
|
||||
def set_cookie(cookie, uri = nil)
|
||||
cookie_jar.merge(cookie, uri)
|
||||
end
|
||||
|
||||
def request(uri, env)
|
||||
env["HTTP_COOKIE"] ||= cookie_jar.for(uri)
|
||||
@last_request = Rack::Request.new(env)
|
||||
status, headers, body = @app.call(@last_request.env)
|
||||
@last_response = MockResponse.new(status, headers, body, env["rack.errors"].flush)
|
||||
cookie_jar.merge(last_response.headers["Set-Cookie"], uri)
|
||||
|
||||
@last_response
|
||||
end
|
||||
|
||||
# Return the last request issued in the session. Raises an error if no
|
||||
# requests have been sent yet.
|
||||
def last_request
|
||||
raise Rack::Test::Error.new("No request yet. Request a page first.") unless @last_request
|
||||
@last_request
|
||||
end
|
||||
|
||||
# Return the last response received in the session. Raises an error if
|
||||
# no requests have been sent yet.
|
||||
def last_response
|
||||
raise Rack::Test::Error.new("No response yet. Request a page first.") unless @last_response
|
||||
@last_response
|
||||
end
|
||||
|
||||
def cookie_jar
|
||||
@cookie_jar ||= Rack::Test::CookieJar.new([], @default_host)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
239
actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb
vendored
Normal file
239
actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__) + "/.."))
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/.."))
|
||||
end
|
||||
|
||||
require "uri"
|
||||
require "rack"
|
||||
require "rack/mock_session"
|
||||
require "rack/test/cookie_jar"
|
||||
require "rack/test/mock_digest_request"
|
||||
require "rack/test/utils"
|
||||
require "rack/test/methods"
|
||||
require "rack/test/uploaded_file"
|
||||
|
||||
module Rack
|
||||
module Test
|
||||
|
||||
VERSION = "0.3.0"
|
||||
|
||||
DEFAULT_HOST = "example.org"
|
||||
MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
|
||||
|
||||
# The common base class for exceptions raised by Rack::Test
|
||||
class Error < StandardError; end
|
||||
|
||||
class Session
|
||||
extend Forwardable
|
||||
include Rack::Test::Utils
|
||||
|
||||
def_delegators :@rack_mock_session, :clear_cookies, :set_cookie, :last_response, :last_request
|
||||
|
||||
# Initialize a new session for the given Rack app
|
||||
def initialize(app, default_host = DEFAULT_HOST)
|
||||
@headers = {}
|
||||
@default_host = default_host
|
||||
@rack_mock_session = Rack::MockSession.new(app, default_host)
|
||||
end
|
||||
|
||||
# Issue a GET request for the given URI with the given params and Rack
|
||||
# environment. Stores the issues request object in #last_request and
|
||||
# the app's response in #last_response. Yield #last_response to a block
|
||||
# if given.
|
||||
#
|
||||
# Example:
|
||||
# get "/"
|
||||
def get(uri, params = {}, env = {}, &block)
|
||||
env = env_for(uri, env.merge(:method => "GET", :params => params))
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Issue a POST request for the given URI. See #get
|
||||
#
|
||||
# Example:
|
||||
# post "/signup", "name" => "Bryan"
|
||||
def post(uri, params = {}, env = {}, &block)
|
||||
env = env_for(uri, env.merge(:method => "POST", :params => params))
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Issue a PUT request for the given URI. See #get
|
||||
#
|
||||
# Example:
|
||||
# put "/"
|
||||
def put(uri, params = {}, env = {}, &block)
|
||||
env = env_for(uri, env.merge(:method => "PUT", :params => params))
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Issue a DELETE request for the given URI. See #get
|
||||
#
|
||||
# Example:
|
||||
# delete "/"
|
||||
def delete(uri, params = {}, env = {}, &block)
|
||||
env = env_for(uri, env.merge(:method => "DELETE", :params => params))
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Issue a HEAD request for the given URI. See #get
|
||||
#
|
||||
# Example:
|
||||
# head "/"
|
||||
def head(uri, params = {}, env = {}, &block)
|
||||
env = env_for(uri, env.merge(:method => "HEAD", :params => params))
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Issue a request to the Rack app for the given URI and optional Rack
|
||||
# environment. Stores the issues request object in #last_request and
|
||||
# the app's response in #last_response. Yield #last_response to a block
|
||||
# if given.
|
||||
#
|
||||
# Example:
|
||||
# request "/"
|
||||
def request(uri, env = {}, &block)
|
||||
env = env_for(uri, env)
|
||||
process_request(uri, env, &block)
|
||||
end
|
||||
|
||||
# Set a header to be included on all subsequent requests through the
|
||||
# session. Use a value of nil to remove a previously configured header.
|
||||
#
|
||||
# Example:
|
||||
# header "User-Agent", "Firefox"
|
||||
def header(name, value)
|
||||
if value.nil?
|
||||
@headers.delete(name)
|
||||
else
|
||||
@headers[name] = value
|
||||
end
|
||||
end
|
||||
|
||||
# Set the username and password for HTTP Basic authorization, to be
|
||||
# included in subsequent requests in the HTTP_AUTHORIZATION header.
|
||||
#
|
||||
# Example:
|
||||
# basic_authorize "bryan", "secret"
|
||||
def basic_authorize(username, password)
|
||||
encoded_login = ["#{username}:#{password}"].pack("m*")
|
||||
header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
|
||||
end
|
||||
|
||||
alias_method :authorize, :basic_authorize
|
||||
|
||||
def digest_authorize(username, password)
|
||||
@digest_username = username
|
||||
@digest_password = password
|
||||
end
|
||||
|
||||
# Rack::Test will not follow any redirects automatically. This method
|
||||
# will follow the redirect returned in the last response. If the last
|
||||
# response was not a redirect, an error will be raised.
|
||||
def follow_redirect!
|
||||
unless last_response.redirect?
|
||||
raise Error.new("Last response was not a redirect. Cannot follow_redirect!")
|
||||
end
|
||||
|
||||
get(last_response["Location"])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def env_for(path, env)
|
||||
uri = URI.parse(path)
|
||||
uri.host ||= @default_host
|
||||
|
||||
env = default_env.merge(env)
|
||||
|
||||
env.update("HTTPS" => "on") if URI::HTTPS === uri
|
||||
env["X-Requested-With"] = "XMLHttpRequest" if env[:xhr]
|
||||
|
||||
if (env[:method] == "POST" || env["REQUEST_METHOD"] == "POST") && !env.has_key?(:input)
|
||||
env["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
|
||||
|
||||
multipart = (Hash === env[:params]) &&
|
||||
env[:params].any? { |_, v| UploadedFile === v }
|
||||
|
||||
if multipart
|
||||
env[:input] = multipart_body(env.delete(:params))
|
||||
env["CONTENT_LENGTH"] ||= env[:input].length.to_s
|
||||
env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
|
||||
else
|
||||
env[:input] = params_to_string(env.delete(:params))
|
||||
end
|
||||
end
|
||||
|
||||
params = env[:params] || {}
|
||||
params.update(parse_query(uri.query))
|
||||
|
||||
uri.query = requestify(params)
|
||||
|
||||
if env.has_key?(:cookie)
|
||||
set_cookie(env.delete(:cookie), uri)
|
||||
end
|
||||
|
||||
Rack::MockRequest.env_for(uri.to_s, env)
|
||||
end
|
||||
|
||||
def process_request(uri, env)
|
||||
uri = URI.parse(uri)
|
||||
uri.host ||= @default_host
|
||||
|
||||
@rack_mock_session.request(uri, env)
|
||||
|
||||
if retry_with_digest_auth?(env)
|
||||
auth_env = env.merge({
|
||||
"HTTP_AUTHORIZATION" => digest_auth_header,
|
||||
"rack-test.digest_auth_retry" => true
|
||||
})
|
||||
auth_env.delete('rack.request')
|
||||
process_request(uri.path, auth_env)
|
||||
else
|
||||
yield last_response if block_given?
|
||||
|
||||
last_response
|
||||
end
|
||||
end
|
||||
|
||||
def digest_auth_header
|
||||
challenge = last_response["WWW-Authenticate"].split(" ", 2).last
|
||||
params = Rack::Auth::Digest::Params.parse(challenge)
|
||||
|
||||
params.merge!({
|
||||
"username" => @digest_username,
|
||||
"nc" => "00000001",
|
||||
"cnonce" => "nonsensenonce",
|
||||
"uri" => last_request.path_info,
|
||||
"method" => last_request.env["REQUEST_METHOD"],
|
||||
})
|
||||
|
||||
params["response"] = MockDigestRequest.new(params).response(@digest_password)
|
||||
|
||||
"Digest #{params}"
|
||||
end
|
||||
|
||||
def retry_with_digest_auth?(env)
|
||||
last_response.status == 401 &&
|
||||
digest_auth_configured? &&
|
||||
!env["rack-test.digest_auth_retry"]
|
||||
end
|
||||
|
||||
def digest_auth_configured?
|
||||
@digest_username
|
||||
end
|
||||
|
||||
def default_env
|
||||
{ "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@headers)
|
||||
end
|
||||
|
||||
def params_to_string(params)
|
||||
case params
|
||||
when Hash then requestify(params)
|
||||
when nil then ""
|
||||
else params
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
169
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb
vendored
Normal file
169
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
require "uri"
|
||||
module Rack
|
||||
module Test
|
||||
|
||||
class Cookie
|
||||
include Rack::Utils
|
||||
|
||||
# :api: private
|
||||
attr_reader :name, :value
|
||||
|
||||
# :api: private
|
||||
def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
|
||||
@default_host = default_host
|
||||
uri ||= default_uri
|
||||
|
||||
# separate the name / value pair from the cookie options
|
||||
@name_value_raw, options = raw.split(/[;,] */n, 2)
|
||||
|
||||
@name, @value = parse_query(@name_value_raw, ';').to_a.first
|
||||
@options = parse_query(options, ';')
|
||||
|
||||
@options["domain"] ||= (uri.host || default_host)
|
||||
@options["path"] ||= uri.path.sub(/\/[^\/]*\Z/, "")
|
||||
end
|
||||
|
||||
def replaces?(other)
|
||||
[name.downcase, domain, path] == [other.name.downcase, other.domain, other.path]
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def raw
|
||||
@name_value_raw
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def empty?
|
||||
@value.nil? || @value.empty?
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def domain
|
||||
@options["domain"]
|
||||
end
|
||||
|
||||
def secure?
|
||||
@options.has_key?("secure")
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def path
|
||||
@options["path"].strip || "/"
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def expires
|
||||
Time.parse(@options["expires"]) if @options["expires"]
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def expired?
|
||||
expires && expires < Time.now
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def valid?(uri)
|
||||
uri ||= default_uri
|
||||
|
||||
if uri.host.nil?
|
||||
uri.host = @default_host
|
||||
end
|
||||
|
||||
(!secure? || (secure? && uri.scheme == "https")) &&
|
||||
uri.host =~ Regexp.new("#{Regexp.escape(domain)}$", Regexp::IGNORECASE) &&
|
||||
uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def matches?(uri)
|
||||
! expired? && valid?(uri)
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def <=>(other)
|
||||
# Orders the cookies from least specific to most
|
||||
[name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_uri
|
||||
URI.parse("//" + @default_host + "/")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class CookieJar
|
||||
|
||||
# :api: private
|
||||
def initialize(cookies = [], default_host = DEFAULT_HOST)
|
||||
@default_host = default_host
|
||||
@cookies = cookies
|
||||
@cookies.sort!
|
||||
end
|
||||
|
||||
def [](name)
|
||||
cookies = hash_for(nil)
|
||||
# TODO: Should be case insensitive
|
||||
cookies[name] && cookies[name].value
|
||||
end
|
||||
|
||||
def []=(name, value)
|
||||
# TODO: needs proper escaping
|
||||
merge("#{name}=#{value}")
|
||||
end
|
||||
|
||||
def merge(raw_cookies, uri = nil)
|
||||
return unless raw_cookies
|
||||
|
||||
raw_cookies.each_line do |raw_cookie|
|
||||
cookie = Cookie.new(raw_cookie, uri, @default_host)
|
||||
self << cookie if cookie.valid?(uri)
|
||||
end
|
||||
end
|
||||
|
||||
def <<(new_cookie)
|
||||
@cookies.reject! do |existing_cookie|
|
||||
new_cookie.replaces?(existing_cookie)
|
||||
end
|
||||
|
||||
@cookies << new_cookie
|
||||
@cookies.sort!
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def for(uri)
|
||||
hash_for(uri).values.map { |c| c.raw }.join(';')
|
||||
end
|
||||
|
||||
def to_hash
|
||||
cookies = {}
|
||||
|
||||
hash_for(nil).each do |name, cookie|
|
||||
cookies[name] = cookie.value
|
||||
end
|
||||
|
||||
return cookies
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def hash_for(uri = nil)
|
||||
cookies = {}
|
||||
|
||||
# The cookies are sorted by most specific first. So, we loop through
|
||||
# all the cookies in order and add it to a hash by cookie name if
|
||||
# the cookie can be sent to the current URI. It's added to the hash
|
||||
# so that when we are done, the cookies will be unique by name and
|
||||
# we'll have grabbed the most specific to the URI.
|
||||
@cookies.each do |cookie|
|
||||
cookies[cookie.name] = cookie if cookie.matches?(uri)
|
||||
end
|
||||
|
||||
return cookies
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
45
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb
vendored
Normal file
45
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
require "forwardable"
|
||||
|
||||
module Rack
|
||||
module Test
|
||||
module Methods
|
||||
extend Forwardable
|
||||
|
||||
def rack_test_session
|
||||
@_rack_test_session ||= Rack::Test::Session.new(app)
|
||||
end
|
||||
|
||||
def rack_mock_session
|
||||
@_rack_mock_session ||= Rack::MockSession.new(app)
|
||||
end
|
||||
|
||||
METHODS = [
|
||||
:request,
|
||||
|
||||
# HTTP verbs
|
||||
:get,
|
||||
:post,
|
||||
:put,
|
||||
:delete,
|
||||
:head,
|
||||
|
||||
# Redirects
|
||||
:follow_redirect!,
|
||||
|
||||
# Header-related features
|
||||
:header,
|
||||
:set_cookie,
|
||||
:clear_cookies,
|
||||
:authorize,
|
||||
:basic_authorize,
|
||||
:digest_authorize,
|
||||
|
||||
# Expose the last request and response
|
||||
:last_response,
|
||||
:last_request
|
||||
]
|
||||
|
||||
def_delegators :rack_test_session, *METHODS
|
||||
end
|
||||
end
|
||||
end
|
27
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb
vendored
Normal file
27
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
module Rack
|
||||
module Test
|
||||
|
||||
class MockDigestRequest
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
def method_missing(sym)
|
||||
if @params.has_key? k = sym.to_s
|
||||
return @params[k]
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def method
|
||||
@params['method']
|
||||
end
|
||||
|
||||
def response(password)
|
||||
Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
36
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb
vendored
Normal file
36
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
require "tempfile"
|
||||
|
||||
module Rack
|
||||
module Test
|
||||
|
||||
class UploadedFile
|
||||
# The filename, *not* including the path, of the "uploaded" file
|
||||
attr_reader :original_filename
|
||||
|
||||
# The content type of the "uploaded" file
|
||||
attr_accessor :content_type
|
||||
|
||||
def initialize(path, content_type = "text/plain", binary = false)
|
||||
raise "#{path} file does not exist" unless ::File.exist?(path)
|
||||
@content_type = content_type
|
||||
@original_filename = ::File.basename(path)
|
||||
@tempfile = Tempfile.new(@original_filename)
|
||||
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
|
||||
@tempfile.binmode if binary
|
||||
FileUtils.copy_file(path, @tempfile.path)
|
||||
end
|
||||
|
||||
def path
|
||||
@tempfile.path
|
||||
end
|
||||
|
||||
alias_method :local_path, :path
|
||||
|
||||
def method_missing(method_name, *args, &block) #:nodoc:
|
||||
@tempfile.__send__(method_name, *args, &block)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
75
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb
vendored
Normal file
75
actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
module Rack
|
||||
module Test
|
||||
|
||||
module Utils
|
||||
include Rack::Utils
|
||||
|
||||
def requestify(value, prefix = nil)
|
||||
case value
|
||||
when Array
|
||||
value.map do |v|
|
||||
requestify(v, "#{prefix}[]")
|
||||
end.join("&")
|
||||
when Hash
|
||||
value.map do |k, v|
|
||||
requestify(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
||||
end.join("&")
|
||||
else
|
||||
"#{prefix}=#{escape(value)}"
|
||||
end
|
||||
end
|
||||
|
||||
module_function :requestify
|
||||
|
||||
def multipart_requestify(params, first=true)
|
||||
p = Hash.new
|
||||
|
||||
params.each do |key, value|
|
||||
k = first ? key.to_s : "[#{key}]"
|
||||
|
||||
if Hash === value
|
||||
multipart_requestify(value, false).each do |subkey, subvalue|
|
||||
p[k + subkey] = subvalue
|
||||
end
|
||||
else
|
||||
p[k] = value
|
||||
end
|
||||
end
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
module_function :multipart_requestify
|
||||
|
||||
def multipart_body(params)
|
||||
multipart_requestify(params).map do |key, value|
|
||||
if value.respond_to?(:original_filename)
|
||||
::File.open(value.path, "rb") do |f|
|
||||
f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
|
||||
|
||||
<<-EOF
|
||||
--#{MULTIPART_BOUNDARY}\r
|
||||
Content-Disposition: form-data; name="#{key}"; filename="#{escape(value.original_filename)}"\r
|
||||
Content-Type: #{value.content_type}\r
|
||||
Content-Length: #{::File.stat(value.path).size}\r
|
||||
\r
|
||||
#{f.read}\r
|
||||
EOF
|
||||
end
|
||||
else
|
||||
<<-EOF
|
||||
--#{MULTIPART_BOUNDARY}\r
|
||||
Content-Disposition: form-data; name="#{key}"\r
|
||||
\r
|
||||
#{value}\r
|
||||
EOF
|
||||
end
|
||||
end.join("")+"--#{MULTIPART_BOUNDARY}--\r"
|
||||
end
|
||||
|
||||
module_function :multipart_body
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -269,15 +269,16 @@ def punctuate_body!(part)
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
# Evaluates the local assigns and controller ivars, pushes them to the view.
|
||||
def _evaluate_assigns_and_ivars #:nodoc:
|
||||
unless @assigns_added
|
||||
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
|
||||
_copy_ivars_from_controller
|
||||
@assigns_added = true
|
||||
end
|
||||
# Evaluates the local assigns and controller ivars, pushes them to the view.
|
||||
def _evaluate_assigns_and_ivars #:nodoc:
|
||||
unless @assigns_added
|
||||
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
|
||||
_copy_ivars_from_controller
|
||||
@assigns_added = true
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _copy_ivars_from_controller #:nodoc:
|
||||
if @controller
|
||||
@ -288,8 +289,11 @@ def _copy_ivars_from_controller #:nodoc:
|
||||
end
|
||||
|
||||
def _set_controller_content_type(content_type) #:nodoc:
|
||||
if controller.respond_to?(:response)
|
||||
controller.response.content_type ||= content_type
|
||||
# TODO: Remove this method when new base is switched
|
||||
unless defined?(ActionController::Http)
|
||||
if controller.respond_to?(:response)
|
||||
controller.response.content_type ||= content_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'cgi'
|
||||
require 'action_view/helpers/form_helper'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
|
||||
module ActionView
|
||||
class Base
|
||||
|
@ -248,6 +248,11 @@ def number_with_precision(number, *args)
|
||||
# number_to_human_size(483989, :precision => 0) # => 473 KB
|
||||
# number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
|
||||
#
|
||||
# Zeros after the decimal point are always stripped out, regardless of the
|
||||
# specified precision:
|
||||
# helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
|
||||
# helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
|
||||
#
|
||||
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the
|
||||
# +precision+ as its optional second parameter:
|
||||
# number_to_human_size(1234567, 2) # => 1.18 MB
|
||||
@ -293,7 +298,7 @@ def number_to_human_size(number, *args)
|
||||
:precision => precision,
|
||||
:separator => separator,
|
||||
:delimiter => delimiter
|
||||
).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
|
||||
).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
|
||||
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
|
||||
rescue
|
||||
number
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'set'
|
||||
require 'active_support/json'
|
||||
require 'active_support/core_ext/object/extending'
|
||||
|
||||
module ActionView
|
||||
module Helpers
|
||||
@ -572,6 +573,7 @@ def observe_form(form_id, options = {})
|
||||
# #include_helpers_from_context has nothing to overwrite.
|
||||
class JavaScriptGenerator #:nodoc:
|
||||
def initialize(context, &block) #:nodoc:
|
||||
context._evaluate_assigns_and_ivars
|
||||
@context, @lines = context, []
|
||||
include_helpers_from_context
|
||||
@context.with_output_buffer(@lines) do
|
||||
|
@ -34,12 +34,16 @@ def concat(string, unused_binding = nil)
|
||||
|
||||
# Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
|
||||
# (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...").
|
||||
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# truncate("Once upon a time in a world far far away")
|
||||
# # => Once upon a time in a world f...
|
||||
#
|
||||
# truncate("Once upon a time in a world far far away", :separator => ' ')
|
||||
# # => Once upon a time in a world...
|
||||
#
|
||||
# truncate("Once upon a time in a world far far away", :length => 14)
|
||||
# # => Once upon a...
|
||||
#
|
||||
@ -71,7 +75,8 @@ def truncate(text, *args)
|
||||
if text
|
||||
l = options[:length] - options[:omission].mb_chars.length
|
||||
chars = text.mb_chars
|
||||
(chars.length > options[:length] ? chars[0...l] + options[:omission] : text).to_s
|
||||
stop = options[:separator] ? (chars.rindex(options[:separator].mb_chars, l) || l) : l
|
||||
(chars.length > options[:length] ? chars[0...stop] + options[:omission] : text).to_s
|
||||
end
|
||||
end
|
||||
|
||||
@ -535,7 +540,7 @@ def auto_link_urls(text, html_options = {})
|
||||
link_attributes = html_options.stringify_keys
|
||||
text.gsub(AUTO_LINK_RE) do
|
||||
href = $&
|
||||
punctuation = ''
|
||||
punctuation = []
|
||||
left, right = $`, $'
|
||||
# detect already linked URLs and URLs in the middle of a tag
|
||||
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
||||
@ -543,17 +548,18 @@ def auto_link_urls(text, html_options = {})
|
||||
href
|
||||
else
|
||||
# don't include trailing punctuation character as part of the URL
|
||||
if href.sub!(/[^\w\/-]$/, '') and punctuation = $& and opening = BRACKETS[punctuation]
|
||||
if href.scan(opening).size > href.scan(punctuation).size
|
||||
href << punctuation
|
||||
punctuation = ''
|
||||
while href.sub!(/[^\w\/-]$/, '')
|
||||
punctuation.push $&
|
||||
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
||||
href << punctuation.pop
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
link_text = block_given?? yield(href) : href
|
||||
href = 'http://' + href unless href.index('http') == 0
|
||||
|
||||
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation
|
||||
content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation.reverse.join('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
require "active_support/core_ext/class/inheritable_attributes"
|
||||
require "action_dispatch/http/mime_type"
|
||||
|
||||
# Legacy TemplateHandler stub
|
||||
module ActionView
|
||||
module TemplateHandlers #:nodoc:
|
||||
@ -19,6 +22,9 @@ def compile(template)
|
||||
end
|
||||
|
||||
class TemplateHandler
|
||||
extlib_inheritable_accessor :default_format
|
||||
self.default_format = Mime::HTML
|
||||
|
||||
def self.call(template)
|
||||
"#{name}.new(self).render(template, local_assigns)"
|
||||
end
|
||||
|
@ -33,7 +33,7 @@ def register_template_handler(extension, klass)
|
||||
end
|
||||
|
||||
def template_handler_extensions
|
||||
@@template_handlers.keys.map(&:to_s).sort
|
||||
@@template_handlers.keys.map {|key| key.to_s }.sort
|
||||
end
|
||||
|
||||
def registered_template_handler(extension)
|
||||
|
@ -5,6 +5,8 @@ module TemplateHandlers
|
||||
class Builder < TemplateHandler
|
||||
include Compilable
|
||||
|
||||
self.default_format = Mime::XML
|
||||
|
||||
def compile(template)
|
||||
"_set_controller_content_type(Mime::XML);" +
|
||||
"xml = ::Builder::XmlMarkup.new(:indent => 2);" +
|
||||
|
@ -13,6 +13,8 @@ class ERB < TemplateHandler
|
||||
cattr_accessor :erb_trim_mode
|
||||
self.erb_trim_mode = '-'
|
||||
|
||||
self.default_format = Mime::HTML
|
||||
|
||||
def compile(template)
|
||||
src = ::ERB.new("<% __in_erb_template=true %>#{template.source}", nil, erb_trim_mode, '@output_buffer').src
|
||||
|
||||
|
@ -3,11 +3,17 @@ module TemplateHandlers
|
||||
class RJS < TemplateHandler
|
||||
include Compilable
|
||||
|
||||
self.default_format = Mime::JS
|
||||
|
||||
def compile(template)
|
||||
"@formats = [:html];" +
|
||||
"controller.response.content_type ||= Mime::JS;" +
|
||||
"update_page do |page|;#{template.source}\nend"
|
||||
end
|
||||
|
||||
def default_format
|
||||
Mime::JS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -7,13 +7,20 @@
|
||||
module ActionView
|
||||
class Template
|
||||
extend TemplateHandlers
|
||||
attr_reader :source, :identifier, :handler
|
||||
attr_reader :source, :identifier, :handler, :mime_type, :details
|
||||
|
||||
def initialize(source, identifier, handler, details)
|
||||
@source = source
|
||||
@identifier = identifier
|
||||
@handler = handler
|
||||
@details = details
|
||||
|
||||
format = details.delete(:format) || begin
|
||||
# TODO: Clean this up
|
||||
handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
|
||||
end
|
||||
@mime_type = Mime::Type.lookup_by_extension(format.to_s)
|
||||
@details[:formats] = Array.wrap(format && format.to_sym)
|
||||
end
|
||||
|
||||
def render(view, locals, &blk)
|
||||
@ -35,12 +42,7 @@ def counter_name
|
||||
def partial?
|
||||
@details[:partial]
|
||||
end
|
||||
|
||||
# TODO: Move out of Template
|
||||
def mime_type
|
||||
Mime::Type.lookup_by_extension(@details[:format].to_s) if @details[:format]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def compile(locals, view)
|
||||
|
@ -1,11 +1,20 @@
|
||||
module ActionView #:nodoc:
|
||||
class TextTemplate < String #:nodoc:
|
||||
|
||||
def initialize(string, content_type = Mime[:html])
|
||||
super(string.to_s)
|
||||
@content_type = Mime[content_type]
|
||||
end
|
||||
|
||||
def details
|
||||
{:formats => [@content_type.to_sym]}
|
||||
end
|
||||
|
||||
def identifier() self end
|
||||
|
||||
def render(*) self end
|
||||
|
||||
def mime_type() Mime::HTML end
|
||||
def mime_type() @content_type end
|
||||
|
||||
def partial?() false end
|
||||
end
|
||||
|
@ -11,7 +11,7 @@ def initialize(*args)
|
||||
attr_internal :rendered
|
||||
alias_method :_render_template_without_template_tracking, :_render_template
|
||||
def _render_template(template, local_assigns = {})
|
||||
if template.respond_to?(:identifier)
|
||||
if template.respond_to?(:identifier) && template.present?
|
||||
@_rendered[:partials][template] += 1 if template.partial?
|
||||
@_rendered[:template] ||= []
|
||||
@_rendered[:template] << template
|
||||
|
@ -1,4 +1,5 @@
|
||||
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
|
||||
require 'active_support/core_ext/class/removal'
|
||||
|
||||
module AbstractControllerTests
|
||||
module Layouts
|
||||
|
@ -1,6 +1,7 @@
|
||||
if ENV["new_base"]
|
||||
require "abstract_unit2"
|
||||
else
|
||||
if ENV['new_base']
|
||||
puts *caller
|
||||
raise 'new_base/abstract_unit already loaded'
|
||||
end
|
||||
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
||||
$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
|
||||
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
|
||||
@ -26,6 +27,8 @@
|
||||
require 'action_controller/testing/process'
|
||||
require 'action_view/test_case'
|
||||
|
||||
$tags[:old_base] = true
|
||||
|
||||
# Show backtraces for deprecated behavior for quicker cleanup.
|
||||
ActiveSupport::Deprecation.debug = true
|
||||
|
||||
@ -41,4 +44,3 @@
|
||||
|
||||
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
||||
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
|
||||
end
|
@ -28,9 +28,9 @@ def get_session_id
|
||||
end
|
||||
|
||||
def call_reset_session
|
||||
session[:bar]
|
||||
session[:foo]
|
||||
reset_session
|
||||
session[:bar] = "baz"
|
||||
session[:foo] = "baz"
|
||||
head :ok
|
||||
end
|
||||
|
||||
@ -91,7 +91,7 @@ def test_setting_session_value_after_session_reset
|
||||
|
||||
get '/get_session_value'
|
||||
assert_response :success
|
||||
assert_equal 'foo: nil', response.body
|
||||
assert_equal 'foo: "baz"', response.body
|
||||
|
||||
get '/get_session_id'
|
||||
assert_response :success
|
||||
|
@ -1,4 +1,5 @@
|
||||
require 'abstract_unit'
|
||||
require 'action_controller/vendor/html-scanner'
|
||||
|
||||
# a controller class to facilitate the tests
|
||||
class ActionPackAssertionsController < ActionController::Base
|
||||
@ -12,6 +13,9 @@ def hello_world() render :template => "test/hello_world"; end
|
||||
# a standard template
|
||||
def hello_xml_world() render :template => "test/hello_xml_world"; end
|
||||
|
||||
# a standard partial
|
||||
def partial() render :partial => 'test/partial'; end
|
||||
|
||||
# a redirect to an internal location
|
||||
def redirect_internal() redirect_to "/nothing"; end
|
||||
|
||||
@ -292,8 +296,8 @@ def test_assert_redirected_to_top_level_named_route_with_same_controller_name_in
|
||||
# make sure that the template objects exist
|
||||
def test_template_objects_alive
|
||||
process :assign_this
|
||||
assert !@controller.template.assigns['hi']
|
||||
assert @controller.template.assigns['howdy']
|
||||
assert !@controller.template.instance_variable_get(:"@hi")
|
||||
assert @controller.template.instance_variable_get(:"@howdy")
|
||||
end
|
||||
|
||||
# make sure we don't have template objects when we shouldn't
|
||||
@ -331,6 +335,26 @@ def test_flash_have_nots
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_template_with_partial
|
||||
get :partial
|
||||
assert_template :partial => '_partial'
|
||||
end
|
||||
|
||||
def test_assert_template_with_nil
|
||||
get :nothing
|
||||
assert_template nil
|
||||
end
|
||||
|
||||
def test_assert_template_with_string
|
||||
get :hello_world
|
||||
assert_template 'hello_world'
|
||||
end
|
||||
|
||||
def test_assert_template_with_symbol
|
||||
get :hello_world
|
||||
assert_template :hello_world
|
||||
end
|
||||
|
||||
# check if we were rendered by a file-based template?
|
||||
def test_rendered_action
|
||||
process :nothing
|
||||
@ -421,7 +445,6 @@ def test_render_based_on_parameters
|
||||
assert_equal "Mr. David", @response.body
|
||||
end
|
||||
|
||||
|
||||
def test_assert_redirection_fails_with_incorrect_controller
|
||||
process :redirect_to_controller
|
||||
assert_raise(ActiveSupport::TestCase::Assertion) do
|
||||
|
@ -48,6 +48,8 @@ def setup
|
||||
super
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
ActionController::Routing::Routes.clear!
|
||||
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.main '', :controller => 'posts'
|
||||
map.formatted_posts 'posts.:format', :controller => 'posts'
|
||||
|
@ -148,12 +148,13 @@ class AcceptBasedContentTypeTest < ActionController::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
@_old_accept_header = ActionController::Base.use_accept_header
|
||||
ActionController::Base.use_accept_header = true
|
||||
end
|
||||
|
||||
def teardown
|
||||
super
|
||||
ActionController::Base.use_accept_header = false
|
||||
ActionController::Base.use_accept_header = @_old_accept_header
|
||||
end
|
||||
|
||||
|
||||
|
@ -4,44 +4,48 @@ class CookieTest < ActionController::TestCase
|
||||
class TestController < ActionController::Base
|
||||
def authenticate
|
||||
cookies["user_name"] = "david"
|
||||
head :ok
|
||||
end
|
||||
|
||||
def set_with_with_escapable_characters
|
||||
cookies["that & guy"] = "foo & bar => baz"
|
||||
head :ok
|
||||
end
|
||||
|
||||
def authenticate_for_fourteen_days
|
||||
cookies["user_name"] = { "value" => "david", "expires" => Time.utc(2005, 10, 10,5) }
|
||||
head :ok
|
||||
end
|
||||
|
||||
def authenticate_for_fourteen_days_with_symbols
|
||||
cookies[:user_name] = { :value => "david", :expires => Time.utc(2005, 10, 10,5) }
|
||||
head :ok
|
||||
end
|
||||
|
||||
def set_multiple_cookies
|
||||
cookies["user_name"] = { "value" => "david", "expires" => Time.utc(2005, 10, 10,5) }
|
||||
cookies["login"] = "XJ-122"
|
||||
head :ok
|
||||
end
|
||||
|
||||
def access_frozen_cookies
|
||||
cookies["will"] = "work"
|
||||
head :ok
|
||||
end
|
||||
|
||||
def logout
|
||||
cookies.delete("user_name")
|
||||
head :ok
|
||||
end
|
||||
|
||||
def delete_cookie_with_path
|
||||
cookies.delete("user_name", :path => '/beaten')
|
||||
render :text => "hello world"
|
||||
head :ok
|
||||
end
|
||||
|
||||
def authenticate_with_http_only
|
||||
cookies["user_name"] = { :value => "david", :httponly => true }
|
||||
end
|
||||
|
||||
def rescue_action(e)
|
||||
raise unless ActionView::MissingTemplate # No templates here, and we don't care about the output
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
@ -54,38 +58,38 @@ def setup
|
||||
|
||||
def test_setting_cookie
|
||||
get :authenticate
|
||||
assert_equal "user_name=david; path=/", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=david; path=/"
|
||||
assert_equal({"user_name" => "david"}, @response.cookies)
|
||||
end
|
||||
|
||||
def test_setting_with_escapable_characters
|
||||
get :set_with_with_escapable_characters
|
||||
assert_equal "that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/"
|
||||
assert_equal({"that & guy" => "foo & bar => baz"}, @response.cookies)
|
||||
end
|
||||
|
||||
def test_setting_cookie_for_fourteen_days
|
||||
get :authenticate_for_fourteen_days
|
||||
assert_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT"
|
||||
assert_equal({"user_name" => "david"}, @response.cookies)
|
||||
end
|
||||
|
||||
def test_setting_cookie_for_fourteen_days_with_symbols
|
||||
get :authenticate_for_fourteen_days_with_symbols
|
||||
assert_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT"
|
||||
assert_equal({"user_name" => "david"}, @response.cookies)
|
||||
end
|
||||
|
||||
def test_setting_cookie_with_http_only
|
||||
get :authenticate_with_http_only
|
||||
assert_equal "user_name=david; path=/; HttpOnly", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=david; path=/; HttpOnly"
|
||||
assert_equal({"user_name" => "david"}, @response.cookies)
|
||||
end
|
||||
|
||||
def test_multiple_cookies
|
||||
get :set_multiple_cookies
|
||||
assert_equal 2, @response.cookies.size
|
||||
assert_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT\nlogin=XJ-122; path=/", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT\nlogin=XJ-122; path=/"
|
||||
assert_equal({"login" => "XJ-122", "user_name" => "david"}, @response.cookies)
|
||||
end
|
||||
|
||||
@ -95,7 +99,7 @@ def test_setting_test_cookie
|
||||
|
||||
def test_expiring_cookie
|
||||
get :logout
|
||||
assert_equal "user_name=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
||||
assert_equal({"user_name" => nil}, @response.cookies)
|
||||
end
|
||||
|
||||
@ -116,6 +120,16 @@ def test_cookiejar_accessor_with_array_value
|
||||
|
||||
def test_delete_cookie_with_path
|
||||
get :delete_cookie_with_path
|
||||
assert_equal "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT", @response.headers["Set-Cookie"]
|
||||
assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
||||
end
|
||||
|
||||
private
|
||||
def assert_cookie_header(expected)
|
||||
header = @response.headers["Set-Cookie"]
|
||||
if header.respond_to?(:to_str)
|
||||
assert_equal expected, header
|
||||
else
|
||||
assert_equal expected.split("\n"), header
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -6,20 +6,20 @@ class DispatcherTest < Test::Unit::TestCase
|
||||
def setup
|
||||
ENV['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
Dispatcher.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
|
||||
middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/dispatch/middlewares.rb"))
|
||||
middleware.instance_eval(File.read(middlewares))
|
||||
end
|
||||
|
||||
# Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
|
||||
Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
ActionDispatch::Callbacks.instance_variable_set("@prepare_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
ActionDispatch::Callbacks.instance_variable_set("@before_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
ActionDispatch::Callbacks.instance_variable_set("@after_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
|
||||
@old_router, Dispatcher.router = Dispatcher.router, mock()
|
||||
Dispatcher.router.stubs(:call).returns([200, {}, 'response'])
|
||||
Dispatcher.router.stubs(:reload)
|
||||
Dispatcher.stubs(:require_dependency)
|
||||
end
|
||||
|
||||
def teardown
|
||||
Dispatcher.router = @old_router
|
||||
@dispatcher = nil
|
||||
ENV.delete 'REQUEST_METHOD'
|
||||
end
|
||||
|
||||
@ -29,12 +29,12 @@ def test_clears_dependencies_after_dispatch_if_in_loading_mode
|
||||
end
|
||||
|
||||
def test_reloads_routes_before_dispatch_if_in_loading_mode
|
||||
ActionController::Routing::Routes.expects(:reload).once
|
||||
Dispatcher.router.expects(:reload).once
|
||||
dispatch(false)
|
||||
end
|
||||
|
||||
def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
|
||||
ActionController::Routing::Routes.expects(:reload).never
|
||||
Dispatcher.router.expects(:reload).never
|
||||
ActiveSupport::Dependencies.expects(:clear).never
|
||||
|
||||
dispatch
|
||||
@ -55,7 +55,7 @@ def test_prepare_callbacks
|
||||
assert_nil a || b || c
|
||||
|
||||
# Run callbacks
|
||||
Dispatcher.run_prepare_callbacks
|
||||
dispatch
|
||||
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
@ -72,16 +72,22 @@ def test_to_prepare_with_identifier_replaces
|
||||
Dispatcher.to_prepare(:unique_id) { |*args| a = b = 1 }
|
||||
Dispatcher.to_prepare(:unique_id) { |*args| a = 2 }
|
||||
|
||||
Dispatcher.run_prepare_callbacks
|
||||
dispatch
|
||||
assert_equal 2, a
|
||||
assert_equal nil, b
|
||||
end
|
||||
|
||||
private
|
||||
def dispatch(cache_classes = true)
|
||||
ActionController::Routing::RouteSet.any_instance.stubs(:call).returns([200, {}, 'response'])
|
||||
ActionController::Dispatcher.prepare_each_request = false
|
||||
Dispatcher.define_dispatcher_callbacks(cache_classes)
|
||||
Dispatcher.new.call({'rack.input' => StringIO.new('')})
|
||||
Dispatcher.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
|
||||
middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/dispatch/middlewares.rb"))
|
||||
middleware.instance_eval(File.read(middlewares))
|
||||
end
|
||||
|
||||
@dispatcher ||= Dispatcher.new
|
||||
@dispatcher.call({'rack.input' => StringIO.new(''), 'action_dispatch.show_exceptions' => false})
|
||||
end
|
||||
|
||||
def assert_subclasses(howmany, klass, message = klass.subclasses.inspect)
|
||||
|
@ -1,13 +1,30 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class FilterParamController < ActionController::Base
|
||||
def payment
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
class FilterParamTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = FilterParamController.new
|
||||
class FilterParamTest < ActionController::TestCase
|
||||
tests FilterParamController
|
||||
|
||||
class MockLogger
|
||||
attr_reader :logged
|
||||
attr_accessor :level
|
||||
|
||||
def initialize
|
||||
@level = Logger::DEBUG
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
@logged ||= []
|
||||
@logged << args.first
|
||||
end
|
||||
end
|
||||
|
||||
setup :set_logger
|
||||
|
||||
def test_filter_parameters
|
||||
assert FilterParamController.respond_to?(:filter_parameter_logging)
|
||||
assert !@controller.respond_to?(:filter_parameters)
|
||||
@ -46,4 +63,26 @@ def test_filter_parameters_is_protected
|
||||
assert !FilterParamController.action_methods.include?('filter_parameters')
|
||||
assert_raise(NoMethodError) { @controller.filter_parameters([{'password' => '[FILTERED]'}]) }
|
||||
end
|
||||
|
||||
def test_filter_parameters_inside_logs
|
||||
FilterParamController.filter_parameter_logging(:lifo, :amount)
|
||||
|
||||
get :payment, :lifo => 'Pratik', :amount => '420', :step => '1'
|
||||
|
||||
filtered_params_logs = logs.detect {|l| l =~ /\AParameters/ }
|
||||
|
||||
assert filtered_params_logs.index('"amount"=>"[FILTERED]"')
|
||||
assert filtered_params_logs.index('"lifo"=>"[FILTERED]"')
|
||||
assert filtered_params_logs.index('"step"=>"1"')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_logger
|
||||
@controller.logger = MockLogger.new
|
||||
end
|
||||
|
||||
def logs
|
||||
@logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip}
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,13 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
# FIXME: crashes Ruby 1.9
|
||||
class << ActionController::Base
|
||||
%w(append_around_filter prepend_after_filter prepend_around_filter prepend_before_filter skip_after_filter skip_before_filter skip_filter).each do |pending|
|
||||
define_method(pending) do |*args|
|
||||
$stderr.puts "#{pending} unimplemented: #{args.inspect}"
|
||||
end unless method_defined?(pending)
|
||||
end
|
||||
end
|
||||
|
||||
class FilterTest < Test::Unit::TestCase
|
||||
include ActionController::TestProcess
|
||||
|
||||
@ -141,14 +148,6 @@ class ConditionalOptionsFilter < ConditionalFilterController
|
||||
before_filter :clean_up_tmp, :if => Proc.new { |c| false }
|
||||
end
|
||||
|
||||
class EmptyFilterChainController < TestController
|
||||
self.filter_chain.clear
|
||||
def show
|
||||
@action_executed = true
|
||||
render :text => "yawp!"
|
||||
end
|
||||
end
|
||||
|
||||
class PrependingController < TestController
|
||||
prepend_before_filter :wonderful_life
|
||||
# skip_before_filter :fire_flash
|
||||
@ -455,12 +454,6 @@ def test_after_filters_are_not_run_if_around_filter_does_not_yield
|
||||
assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters']
|
||||
end
|
||||
|
||||
def test_empty_filter_chain
|
||||
assert_equal 0, EmptyFilterChainController.filter_chain.size
|
||||
test_process(EmptyFilterChainController)
|
||||
assert @controller.template.assigns['action_executed']
|
||||
end
|
||||
|
||||
def test_added_filter_to_inheritance_graph
|
||||
assert_equal [ :ensure_login ], TestController.before_filters
|
||||
end
|
||||
@ -607,7 +600,6 @@ def test_filters_with_mixed_specialization_run_in_order
|
||||
def test_dynamic_dispatch
|
||||
%w(foo bar baz).each do |action|
|
||||
request = ActionController::TestRequest.new
|
||||
request.env["action_controller.rescue.request"] = request
|
||||
request.query_parameters[:choose] = action
|
||||
response = DynamicDispatchController.action.call(request.env).last
|
||||
assert_equal action, response.body
|
||||
@ -615,7 +607,6 @@ def test_dynamic_dispatch
|
||||
end
|
||||
|
||||
def test_running_prepended_before_and_after_filter
|
||||
assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length
|
||||
test_process(PrependingBeforeAndAfterController)
|
||||
assert_equal %w( before_all between_before_all_and_after_all after_all ), @controller.template.assigns["ran_filter"]
|
||||
end
|
||||
@ -819,15 +810,6 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase
|
||||
include PostsController::AroundExceptions
|
||||
include ActionController::TestProcess
|
||||
|
||||
def test_filters_registering
|
||||
assert_equal 1, ControllerWithFilterMethod.filter_chain.size
|
||||
assert_equal 1, ControllerWithFilterClass.filter_chain.size
|
||||
assert_equal 1, ControllerWithFilterInstance.filter_chain.size
|
||||
assert_equal 3, ControllerWithSymbolAsFilter.filter_chain.size
|
||||
assert_equal 6, ControllerWithNestedFilters.filter_chain.size
|
||||
assert_equal 4, ControllerWithAllTypesOfFilters.filter_chain.size
|
||||
end
|
||||
|
||||
def test_base
|
||||
controller = PostsController
|
||||
assert_nothing_raised { test_process(controller,'no_raise') }
|
||||
|
@ -60,6 +60,7 @@ def rescue_action(e)
|
||||
|
||||
def std_action
|
||||
@flash_copy = {}.update(flash)
|
||||
render :nothing => true
|
||||
end
|
||||
|
||||
def filter_halting_action
|
||||
@ -79,64 +80,64 @@ def test_flash
|
||||
get :set_flash
|
||||
|
||||
get :use_flash
|
||||
assert_equal "hello", @controller.template.assigns["flash_copy"]["that"]
|
||||
assert_equal "hello", @controller.template.assigns["flashy"]
|
||||
assert_equal "hello", assigns["flash_copy"]["that"]
|
||||
assert_equal "hello", assigns["flashy"]
|
||||
|
||||
get :use_flash
|
||||
assert_nil @controller.template.assigns["flash_copy"]["that"], "On second flash"
|
||||
assert_nil assigns["flash_copy"]["that"], "On second flash"
|
||||
end
|
||||
|
||||
def test_keep_flash
|
||||
get :set_flash
|
||||
|
||||
get :use_flash_and_keep_it
|
||||
assert_equal "hello", @controller.template.assigns["flash_copy"]["that"]
|
||||
assert_equal "hello", @controller.template.assigns["flashy"]
|
||||
assert_equal "hello", assigns["flash_copy"]["that"]
|
||||
assert_equal "hello", assigns["flashy"]
|
||||
|
||||
get :use_flash
|
||||
assert_equal "hello", @controller.template.assigns["flash_copy"]["that"], "On second flash"
|
||||
assert_equal "hello", assigns["flash_copy"]["that"], "On second flash"
|
||||
|
||||
get :use_flash
|
||||
assert_nil @controller.template.assigns["flash_copy"]["that"], "On third flash"
|
||||
assert_nil assigns["flash_copy"]["that"], "On third flash"
|
||||
end
|
||||
|
||||
def test_flash_now
|
||||
get :set_flash_now
|
||||
assert_equal "hello", @controller.template.assigns["flash_copy"]["that"]
|
||||
assert_equal "bar" , @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_equal "hello", @controller.template.assigns["flashy"]
|
||||
assert_equal "hello", assigns["flash_copy"]["that"]
|
||||
assert_equal "bar" , assigns["flash_copy"]["foo"]
|
||||
assert_equal "hello", assigns["flashy"]
|
||||
|
||||
get :attempt_to_use_flash_now
|
||||
assert_nil @controller.template.assigns["flash_copy"]["that"]
|
||||
assert_nil @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_nil @controller.template.assigns["flashy"]
|
||||
assert_nil assigns["flash_copy"]["that"]
|
||||
assert_nil assigns["flash_copy"]["foo"]
|
||||
assert_nil assigns["flashy"]
|
||||
end
|
||||
|
||||
def test_update_flash
|
||||
get :set_flash
|
||||
get :use_flash_and_update_it
|
||||
assert_equal "hello", @controller.template.assigns["flash_copy"]["that"]
|
||||
assert_equal "hello again", @controller.template.assigns["flash_copy"]["this"]
|
||||
assert_equal "hello", assigns["flash_copy"]["that"]
|
||||
assert_equal "hello again", assigns["flash_copy"]["this"]
|
||||
get :use_flash
|
||||
assert_nil @controller.template.assigns["flash_copy"]["that"], "On second flash"
|
||||
assert_equal "hello again", @controller.template.assigns["flash_copy"]["this"], "On second flash"
|
||||
assert_nil assigns["flash_copy"]["that"], "On second flash"
|
||||
assert_equal "hello again", assigns["flash_copy"]["this"], "On second flash"
|
||||
end
|
||||
|
||||
def test_flash_after_reset_session
|
||||
get :use_flash_after_reset_session
|
||||
assert_equal "hello", @controller.template.assigns["flashy_that"]
|
||||
assert_equal "good-bye", @controller.template.assigns["flashy_this"]
|
||||
assert_nil @controller.template.assigns["flashy_that_reset"]
|
||||
assert_equal "hello", assigns["flashy_that"]
|
||||
assert_equal "good-bye", assigns["flashy_this"]
|
||||
assert_nil assigns["flashy_that_reset"]
|
||||
end
|
||||
|
||||
def test_sweep_after_halted_filter_chain
|
||||
get :std_action
|
||||
assert_nil @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_nil assigns["flash_copy"]["foo"]
|
||||
get :filter_halting_action
|
||||
assert_equal "bar", @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_equal "bar", assigns["flash_copy"]["foo"]
|
||||
get :std_action # follow redirection
|
||||
assert_equal "bar", @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_equal "bar", assigns["flash_copy"]["foo"]
|
||||
get :std_action
|
||||
assert_nil @controller.template.assigns["flash_copy"]["foo"]
|
||||
assert_nil assigns["flash_copy"]["foo"]
|
||||
end
|
||||
end
|
||||
|
@ -27,7 +27,7 @@ def rescue_action(e) raise end
|
||||
end
|
||||
end
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
class AllHelpersController < ActionController::Base
|
||||
helper :all
|
||||
end
|
||||
|
||||
@ -104,7 +104,6 @@ def test_helper_attr
|
||||
|
||||
def call_controller(klass, action)
|
||||
request = ActionController::TestRequest.new
|
||||
request.env["action_controller.rescue.request"] = request
|
||||
klass.action(action).call(request.env)
|
||||
end
|
||||
|
||||
@ -112,7 +111,6 @@ def test_helper_for_nested_controller
|
||||
assert_equal 'hello: Iz guuut!',
|
||||
call_controller(Fun::GamesController, "render_hello_world").last.body
|
||||
# request = ActionController::TestRequest.new
|
||||
# request.env["action_controller.rescue.request"] = request
|
||||
#
|
||||
# resp = Fun::GamesController.action(:render_hello_world).call(request.env)
|
||||
# assert_equal 'hello: Iz guuut!', resp.last.body
|
||||
@ -129,7 +127,7 @@ def test_helper_for_acronym_controller
|
||||
end
|
||||
|
||||
def test_all_helpers
|
||||
methods = ApplicationController.master_helper_module.instance_methods.map(&:to_s)
|
||||
methods = AllHelpersController.master_helper_module.instance_methods.map(&:to_s)
|
||||
|
||||
# abc_helper.rb
|
||||
assert methods.include?('bare_a')
|
||||
@ -156,7 +154,7 @@ def test_all_helpers_with_alternate_helper_dir
|
||||
end
|
||||
|
||||
def test_helper_proxy
|
||||
methods = ApplicationController.helpers.methods.map(&:to_s)
|
||||
methods = AllHelpersController.helpers.methods.map(&:to_s)
|
||||
|
||||
# ActionView
|
||||
assert methods.include?('pluralize')
|
||||
@ -217,7 +215,6 @@ def index
|
||||
|
||||
def call_controller(klass, action)
|
||||
request = ActionController::TestRequest.new
|
||||
request.env["action_controller.rescue.request"] = request
|
||||
klass.action(action).call(request.env)
|
||||
end
|
||||
|
||||
|
@ -38,6 +38,15 @@ def authenticate_with_request
|
||||
|
||||
tests DummyDigestController
|
||||
|
||||
setup do
|
||||
# Used as secret in generating nonce to prevent tampering of timestamp
|
||||
@old_secret, ActionController::Base.session_options[:secret] = ActionController::Base.session_options[:secret], "session_options_secret"
|
||||
end
|
||||
|
||||
teardown do
|
||||
ActionController::Base.session_options[:secret] = @old_secret
|
||||
end
|
||||
|
||||
AUTH_HEADERS.each do |header|
|
||||
test "successful authentication with #{header.downcase}" do
|
||||
@request.env[header] = encode_credentials(:username => 'lifo', :password => 'world')
|
||||
@ -149,25 +158,38 @@ def authenticate_with_request
|
||||
assert_equal 'Definitely Maybe', @response.body
|
||||
end
|
||||
|
||||
test "authentication request with _method" do
|
||||
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :method => :post)
|
||||
@request.env['rack.methodoverride.original_method'] = 'POST'
|
||||
put :display
|
||||
|
||||
assert_response :success
|
||||
assert assigns(:logged_in)
|
||||
assert_equal 'Definitely Maybe', @response.body
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def encode_credentials(options)
|
||||
options.reverse_merge!(:nc => "00000001", :cnonce => "0a4f113b", :password_is_ha1 => false)
|
||||
password = options.delete(:password)
|
||||
|
||||
# Set in /initializers/session_store.rb. Used as secret in generating nonce
|
||||
# to prevent tampering of timestamp
|
||||
ActionController::Base.session_options[:secret] = "session_options_secret"
|
||||
# Perform unauthenticated request to retrieve digest parameters to use on subsequent request
|
||||
method = options.delete(:method) || 'GET'
|
||||
|
||||
# Perform unauthenticated GET to retrieve digest parameters to use on subsequent request
|
||||
get :index
|
||||
case method.to_s.upcase
|
||||
when 'GET'
|
||||
get :index
|
||||
when 'POST'
|
||||
post :index
|
||||
end
|
||||
|
||||
assert_response :unauthorized
|
||||
|
||||
credentials = decode_credentials(@response.headers['WWW-Authenticate'])
|
||||
credentials.merge!(options)
|
||||
credentials.reverse_merge!(:uri => "#{@request.env['REQUEST_URI']}")
|
||||
ActionController::HttpAuthentication::Digest.encode_credentials("GET", credentials, password, options[:password_is_ha1])
|
||||
ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1])
|
||||
end
|
||||
|
||||
def decode_credentials(header)
|
||||
|
@ -1,4 +1,5 @@
|
||||
require 'abstract_unit'
|
||||
require 'action_controller/vendor/html-scanner'
|
||||
|
||||
class SessionTest < Test::Unit::TestCase
|
||||
StubApp = lambda { |env|
|
||||
@ -123,8 +124,8 @@ def test_head
|
||||
def test_xml_http_request_get
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest",
|
||||
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
||||
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
)
|
||||
@session.expects(:process).with(:get,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:get,path,params,headers)
|
||||
@ -133,8 +134,8 @@ def test_xml_http_request_get
|
||||
def test_xml_http_request_post
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest",
|
||||
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
||||
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
)
|
||||
@session.expects(:process).with(:post,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:post,path,params,headers)
|
||||
@ -143,8 +144,8 @@ def test_xml_http_request_post
|
||||
def test_xml_http_request_put
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest",
|
||||
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
||||
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
)
|
||||
@session.expects(:process).with(:put,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:put,path,params,headers)
|
||||
@ -153,8 +154,8 @@ def test_xml_http_request_put
|
||||
def test_xml_http_request_delete
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest",
|
||||
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
||||
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
)
|
||||
@session.expects(:process).with(:delete,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:delete,path,params,headers)
|
||||
@ -163,17 +164,17 @@ def test_xml_http_request_delete
|
||||
def test_xml_http_request_head
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest",
|
||||
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
||||
"HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
|
||||
)
|
||||
@session.expects(:process).with(:head,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:head,path,params,headers)
|
||||
end
|
||||
|
||||
def test_xml_http_request_override_accept
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah', "Accept" => "application/xml"}
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah', "HTTP_ACCEPT" => "application/xml"}
|
||||
headers_after_xhr = headers.merge(
|
||||
"X-Requested-With" => "XMLHttpRequest"
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
|
||||
)
|
||||
@session.expects(:process).with(:post,path,params,headers_after_xhr)
|
||||
@session.xml_http_request(:post,path,params,headers)
|
||||
@ -253,7 +254,7 @@ def test_get
|
||||
assert_response 200
|
||||
assert_response :success
|
||||
assert_response :ok
|
||||
assert_equal({}, cookies)
|
||||
assert_equal({}, cookies.to_hash)
|
||||
assert_equal "OK", body
|
||||
assert_equal "OK", response.body
|
||||
assert_kind_of HTML::Document, html_document
|
||||
@ -269,7 +270,7 @@ def test_post
|
||||
assert_response 201
|
||||
assert_response :success
|
||||
assert_response :created
|
||||
assert_equal({}, cookies)
|
||||
assert_equal({}, cookies.to_hash)
|
||||
assert_equal "Created", body
|
||||
assert_equal "Created", response.body
|
||||
assert_kind_of HTML::Document, html_document
|
||||
@ -287,7 +288,7 @@ def test_cookie_monster
|
||||
assert_response 410
|
||||
assert_response :gone
|
||||
assert_equal "cookie_1=; path=/\ncookie_3=chocolate; path=/", headers["Set-Cookie"]
|
||||
assert_equal({"cookie_1"=>nil, "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies)
|
||||
assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies.to_hash)
|
||||
assert_equal "Gone", response.body
|
||||
end
|
||||
end
|
||||
|
@ -9,8 +9,11 @@
|
||||
|
||||
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ]
|
||||
|
||||
require "fixture_template"
|
||||
|
||||
class LayoutTest < ActionController::Base
|
||||
def self.controller_path; 'views' end
|
||||
def self._implied_layout_name; to_s.underscore.gsub(/_controller$/, '') ; end
|
||||
self.view_paths = ActionController::Base.view_paths.dup
|
||||
end
|
||||
|
||||
@ -35,6 +38,15 @@ class ControllerNameSpace::NestedController < LayoutTest
|
||||
class MultipleExtensions < LayoutTest
|
||||
end
|
||||
|
||||
if defined?(ActionController::Http)
|
||||
LayoutTest._write_layout_method
|
||||
ProductController._write_layout_method
|
||||
ItemController._write_layout_method
|
||||
ThirdPartyTemplateLibraryController._write_layout_method
|
||||
MultipleExtensions._write_layout_method
|
||||
ControllerNameSpace::NestedController._write_layout_method
|
||||
end
|
||||
|
||||
class LayoutAutoDiscoveryTest < ActionController::TestCase
|
||||
def setup
|
||||
super
|
||||
@ -56,23 +68,19 @@ def test_controller_name_layout_name_match
|
||||
def test_third_party_template_library_auto_discovers_layout
|
||||
@controller = ThirdPartyTemplateLibraryController.new
|
||||
get :hello
|
||||
assert @controller.active_layout(true).identifier.include?('layouts/third_party_template_library.mab')
|
||||
assert @controller.template.layout.include?('layouts/third_party_template_library')
|
||||
assert_response :success
|
||||
assert_equal 'Mab', @response.body
|
||||
assert_equal 'layouts/third_party_template_library.mab', @response.body
|
||||
end
|
||||
|
||||
def test_namespaced_controllers_auto_detect_layouts
|
||||
def test_namespaced_controllers_auto_detect_layouts1
|
||||
@controller = ControllerNameSpace::NestedController.new
|
||||
get :hello
|
||||
assert_equal 'layouts/controller_name_space/nested', @controller.active_layout(true).to_s
|
||||
assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
|
||||
end
|
||||
|
||||
def test_namespaced_controllers_auto_detect_layouts
|
||||
def test_namespaced_controllers_auto_detect_layouts2
|
||||
@controller = MultipleExtensions.new
|
||||
get :hello
|
||||
assert @controller.active_layout(true).identifier.include?('layouts/multiple_extensions.html.erb')
|
||||
assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
|
||||
end
|
||||
end
|
||||
@ -139,7 +147,7 @@ def test_layout_only_exception_when_included
|
||||
def test_layout_only_exception_when_excepted
|
||||
@controller = OnlyLayoutController.new
|
||||
get :goodbye
|
||||
assert_equal nil, @controller.template.layout
|
||||
assert !@response.body.include?("item.rhtml"), "#{@response.body.inspect} included 'item.rhtml'"
|
||||
end
|
||||
|
||||
def test_layout_except_exception_when_included
|
||||
@ -151,7 +159,7 @@ def test_layout_except_exception_when_included
|
||||
def test_layout_except_exception_when_excepted
|
||||
@controller = ExceptLayoutController.new
|
||||
get :goodbye
|
||||
assert_equal nil, @controller.template.layout
|
||||
assert !@response.body.include?("item.rhtml"), "#{@response.body.inspect} included 'item.rhtml'"
|
||||
end
|
||||
|
||||
def test_layout_set_when_using_render
|
||||
@ -166,15 +174,18 @@ def test_layout_is_not_set_when_none_rendered
|
||||
assert_nil @controller.template.layout
|
||||
end
|
||||
|
||||
def test_exempt_from_layout_honored_by_render_template
|
||||
ActionController::Base.exempt_from_layout :erb
|
||||
@controller = RenderWithTemplateOptionController.new
|
||||
for_tag(:old_base) do
|
||||
# exempt_from_layout is deprecated
|
||||
def test_exempt_from_layout_honored_by_render_template
|
||||
ActionController::Base.exempt_from_layout :erb
|
||||
@controller = RenderWithTemplateOptionController.new
|
||||
|
||||
get :hello
|
||||
assert_equal "alt/hello.rhtml", @response.body.strip
|
||||
get :hello
|
||||
assert_equal "alt/hello.rhtml", @response.body.strip
|
||||
|
||||
ensure
|
||||
ActionController::Base.exempt_from_layout.delete(ERB)
|
||||
ensure
|
||||
ActionController::Base.exempt_from_layout.delete(ERB)
|
||||
end
|
||||
end
|
||||
|
||||
def test_layout_is_picked_from_the_controller_instances_view_path
|
||||
|
@ -11,6 +11,11 @@ class LoggingTest < ActionController::TestCase
|
||||
|
||||
class MockLogger
|
||||
attr_reader :logged
|
||||
attr_accessor :level
|
||||
|
||||
def initialize
|
||||
@level = Logger::DEBUG
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
@logged ||= []
|
||||
@ -30,7 +35,7 @@ def test_logging_without_parameters
|
||||
end
|
||||
|
||||
def test_logging_with_parameters
|
||||
get :show, :id => 10
|
||||
get :show, :id => '10'
|
||||
assert_equal 3, logs.size
|
||||
|
||||
params = logs.detect {|l| l =~ /Parameters/ }
|
||||
@ -44,6 +49,6 @@ def set_logger
|
||||
end
|
||||
|
||||
def logs
|
||||
@logs ||= @controller.logger.logged.compact.map {|l| l.strip}
|
||||
@logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip}
|
||||
end
|
||||
end
|
||||
|
@ -375,9 +375,11 @@ def test_handle_any_any_xml
|
||||
end
|
||||
|
||||
def test_rjs_type_skips_layout
|
||||
@request.accept = "text/javascript"
|
||||
get :all_types_with_layout
|
||||
assert_equal 'RJS for all_types_with_layout', @response.body
|
||||
pending(:new_base) do
|
||||
@request.accept = "text/javascript"
|
||||
get :all_types_with_layout
|
||||
assert_equal 'RJS for all_types_with_layout', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_html_type_with_layout
|
||||
@ -437,7 +439,7 @@ def test_render_action_for_html
|
||||
@controller.instance_eval do
|
||||
def render(*args)
|
||||
unless args.empty?
|
||||
@action = args.first[:action]
|
||||
@action = args.first[:action] || action_name
|
||||
end
|
||||
response.body = "#{@action} - #{@template.formats}"
|
||||
end
|
||||
@ -490,14 +492,15 @@ def index
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def with_iphone
|
||||
Mime::Type.register_alias("text/html", :iphone)
|
||||
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
|
||||
yield
|
||||
ensure
|
||||
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
|
||||
end
|
||||
protected
|
||||
|
||||
def with_iphone
|
||||
Mime::Type.register_alias("text/html", :iphone)
|
||||
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
|
||||
yield
|
||||
ensure
|
||||
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
|
||||
end
|
||||
end
|
||||
|
||||
class SuperPostController < PostController
|
||||
@ -509,6 +512,11 @@ def index
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActionController::Http)
|
||||
PostController._write_layout_method
|
||||
SuperPostController._write_layout_method
|
||||
end
|
||||
|
||||
class MimeControllerLayoutsTest < ActionController::TestCase
|
||||
tests PostController
|
||||
|
||||
@ -526,14 +534,16 @@ def test_missing_layout_renders_properly
|
||||
assert_equal 'Hello iPhone', @response.body
|
||||
end
|
||||
|
||||
def test_format_with_inherited_layouts
|
||||
@controller = SuperPostController.new
|
||||
for_tag(:old_base) do
|
||||
def test_format_with_inherited_layouts
|
||||
@controller = SuperPostController.new
|
||||
|
||||
get :index
|
||||
assert_equal 'Super Firefox', @response.body
|
||||
get :index
|
||||
assert_equal 'Super Firefox', @response.body
|
||||
|
||||
@request.accept = "text/iphone"
|
||||
get :index
|
||||
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
|
||||
@request.accept = "text/iphone"
|
||||
get :index
|
||||
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -19,6 +19,8 @@ def partial
|
||||
end
|
||||
|
||||
class RenderTest < ActionController::TestCase
|
||||
tests TestController
|
||||
|
||||
def test_render_vanilla_js
|
||||
get :render_vanilla_js_hello
|
||||
assert_equal "alert('hello')", @response.body
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
class TestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
layout :determine_layout
|
||||
|
||||
module RenderTestHelper
|
||||
def rjs_helper_method_from_module
|
||||
@ -103,11 +104,26 @@ def render_alternate_default
|
||||
end
|
||||
|
||||
private
|
||||
def default_render
|
||||
if @alternate_default_render
|
||||
@alternate_default_render.call
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def determine_layout
|
||||
case action_name
|
||||
when "render_js_with_explicit_template",
|
||||
"render_js_with_explicit_action_template",
|
||||
"delete_with_js", "update_page", "update_page_with_instance_variables"
|
||||
when "hello_world", "layout_test", "rendering_without_layout",
|
||||
"rendering_nothing_on_layout", "render_text_hello_world",
|
||||
"render_text_hello_world_with_layout",
|
||||
"hello_world_with_layout_false",
|
||||
"partial_only", "partial_only_with_layout",
|
||||
"accessing_params_in_template",
|
||||
"accessing_params_in_template_with_layout",
|
||||
"render_with_explicit_template",
|
||||
"render_with_explicit_string_template",
|
||||
"update_page", "update_page_with_instance_variables"
|
||||
|
||||
"layouts/standard"
|
||||
when "action_talk_to_layout", "layout_overriding_layout"
|
||||
|
@ -625,9 +625,7 @@ def determine_layout
|
||||
"accessing_params_in_template_with_layout",
|
||||
"render_with_explicit_template",
|
||||
"render_with_explicit_string_template",
|
||||
"render_js_with_explicit_template",
|
||||
"render_js_with_explicit_action_template",
|
||||
"delete_with_js", "update_page", "update_page_with_instance_variables"
|
||||
"update_page", "update_page_with_instance_variables"
|
||||
|
||||
"layouts/standard"
|
||||
when "action_talk_to_layout", "layout_overriding_layout"
|
||||
|
@ -1,5 +1,19 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
module ActionDispatch
|
||||
class ShowExceptions
|
||||
private
|
||||
def public_path
|
||||
"#{FIXTURE_LOAD_PATH}/public"
|
||||
end
|
||||
|
||||
# Silence logger
|
||||
def logger
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RescueController < ActionController::Base
|
||||
class NotAuthorized < StandardError
|
||||
end
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'abstract_unit'
|
||||
require 'controller/fake_controllers'
|
||||
require 'active_support/dependencies'
|
||||
|
||||
class MilestonesController < ActionController::Base
|
||||
def index() head :ok end
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
require 'abstract_unit'
|
||||
require 'controller/fake_controllers'
|
||||
require 'action_controller/vendor/html-scanner'
|
||||
|
||||
class SelectorTest < Test::Unit::TestCase
|
||||
#
|
||||
|
@ -11,12 +11,17 @@ class SendFileController < ActionController::Base
|
||||
layout "layouts/standard" # to make sure layouts don't interfere
|
||||
|
||||
attr_writer :options
|
||||
def options() @options ||= {} end
|
||||
def options
|
||||
@options ||= {}
|
||||
end
|
||||
|
||||
def file() send_file(file_path, options) end
|
||||
def data() send_data(file_data, options) end
|
||||
def file
|
||||
send_file(file_path, options)
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
def data
|
||||
send_data(file_data, options)
|
||||
end
|
||||
end
|
||||
|
||||
class SendFileTest < ActionController::TestCase
|
||||
@ -40,17 +45,19 @@ def test_file_nostream
|
||||
assert_equal file_data, response.body
|
||||
end
|
||||
|
||||
def test_file_stream
|
||||
response = nil
|
||||
assert_nothing_raised { response = process('file') }
|
||||
assert_not_nil response
|
||||
assert_kind_of Array, response.body_parts
|
||||
for_tag(:old_base) do
|
||||
def test_file_stream
|
||||
response = nil
|
||||
assert_nothing_raised { response = process('file') }
|
||||
assert_not_nil response
|
||||
assert_kind_of Array, response.body_parts
|
||||
|
||||
require 'stringio'
|
||||
output = StringIO.new
|
||||
output.binmode
|
||||
assert_nothing_raised { response.body_parts.each { |part| output << part.to_s } }
|
||||
assert_equal file_data, output.string
|
||||
require 'stringio'
|
||||
output = StringIO.new
|
||||
output.binmode
|
||||
assert_nothing_raised { response.body_parts.each { |part| output << part.to_s } }
|
||||
assert_equal file_data, output.string
|
||||
end
|
||||
end
|
||||
|
||||
def test_file_url_based_filename
|
||||
|
@ -103,17 +103,15 @@ def no_default_action
|
||||
end
|
||||
|
||||
protected
|
||||
def rescue_action(e) raise end
|
||||
|
||||
def unconditional_redirect
|
||||
redirect_to :action => "unguarded"
|
||||
end
|
||||
def unconditional_redirect
|
||||
redirect_to :action => "unguarded"
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@controller = TestController.new
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
tests TestController
|
||||
|
||||
setup do
|
||||
ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo'
|
||||
end
|
||||
|
||||
@ -184,7 +182,7 @@ def test_unguarded_with_params
|
||||
|
||||
def test_unguarded_without_params
|
||||
get :unguarded
|
||||
assert_equal "", @response.body
|
||||
assert @response.body.blank?
|
||||
end
|
||||
|
||||
def test_guarded_in_session_with_prereqs
|
||||
|
@ -34,7 +34,7 @@ def teardown
|
||||
def test_check_parameters
|
||||
with_test_route_set do
|
||||
get "/"
|
||||
assert_equal '', @controller.response.body
|
||||
assert @controller.response.body.blank?
|
||||
end
|
||||
end
|
||||
|
||||
@ -163,7 +163,7 @@ def test_use_xml_ximple_with_empty_request
|
||||
with_test_route_set do
|
||||
ActionController::Base.param_parsers[Mime::XML] = :xml_simple
|
||||
assert_nothing_raised { post "/", "", {'CONTENT_TYPE' => 'application/xml'} }
|
||||
assert_equal "", @controller.response.body
|
||||
assert @controller.response.body.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -6,6 +6,11 @@ class ShowExceptions
|
||||
def public_path
|
||||
"#{FIXTURE_LOAD_PATH}/public"
|
||||
end
|
||||
|
||||
# Silence logger
|
||||
def logger
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user