From ab321268f86d9013cbd4ecd0b5f46e7b05ec55a9 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 22 Apr 2009 16:10:49 -0700 Subject: No more free lunch --- actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_dispatch.rb | 1 + actionpack/lib/action_view.rb | 1 + 3 files changed, 3 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 100a0be1db..aee6b9dc9f 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -30,6 +30,7 @@ rescue LoadError require 'active_support' end end +require 'active_support/core/all' require File.join(File.dirname(__FILE__), "action_pack") diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index bd5a38cc82..5feb8a4863 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -30,6 +30,7 @@ rescue LoadError require 'active_support' end end +require 'active_support/core/all' $:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-1.0" begin diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index e604c2a581..dd352f9ce0 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -30,6 +30,7 @@ rescue LoadError require 'active_support' end end +require 'active_support/core/all' require File.join(File.dirname(__FILE__), "action_pack") -- cgit v1.2.3 From f5d720fb96f2e085acc4ed17f63272c4d38e567e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 22 Apr 2009 16:41:06 -0700 Subject: Opt in to Dependencies --- actionpack/lib/action_view/template/template.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 0d2f201458..b6967a2013 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -1,3 +1,4 @@ +require 'set' require "action_view/template/path" module ActionView #:nodoc: -- cgit v1.2.3 From 6fee981fa4ea2654f825c58b58327fc15fddf3a6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 22 Apr 2009 16:48:58 -0700 Subject: Opt in to JSON --- actionpack/lib/action_dispatch/middleware/params_parser.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 6df572268c..abaee2829e 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -1,3 +1,5 @@ +require 'active_support/json' + module ActionDispatch class ParamsParser ActionController::Base.param_parsers[Mime::XML] = :xml_simple -- cgit v1.2.3 From b2d6fdae353be4fca41d7ac1839f30d9737162fd Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 22 Apr 2009 17:00:33 -0700 Subject: Fix tests on 1.9 --- actionpack/lib/action_view/helpers/number_helper.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index dea958deaf..c02692b09a 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/float/rounding' + module ActionView module Helpers #:nodoc: # Provides methods for converting numbers into formatted strings. -- cgit v1.2.3 From 0a132c2fe13fb2b8d5dade9cf6abd70601376287 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 22 Apr 2009 17:16:28 -0700 Subject: Refactor ActionView::Path * Decouple from ActionController and ActionMailer * Bring back localization support. * Prepare to decouple templates from the filesystem. * Prepare to decouple localization from ActionView * Fix ActionMailer to take advantage of ActionView::Path --- .../lib/action_controller/abstract/layouts.rb | 4 +- .../lib/action_controller/abstract/renderer.rb | 2 +- actionpack/lib/action_controller/base/layout.rb | 2 +- actionpack/lib/action_controller/base/render.rb | 7 +- actionpack/lib/action_view/paths.rb | 6 +- actionpack/lib/action_view/render/partials.rb | 7 +- actionpack/lib/action_view/render/rendering.rb | 4 +- actionpack/lib/action_view/template/handlers.rb | 4 + actionpack/lib/action_view/template/path.rb | 151 +++++++++++++-------- actionpack/lib/action_view/template/template.rb | 2 +- .../abstract_controller_test.rb | 4 +- actionpack/test/template/render_test.rb | 20 ++- 12 files changed, 131 insertions(+), 82 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 478b301a26..0039e67c5a 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -38,7 +38,7 @@ module AbstractController else self.class_eval %{ def _layout - if view_paths.find_by_parts?("#{_implied_layout_name}", formats, "layouts") + if view_paths.find_by_parts?("#{_implied_layout_name}", {:formats => formats}, "layouts") "#{_implied_layout_name}" else super @@ -62,7 +62,7 @@ module AbstractController raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}" end - name && view_paths.find_by_parts(name, formats, "layouts") + name && view_paths.find_by_parts(name, {:formats => formats}, "layouts") end def _default_layout(require_layout = false) diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index a86eef889e..e31accbbfc 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -29,7 +29,7 @@ module AbstractController def render_to_body(options = {}) name = options[:_template_name] || action_name - template = options[:_template] || view_paths.find_by_parts(name.to_s, formats, options[:_prefix]) + template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) _render_template(template, options) end diff --git a/actionpack/lib/action_controller/base/layout.rb b/actionpack/lib/action_controller/base/layout.rb index 4fcef6c5d9..1ad5191c73 100644 --- a/actionpack/lib/action_controller/base/layout.rb +++ b/actionpack/lib/action_controller/base/layout.rb @@ -182,7 +182,7 @@ module ActionController #:nodoc: def memoized_find_layout(layout, formats) #:nodoc: return layout if layout.nil? || layout.respond_to?(:render) prefix = layout.to_s =~ /layouts\// ? nil : "layouts" - view_paths.find_by_parts(layout.to_s, formats, prefix) + view_paths.find_by_parts(layout.to_s, {:formats => formats}, prefix) end def find_layout(*args) diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 606df58518..52934076e6 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -374,8 +374,13 @@ module ActionController render_for_file(name.sub(/^\//, ''), [layout, true], options) end end - + + # ==== Arguments + # parts:: + # Example: ["show", [:html, :xml], "users", false] def render_for_parts(parts, layout, options = {}) + parts[1] = {:formats => parts[1], :locales => [I18n.locale]} + tmp = view_paths.find_by_parts(*parts) layout = _pick_layout(*layout) unless tmp.exempt_from_layout? diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index 1d0279889c..e48088f344 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -33,18 +33,18 @@ module ActionView #:nodoc: super(*objs.map { |obj| self.class.type_cast(obj) }) end - def find_by_parts(path, extension = nil, prefix = nil, partial = false) + def find_by_parts(path, details = {}, prefix = nil, partial = false) template_path = path.sub(/^\//, '') each do |load_path| - if template = load_path.find_by_parts(template_path, extension, prefix, partial) + if template = load_path.find_by_parts(template_path, details, prefix, partial) return template end end Template.new(path, self) rescue ActionView::MissingTemplate => e - extension ||= [] + extension = details[:formats] || [] raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}") end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index e337dcb63b..43f8a1edf8 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -187,6 +187,7 @@ module ActionView path = ActionController::RecordIdentifier.partial_path(object, controller_path) end _, _, prefix, object = parts = partial_parts(path, options) + parts[1] = {:formats => parts[1]} template = find_by_parts(*parts) _render_partial_object(template, options, (object unless object == true)) end @@ -225,7 +226,7 @@ module ActionView def _render_partial_with_layout(layout, options) if layout prefix = controller && !layout.include?("/") ? controller.controller_path : nil - layout = find_by_parts(layout, formats, prefix, true) + layout = find_by_parts(layout, {:formats => formats}, prefix, true) end content = _render_partial(options) return _render_content_with_layout(content, layout, options[:locals]) @@ -253,7 +254,7 @@ module ActionView def _render_partial_with_layout(layout, options) if layout prefix = controller && !layout.include?("/") ? controller.controller_path : nil - layout = find_by_parts(layout, formats, prefix, true) + layout = find_by_parts(layout, {:formats => formats}, prefix, true) end content = _render_partial(options) return _render_content_with_layout(content, layout, options[:locals]) @@ -321,7 +322,7 @@ module ActionView def _pick_partial_template(partial_path) #:nodoc: prefix = controller_path unless partial_path.include?('/') - find_by_parts(partial_path, formats, prefix, true) + find_by_parts(partial_path, {:formats => formats}, prefix, true) end memoize :_pick_partial_template end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index a9b2acecd5..4213b09e48 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -23,10 +23,10 @@ module ActionView return _render_partial_with_layout(layout, options) if options.key?(:partial) return _render_partial_with_block(layout, block, options) if block_given? - layout = find_by_parts(layout, formats) if layout + layout = find_by_parts(layout, {:formats => formats}) if layout if file = options[:file] - template = find_by_parts(file, formats) + template = find_by_parts(file, {:formats => formats}) _render_template_with_layout(template, layout, :locals => options[:locals]) elsif inline = options[:inline] _render_inline(inline, layout, options) diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index fb85f28851..448ab6731b 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -16,6 +16,10 @@ module ActionView #:nodoc: @@template_handlers = {} @@default_template_handlers = nil + + def self.extensions + @@template_handlers.keys + end # Register a class that knows how to handle template files with the given # extension. This can be used to implement new template types. diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb index 9709549b70..660a7e91a2 100644 --- a/actionpack/lib/action_view/template/path.rb +++ b/actionpack/lib/action_view/template/path.rb @@ -1,13 +1,81 @@ module ActionView class Template + # Abstract super class class Path - attr_reader :path, :paths - delegate :hash, :inspect, :to => :path - def initialize(options) - @cache = options[:cache] + @cache = options[:cache] + @cached = {} end - + + # Normalizes the arguments and passes it on to find_template + def find_by_parts(*args) + find_all_by_parts(*args).first + end + + def find_all_by_parts(name, details = {}, prefix = nil, partial = nil) + details[:locales] = [I18n.locale] + name = name.to_s.gsub(handler_matcher, '').split("/") + find_templates(name.pop, details, [prefix, *name].compact.join("/"), partial) + end + + private + + # This is what child classes implement. No defaults are needed + # because Path guarentees that the arguments are present and + # normalized. + def find_templates(name, details, prefix, partial) + raise NotImplementedError + end + + # TODO: Refactor this to abstract out the file system + def initialize_template(file) + t = Template.new(file.split("#{self}/").last, self) + t.load! + t + end + + def valid_handlers + @valid_handlers ||= TemplateHandlers.extensions + end + + def handler_matcher + @handler_matcher ||= begin + e = valid_handlers.join('|') + /\.(?:#{e})$/ + end + end + + def handler_glob + e = TemplateHandlers.extensions.join(',') + ".{#{e}}" + end + + def formats_glob + @formats_glob ||= begin + formats = Mime::SET.map { |m| m.symbol } + '{' + formats.map { |l| ".#{l}," }.join + '}' + end + end + + def cached(key) + return yield unless @cache + return @cached[key] if @cached.key?(key) + @cached[key] = yield + end + end + + class FileSystemPath < Path + + def initialize(path, options = {}) + raise ArgumentError, "path already is a Path class" if path.is_a?(Path) + super(options) + @path = path + end + + # TODO: This is the currently needed API. Make this suck less + # ==== + attr_reader :path + def to_s if defined?(RAILS_ROOT) path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') @@ -27,61 +95,36 @@ module ActionView def eql?(path) to_str == path.to_str end - - def find_by_parts(name, extensions = nil, prefix = nil, partial = nil) - path = prefix ? "#{prefix}/" : "" + # ==== - name = name.to_s.split("/") - name[-1] = "_#{name[-1]}" if partial - - path << name.join("/") - - template = nil - - Array(extensions).each do |extension| - extensioned_path = extension ? "#{path}.#{extension}" : path - break if (template = find_template(extensioned_path)) + def find_templates(name, details, prefix, partial) + if glob = parts_to_glob(name, details, prefix, partial) + cached(glob) do + Dir[glob].map do |path| + initialize_template(path) unless File.directory?(path) + end.compact + end end - template || find_template(path) end - - private - def create_template(file) - Template.new(file.split("#{self}/").last, self) - end - end - - class FileSystemPath < Path - def initialize(path, options = {}) - raise ArgumentError, "path already is a Path class" if path.is_a?(Path) - - super(options) - @path, @paths = path, {} - - # **/*/** is a hax for symlinked directories - load_templates("#{@path}/{**/*,**}/**") if @cache - end - - private - - def load_template(template) - template.load! - template.accessible_paths.each do |path| - @paths[path] = template - end - end - - def find_template(path) - load_templates("#{@path}/#{path}{,.*}") unless @cache - @paths[path] - end - def load_templates(glob) - Dir[glob].each do |file| - load_template(create_template(file)) unless File.directory?(file) + private + + def parts_to_glob(name, details, prefix, partial) + path = "" + path << "#{prefix}/" unless prefix.empty? + path << (partial ? "_#{name}" : name) + + extensions = "" + [:locales, :formats].each do |k| + extensions << if exts = details[k] + '{' + exts.map {|e| ".#{e},"}.join + '}' + else + k == :formats ? formats_glob : '' + end end + + "#{@path}/#{path}#{extensions}#{handler_glob}" end - end end end \ No newline at end of file diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index b6967a2013..e541336613 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -101,7 +101,7 @@ module ActionView #:nodoc: end def content_type - format.gsub('.', '/') + format && format.gsub('.', '/') end private diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index 918062c7db..f1dcb39ef1 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -139,10 +139,10 @@ module AbstractController private def self.layout(formats) begin - view_paths.find_by_parts(name.underscore, formats, "layouts") + view_paths.find_by_parts(name.underscore, {:formats => formats}t, "layouts") rescue ActionView::MissingTemplate begin - view_paths.find_by_parts("application", formats, "layouts") + view_paths.find_by_parts("application", {:formats => formats}, "layouts") rescue ActionView::MissingTemplate end end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 8843f6fdd7..7191df0dfd 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -29,23 +29,19 @@ module RenderTestCases end def test_render_file_with_localization - pending do - begin - old_locale = I18n.locale - I18n.locale = :da - assert_equal "Hey verden", @view.render(:file => "test/hello_world") - ensure - I18n.locale = old_locale - end + begin + old_locale = I18n.locale + I18n.locale = :da + assert_equal "Hey verden", @view.render(:file => "test/hello_world") + ensure + I18n.locale = old_locale end end def test_render_file_with_dashed_locale old_locale = I18n.locale - pending do - I18n.locale = :"pt-BR" - assert_equal "Ola mundo", @view.render(:file => "test/hello_world") - end + I18n.locale = :"pt-BR" + assert_equal "Ola mundo", @view.render(:file => "test/hello_world") ensure I18n.locale = old_locale end -- cgit v1.2.3 From 3c4c6bd0df598f865f49a983b4c65c415af4bcfc Mon Sep 17 00:00:00 2001 From: rick Date: Thu, 23 Apr 2009 00:08:40 -0700 Subject: * Add pluggable JSON backends with support for the JSON gem. [rick] Example: ActiveSupport::JSON.backend = "JSONGem" All internal Rails JSON encoding is now handled by ActiveSupport::JSON.encode(). Use of #to_json is not recommended, as it may clash with other libraries that overwrite it. However, you can recover Rails specific functionality if you really want to use #to_json. gem 'json' ActiveSupport::JSON.backend = "JSONGem" class ActiveRecord::Base alias to_json rails_to_json end --- actionpack/lib/action_controller/base/render.rb | 2 +- actionpack/lib/action_view/helpers/prototype_helper.rb | 16 +++++++++------- .../lib/action_view/helpers/scriptaculous_helper.rb | 10 +++++----- actionpack/test/controller/render_test.rb | 18 +++++++++--------- actionpack/test/template/prototype_helper_test.rb | 16 ++++++++-------- 5 files changed, 32 insertions(+), 30 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 52934076e6..33695cd78e 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -254,7 +254,7 @@ module ActionController render_for_text(js) elsif json = options[:json] - json = json.to_json unless json.is_a?(String) + json = ActiveSupport::JSON.encode(json) unless json.is_a?(String) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? response.content_type ||= Mime::JSON render_for_text(json) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 6bad11e354..fb8122af35 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -973,7 +973,7 @@ module ActionView def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{ids.first.to_json})") + "#{method}(#{ActiveSupport::JSON.encode(ids.first)})") end def page @@ -997,7 +997,7 @@ module ActionView end def javascript_object_for(object) - object.respond_to?(:to_json) ? object.to_json : object.inspect + ActiveSupport::JSON.encode(object) end def arguments_for_call(arguments, block = nil) @@ -1139,7 +1139,7 @@ module ActionView class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id - super(generator, "$(#{id.to_json})") + super(generator, "$(#{ActiveSupport::JSON.encode(id)})") end # Allows access of element attributes through +attribute+. Examples: @@ -1184,10 +1184,12 @@ module ActionView true end - def to_json(options = nil) + def rails_to_json(options = nil) @variable end + alias to_json rails_to_json + private def append_to_function_chain!(call) @generator << @variable if @empty @@ -1211,7 +1213,7 @@ module ActionView enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block else add_variable_assignment!(variable) - append_enumerable_function!("eachSlice(#{number.to_json});") + append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});") end end @@ -1232,7 +1234,7 @@ module ActionView def pluck(variable, property) add_variable_assignment!(variable) - append_enumerable_function!("pluck(#{property.to_json});") + append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});") end def zip(variable, *arguments, &block) @@ -1296,7 +1298,7 @@ module ActionView class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) - super(generator, "$$(#{pattern.to_json})") + super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})") end end end diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index e16935ea87..04af2781d7 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -43,7 +43,7 @@ module ActionView # You can change the behaviour with various options, see # http://script.aculo.us for more documentation. def visual_effect(name, element_id = false, js_options = {}) - element = element_id ? element_id.to_json : "element" + element = element_id ? ActiveSupport::JSON.encode(element_id) : "element" js_options[:queue] = if js_options[:queue].is_a?(Hash) '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}' @@ -138,7 +138,7 @@ module ActionView end def sortable_element_js(element_id, options = {}) #:nodoc: - options[:with] ||= "Sortable.serialize(#{element_id.to_json})" + options[:with] ||= "Sortable.serialize(#{ActiveSupport::JSON.encode(element_id)})" options[:onUpdate] ||= "function(){" + remote_function(options) + "}" options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) } @@ -149,7 +149,7 @@ module ActionView options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment] options[:only] = array_or_string_for_javascript(options[:only]) if options[:only] - %(Sortable.create(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Sortable.create(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ draggable. @@ -164,7 +164,7 @@ module ActionView end def draggable_element_js(element_id, options = {}) #:nodoc: - %(new Draggable(#{element_id.to_json}, #{options_for_javascript(options)});) + %(new Draggable(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end # Makes the element with the DOM ID specified by +element_id+ receive @@ -219,7 +219,7 @@ module ActionView # Confirmation happens during the onDrop callback, so it can be removed from the options options.delete(:confirm) if options[:confirm] - %(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});) + %(Droppables.add(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});) end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 9a34bcebe6..bf72730bea 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -194,19 +194,19 @@ class TestController < ActionController::Base end def render_json_hello_world - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_hello_world_with_callback - render :json => {:hello => 'world'}.to_json, :callback => 'alert' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' end def render_json_with_custom_content_type - render :json => {:hello => 'world'}.to_json, :content_type => 'text/javascript' + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' end def render_symbol_json - render :json => {:hello => 'world'}.to_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') end def render_json_with_render_to_string @@ -875,31 +875,31 @@ class RenderTest < ActionController::TestCase def test_render_json get :render_json_hello_world - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_callback get :render_json_hello_world_with_callback - assert_equal 'alert({"hello": "world"})', @response.body + assert_equal 'alert({"hello":"world"})', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_custom_content_type get :render_json_with_custom_content_type - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'text/javascript', @response.content_type end def test_render_symbol_json get :render_symbol_json - assert_equal '{"hello": "world"}', @response.body + assert_equal '{"hello":"world"}', @response.body assert_equal 'application/json', @response.content_type end def test_render_json_with_render_to_string get :render_json_with_render_to_string - assert_equal '{"hello": "partial html"}', @response.body + assert_equal '{"hello":"partial html"}', @response.body assert_equal 'application/json', @response.content_type end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index cd6ee6ea11..28851f113f 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -328,28 +328,28 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest def test_remove assert_equal 'Element.remove("foo");', @generator.remove('foo') - assert_equal '["foo", "bar", "baz"].each(Element.remove);', + assert_equal '["foo","bar","baz"].each(Element.remove);', @generator.remove('foo', 'bar', 'baz') end def test_show assert_equal 'Element.show("foo");', @generator.show('foo') - assert_equal '["foo", "bar", "baz"].each(Element.show);', + assert_equal '["foo","bar","baz"].each(Element.show);', @generator.show('foo', 'bar', 'baz') end def test_hide assert_equal 'Element.hide("foo");', @generator.hide('foo') - assert_equal '["foo", "bar", "baz"].each(Element.hide);', + assert_equal '["foo","bar","baz"].each(Element.hide);', @generator.hide('foo', 'bar', 'baz') end def test_toggle assert_equal 'Element.toggle("foo");', @generator.toggle('foo') - assert_equal '["foo", "bar", "baz"].each(Element.toggle);', + assert_equal '["foo","bar","baz"].each(Element.toggle);', @generator.toggle('foo', 'bar', 'baz') end @@ -386,7 +386,7 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest assert_equal <<-EOS.chomp, @generator.to_s Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); Element.insert("element", { bottom: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" }); -["foo", "bar"].each(Element.remove); +["foo","bar"].each(Element.remove); Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E"); EOS end @@ -555,8 +555,8 @@ return (value.className == "welcome"); end assert_equal <<-EOS.strip, @generator.to_s -var a = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]); -var b = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) { +var a = [1, 2, 3].zip([4,5,6], [7,8,9]); +var b = [1, 2, 3].zip([4,5,6], [7,8,9], function(array) { return array.reverse(); }); EOS @@ -607,7 +607,7 @@ return value.reverse(); def test_literal literal = @generator.literal("function() {}") - assert_equal "function() {}", literal.to_json + assert_equal "function() {}", ActiveSupport::JSON.encode(literal) assert_equal "", @generator.to_s end -- cgit v1.2.3 From dd2ed32418a74ca9126834f98a1b0bca926c0c4f Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 24 Apr 2009 20:24:03 -0500 Subject: Start to integrate some of the features in Rack::Test. Eventually commit ActionDispatch::Test::MockRequest and ActionDispatch::Test:: UploadedFile upstream. --- .../lib/action_controller/testing/integration.rb | 175 +++------------------ .../lib/action_controller/testing/process.rb | 29 +--- actionpack/lib/action_dispatch.rb | 5 + actionpack/lib/action_dispatch/test/mock.rb | 127 +++++++++++++++ .../lib/action_dispatch/test/uploaded_file.rb | 33 ++++ actionpack/test/controller/integration_test.rb | 2 +- 6 files changed, 192 insertions(+), 179 deletions(-) create mode 100644 actionpack/lib/action_dispatch/test/mock.rb create mode 100644 actionpack/lib/action_dispatch/test/uploaded_file.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index d51b9b63ff..8bba6dfd59 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -17,9 +17,6 @@ module ActionController include ActionController::TestCase::Assertions include ActionController::TestProcess - # Rack application to use - attr_accessor :application - # The integer HTTP status code of the last request. attr_reader :status @@ -60,12 +57,9 @@ module ActionController # A running counter of the number of requests processed. attr_accessor :request_count - class MultiPartNeededException < Exception - end - # Create and initialize a new Session instance. def initialize(app = nil) - @application = app || ActionController::Dispatcher.new + @app = app || ActionController::Dispatcher.new reset! end @@ -255,103 +249,65 @@ module ActionController # Performs the actual request. def process(method, path, parameters = nil, headers = nil) - data = requestify(parameters) path = interpret_uri(path) if path =~ %r{://} - path = "/#{path}" unless path[0] == ?/ @path = path - env = {} - if method == :get - env["QUERY_STRING"] = data - data = nil + [ControllerCapture, ActionController::ProcessWithTest].each do |mod| + unless ActionController::Base < mod + ActionController::Base.class_eval { include mod } + end end - env["QUERY_STRING"] ||= "" + ActionController::Base.clear_last_instantiation! - data = data.is_a?(IO) ? data : StringIO.new(data || '') + opts = { + :method => method.to_s.upcase, + :params => parameters, + :headers => headers, - env.update( - "REQUEST_METHOD" => method.to_s.upcase, "SERVER_NAME" => host, "SERVER_PORT" => (https? ? "443" : "80"), "HTTPS" => https? ? "on" : "off", "rack.url_scheme" => https? ? "https" : "http", - "SCRIPT_NAME" => "", "REQUEST_URI" => path, "PATH_INFO" => path, "HTTP_HOST" => host, "REMOTE_ADDR" => remote_addr, "CONTENT_TYPE" => "application/x-www-form-urlencoded", - "CONTENT_LENGTH" => data ? data.length.to_s : nil, - "HTTP_COOKIE" => encode_cookies, "HTTP_ACCEPT" => accept, + "HTTP_COOKIE" => cookies.inject("") { |string, (name, value)| + string << "#{name}=#{value}; " + }, - "rack.version" => [0,1], - "rack.input" => data, - "rack.errors" => StringIO.new, - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.test" => true - ) - - (headers || {}).each do |key, value| - key = key.to_s.upcase.gsub(/-/, "_") - key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/ - env[key] = value - end - - [ControllerCapture, ActionController::ProcessWithTest].each do |mod| - unless ActionController::Base < mod - ActionController::Base.class_eval { include mod } - end - end - - ActionController::Base.clear_last_instantiation! - - app = @application - # Rack::Lint doesn't accept String headers or bodies in Ruby 1.9 - unless RUBY_VERSION >= '1.9.0' && Rack.release <= '0.9.0' - app = Rack::Lint.new(app) - end + "rack.test" => true + } + env = ActionDispatch::Test::MockRequest.env_for(@path, opts) + app = Rack::Lint.new(@app) status, headers, body = app.call(env) + response = ::Rack::MockResponse.new(status, headers, body) @request_count += 1 @html_document = nil - @status = status.to_i + @status = response.status @status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status] - - @headers = Rack::Utils::HeaderHash.new(headers) + @headers = response.headers + @body = response.body (@headers['Set-Cookie'] || "").split("\n").each do |cookie| name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2] @cookies[name] = value end - if body.is_a?(String) - @body_parts = [body] - @body = body - else - @body_parts = [] - body.each { |part| @body_parts << part.to_s } - @body = @body_parts.join - end - if @controller = ActionController::Base.last_instantiation @request = @controller.request @response = @controller.response @controller.send(:set_test_assigns) else - # Decorate responses from Rack Middleware and Rails Metal - # as an Response for the purposes of integration testing - @response = ActionDispatch::Response.new - @response.status = status.to_s - @response.headers.replace(@headers) - @response.body = @body_parts + @request = ::Rack::Request.new(env) + @response = response end # Decorate the response with the standard behavior of the @@ -360,21 +316,6 @@ module ActionController @response.extend(TestResponseBehavior) return @status - rescue MultiPartNeededException - boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1" - status = process(method, path, - multipart_body(parameters, boundary), - (headers || {}).merge( - {"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"})) - return status - end - - # Encode the cookies hash in a format suitable for passing to a - # request. - def encode_cookies - cookies.inject("") do |string, (name, value)| - string << "#{name}=#{value}; " - end end # Get a temporary URL writer object @@ -389,72 +330,6 @@ module ActionController } UrlRewriter.new(ActionDispatch::Request.new(env), {}) end - - def name_with_prefix(prefix, name) - prefix ? "#{prefix}[#{name}]" : name.to_s - end - - # Convert the given parameters to a request string. The parameters may - # be a string, +nil+, or a Hash. - def requestify(parameters, prefix=nil) - if TestUploadedFile === parameters - raise MultiPartNeededException - elsif Hash === parameters - return nil if parameters.empty? - parameters.map { |k,v| - requestify(v, name_with_prefix(prefix, k)) - }.join("&") - elsif Array === parameters - parameters.map { |v| - requestify(v, name_with_prefix(prefix, "")) - }.join("&") - elsif prefix.nil? - parameters - else - "#{CGI.escape(prefix)}=#{CGI.escape(parameters.to_s)}" - end - end - - def multipart_requestify(params, first=true) - returning Hash.new do |p| - params.each do |key, value| - k = first ? CGI.escape(key.to_s) : "[#{CGI.escape(key.to_s)}]" - if Hash === value - multipart_requestify(value, false).each do |subkey, subvalue| - p[k + subkey] = subvalue - end - else - p[k] = value - end - end - end - end - - def multipart_body(params, boundary) - 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 ---#{boundary}\r -Content-Disposition: form-data; name="#{key}"; filename="#{CGI.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 ---#{boundary}\r -Content-Disposition: form-data; name="#{key}"\r -\r -#{value}\r -EOF - end - end.join("")+"--#{boundary}--\r" - end end # A module used to extend ActionController::Base, so that integration tests @@ -513,8 +388,8 @@ EOF # By default, a single session is automatically created for you, but you # can use this method to open multiple sessions that ought to be tested # simultaneously. - def open_session(application = nil) - session = Integration::Session.new(application) + def open_session(app = nil) + session = Integration::Session.new(app) # delegate the fixture accessors back to the test instance extras = Module.new { attr_accessor :delegate, :test_result } diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 7e2857614c..f5742af472 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -363,34 +363,7 @@ module ActionController #:nodoc: # # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows): # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary) - require 'tempfile' - class TestUploadedFile - # 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 = Mime::TEXT, binary = false) - raise "#{path} file does not exist" unless File.exist?(path) - @content_type = content_type - @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 } - @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 #:nodoc: - @tempfile.path - end - - alias local_path path - - def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.__send__(method_name, *args, &block) - end - end + TestUploadedFile = ActionDispatch::Test::UploadedFile module TestProcess def self.included(base) diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 5feb8a4863..13ce38e928 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -60,6 +60,11 @@ module ActionDispatch autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store' autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store' end + + module Test + autoload :UploadedFile, 'action_dispatch/test/uploaded_file' + autoload :MockRequest, 'action_dispatch/test/mock' + end end autoload :Mime, 'action_dispatch/http/mime_type' diff --git a/actionpack/lib/action_dispatch/test/mock.rb b/actionpack/lib/action_dispatch/test/mock.rb new file mode 100644 index 0000000000..86269fad01 --- /dev/null +++ b/actionpack/lib/action_dispatch/test/mock.rb @@ -0,0 +1,127 @@ +module ActionDispatch + module Test + class MockRequest < Rack::MockRequest + MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1" + + class << self + def env_for(path, opts) + headers = opts.delete(:headers) + + method = (opts[:method] || opts["REQUEST_METHOD"]).to_s.upcase + opts[:method] = opts["REQUEST_METHOD"] = method + + path = "/#{path}" unless path[0] == ?/ + uri = URI.parse(path) + uri.host ||= "example.org" + + if URI::HTTPS === uri + opts.update("SERVER_PORT" => "443", "HTTPS" => "on") + end + + if method == "POST" && !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + + multipart = (opts[:params] || {}).any? do |k, v| + UploadedFile === v + end + + if multipart + opts[:input] = multipart_body(opts.delete(:params)) + opts["CONTENT_LENGTH"] ||= opts[:input].length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}" + else + params = opts.delete(:params) + opts[:input] = case params + when Hash then requestify(params) + when nil then "" + else params + end + end + end + + params = opts[:params] || {} + if params.is_a?(String) + if method == "GET" + uri.query = params + else + opts[:input] = params + end + else + params.update(::Rack::Utils.parse_query(uri.query)) + uri.query = requestify(params) + end + + env = ::Rack::MockRequest.env_for(uri.to_s, opts) + + (headers || {}).each do |key, value| + key = key.to_s.upcase.gsub(/-/, "_") + key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/ + env[key] = value + end + + env + end + + private + 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}[#{::Rack::Utils.escape(k)}]" : ::Rack::Utils.escape(k)) + end.join("&") + else + "#{prefix}=#{::Rack::Utils.escape(value)}" + end + end + + 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 + + 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="#{::Rack::Utils.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 + end + end + end +end diff --git a/actionpack/lib/action_dispatch/test/uploaded_file.rb b/actionpack/lib/action_dispatch/test/uploaded_file.rb new file mode 100644 index 0000000000..0ac7db4863 --- /dev/null +++ b/actionpack/lib/action_dispatch/test/uploaded_file.rb @@ -0,0 +1,33 @@ +require "tempfile" + +module ActionDispatch + 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 diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index e39a934c24..9eeaa7b4e1 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -337,7 +337,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest get '/get_with_params?foo=bar' assert_equal '/get_with_params?foo=bar', request.env["REQUEST_URI"] assert_equal '/get_with_params?foo=bar', request.request_uri - assert_equal "", request.env["QUERY_STRING"] + assert_equal "foo=bar", request.env["QUERY_STRING"] assert_equal 'foo=bar', request.query_string assert_equal 'bar', request.parameters['foo'] -- cgit v1.2.3 From dc2caea9dc1535f30e8809b489c4ec1cf35febe6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 24 Apr 2009 23:17:15 -0700 Subject: test uses Pathname --- actionpack/test/controller/render_test.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index bf72730bea..af7236ed26 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'controller/fake_models' +require 'pathname' module Fun class GamesController < ActionController::Base -- cgit v1.2.3 From 044794fc9e1235981d20172b96f3b34b044ad19c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 25 Apr 2009 13:41:30 -0500 Subject: Remove pending rack specifications until they are official --- actionpack/lib/action_controller/testing/integration.rb | 4 +--- actionpack/lib/action_dispatch/http/request.rb | 4 ++-- actionpack/lib/action_dispatch/middleware/failsafe.rb | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 8bba6dfd59..15d0603ac1 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -278,9 +278,7 @@ module ActionController "HTTP_ACCEPT" => accept, "HTTP_COOKIE" => cookies.inject("") { |string, (name, value)| string << "#{name}=#{value}; " - }, - - "rack.test" => true + } } env = ActionDispatch::Test::MockRequest.env_for(@path, opts) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 523ab32b35..b8c547b696 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -397,7 +397,7 @@ EOM alias_method :params, :parameters def path_parameters=(parameters) #:nodoc: - @env["rack.routing_args"] = parameters + @env["action_dispatch.request.path_parameters"] = parameters @symbolized_path_parameters = @parameters = nil end @@ -413,7 +413,7 @@ EOM # # See symbolized_path_parameters for symbolized keys. def path_parameters - @env["rack.routing_args"] ||= {} + @env["action_dispatch.request.path_parameters"] ||= {} end # The request body is an IO input stream. If the RAW_POST_DATA environment diff --git a/actionpack/lib/action_dispatch/middleware/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb index 7379a696aa..b5a3abcc92 100644 --- a/actionpack/lib/action_dispatch/middleware/failsafe.rb +++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb @@ -11,7 +11,7 @@ module ActionDispatch @app.call(env) rescue Exception => exception # Reraise exception in test environment - if env["rack.test"] + if defined?(Rails) && Rails.test? raise exception else failsafe_response(exception) -- cgit v1.2.3 From b69da86ea545b342036fb37a472ec5abefaf3bd5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 25 Apr 2009 13:56:37 -0500 Subject: Remove vendored version of Rack --- actionpack/lib/action_dispatch.rb | 9 +- actionpack/lib/action_dispatch/http/request.rb | 6 +- .../lib/action_dispatch/vendor/rack-1.0/rack.rb | 89 ---- .../vendor/rack-1.0/rack/adapter/camping.rb | 22 - .../vendor/rack-1.0/rack/auth/abstract/handler.rb | 37 -- .../vendor/rack-1.0/rack/auth/abstract/request.rb | 37 -- .../vendor/rack-1.0/rack/auth/basic.rb | 58 --- .../vendor/rack-1.0/rack/auth/digest/md5.rb | 124 ------ .../vendor/rack-1.0/rack/auth/digest/nonce.rb | 51 --- .../vendor/rack-1.0/rack/auth/digest/params.rb | 55 --- .../vendor/rack-1.0/rack/auth/digest/request.rb | 40 -- .../vendor/rack-1.0/rack/auth/openid.rb | 480 --------------------- .../vendor/rack-1.0/rack/builder.rb | 63 --- .../vendor/rack-1.0/rack/cascade.rb | 36 -- .../vendor/rack-1.0/rack/chunked.rb | 49 --- .../vendor/rack-1.0/rack/commonlogger.rb | 61 --- .../vendor/rack-1.0/rack/conditionalget.rb | 45 -- .../vendor/rack-1.0/rack/content_length.rb | 29 -- .../vendor/rack-1.0/rack/content_type.rb | 23 - .../vendor/rack-1.0/rack/deflater.rb | 85 ---- .../vendor/rack-1.0/rack/directory.rb | 153 ------- .../action_dispatch/vendor/rack-1.0/rack/file.rb | 88 ---- .../vendor/rack-1.0/rack/handler.rb | 48 --- .../vendor/rack-1.0/rack/handler/cgi.rb | 61 --- .../rack-1.0/rack/handler/evented_mongrel.rb | 8 - .../vendor/rack-1.0/rack/handler/fastcgi.rb | 89 ---- .../vendor/rack-1.0/rack/handler/lsws.rb | 55 --- .../vendor/rack-1.0/rack/handler/mongrel.rb | 84 ---- .../vendor/rack-1.0/rack/handler/scgi.rb | 59 --- .../rack-1.0/rack/handler/swiftiplied_mongrel.rb | 8 - .../vendor/rack-1.0/rack/handler/thin.rb | 18 - .../vendor/rack-1.0/rack/handler/webrick.rb | 67 --- .../action_dispatch/vendor/rack-1.0/rack/head.rb | 19 - .../action_dispatch/vendor/rack-1.0/rack/lint.rb | 462 -------------------- .../vendor/rack-1.0/rack/lobster.rb | 65 --- .../action_dispatch/vendor/rack-1.0/rack/lock.rb | 16 - .../vendor/rack-1.0/rack/methodoverride.rb | 27 -- .../action_dispatch/vendor/rack-1.0/rack/mime.rb | 204 --------- .../action_dispatch/vendor/rack-1.0/rack/mock.rb | 160 ------- .../vendor/rack-1.0/rack/recursive.rb | 57 --- .../vendor/rack-1.0/rack/reloader.rb | 64 --- .../vendor/rack-1.0/rack/request.rb | 241 ----------- .../vendor/rack-1.0/rack/response.rb | 179 -------- .../vendor/rack-1.0/rack/session/abstract/id.rb | 142 ------ .../vendor/rack-1.0/rack/session/cookie.rb | 91 ---- .../vendor/rack-1.0/rack/session/memcache.rb | 109 ----- .../vendor/rack-1.0/rack/session/pool.rb | 100 ----- .../vendor/rack-1.0/rack/showexceptions.rb | 349 --------------- .../vendor/rack-1.0/rack/showstatus.rb | 106 ----- .../action_dispatch/vendor/rack-1.0/rack/static.rb | 38 -- .../action_dispatch/vendor/rack-1.0/rack/urlmap.rb | 55 --- .../action_dispatch/vendor/rack-1.0/rack/utils.rb | 392 ----------------- .../request/multipart_params_parsing_test.rb | 2 +- 53 files changed, 8 insertions(+), 5007 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 13ce38e928..0c915d9fd5 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -32,13 +32,8 @@ rescue LoadError end require 'active_support/core/all' -$:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-1.0" -begin - gem 'rack', '~> 1.0.0' - require 'rack' -rescue Gem::LoadError - require 'action_dispatch/vendor/rack-1.0/rack' -end +gem 'rack', '~> 1.0.0' +require 'rack' module ActionDispatch autoload :Request, 'action_dispatch/http/request' diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b8c547b696..ab654b9a50 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -93,7 +93,11 @@ module ActionDispatch end end end - + + def media_type + content_type.to_s + end + # Returns the accepted MIME type for the request. def accepts @accepts ||= begin diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb deleted file mode 100644 index 6349b95094..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2007, 2008, 2009 Christian Neukirchen -# -# Rack is freely distributable under the terms of an MIT-style license. -# See COPYING or http://www.opensource.org/licenses/mit-license.php. - -$:.unshift(File.expand_path(File.dirname(__FILE__))) - - -# The Rack main module, serving as a namespace for all core Rack -# modules and classes. -# -# All modules meant for use in your application are autoloaded here, -# so it should be enough just to require rack.rb in your code. - -module Rack - # The Rack protocol version number implemented. - VERSION = [0,1] - - # Return the Rack protocol version as a dotted string. - def self.version - VERSION.join(".") - end - - # Return the Rack release as a dotted string. - def self.release - "1.0 bundled" - end - - autoload :Builder, "rack/builder" - autoload :Cascade, "rack/cascade" - autoload :Chunked, "rack/chunked" - autoload :CommonLogger, "rack/commonlogger" - autoload :ConditionalGet, "rack/conditionalget" - autoload :ContentLength, "rack/content_length" - autoload :ContentType, "rack/content_type" - autoload :File, "rack/file" - autoload :Deflater, "rack/deflater" - autoload :Directory, "rack/directory" - autoload :ForwardRequest, "rack/recursive" - autoload :Handler, "rack/handler" - autoload :Head, "rack/head" - autoload :Lint, "rack/lint" - autoload :Lock, "rack/lock" - autoload :MethodOverride, "rack/methodoverride" - autoload :Mime, "rack/mime" - autoload :Recursive, "rack/recursive" - autoload :Reloader, "rack/reloader" - autoload :ShowExceptions, "rack/showexceptions" - autoload :ShowStatus, "rack/showstatus" - autoload :Static, "rack/static" - autoload :URLMap, "rack/urlmap" - autoload :Utils, "rack/utils" - - autoload :MockRequest, "rack/mock" - autoload :MockResponse, "rack/mock" - - autoload :Request, "rack/request" - autoload :Response, "rack/response" - - module Auth - autoload :Basic, "rack/auth/basic" - autoload :AbstractRequest, "rack/auth/abstract/request" - autoload :AbstractHandler, "rack/auth/abstract/handler" - autoload :OpenID, "rack/auth/openid" - module Digest - autoload :MD5, "rack/auth/digest/md5" - autoload :Nonce, "rack/auth/digest/nonce" - autoload :Params, "rack/auth/digest/params" - autoload :Request, "rack/auth/digest/request" - end - end - - module Session - autoload :Cookie, "rack/session/cookie" - autoload :Pool, "rack/session/pool" - autoload :Memcache, "rack/session/memcache" - end - - # *Adapters* connect Rack with third party web frameworks. - # - # Rack includes an adapter for Camping, see README for other - # frameworks supporting Rack in their code bases. - # - # Refer to the submodules for framework-specific calling details. - - module Adapter - autoload :Camping, "rack/adapter/camping" - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb deleted file mode 100644 index 63bc787f54..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Rack - module Adapter - class Camping - def initialize(app) - @app = app - end - - def call(env) - env["PATH_INFO"] ||= "" - env["SCRIPT_NAME"] ||= "" - controller = @app.run(env['rack.input'], env) - h = controller.headers - h.each_pair do |k,v| - if v.kind_of? URI - h[k] = v.to_s - end - end - [controller.status, controller.headers, [controller.body.to_s]] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb deleted file mode 100644 index 214df6299e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - # Rack::Auth::AbstractHandler implements common authentication functionality. - # - # +realm+ should be set for all handlers. - - class AbstractHandler - - attr_accessor :realm - - def initialize(app, realm=nil, &authenticator) - @app, @realm, @authenticator = app, realm, authenticator - end - - - private - - def unauthorized(www_authenticate = challenge) - return [ 401, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0', - 'WWW-Authenticate' => www_authenticate.to_s }, - [] - ] - end - - def bad_request - return [ 400, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0' }, - [] - ] - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb deleted file mode 100644 index 1d9ccec685..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - class AbstractRequest - - def initialize(env) - @env = env - end - - def provided? - !authorization_key.nil? - end - - def parts - @parts ||= @env[authorization_key].split(' ', 2) - end - - def scheme - @scheme ||= parts.first.downcase.to_sym - end - - def params - @params ||= parts.last - end - - - private - - AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] - - def authorization_key - @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb deleted file mode 100644 index 9557224648..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/abstract/request' - -module Rack - module Auth - # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. - # - # Initialize with the Rack application that you want protecting, - # and a block that checks if a username and password pair are valid. - # - # See also: example/protectedlobster.rb - - class Basic < AbstractHandler - - def call(env) - auth = Basic::Request.new(env) - - return unauthorized unless auth.provided? - - return bad_request unless auth.basic? - - if valid?(auth) - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - - unauthorized - end - - - private - - def challenge - 'Basic realm="%s"' % realm - end - - def valid?(auth) - @authenticator.call(*auth.credentials) - end - - class Request < Auth::AbstractRequest - def basic? - :basic == scheme - end - - def credentials - @credentials ||= params.unpack("m*").first.split(/:/, 2) - end - - def username - credentials.first - end - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb deleted file mode 100644 index e579dc9632..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/digest/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of - # HTTP Digest Authentication, as per RFC 2617. - # - # Initialize with the [Rack] application that you want protecting, - # and a block that looks up a plaintext password for a given username. - # - # +opaque+ needs to be set to a constant base64/hexadecimal string. - # - class MD5 < AbstractHandler - - attr_accessor :opaque - - attr_writer :passwords_hashed - - def initialize(*args) - super - @passwords_hashed = nil - end - - def passwords_hashed? - !!@passwords_hashed - end - - def call(env) - auth = Request.new(env) - - unless auth.provided? - return unauthorized - end - - if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) - return bad_request - end - - if valid?(auth) - if auth.nonce.stale? - return unauthorized(challenge(:stale => true)) - else - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - end - - unauthorized - end - - - private - - QOP = 'auth'.freeze - - def params(hash = {}) - Params.new do |params| - params['realm'] = realm - params['nonce'] = Nonce.new.to_s - params['opaque'] = H(opaque) - params['qop'] = QOP - - hash.each { |k, v| params[k] = v } - end - end - - def challenge(hash = {}) - "Digest #{params(hash)}" - end - - def valid?(auth) - valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) - end - - def valid_qop?(auth) - QOP == auth.qop - end - - def valid_opaque?(auth) - H(opaque) == auth.opaque - end - - def valid_nonce?(auth) - auth.nonce.valid? - end - - def valid_digest?(auth) - digest(auth, @authenticator.call(auth.username)) == auth.response - end - - def md5(data) - ::Digest::MD5.hexdigest(data) - end - - alias :H :md5 - - def KD(secret, data) - H([secret, data] * ':') - end - - def A1(auth, password) - [ auth.username, auth.realm, password ] * ':' - end - - def A2(auth) - [ auth.method, auth.uri ] * ':' - end - - def digest(auth, password) - password_hash = passwords_hashed? ? password : H(A1(auth, password)) - - KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb deleted file mode 100644 index dbe109f29a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::Nonce is the default nonce generator for the - # Rack::Auth::Digest::MD5 authentication handler. - # - # +private_key+ needs to set to a constant string. - # - # +time_limit+ can be optionally set to an integer (number of seconds), - # to limit the validity of the generated nonces. - - class Nonce - - class << self - attr_accessor :private_key, :time_limit - end - - def self.parse(string) - new(*string.unpack("m*").first.split(' ', 2)) - end - - def initialize(timestamp = Time.now, given_digest = nil) - @timestamp, @given_digest = timestamp.to_i, given_digest - end - - def to_s - [([ @timestamp, digest ] * ' ')].pack("m*").strip - end - - def digest - ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') - end - - def valid? - digest == @given_digest - end - - def stale? - !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit - end - - def fresh? - !stale? - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb deleted file mode 100644 index 730e2efdc8..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - module Auth - module Digest - class Params < Hash - - def self.parse(str) - split_header_value(str).inject(new) do |header, param| - k, v = param.split('=', 2) - header[k] = dequote(v) - header - end - end - - def self.dequote(str) # From WEBrick::HTTPUtils - ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup - ret.gsub!(/\\(.)/, "\\1") - ret - end - - def self.split_header_value(str) - str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } - end - - def initialize - super - - yield self if block_given? - end - - def [](k) - super k.to_s - end - - def []=(k, v) - super k.to_s, v.to_s - end - - UNQUOTED = ['qop', 'nc', 'stale'] - - def to_s - inject([]) do |parts, (k, v)| - parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) - parts - end.join(', ') - end - - def quote(str) # From WEBrick::HTTPUtils - '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' - end - - end - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb deleted file mode 100644 index a8aa3bf996..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'rack/auth/abstract/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' - -module Rack - module Auth - module Digest - class Request < Auth::AbstractRequest - - def method - @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] - end - - def digest? - :digest == scheme - end - - def correct_uri? - (@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri - end - - def nonce - @nonce ||= Nonce.parse(params['nonce']) - end - - def params - @params ||= Params.parse(parts.last) - end - - def method_missing(sym) - if params.has_key? key = sym.to_s - return params[key] - end - super - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb deleted file mode 100644 index c5f6a5143e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb +++ /dev/null @@ -1,480 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -gem 'ruby-openid', '~> 2' if defined? Gem -require 'rack/request' -require 'rack/utils' -require 'rack/auth/abstract/handler' -require 'uri' -require 'openid' #gem -require 'openid/extension' #gem -require 'openid/store/memory' #gem - -module Rack - class Request - def openid_request - @env['rack.auth.openid.request'] - end - - def openid_response - @env['rack.auth.openid.response'] - end - end - - module Auth - - # Rack::Auth::OpenID provides a simple method for setting up an OpenID - # Consumer. It requires the ruby-openid library from janrain to operate, - # as well as a rack method of session management. - # - # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. - # - # The OpenID specifications can be found at - # http://openid.net/specs/openid-authentication-1_1.html - # and - # http://openid.net/specs/openid-authentication-2_0.html. Documentation - # for published OpenID extensions and related topics can be found at - # http://openid.net/developers/specs/. - # - # It is recommended to read through the OpenID spec, as well as - # ruby-openid's documentation, to understand what exactly goes on. However - # a setup as simple as the presented examples is enough to provide - # Consumer functionality. - # - # This library strongly intends to utilize the OpenID 2.0 features of the - # ruby-openid library, which provides OpenID 1.0 compatiblity. - # - # NOTE: Due to the amount of data that this library stores in the - # session, Rack::Session::Cookie may fault. - - class OpenID - - class NoSession < RuntimeError; end - class BadExtension < RuntimeError; end - # Required for ruby-openid - ValidStatus = [:success, :setup_needed, :cancel, :failure] - - # = Arguments - # - # The first argument is the realm, identifying the site they are trusting - # with their identity. This is required, also treated as the trust_root - # in OpenID 1.x exchanges. - # - # The optional second argument is a hash of options. - # - # == Options - # - # :return_to defines the url to return to after the client - # authenticates with the openid service provider. This url should point - # to where Rack::Auth::OpenID is mounted. If :return_to is not - # provided, return_to will be the current url which allows flexibility - # with caveats. - # - # :session_key defines the key to the session hash in the env. - # It defaults to 'rack.session'. - # - # :openid_param defines at what key in the request parameters to - # find the identifier to resolve. As per the 2.0 spec, the default is - # 'openid_identifier'. - # - # :store defined what OpenID Store to use for persistant - # information. By default a Store::Memory will be used. - # - # :immediate as true will make initial requests to be of an - # immediate type. This is false by default. See OpenID specification - # documentation. - # - # :extensions should be a hash of openid extension - # implementations. The key should be the extension main module, the value - # should be an array of arguments for extension::Request.new. - # The hash is iterated over and passed to #add_extension for processing. - # Please see #add_extension for further documentation. - # - # == Examples - # - # simple_oid = OpenID.new('http://mysite.com/') - # - # return_oid = OpenID.new('http://mysite.com/', { - # :return_to => 'http://mysite.com/openid' - # }) - # - # complex_oid = OpenID.new('http://mysite.com/', - # :immediate => true, - # :extensions => { - # ::OpenID::SReg => [['email'],['nickname']] - # } - # ) - # - # = Advanced - # - # Most of the functionality of this library is encapsulated such that - # expansion and overriding functions isn't difficult nor tricky. - # Alternately, to avoid opening up singleton objects or subclassing, a - # wrapper rack middleware can be composed to act upon Auth::OpenID's - # responses. See #check and #finish for locations of pertinent data. - # - # == Responses - # - # To change the responses that Auth::OpenID returns, override the methods - # #redirect, #bad_request, #unauthorized, #access_denied, and - # #foreign_server_failure. - # - # Additionally #confirm_post_params is used when the URI would exceed - # length limits on a GET request when doing the initial verification - # request. - # - # == Processing - # - # To change methods of processing completed transactions, override the - # methods #success, #setup_needed, #cancel, and #failure. Please ensure - # the returned object is a rack compatible response. - # - # The first argument is an OpenID::Response, the second is a - # Rack::Request of the current request, the last is the hash used in - # ruby-openid handling, which can be found manually at - # env['rack.session'][:openid]. - # - # This is useful if you wanted to expand the processing done, such as - # setting up user accounts. - # - # oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to - # def oid_app.success oid, request, session - # user = Models::User[oid.identity_url] - # user ||= Models::User.create_from_openid oid - # request['rack.session'][:user] = user.id - # redirect MyApp.site_home - # end - # - # site_map['/openid'] = oid_app - # map = Rack::URLMap.new site_map - # ... - - def initialize(realm, options={}) - realm = URI(realm) - raise ArgumentError, "Invalid realm: #{realm}" \ - unless realm.absolute? \ - and realm.fragment.nil? \ - and realm.scheme =~ /^https?$/ \ - and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/ - realm.path = '/' if realm.path.empty? - @realm = realm.to_s - - if ruri = options[:return_to] - ruri = URI(ruri) - raise ArgumentError, "Invalid return_to: #{ruri}" \ - unless ruri.absolute? \ - and ruri.scheme =~ /^https?$/ \ - and ruri.fragment.nil? - raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \ - unless self.within_realm?(ruri) - @return_to = ruri.to_s - end - - @session_key = options[:session_key] || 'rack.session' - @openid_param = options[:openid_param] || 'openid_identifier' - @store = options[:store] || ::OpenID::Store::Memory.new - @immediate = !!options[:immediate] - - @extensions = {} - if extensions = options.delete(:extensions) - extensions.each do |ext, args| - add_extension ext, *args - end - end - - # Undocumented, semi-experimental - @anonymous = !!options[:anonymous] - end - - attr_reader :realm, :return_to, :session_key, :openid_param, :store, - :immediate, :extensions - - # Sets up and uses session data at :openid within the session. - # Errors in this setup will raise a NoSession exception. - # - # If the parameter 'openid.mode' is set, which implies a followup from - # the openid server, processing is passed to #finish and the result is - # returned. However, if there is no appropriate openid information in the - # session, a 400 error is returned. - # - # If the parameter specified by options[:openid_param] is - # present, processing is passed to #check and the result is returned. - # - # If neither of these conditions are met, #unauthorized is called. - - def call(env) - env['rack.auth.openid'] = self - env_session = env[@session_key] - unless env_session and env_session.is_a?(Hash) - raise NoSession, 'No compatible session' - end - # let us work in our own namespace... - session = (env_session[:openid] ||= {}) - unless session and session.is_a?(Hash) - raise NoSession, 'Incompatible openid session' - end - - request = Rack::Request.new(env) - consumer = ::OpenID::Consumer.new(session, @store) - - if mode = request.GET['openid.mode'] - if session.key?(:openid_param) - finish(consumer, session, request) - else - bad_request - end - elsif request.GET[@openid_param] - check(consumer, session, request) - else - unauthorized - end - end - - # As the first part of OpenID consumer action, #check retrieves the data - # required for completion. - # - # If all parameters fit within the max length of a URI, a 303 redirect - # will be returned. Otherwise #confirm_post_params will be called. - # - # Any messages from OpenID's request are logged to env['rack.errors'] - # - # env['rack.auth.openid.request'] is the openid checkid request - # instance. - # - # session[:openid_param] is set to the openid identifier - # provided by the user. - # - # session[:return_to] is set to the return_to uri given to the - # identity provider. - - def check(consumer, session, req) - oid = consumer.begin(req.GET[@openid_param], @anonymous) - req.env['rack.auth.openid.request'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - ## Extension support - extensions.each do |ext,args| - oid.add_extension(ext::Request.new(*args)) - end - - session[:openid_param] = req.GET[openid_param] - return_to_uri = return_to ? return_to : req.url - session[:return_to] = return_to_uri - immediate = session.key?(:setup_needed) ? false : immediate - - if oid.send_redirect?(realm, return_to_uri, immediate) - uri = oid.redirect_url(realm, return_to_uri, immediate) - redirect(uri) - else - confirm_post_params(oid, realm, return_to_uri, immediate) - end - rescue ::OpenID::DiscoveryFailure => e - # thrown from inside OpenID::Consumer#begin by yadis stuff - req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n") - return foreign_server_failure - end - - # This is the final portion of authentication. - # If successful, a redirect to the realm is be returned. - # Data gathered from extensions are stored in session[:openid] with the - # extension's namespace uri as the key. - # - # Any messages from OpenID's response are logged to env['rack.errors'] - # - # env['rack.auth.openid.response'] will contain the openid - # response. - - def finish(consumer, session, req) - oid = consumer.complete(req.GET, req.url) - req.env['rack.auth.openid.response'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - raise unless ValidStatus.include?(oid.status) - __send__(oid.status, oid, req, session) - end - - # The first argument should be the main extension module. - # The extension module should contain the constants: - # * class Request, should have OpenID::Extension as an ancestor - # * class Response, should have OpenID::Extension as an ancestor - # * string NS_URI, which defining the namespace of the extension - # - # All trailing arguments will be passed to extension::Request.new in - # #check. - # The openid response will be passed to - # extension::Response#from_success_response, #get_extension_args will be - # called on the result to attain the gathered data. - # - # This method returns the key at which the response data will be found in - # the session, which is the namespace uri by default. - - def add_extension(ext, *args) - raise BadExtension unless valid_extension?(ext) - extensions[ext] = args - return ext::NS_URI - end - - # Checks the validitity, in the context of usage, of a submitted - # extension. - - def valid_extension?(ext) - if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) } - raise ArgumentError, 'Extension is missing constants.' - elsif not ext::Response.respond_to?(:from_success_response) - raise ArgumentError, 'Response is missing required method.' - end - return true - rescue - return false - end - - # Checks the provided uri to ensure it'd be considered within the realm. - # is currently not compatible with wildcard realms. - - def within_realm? uri - uri = URI.parse(uri.to_s) - realm = URI.parse(self.realm) - return false unless uri.absolute? - return false unless uri.path[0, realm.path.size] == realm.path - return false unless uri.host == realm.host or realm.host[/^\*\./] - # for wildcard support, is awkward with URI limitations - realm_match = Regexp.escape(realm.host). - sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$' - return false unless uri.host.match(realm_match) - return true - end - alias_method :include?, :within_realm? - - protected - - ### These methods define some of the boilerplate responses. - - # Returns an html form page for posting to an Identity Provider if the - # GET request would exceed the upper URI length limit. - - def confirm_post_params(oid, realm, return_to, immediate) - Rack::Response.new.finish do |r| - r.write 'Confirm...' - r.write oid.form_markup(realm, return_to, immediate) - r.write '' - end - end - - # Returns a 303 redirect with the destination of that provided by the - # argument. - - def redirect(uri) - [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain', - 'Location' => uri}, - [] ] - end - - # Returns an empty 400 response. - - def bad_request - [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'}, - [''] ] - end - - # Returns a basic unauthorized 401 response. - - def unauthorized - [ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'}, - ['Unauthorized.'] ] - end - - # Returns a basic access denied 403 response. - - def access_denied - [ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'}, - ['Access denied.'] ] - end - - # Returns a 503 response to be used if communication with the remote - # OpenID server fails. - - def foreign_server_failure - [ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'}, - ['Foreign server failure.'] ] - end - - private - - ### These methods are called after a transaction is completed, depending - # on its outcome. These should all return a rack compatible response. - # You'd want to override these to provide additional functionality. - - # Called to complete processing on a successful transaction. - # Within the openid session, :openid_identity and :openid_identifier are - # set to the user friendly and the standard representation of the - # validated identity. All other data in the openid session is cleared. - - def success(oid, request, session) - session.clear - session[:openid_identity] = oid.display_identifier - session[:openid_identifier] = oid.identity_url - extensions.keys.each do |ext| - label = ext.name[/[^:]+$/].downcase - response = ext::Response.from_success_response(oid) - session[label] = response.data - end - redirect(realm) - end - - # Called if the Identity Provider indicates further setup by the user is - # required. - # The identifier is retrived from the openid session at :openid_param. - # And :setup_needed is set to true to prevent looping. - - def setup_needed(oid, request, session) - identifier = session[:openid_param] - session[:setup_needed] = true - redirect req.script_name + '?' + openid_param + '=' + identifier - end - - # Called if the user indicates they wish to cancel identification. - # Data within openid session is cleared. - - def cancel(oid, request, session) - session.clear - access_denied - end - - # Called if the Identity Provider indicates the user is unable to confirm - # their identity. Data within the openid session is left alone, in case - # of swarm auth attacks. - - def failure(oid, request, session) - unauthorized - end - end - - # A class developed out of the request to use OpenID as an authentication - # middleware. The request will be sent to the OpenID instance unless the - # block evaluates to true. For example in rackup, you can use it as such: - # - # use Rack::Session::Pool - # use Rack::Auth::OpenIDAuth, realm, openid_options do |env| - # env['rack.session'][:authkey] == a_string - # end - # run RackApp - # - # Or simply: - # - # app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth - - class OpenIDAuth < Rack::Auth::AbstractHandler - attr_reader :oid - def initialize(app, realm, options={}, &auth) - @oid = OpenID.new(realm, options) - super(app, &auth) - end - - def call(env) - to = auth.call(env) ? @app : @oid - to.call env - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb deleted file mode 100644 index 295235e56a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Rack - # Rack::Builder implements a small DSL to iteratively construct Rack - # applications. - # - # Example: - # - # app = Rack::Builder.new { - # use Rack::CommonLogger - # use Rack::ShowExceptions - # map "/lobster" do - # use Rack::Lint - # run Rack::Lobster.new - # end - # } - # - # Or - # - # app = Rack::Builder.app do - # use Rack::CommonLogger - # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } - # end - # - # +use+ adds a middleware to the stack, +run+ dispatches to an application. - # You can use +map+ to construct a Rack::URLMap in a convenient way. - - class Builder - def initialize(&block) - @ins = [] - instance_eval(&block) if block_given? - end - - def self.app(&block) - self.new(&block).to_app - end - - def use(middleware, *args, &block) - @ins << lambda { |app| middleware.new(app, *args, &block) } - end - - def run(app) - @ins << app #lambda { |nothing| app } - end - - def map(path, &block) - if @ins.last.kind_of? Hash - @ins.last[path] = self.class.new(&block).to_app - else - @ins << {} - map(path, &block) - end - end - - def to_app - @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last - inner_app = @ins.last - @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } - end - - def call(env) - to_app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb deleted file mode 100644 index a038aa1105..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Rack - # Rack::Cascade tries an request on several apps, and returns the - # first response that is not 404 (or in a list of configurable - # status codes). - - class Cascade - attr_reader :apps - - def initialize(apps, catch=404) - @apps = apps - @catch = [*catch] - end - - def call(env) - status = headers = body = nil - raise ArgumentError, "empty cascade" if @apps.empty? - @apps.each { |app| - begin - status, headers, body = app.call(env) - break unless @catch.include?(status.to_i) - end - } - [status, headers, body] - end - - def add app - @apps << app - end - - def include? app - @apps.include? app - end - - alias_method :<<, :add - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb deleted file mode 100644 index 280d89dd65..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that applies chunked transfer encoding to response bodies - # when the response does not include a Content-Length header. - class Chunked - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if env['HTTP_VERSION'] == 'HTTP/1.0' || - STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Content-Length'] || - headers['Transfer-Encoding'] - [status, headers.to_hash, body] - else - dup.chunk(status, headers, body) - end - end - - def chunk(status, headers, body) - @body = body - headers.delete('Content-Length') - headers['Transfer-Encoding'] = 'chunked' - [status, headers.to_hash, self] - end - - def each - term = "\r\n" - @body.each do |chunk| - size = bytesize(chunk) - next if size == 0 - yield [size.to_s(16), term, chunk, term].join - end - yield ["0", term, "", term].join - end - - def close - @body.close if @body.respond_to?(:close) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb deleted file mode 100644 index 5e68ac626d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb +++ /dev/null @@ -1,61 +0,0 @@ -module Rack - # Rack::CommonLogger forwards every request to an +app+ given, and - # logs a line in the Apache common log format to the +logger+, or - # rack.errors by default. - - class CommonLogger - def initialize(app, logger=nil) - @app = app - @logger = logger - end - - def call(env) - dup._call(env) - end - - def _call(env) - @env = env - @logger ||= self - @time = Time.now - @status, @header, @body = @app.call(env) - [@status, @header, self] - end - - def close - @body.close if @body.respond_to? :close - end - - # By default, log to rack.errors. - def <<(str) - @env["rack.errors"].write(str) - @env["rack.errors"].flush - end - - def each - length = 0 - @body.each { |part| - length += part.size - yield part - } - - @now = Time.now - - # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common - # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - - # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % - @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % - [ - @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", - @env["REMOTE_USER"] || "-", - @now.strftime("%d/%b/%Y %H:%M:%S"), - @env["REQUEST_METHOD"], - @env["PATH_INFO"], - @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], - @env["HTTP_VERSION"], - @status.to_s[0..3], - (length.zero? ? "-" : length.to_s), - @now - @time - ] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb deleted file mode 100644 index 7bec824181..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that enables conditional GET using If-None-Match and - # If-Modified-Since. The application should set either or both of the - # Last-Modified or Etag response headers according to RFC 2616. When - # either of the conditions is met, the response body is set to be zero - # length and the response status is set to 304 Not Modified. - # - # Applications that defer response body generation until the body's each - # message is received will avoid response body generation completely when - # a conditional GET matches. - # - # Adapted from Michael Klishin's Merb implementation: - # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb - class ConditionalGet - def initialize(app) - @app = app - end - - def call(env) - return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD']) - - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - if etag_matches?(env, headers) || modified_since?(env, headers) - status = 304 - body = [] - end - [status, headers, body] - end - - private - def etag_matches?(env, headers) - etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH'] - end - - def modified_since?(env, headers) - last_modified = headers['Last-Modified'] and - last_modified == env['HTTP_IF_MODIFIED_SINCE'] - end - end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb deleted file mode 100644 index 1e56d43853..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'rack/utils' - -module Rack - # Sets the Content-Length header on responses with fixed-length bodies. - class ContentLength - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && - !headers['Content-Length'] && - !headers['Transfer-Encoding'] && - (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) - - body = [body] if body.respond_to?(:to_str) # rack 0.4 compat - length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } - headers['Content-Length'] = length.to_s - end - - [status, headers, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb deleted file mode 100644 index 0c1e1ca3e1..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'rack/utils' - -module Rack - - # Sets the Content-Type header on responses which don't have one. - # - # Builder Usage: - # use Rack::ContentType, "text/plain" - # - # When no content type argument is provided, "text/html" is assumed. - class ContentType - def initialize(app, content_type = "text/html") - @app, @content_type = app, content_type - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - headers['Content-Type'] ||= @content_type - [status, headers.to_hash, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb deleted file mode 100644 index a42b7477ae..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb +++ /dev/null @@ -1,85 +0,0 @@ -require "zlib" -require "stringio" -require "time" # for Time.httpdate -require 'rack/utils' - -module Rack - class Deflater - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - - # Skip compressing empty entity body responses and responses with - # no-transform set. - if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Cache-Control'].to_s =~ /\bno-transform\b/ - return [status, headers, body] - end - - request = Request.new(env) - - encoding = Utils.select_best_encoding(%w(gzip deflate identity), - request.accept_encoding) - - # Set the Vary HTTP header. - vary = headers["Vary"].to_s.split(",").map { |v| v.strip } - unless vary.include?("*") || vary.include?("Accept-Encoding") - headers["Vary"] = vary.push("Accept-Encoding").join(",") - end - - case encoding - when "gzip" - mtime = headers.key?("Last-Modified") ? - Time.httpdate(headers["Last-Modified"]) : Time.now - body = self.class.gzip(body, mtime) - size = Rack::Utils.bytesize(body) - headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s) - [status, headers, [body]] - when "deflate" - body = self.class.deflate(body) - size = Rack::Utils.bytesize(body) - headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s) - [status, headers, [body]] - when "identity" - [status, headers, body] - when nil - message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." - [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]] - end - end - - def self.gzip(body, mtime) - io = StringIO.new - gzip = Zlib::GzipWriter.new(io) - gzip.mtime = mtime - - # TODO: Add streaming - body.each { |part| gzip << part } - - gzip.close - return io.string - end - - DEFLATE_ARGS = [ - Zlib::DEFAULT_COMPRESSION, - # drop the zlib header which causes both Safari and IE to choke - -Zlib::MAX_WBITS, - Zlib::DEF_MEM_LEVEL, - Zlib::DEFAULT_STRATEGY - ] - - # Loosely based on Mongrel's Deflate handler - def self.deflate(body) - deflater = Zlib::Deflate.new(*DEFLATE_ARGS) - - # TODO: Add streaming - body.each { |part| deflater << part } - - return deflater.finish - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb deleted file mode 100644 index acdd3029d3..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb +++ /dev/null @@ -1,153 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::Directory serves entries below the +root+ given, according to the - # path info of the Rack request. If a directory is found, the file's contents - # will be presented in an html based index. If a file is found, the env will - # be passed to the specified +app+. - # - # If +app+ is not specified, a Rack::File of the same +root+ will be used. - - class Directory - DIR_FILE = "%s%s%s%s" - DIR_PAGE = <<-PAGE - - %s - - - -

%s

-
- - - - - - - -%s -
NameSizeTypeLast Modified
-
- - PAGE - - attr_reader :files - attr_accessor :root, :path - - def initialize(root, app=nil) - @root = F.expand_path(root) - @app = app || Rack::File.new(@root) - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @env = env - @script_name = env['SCRIPT_NAME'] - @path_info = Utils.unescape(env['PATH_INFO']) - - if forbidden = check_forbidden - forbidden - else - @path = F.join(@root, @path_info) - list_path - end - end - - def check_forbidden - return unless @path_info.include? ".." - - body = "Forbidden\n" - size = Rack::Utils.bytesize(body) - return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] - end - - def list_directory - @files = [['../','Parent Directory','','','']] - glob = F.join(@path, '*') - - Dir[glob].sort.each do |node| - stat = stat(node) - next unless stat - basename = F.basename(node) - ext = F.extname(node) - - url = F.join(@script_name, @path_info, basename) - size = stat.size - type = stat.directory? ? 'directory' : Mime.mime_type(ext) - size = stat.directory? ? '-' : filesize_format(size) - mtime = stat.mtime.httpdate - url << '/' if stat.directory? - basename << '/' if stat.directory? - - @files << [ url, basename, size, type, mtime ] - end - - return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] - end - - def stat(node, max = 10) - F.stat(node) - rescue Errno::ENOENT, Errno::ELOOP - return nil - end - - # TODO: add correct response if not readable, not sure if 404 is the best - # option - def list_path - @stat = F.stat(@path) - - if @stat.readable? - return @app.call(@env) if @stat.file? - return list_directory if @stat.directory? - else - raise Errno::ENOENT, 'No such file or directory' - end - - rescue Errno::ENOENT, Errno::ELOOP - return entity_not_found - end - - def entity_not_found - body = "Entity not found: #{@path_info}\n" - size = Rack::Utils.bytesize(body) - return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] - end - - def each - show_path = @path.sub(/^#{@root}/,'') - files = @files.map{|f| DIR_FILE % f }*"\n" - page = DIR_PAGE % [ show_path, show_path , files ] - page.each_line{|l| yield l } - end - - # Stolen from Ramaze - - FILESIZE_FORMAT = [ - ['%.1fT', 1 << 40], - ['%.1fG', 1 << 30], - ['%.1fM', 1 << 20], - ['%.1fK', 1 << 10], - ] - - def filesize_format(int) - FILESIZE_FORMAT.each do |format, size| - return format % (int.to_f / size) if int >= size - end - - int.to_s + 'B' - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb deleted file mode 100644 index fe62bd6b86..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::File serves files below the +root+ given, according to the - # path info of the Rack request. - # - # Handlers can detect if bodies are a Rack::File, and use mechanisms - # like sendfile on the +path+. - - class File - attr_accessor :root - attr_accessor :path - - alias :to_path :path - - def initialize(root) - @root = root - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @path_info = Utils.unescape(env["PATH_INFO"]) - return forbidden if @path_info.include? ".." - - @path = F.join(@root, @path_info) - - begin - if F.file?(@path) && F.readable?(@path) - serving - else - raise Errno::EPERM - end - rescue SystemCallError - not_found - end - end - - def forbidden - body = "Forbidden\n" - [403, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - # NOTE: - # We check via File::size? whether this file provides size info - # via stat (e.g. /proc files often don't), otherwise we have to - # figure it out by reading the whole file into memory. And while - # we're at it we also use this as body then. - - def serving - if size = F.size?(@path) - body = self - else - body = [F.read(@path)] - size = Utils.bytesize(body.first) - end - - [200, { - "Last-Modified" => F.mtime(@path).httpdate, - "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), - "Content-Length" => size.to_s - }, body] - end - - def not_found - body = "File not found: #{@path_info}\n" - [404, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - def each - F.open(@path, "rb") { |file| - while part = file.read(8192) - yield part - end - } - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb deleted file mode 100644 index 1018af64c7..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb +++ /dev/null @@ -1,48 +0,0 @@ -module Rack - # *Handlers* connect web servers with Rack. - # - # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI - # and LiteSpeed. - # - # Handlers usually are activated by calling MyHandler.run(myapp). - # A second optional hash can be passed to include server-specific - # configuration. - module Handler - def self.get(server) - return unless server - - if klass = @handlers[server] - obj = Object - klass.split("::").each { |x| obj = obj.const_get(x) } - obj - else - Rack::Handler.const_get(server.capitalize) - end - end - - def self.register(server, klass) - @handlers ||= {} - @handlers[server] = klass - end - - autoload :CGI, "rack/handler/cgi" - autoload :FastCGI, "rack/handler/fastcgi" - autoload :Mongrel, "rack/handler/mongrel" - autoload :EventedMongrel, "rack/handler/evented_mongrel" - autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel" - autoload :WEBrick, "rack/handler/webrick" - autoload :LSWS, "rack/handler/lsws" - autoload :SCGI, "rack/handler/scgi" - autoload :Thin, "rack/handler/thin" - - register 'cgi', 'Rack::Handler::CGI' - register 'fastcgi', 'Rack::Handler::FastCGI' - register 'mongrel', 'Rack::Handler::Mongrel' - register 'emongrel', 'Rack::Handler::EventedMongrel' - register 'smongrel', 'Rack::Handler::SwiftipliedMongrel' - register 'webrick', 'Rack::Handler::WEBrick' - register 'lsws', 'Rack::Handler::LSWS' - register 'scgi', 'Rack::Handler::SCGI' - register 'thin', 'Rack::Handler::Thin' - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb deleted file mode 100644 index e38156c7f0..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'rack/content_length' - -module Rack - module Handler - class CGI - def self.run(app, options=nil) - serve app - end - - def self.serve(app) - app = ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [0,1], - "rack.input" => $stdin, - "rack.errors" => $stderr, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => true, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - - def self.send_headers(status, headers) - STDOUT.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - STDOUT.print "#{k}: #{v}\r\n" - } - } - STDOUT.print "\r\n" - STDOUT.flush - end - - def self.send_body(body) - body.each { |part| - STDOUT.print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb deleted file mode 100644 index 0f5cbf7293..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/evented_mongrel' - -module Rack - module Handler - class EventedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb deleted file mode 100644 index 6324c7d274..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb +++ /dev/null @@ -1,89 +0,0 @@ -require 'fcgi' -require 'socket' -require 'rack/content_length' - -module Rack - module Handler - class FastCGI - def self.run(app, options={}) - file = options[:File] and STDIN.reopen(UNIXServer.new(file)) - port = options[:Port] and STDIN.reopen(TCPServer.new(port)) - FCGI.each { |request| - serve request, app - } - end - - module ProperStream # :nodoc: - def each # This is missing by default. - while line = gets - yield line - end - end - - def read(*args) - if args.empty? - super || "" # Empty string on EOF. - else - super - end - end - end - - def self.serve(request, app) - app = Rack::ContentLength.new(app) - - env = request.env - env.delete "HTTP_CONTENT_LENGTH" - - request.in.extend ProperStream - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [0,1], - "rack.input" => request.in, - "rack.errors" => request.err, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" - env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" - - status, headers, body = app.call(env) - begin - send_headers request.out, status, headers - send_body request.out, body - ensure - body.close if body.respond_to? :close - request.finish - end - end - - def self.send_headers(out, status, headers) - out.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - out.print "#{k}: #{v}\r\n" - } - } - out.print "\r\n" - out.flush - end - - def self.send_body(out, body) - body.each { |part| - out.print part - out.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb deleted file mode 100644 index c65ba3ec8e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'lsapi' -require 'rack/content_length' - -module Rack - module Handler - class LSWS - def self.run(app, options=nil) - while LSAPI.accept != nil - serve app - end - end - def self.serve(app) - app = Rack::ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [0,1], - "rack.input" => StringIO.new($stdin.read.to_s), - "rack.errors" => $stderr, - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - def self.send_headers(status, headers) - print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - print "#{k}: #{v}\r\n" - } - } - print "\r\n" - STDOUT.flush - end - def self.send_body(body) - body.each { |part| - print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb deleted file mode 100644 index f0c0d58330..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'mongrel' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class Mongrel < ::Mongrel::HttpHandler - def self.run(app, options={}) - server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080) - # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of - # { path=>app, ... } or an instance of Rack::URLMap. - if options[:map] - if app.is_a? Hash - app.each do |path, appl| - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - elsif app.is_a? URLMap - app.instance_variable_get(:@mapping).each do |(host, path, appl)| - next if !host.nil? && !options[:Host].nil? && options[:Host] != host - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - else - raise ArgumentError, "first argument should be a Hash or URLMap" - end - else - server.register('/', Rack::Handler::Mongrel.new(app)) - end - yield server if block_given? - server.run.join - end - - def initialize(app) - @app = Rack::Chunked.new(Rack::ContentLength.new(app)) - end - - def process(request, response) - env = {}.replace(request.params) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [0,1], - "rack.input" => request.body || StringIO.new(""), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, # ??? - "rack.run_once" => false, - - "rack.url_scheme" => "http", - }) - env["QUERY_STRING"] ||= "" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - - status, headers, body = @app.call(env) - - begin - response.status = status.to_i - response.send_status(nil) - - headers.each { |k, vs| - vs.split("\n").each { |v| - response.header[k] = v - } - } - response.send_header - - body.each { |part| - response.write part - response.socket.flush - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb deleted file mode 100644 index 9495c66374..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'scgi' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class SCGI < ::SCGI::Processor - attr_accessor :app - - def self.run(app, options=nil) - new(options.merge(:app=>app, - :host=>options[:Host], - :port=>options[:Port], - :socket=>options[:Socket])).listen - end - - def initialize(settings = {}) - @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) - @log = Object.new - def @log.info(*args); end - def @log.error(*args); end - super(settings) - end - - def process_request(request, input_body, socket) - env = {}.replace(request) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["PATH_INFO"] = env["REQUEST_PATH"] - env["QUERY_STRING"] ||= "" - env["SCRIPT_NAME"] = "" - env.update({"rack.version" => [0,1], - "rack.input" => StringIO.new(input_body), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - status, headers, body = app.call(env) - begin - socket.write("Status: #{status}\r\n") - headers.each do |k, vs| - vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} - end - socket.write("\r\n") - body.each {|s| socket.write(s)} - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb deleted file mode 100644 index 4bafd0b953..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/swiftiplied_mongrel' - -module Rack - module Handler - class SwiftipliedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb deleted file mode 100644 index 3d4fedff75..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "thin" -require "rack/content_length" -require "rack/chunked" - -module Rack - module Handler - class Thin - def self.run(app, options={}) - app = Rack::Chunked.new(Rack::ContentLength.new(app)) - server = ::Thin::Server.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080, - app) - yield server if block_given? - server.start - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb deleted file mode 100644 index 829e7d6bf8..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'webrick' -require 'stringio' -require 'rack/content_length' - -module Rack - module Handler - class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet - def self.run(app, options={}) - server = ::WEBrick::HTTPServer.new(options) - server.mount "/", Rack::Handler::WEBrick, app - trap(:INT) { server.shutdown } - yield server if block_given? - server.start - end - - def initialize(server, app) - super server - @app = Rack::ContentLength.new(app) - end - - def service(req, res) - env = req.meta_vars - env.delete_if { |k, v| v.nil? } - - env.update({"rack.version" => [0,1], - "rack.input" => StringIO.new(req.body.to_s), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["QUERY_STRING"] ||= "" - env["REQUEST_PATH"] ||= "/" - if env["PATH_INFO"] == "" - env.delete "PATH_INFO" - else - path, n = req.request_uri.path, env["SCRIPT_NAME"].length - env["PATH_INFO"] = path[n, path.length-n] - end - - status, headers, body = @app.call(env) - begin - res.status = status.to_i - headers.each { |k, vs| - if k.downcase == "set-cookie" - res.cookies.concat vs.split("\n") - else - vs.split("\n").each { |v| - res[k] = v - } - end - } - body.each { |part| - res.body << part - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb deleted file mode 100644 index deab822a99..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Rack - -class Head - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - - if env["REQUEST_METHOD"] == "HEAD" - [status, headers, []] - else - [status, headers, body] - end - end -end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb deleted file mode 100644 index 44a33ce36e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb +++ /dev/null @@ -1,462 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Lint validates your application and the requests and - # responses according to the Rack spec. - - class Lint - def initialize(app) - @app = app - end - - # :stopdoc: - - class LintError < RuntimeError; end - module Assertion - def assert(message, &block) - unless block.call - raise LintError, message - end - end - end - include Assertion - - ## This specification aims to formalize the Rack protocol. You - ## can (and should) use Rack::Lint to enforce it. - ## - ## When you develop middleware, be sure to add a Lint before and - ## after to catch all mistakes. - - ## = Rack applications - - ## A Rack application is an Ruby object (not a class) that - ## responds to +call+. - def call(env=nil) - dup._call(env) - end - - def _call(env) - ## It takes exactly one argument, the *environment* - assert("No env given") { env } - check_env env - - env['rack.input'] = InputWrapper.new(env['rack.input']) - env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) - - ## and returns an Array of exactly three values: - status, headers, @body = @app.call(env) - ## The *status*, - check_status status - ## the *headers*, - check_headers headers - ## and the *body*. - check_content_type status, headers - check_content_length status, headers, env - [status, headers, self] - end - - ## == The Environment - def check_env(env) - ## The environment must be an true instance of Hash (no - ## subclassing allowed) that includes CGI-like headers. - ## The application is free to modify the environment. - assert("env #{env.inspect} is not a Hash, but #{env.class}") { - env.instance_of? Hash - } - - ## - ## The environment is required to include these variables - ## (adopted from PEP333), except when they'd be empty, but see - ## below. - - ## REQUEST_METHOD:: The HTTP request method, such as - ## "GET" or "POST". This cannot ever - ## be an empty string, and so is - ## always required. - - ## SCRIPT_NAME:: The initial portion of the request - ## URL's "path" that corresponds to the - ## application object, so that the - ## application knows its virtual - ## "location". This may be an empty - ## string, if the application corresponds - ## to the "root" of the server. - - ## PATH_INFO:: The remainder of the request URL's - ## "path", designating the virtual - ## "location" of the request's target - ## within the application. This may be an - ## empty string, if the request URL targets - ## the application root and does not have a - ## trailing slash. This information should be - ## decoded by the server if it comes from a - ## URL. - - ## QUERY_STRING:: The portion of the request URL that - ## follows the ?, if any. May be - ## empty, but is always required! - - ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. - - ## HTTP_ Variables:: Variables corresponding to the - ## client-supplied HTTP request - ## headers (i.e., variables whose - ## names begin with HTTP_). The - ## presence or absence of these - ## variables should correspond with - ## the presence or absence of the - ## appropriate HTTP header in the - ## request. - - ## In addition to this, the Rack environment must include these - ## Rack-specific variables: - - ## rack.version:: The Array [0,1], representing this version of Rack. - ## rack.url_scheme:: +http+ or +https+, depending on the request URL. - ## rack.input:: See below, the input stream. - ## rack.errors:: See below, the error stream. - ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. - ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. - ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). - - ## The server or the application can store their own data in the - ## environment, too. The keys must contain at least one dot, - ## and should be prefixed uniquely. The prefix rack. - ## is reserved for use with the Rack core distribution and must - ## not be used otherwise. - ## - - %w[REQUEST_METHOD SERVER_NAME SERVER_PORT - QUERY_STRING - rack.version rack.input rack.errors - rack.multithread rack.multiprocess rack.run_once].each { |header| - assert("env missing required key #{header}") { env.include? header } - } - - ## The environment must not contain the keys - ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH - ## (use the versions without HTTP_). - %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| - assert("env contains #{header}, must use #{header[5,-1]}") { - not env.include? header - } - } - - ## The CGI keys (named without a period) must have String values. - env.each { |key, value| - next if key.include? "." # Skip extensions - assert("env variable #{key} has non-string value #{value.inspect}") { - value.instance_of? String - } - } - - ## - ## There are the following restrictions: - - ## * rack.version must be an array of Integers. - assert("rack.version must be an Array, was #{env["rack.version"].class}") { - env["rack.version"].instance_of? Array - } - ## * rack.url_scheme must either be +http+ or +https+. - assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { - %w[http https].include? env["rack.url_scheme"] - } - - ## * There must be a valid input stream in rack.input. - check_input env["rack.input"] - ## * There must be a valid error stream in rack.errors. - check_error env["rack.errors"] - - ## * The REQUEST_METHOD must be a valid token. - assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { - env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ - } - - ## * The SCRIPT_NAME, if non-empty, must start with / - assert("SCRIPT_NAME must start with /") { - !env.include?("SCRIPT_NAME") || - env["SCRIPT_NAME"] == "" || - env["SCRIPT_NAME"] =~ /\A\// - } - ## * The PATH_INFO, if non-empty, must start with / - assert("PATH_INFO must start with /") { - !env.include?("PATH_INFO") || - env["PATH_INFO"] == "" || - env["PATH_INFO"] =~ /\A\// - } - ## * The CONTENT_LENGTH, if given, must consist of digits only. - assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { - !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ - } - - ## * One of SCRIPT_NAME or PATH_INFO must be - ## set. PATH_INFO should be / if - ## SCRIPT_NAME is empty. - assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { - env["SCRIPT_NAME"] || env["PATH_INFO"] - } - ## SCRIPT_NAME never should be /, but instead be empty. - assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { - env["SCRIPT_NAME"] != "/" - } - end - - ## === The Input Stream - def check_input(input) - ## The input stream must respond to +gets+, +each+ and +read+. - [:gets, :each, :read].each { |method| - assert("rack.input #{input} does not respond to ##{method}") { - input.respond_to? method - } - } - end - - class InputWrapper - include Assertion - - def initialize(input) - @input = input - end - - def size - @input.size - end - - def rewind - @input.rewind - end - - ## * +gets+ must be called without arguments and return a string, - ## or +nil+ on EOF. - def gets(*args) - assert("rack.input#gets called with arguments") { args.size == 0 } - v = @input.gets - assert("rack.input#gets didn't return a String") { - v.nil? or v.instance_of? String - } - v - end - - ## * +read+ must be called without or with one integer argument - ## and return a string, or +nil+ on EOF. - def read(*args) - assert("rack.input#read called with too many arguments") { - args.size <= 1 - } - if args.size == 1 - assert("rack.input#read called with non-integer argument") { - args.first.kind_of? Integer - } - end - v = @input.read(*args) - assert("rack.input#read didn't return a String") { - v.nil? or v.instance_of? String - } - v - end - - ## * +each+ must be called without arguments and only yield Strings. - def each(*args) - assert("rack.input#each called with arguments") { args.size == 0 } - @input.each { |line| - assert("rack.input#each didn't yield a String") { - line.instance_of? String - } - yield line - } - end - - ## * +close+ must never be called on the input stream. - def close(*args) - assert("rack.input#close must not be called") { false } - end - end - - ## === The Error Stream - def check_error(error) - ## The error stream must respond to +puts+, +write+ and +flush+. - [:puts, :write, :flush].each { |method| - assert("rack.error #{error} does not respond to ##{method}") { - error.respond_to? method - } - } - end - - class ErrorWrapper - include Assertion - - def initialize(error) - @error = error - end - - ## * +puts+ must be called with a single argument that responds to +to_s+. - def puts(str) - @error.puts str - end - - ## * +write+ must be called with a single argument that is a String. - def write(str) - assert("rack.errors#write not called with a String") { str.instance_of? String } - @error.write str - end - - ## * +flush+ must be called without arguments and must be called - ## in order to make the error appear for sure. - def flush - @error.flush - end - - ## * +close+ must never be called on the error stream. - def close(*args) - assert("rack.errors#close must not be called") { false } - end - end - - ## == The Response - - ## === The Status - def check_status(status) - ## The status, if parsed as integer (+to_i+), must be greater than or equal to 100. - assert("Status must be >=100 seen as integer") { status.to_i >= 100 } - end - - ## === The Headers - def check_headers(header) - ## The header must respond to each, and yield values of key and value. - assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { - header.respond_to? :each - } - header.each { |key, value| - ## The header keys must be Strings. - assert("header key must be a string, was #{key.class}") { - key.instance_of? String - } - ## The header must not contain a +Status+ key, - assert("header must not contain Status") { key.downcase != "status" } - ## contain keys with : or newlines in their name, - assert("header names must not contain : or \\n") { key !~ /[:\n]/ } - ## contain keys names that end in - or _, - assert("header names must not end in - or _") { key !~ /[-_]\z/ } - ## but only contain keys that consist of - ## letters, digits, _ or - and start with a letter. - assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } - - ## The values of the header must be Strings, - assert("a header value must be a String, but the value of " + - "'#{key}' is a #{value.class}") { value.kind_of? String } - ## consisting of lines (for multiple header values) seperated by "\n". - value.split("\n").each { |item| - ## The lines must not contain characters below 037. - assert("invalid header value #{key}: #{item.inspect}") { - item !~ /[\000-\037]/ - } - } - } - end - - ## === The Content-Type - def check_content_type(status, headers) - headers.each { |key, value| - ## There must be a Content-Type, except when the - ## +Status+ is 1xx, 204 or 304, in which case there must be none - ## given. - if key.downcase == "content-type" - assert("Content-Type header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - return - end - } - assert("No Content-Type header found") { - Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - end - - ## === The Content-Length - def check_content_length(status, headers, env) - headers.each { |key, value| - if key.downcase == 'content-length' - ## There must not be a Content-Length header when the - ## +Status+ is 1xx, 204 or 304. - assert("Content-Length header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - - bytes = 0 - string_body = true - - if @body.respond_to?(:to_ary) - @body.each { |part| - unless part.kind_of?(String) - string_body = false - break - end - - bytes += Rack::Utils.bytesize(part) - } - - if env["REQUEST_METHOD"] == "HEAD" - assert("Response body was given for HEAD request, but should be empty") { - bytes == 0 - } - else - if string_body - assert("Content-Length header was #{value}, but should be #{bytes}") { - value == bytes.to_s - } - end - end - end - - return - end - } - end - - ## === The Body - def each - @closed = false - ## The Body must respond to #each - @body.each { |part| - ## and must only yield String values. - assert("Body yielded non-string value #{part.inspect}") { - part.instance_of? String - } - yield part - } - ## - ## If the Body responds to #close, it will be called after iteration. - # XXX howto: assert("Body has not been closed") { @closed } - - - ## - ## If the Body responds to #to_path, it must return a String - ## identifying the location of a file whose contents are identical - ## to that produced by calling #each. - - if @body.respond_to?(:to_path) - assert("The file identified by body.to_path does not exist") { - ::File.exist? @body.to_path - } - end - - ## - ## The Body commonly is an Array of Strings, the application - ## instance itself, or a File-like object. - end - - def close - @closed = true - @body.close if @body.respond_to?(:close) - end - - # :startdoc: - - end -end - -## == Thanks -## Some parts of this specification are adopted from PEP333: Python -## Web Server Gateway Interface -## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank -## everyone involved in that effort. diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb deleted file mode 100644 index f63f419a49..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'zlib' - -require 'rack/request' -require 'rack/response' - -module Rack - # Paste has a Pony, Rack has a Lobster! - class Lobster - LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 - P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 - t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ - I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) - - LambdaLobster = lambda { |env| - if env["QUERY_STRING"].include?("flip") - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?" - else - lobster = LobsterString - href = "?flip" - end - - content = ["Lobstericious!", - "
", lobster, "
", - "flip!"] - length = content.inject(0) { |a,e| a+e.size }.to_s - [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] - } - - def call(env) - req = Request.new(env) - if req.GET["flip"] == "left" - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?flip=right" - elsif req.GET["flip"] == "crash" - raise "Lobster crashed" - else - lobster = LobsterString - href = "?flip=left" - end - - res = Response.new - res.write "Lobstericious!" - res.write "
"
-      res.write lobster
-      res.write "
" - res.write "

flip!

" - res.write "

crash!

" - res.finish - end - - end -end - -if $0 == __FILE__ - require 'rack' - require 'rack/showexceptions' - Rack::Handler::WEBrick.run \ - Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), - :Port => 9292 -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb deleted file mode 100644 index 93238528c4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Rack - class Lock - FLAG = 'rack.multithread'.freeze - - def initialize(app, lock = Mutex.new) - @app, @lock = app, lock - end - - def call(env) - old, env[FLAG] = env[FLAG], false - @lock.synchronize { @app.call(env) } - ensure - env[FLAG] = old - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb deleted file mode 100644 index 0eed29f471..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Rack - class MethodOverride - HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS) - - METHOD_OVERRIDE_PARAM_KEY = "_method".freeze - HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze - - def initialize(app) - @app = app - end - - def call(env) - if env["REQUEST_METHOD"] == "POST" - req = Request.new(env) - method = req.POST[METHOD_OVERRIDE_PARAM_KEY] || - env[HTTP_METHOD_OVERRIDE_HEADER] - method = method.to_s.upcase - if HTTP_METHODS.include?(method) - env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] - env["REQUEST_METHOD"] = method - end - end - - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb deleted file mode 100644 index 5a6a73a97b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb +++ /dev/null @@ -1,204 +0,0 @@ -module Rack - module Mime - # Returns String with mime type if found, otherwise use +fallback+. - # +ext+ should be filename extension in the '.ext' format that - # File.extname(file) returns. - # +fallback+ may be any object - # - # Also see the documentation for MIME_TYPES - # - # Usage: - # Rack::Mime.mime_type('.foo') - # - # This is a shortcut for: - # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') - - def mime_type(ext, fallback='application/octet-stream') - MIME_TYPES.fetch(ext, fallback) - end - module_function :mime_type - - # List of most common mime-types, selected various sources - # according to their usefulness in a webserving scope for Ruby - # users. - # - # To amend this list with your local mime.types list you can use: - # - # require 'webrick/httputils' - # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') - # Rack::Mime::MIME_TYPES.merge!(list) - # - # To add the list mongrel provides, use: - # - # require 'mongrel/handlers' - # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES) - - MIME_TYPES = { - ".3gp" => "video/3gpp", - ".a" => "application/octet-stream", - ".ai" => "application/postscript", - ".aif" => "audio/x-aiff", - ".aiff" => "audio/x-aiff", - ".asc" => "application/pgp-signature", - ".asf" => "video/x-ms-asf", - ".asm" => "text/x-asm", - ".asx" => "video/x-ms-asf", - ".atom" => "application/atom+xml", - ".au" => "audio/basic", - ".avi" => "video/x-msvideo", - ".bat" => "application/x-msdownload", - ".bin" => "application/octet-stream", - ".bmp" => "image/bmp", - ".bz2" => "application/x-bzip2", - ".c" => "text/x-c", - ".cab" => "application/vnd.ms-cab-compressed", - ".cc" => "text/x-c", - ".chm" => "application/vnd.ms-htmlhelp", - ".class" => "application/octet-stream", - ".com" => "application/x-msdownload", - ".conf" => "text/plain", - ".cpp" => "text/x-c", - ".crt" => "application/x-x509-ca-cert", - ".css" => "text/css", - ".csv" => "text/csv", - ".cxx" => "text/x-c", - ".deb" => "application/x-debian-package", - ".der" => "application/x-x509-ca-cert", - ".diff" => "text/x-diff", - ".djv" => "image/vnd.djvu", - ".djvu" => "image/vnd.djvu", - ".dll" => "application/x-msdownload", - ".dmg" => "application/octet-stream", - ".doc" => "application/msword", - ".dot" => "application/msword", - ".dtd" => "application/xml-dtd", - ".dvi" => "application/x-dvi", - ".ear" => "application/java-archive", - ".eml" => "message/rfc822", - ".eps" => "application/postscript", - ".exe" => "application/x-msdownload", - ".f" => "text/x-fortran", - ".f77" => "text/x-fortran", - ".f90" => "text/x-fortran", - ".flv" => "video/x-flv", - ".for" => "text/x-fortran", - ".gem" => "application/octet-stream", - ".gemspec" => "text/x-script.ruby", - ".gif" => "image/gif", - ".gz" => "application/x-gzip", - ".h" => "text/x-c", - ".hh" => "text/x-c", - ".htm" => "text/html", - ".html" => "text/html", - ".ico" => "image/vnd.microsoft.icon", - ".ics" => "text/calendar", - ".ifb" => "text/calendar", - ".iso" => "application/octet-stream", - ".jar" => "application/java-archive", - ".java" => "text/x-java-source", - ".jnlp" => "application/x-java-jnlp-file", - ".jpeg" => "image/jpeg", - ".jpg" => "image/jpeg", - ".js" => "application/javascript", - ".json" => "application/json", - ".log" => "text/plain", - ".m3u" => "audio/x-mpegurl", - ".m4v" => "video/mp4", - ".man" => "text/troff", - ".mathml" => "application/mathml+xml", - ".mbox" => "application/mbox", - ".mdoc" => "text/troff", - ".me" => "text/troff", - ".mid" => "audio/midi", - ".midi" => "audio/midi", - ".mime" => "message/rfc822", - ".mml" => "application/mathml+xml", - ".mng" => "video/x-mng", - ".mov" => "video/quicktime", - ".mp3" => "audio/mpeg", - ".mp4" => "video/mp4", - ".mp4v" => "video/mp4", - ".mpeg" => "video/mpeg", - ".mpg" => "video/mpeg", - ".ms" => "text/troff", - ".msi" => "application/x-msdownload", - ".odp" => "application/vnd.oasis.opendocument.presentation", - ".ods" => "application/vnd.oasis.opendocument.spreadsheet", - ".odt" => "application/vnd.oasis.opendocument.text", - ".ogg" => "application/ogg", - ".p" => "text/x-pascal", - ".pas" => "text/x-pascal", - ".pbm" => "image/x-portable-bitmap", - ".pdf" => "application/pdf", - ".pem" => "application/x-x509-ca-cert", - ".pgm" => "image/x-portable-graymap", - ".pgp" => "application/pgp-encrypted", - ".pkg" => "application/octet-stream", - ".pl" => "text/x-script.perl", - ".pm" => "text/x-script.perl-module", - ".png" => "image/png", - ".pnm" => "image/x-portable-anymap", - ".ppm" => "image/x-portable-pixmap", - ".pps" => "application/vnd.ms-powerpoint", - ".ppt" => "application/vnd.ms-powerpoint", - ".ps" => "application/postscript", - ".psd" => "image/vnd.adobe.photoshop", - ".py" => "text/x-script.python", - ".qt" => "video/quicktime", - ".ra" => "audio/x-pn-realaudio", - ".rake" => "text/x-script.ruby", - ".ram" => "audio/x-pn-realaudio", - ".rar" => "application/x-rar-compressed", - ".rb" => "text/x-script.ruby", - ".rdf" => "application/rdf+xml", - ".roff" => "text/troff", - ".rpm" => "application/x-redhat-package-manager", - ".rss" => "application/rss+xml", - ".rtf" => "application/rtf", - ".ru" => "text/x-script.ruby", - ".s" => "text/x-asm", - ".sgm" => "text/sgml", - ".sgml" => "text/sgml", - ".sh" => "application/x-sh", - ".sig" => "application/pgp-signature", - ".snd" => "audio/basic", - ".so" => "application/octet-stream", - ".svg" => "image/svg+xml", - ".svgz" => "image/svg+xml", - ".swf" => "application/x-shockwave-flash", - ".t" => "text/troff", - ".tar" => "application/x-tar", - ".tbz" => "application/x-bzip-compressed-tar", - ".tcl" => "application/x-tcl", - ".tex" => "application/x-tex", - ".texi" => "application/x-texinfo", - ".texinfo" => "application/x-texinfo", - ".text" => "text/plain", - ".tif" => "image/tiff", - ".tiff" => "image/tiff", - ".torrent" => "application/x-bittorrent", - ".tr" => "text/troff", - ".txt" => "text/plain", - ".vcf" => "text/x-vcard", - ".vcs" => "text/x-vcalendar", - ".vrml" => "model/vrml", - ".war" => "application/java-archive", - ".wav" => "audio/x-wav", - ".wma" => "audio/x-ms-wma", - ".wmv" => "video/x-ms-wmv", - ".wmx" => "video/x-ms-wmx", - ".wrl" => "model/vrml", - ".wsdl" => "application/wsdl+xml", - ".xbm" => "image/x-xbitmap", - ".xhtml" => "application/xhtml+xml", - ".xls" => "application/vnd.ms-excel", - ".xml" => "application/xml", - ".xpm" => "image/x-xpixmap", - ".xsl" => "application/xml", - ".xslt" => "application/xslt+xml", - ".yaml" => "text/yaml", - ".yml" => "text/yaml", - ".zip" => "application/zip", - } - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb deleted file mode 100644 index 70852da3db..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb +++ /dev/null @@ -1,160 +0,0 @@ -require 'uri' -require 'stringio' -require 'rack/lint' -require 'rack/utils' -require 'rack/response' - -module Rack - # Rack::MockRequest helps testing your Rack application without - # actually using HTTP. - # - # After performing a request on a URL with get/post/put/delete, it - # returns a MockResponse with useful helper methods for effective - # testing. - # - # You can pass a hash with additional configuration to the - # get/post/put/delete. - # :input:: A String or IO-like to be used as rack.input. - # :fatal:: Raise a FatalWarning if the app writes to rack.errors. - # :lint:: If true, wrap the application in a Rack::Lint. - - class MockRequest - class FatalWarning < RuntimeError - end - - class FatalWarner - def puts(warning) - raise FatalWarning, warning - end - - def write(warning) - raise FatalWarning, warning - end - - def flush - end - - def string - "" - end - end - - DEFAULT_ENV = { - "rack.version" => [0,1], - "rack.input" => StringIO.new, - "rack.errors" => StringIO.new, - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - } - - def initialize(app) - @app = app - end - - def get(uri, opts={}) request("GET", uri, opts) end - def post(uri, opts={}) request("POST", uri, opts) end - def put(uri, opts={}) request("PUT", uri, opts) end - def delete(uri, opts={}) request("DELETE", uri, opts) end - - def request(method="GET", uri="", opts={}) - env = self.class.env_for(uri, opts.merge(:method => method)) - - if opts[:lint] - app = Rack::Lint.new(@app) - else - app = @app - end - - errors = env["rack.errors"] - MockResponse.new(*(app.call(env) + [errors])) - end - - # Return the Rack environment used for a request to +uri+. - def self.env_for(uri="", opts={}) - uri = URI(uri) - env = DEFAULT_ENV.dup - - env["REQUEST_METHOD"] = opts[:method] || "GET" - env["SERVER_NAME"] = uri.host || "example.org" - env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" - env["QUERY_STRING"] = uri.query.to_s - env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path - env["rack.url_scheme"] = uri.scheme || "http" - - env["SCRIPT_NAME"] = opts[:script_name] || "" - - if opts[:fatal] - env["rack.errors"] = FatalWarner.new - else - env["rack.errors"] = StringIO.new - end - - opts[:input] ||= "" - if String === opts[:input] - env["rack.input"] = StringIO.new(opts[:input]) - else - env["rack.input"] = opts[:input] - end - - env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s - - opts.each { |field, value| - env[field] = value if String === field - } - - env - end - end - - # Rack::MockResponse provides useful helpers for testing your apps. - # Usually, you don't create the MockResponse on your own, but use - # MockRequest. - - class MockResponse - def initialize(status, headers, body, errors=StringIO.new("")) - @status = status.to_i - - @original_headers = headers - @headers = Rack::Utils::HeaderHash.new - headers.each { |field, values| - @headers[field] = values - @headers[field] = "" if values.empty? - } - - @body = "" - body.each { |part| @body << part } - - @errors = errors.string - end - - # Status - attr_reader :status - - # Headers - attr_reader :headers, :original_headers - - def [](field) - headers[field] - end - - - # Body - attr_reader :body - - def =~(other) - @body =~ other - end - - def match(other) - @body.match other - end - - - # Errors - attr_accessor :errors - - - include Response::Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb deleted file mode 100644 index bf8b965925..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'uri' - -module Rack - # Rack::ForwardRequest gets caught by Rack::Recursive and redirects - # the current request to the app at +url+. - # - # raise ForwardRequest.new("/not-found") - # - - class ForwardRequest < Exception - attr_reader :url, :env - - def initialize(url, env={}) - @url = URI(url) - @env = env - - @env["PATH_INFO"] = @url.path - @env["QUERY_STRING"] = @url.query if @url.query - @env["HTTP_HOST"] = @url.host if @url.host - @env["HTTP_PORT"] = @url.port if @url.port - @env["rack.url_scheme"] = @url.scheme if @url.scheme - - super "forwarding to #{url}" - end - end - - # Rack::Recursive allows applications called down the chain to - # include data from other applications (by using - # rack['rack.recursive.include'][...] or raise a - # ForwardRequest to redirect internally. - - class Recursive - def initialize(app) - @app = app - end - - def call(env) - @script_name = env["SCRIPT_NAME"] - @app.call(env.merge('rack.recursive.include' => method(:include))) - rescue ForwardRequest => req - call(env.merge(req.env)) - end - - def include(env, path) - unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || - path[@script_name.size].nil?) - raise ArgumentError, "can only include below #{@script_name}, not #{path}" - end - - env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, - "REQUEST_METHOD" => "GET", - "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", - "rack.input" => StringIO.new("")) - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb deleted file mode 100644 index b17d8c0926..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb +++ /dev/null @@ -1,64 +0,0 @@ -require 'thread' - -module Rack - # Rack::Reloader checks on every request, but at most every +secs+ - # seconds, if a file loaded changed, and reloads it, logging to - # rack.errors. - # - # It is recommended you use ShowExceptions to catch SyntaxErrors etc. - - class Reloader - def initialize(app, secs=10) - @app = app - @secs = secs # reload every @secs seconds max - @last = Time.now - end - - def call(env) - if Time.now > @last + @secs - Thread.exclusive { - reload!(env['rack.errors']) - @last = Time.now - } - end - - @app.call(env) - end - - def reload!(stderr=$stderr) - need_reload = $LOADED_FEATURES.find_all { |loaded| - begin - if loaded =~ /\A[.\/]/ # absolute filename or 1.9 - abs = loaded - else - abs = $LOAD_PATH.map { |path| ::File.join(path, loaded) }. - find { |file| ::File.exist? file } - end - - if abs - ::File.mtime(abs) > @last - @secs rescue false - else - false - end - end - } - - need_reload.each { |l| - $LOADED_FEATURES.delete l - } - - need_reload.each { |to_load| - begin - if require to_load - stderr.puts "#{self.class}: reloaded `#{to_load}'" - end - rescue LoadError, SyntaxError => e - raise e # Possibly ShowExceptions - end - } - - stderr.flush - need_reload - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb deleted file mode 100644 index d77fa26575..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb +++ /dev/null @@ -1,241 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Request provides a convenient interface to a Rack - # environment. It is stateless, the environment +env+ passed to the - # constructor will be directly modified. - # - # req = Rack::Request.new(env) - # req.post? - # req.params["data"] - # - # The environment hash passed will store a reference to the Request object - # instantiated so that it will only instantiate if an instance of the Request - # object doesn't already exist. - - class Request - # The environment of the request. - attr_reader :env - - def self.new(env) - if self == Rack::Request - env["rack.request"] ||= super - else - super - end - end - - def initialize(env) - @env = env - end - - def body; @env["rack.input"] end - def scheme; @env["rack.url_scheme"] end - def script_name; @env["SCRIPT_NAME"].to_s end - def path_info; @env["PATH_INFO"].to_s end - def port; @env["SERVER_PORT"].to_i end - def request_method; @env["REQUEST_METHOD"] end - def query_string; @env["QUERY_STRING"].to_s end - def content_length; @env['CONTENT_LENGTH'] end - def content_type; @env['CONTENT_TYPE'] end - - # The media type (type/subtype) portion of the CONTENT_TYPE header - # without any media type parameters. e.g., when CONTENT_TYPE is - # "text/plain;charset=utf-8", the media-type is "text/plain". - # - # For more information on the use of media types in HTTP, see: - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 - def media_type - content_type && content_type.split(/\s*[;,]\s*/, 2)[0].downcase - end - - # The media type parameters provided in CONTENT_TYPE as a Hash, or - # an empty Hash if no CONTENT_TYPE or media-type parameters were - # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", - # this method responds with the following Hash: - # { 'charset' => 'utf-8' } - def media_type_params - return {} if content_type.nil? - content_type.split(/\s*[;,]\s*/)[1..-1]. - collect { |s| s.split('=', 2) }. - inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } - end - - # The character set of the request body if a "charset" media type - # parameter was given, or nil if no "charset" was specified. Note - # that, per RFC2616, text/* media types that specify no explicit - # charset are to be considered ISO-8859-1. - def content_charset - media_type_params['charset'] - end - - def host - # Remove port number. - (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') - end - - def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end - def path_info=(s); @env["PATH_INFO"] = s.to_s end - - def get?; request_method == "GET" end - def post?; request_method == "POST" end - def put?; request_method == "PUT" end - def delete?; request_method == "DELETE" end - def head?; request_method == "HEAD" end - - # The set of form-data media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for form-data / param parsing. - FORM_DATA_MEDIA_TYPES = [ - nil, - 'application/x-www-form-urlencoded', - 'multipart/form-data' - ] - - # Determine whether the request body contains form-data by checking - # the request media_type against registered form-data media-types: - # "application/x-www-form-urlencoded" and "multipart/form-data". The - # list of form-data media types can be modified through the - # +FORM_DATA_MEDIA_TYPES+ array. - def form_data? - FORM_DATA_MEDIA_TYPES.include?(media_type) - end - - # Returns the data recieved in the query string. - def GET - if @env["rack.request.query_string"] == query_string - @env["rack.request.query_hash"] - else - @env["rack.request.query_string"] = query_string - @env["rack.request.query_hash"] = - Utils.parse_nested_query(query_string) - end - end - - # Returns the data recieved in the request body. - # - # This method support both application/x-www-form-urlencoded and - # multipart/form-data. - def POST - if @env["rack.request.form_input"].eql? @env["rack.input"] - @env["rack.request.form_hash"] - elsif form_data? - @env["rack.request.form_input"] = @env["rack.input"] - unless @env["rack.request.form_hash"] = - Utils::Multipart.parse_multipart(env) - form_vars = @env["rack.input"].read - - # Fix for Safari Ajax postings that always append \0 - form_vars.sub!(/\0\z/, '') - - @env["rack.request.form_vars"] = form_vars - @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) - - begin - @env["rack.input"].rewind if @env["rack.input"].respond_to?(:rewind) - rescue Errno::ESPIPE - # Handles exceptions raised by input streams that cannot be rewound - # such as when using plain CGI under Apache - end - end - @env["rack.request.form_hash"] - else - {} - end - end - - # The union of GET and POST data. - def params - self.put? ? self.GET : self.GET.update(self.POST) - rescue EOFError => e - self.GET - end - - # shortcut for request.params[key] - def [](key) - params[key.to_s] - end - - # shortcut for request.params[key] = value - def []=(key, value) - params[key.to_s] = value - end - - # like Hash#values_at - def values_at(*keys) - keys.map{|key| params[key] } - end - - # the referer of the client or '/' - def referer - @env['HTTP_REFERER'] || '/' - end - alias referrer referer - - - def cookies - return {} unless @env["HTTP_COOKIE"] - - if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] - @env["rack.request.cookie_hash"] - else - @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] - # According to RFC 2109: - # If multiple cookies satisfy the criteria above, they are ordered in - # the Cookie header such that those with more specific Path attributes - # precede those with less specific. Ordering with respect to other - # attributes (e.g., Domain) is unspecified. - @env["rack.request.cookie_hash"] = - Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| - h[k] = Array === v ? v.first : v - h - } - end - end - - def xhr? - @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" - end - - # Tries to return a remake of the original request URL as a string. - def url - url = scheme + "://" - url << host - - if scheme == "https" && port != 443 || - scheme == "http" && port != 80 - url << ":#{port}" - end - - url << fullpath - - url - end - - def fullpath - path = script_name + path_info - path << "?" << query_string unless query_string.empty? - path - end - - def accept_encoding - @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| - m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick - - if m - [m[1], (m[2] || 1.0).to_f] - else - raise "Invalid value for Accept-Encoding: #{part.inspect}" - end - end - end - - def ip - if addr = @env['HTTP_X_FORWARDED_FOR'] - addr.split(',').last.strip - else - @env['REMOTE_ADDR'] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb deleted file mode 100644 index caf60d5b19..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb +++ /dev/null @@ -1,179 +0,0 @@ -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::Response provides a convenient interface to create a Rack - # response. - # - # It allows setting of headers and cookies, and provides useful - # defaults (a OK response containing HTML). - # - # You can use Response#write to iteratively generate your response, - # but note that this is buffered by Rack::Response until you call - # +finish+. +finish+ however can take a block inside which calls to - # +write+ are syncronous with the Rack response. - # - # Your application's +call+ should end returning Response#finish. - - class Response - attr_accessor :length - - def initialize(body=[], status=200, header={}, &block) - @status = status - @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. - merge(header)) - - @writer = lambda { |x| @body << x } - @block = nil - @length = 0 - - @body = [] - - if body.respond_to? :to_str - write body.to_str - elsif body.respond_to?(:each) - body.each { |part| - write part.to_s - } - else - raise TypeError, "stringable or iterable required" - end - - yield self if block_given? - end - - attr_reader :header - attr_accessor :status, :body - - def [](key) - header[key] - end - - def []=(key, value) - header[key] = value - end - - def set_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Utils.escape(key) + "=" + - value.map { |v| Utils.escape v }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - - case self["Set-Cookie"] - when Array - self["Set-Cookie"] << cookie - when String - self["Set-Cookie"] = [self["Set-Cookie"], cookie] - when nil - self["Set-Cookie"] = cookie - end - end - - def delete_cookie(key, value={}) - unless Array === self["Set-Cookie"] - self["Set-Cookie"] = [self["Set-Cookie"]].compact - end - - self["Set-Cookie"].reject! { |cookie| - cookie =~ /\A#{Utils.escape(key)}=/ - } - - set_cookie(key, - {:value => '', :path => nil, :domain => nil, - :expires => Time.at(0) }.merge(value)) - end - - - def finish(&block) - @block = block - - if [204, 304].include?(status.to_i) - header.delete "Content-Type" - [status.to_i, header.to_hash, []] - else - [status.to_i, header.to_hash, self] - end - end - alias to_a finish # For *response - - def each(&callback) - @body.each(&callback) - @writer = callback - @block.call(self) if @block - end - - # Append to body and update Content-Length. - # - # NOTE: Do not mix #write and direct #body access! - # - def write(str) - s = str.to_s - @length += s.size - @writer.call s - - header["Content-Length"] = @length.to_s - str - end - - def close - body.close if body.respond_to?(:close) - end - - def empty? - @block == nil && @body.empty? - end - - alias headers header - - module Helpers - def invalid?; @status < 100 || @status >= 600; end - - def informational?; @status >= 100 && @status < 200; end - def successful?; @status >= 200 && @status < 300; end - def redirection?; @status >= 300 && @status < 400; end - def client_error?; @status >= 400 && @status < 500; end - def server_error?; @status >= 500 && @status < 600; end - - def ok?; @status == 200; end - def forbidden?; @status == 403; end - def not_found?; @status == 404; end - - def redirect?; [301, 302, 303, 307].include? @status; end - def empty?; [201, 204, 304].include? @status; end - - # Headers - attr_reader :headers, :original_headers - - def include?(header) - !!headers[header] - end - - def content_type - headers["Content-Type"] - end - - def content_length - cl = headers["Content-Length"] - cl ? cl.to_i : cl - end - - def location - headers["Location"] - end - end - - include Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb deleted file mode 100644 index 218144c17f..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb +++ /dev/null @@ -1,142 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# bugrep: Andreas Zehnder - -require 'time' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - module Abstract - - # ID sets up a basic framework for implementing an id based sessioning - # service. Cookies sent to the client for maintaining sessions will only - # contain an id reference. Only #get_session and #set_session are - # required to be overwritten. - # - # All parameters are optional. - # * :key determines the name of the cookie, by default it is - # 'rack.session' - # * :path, :domain, :expire_after, :secure, and :httponly set the related - # cookie options as by Rack::Response#add_cookie - # * :defer will not set a cookie in the response. - # * :renew (implementation dependent) will prompt the generation of a new - # session id, and migration of data to be referenced at the new id. If - # :defer is set, it will be overridden and the cookie will be set. - # * :sidbits sets the number of bits in length that a generated session - # id will be. - # - # These options can be set on a per request basis, at the location of - # env['rack.session.options']. Additionally the id of the session can be - # found within the options hash at the key :id. It is highly not - # recommended to change its value. - # - # Is Rack::Utils::Context compatible. - - class ID - DEFAULT_OPTIONS = { - :path => '/', - :domain => nil, - :expire_after => nil, - :secure => false, - :httponly => true, - :defer => false, - :renew => false, - :sidbits => 128 - } - - attr_reader :key, :default_options - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @default_options = self.class::DEFAULT_OPTIONS.merge(options) - end - - def call(env) - context(env) - end - - def context(env, app=@app) - load_session(env) - status, headers, body = app.call(env) - commit_session(env, status, headers, body) - end - - private - - # Generate a new session id using Ruby #rand. The size of the - # session id is controlled by the :sidbits option. - # Monkey patch this to use custom methods for session id generation. - - def generate_sid - "%0#{@default_options[:sidbits] / 4}x" % - rand(2**@default_options[:sidbits] - 1) - end - - # Extracts the session id from provided cookies and passes it and the - # environment to #get_session. It then sets the resulting session into - # 'rack.session', and places options and session metadata into - # 'rack.session.options'. - - def load_session(env) - request = Rack::Request.new(env) - session_id = request.cookies[@key] - - begin - session_id, session = get_session(env, session_id) - env['rack.session'] = session - rescue - env['rack.session'] = Hash.new - end - - env['rack.session.options'] = @default_options. - merge(:id => session_id) - end - - # Acquires the session from the environment and the session id from - # the session options and passes them to #set_session. If successful - # and the :defer option is not true, a cookie will be added to the - # response with the session's id. - - def commit_session(env, status, headers, body) - session = env['rack.session'] - options = env['rack.session.options'] - session_id = options[:id] - - if not session_id = set_session(env, session_id, session, options) - env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") - [status, headers, body] - elsif options[:defer] and not options[:renew] - env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE - [status, headers, body] - else - cookie = Hash.new - cookie[:value] = session_id - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - # All thread safety and session retrival proceedures should occur here. - # Should return [session_id, session]. - # If nil is provided as the session id, generation of a new valid id - # should occur within. - - def get_session(env, sid) - raise '#get_session not implemented.' - end - - # All thread safety and session storage proceedures should occur here. - # Should return true or false dependant on whether or not the session - # was saved or not. - def set_session(env, sid, session, options) - raise '#set_session not implemented.' - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb deleted file mode 100644 index eace9bd0c6..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'openssl' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - # Rack::Session::Cookie provides simple cookie based session management. - # The session is a Ruby Hash stored as base64 encoded marshalled data - # set to :key (default: rack.session). - # When the secret key is set, cookie data is checked for data integrity. - # - # Example: - # - # use Rack::Session::Cookie, :key => 'rack.session', - # :domain => 'foo.com', - # :path => '/', - # :expire_after => 2592000, - # :secret => 'change_me' - # - # All parameters are optional. - - class Cookie - - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @secret = options[:secret] - @default_options = {:domain => nil, - :path => "/", - :expire_after => nil}.merge(options) - end - - def call(env) - load_session(env) - status, headers, body = @app.call(env) - commit_session(env, status, headers, body) - end - - private - - def load_session(env) - request = Rack::Request.new(env) - session_data = request.cookies[@key] - - if @secret && session_data - session_data, digest = session_data.split("--") - session_data = nil unless digest == generate_hmac(session_data) - end - - begin - session_data = session_data.unpack("m*").first - session_data = Marshal.load(session_data) - env["rack.session"] = session_data - rescue - env["rack.session"] = Hash.new - end - - env["rack.session.options"] = @default_options.dup - end - - def commit_session(env, status, headers, body) - session_data = Marshal.dump(env["rack.session"]) - session_data = [session_data].pack("m*") - - if @secret - session_data = "#{session_data}--#{generate_hmac(session_data)}" - end - - if session_data.size > (4096 - @key.size) - env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") - [status, headers, body] - else - options = env["rack.session.options"] - cookie = Hash.new - cookie[:value] = session_data - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - def generate_hmac(data) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb deleted file mode 100644 index 4a65cbf35d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb +++ /dev/null @@ -1,109 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -require 'rack/session/abstract/id' -require 'memcache' - -module Rack - module Session - # Rack::Session::Memcache provides simple cookie based session management. - # Session data is stored in memcached. The corresponding session key is - # maintained in the cookie. - # You may treat Session::Memcache as you would Session::Pool with the - # following caveats. - # - # * Setting :expire_after to 0 would note to the Memcache server to hang - # onto the session data until it would drop it according to it's own - # specifications. However, the cookie sent to the client would expire - # immediately. - # - # Note that memcache does drop data before it may be listed to expire. For - # a full description of behaviour, please see memcache's documentation. - - class Memcache < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \ - :namespace => 'rack:session', - :memcache_server => 'localhost:11211' - - def initialize(app, options={}) - super - - @mutex = Mutex.new - @pool = MemCache. - new @default_options[:memcache_server], @default_options - raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} - end - - def generate_sid - loop do - sid = super - break sid unless @pool.get(sid, true) - end - end - - def get_session(env, sid) - session = @pool.get(sid) if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - ret = @pool.add sid, session - raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return [ nil, {} ] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - expiry = options[:expire_after] - expiry = expiry.nil? ? 0 : expiry + 1 - - @mutex.lock if env['rack.multithread'] - session = @pool.get(session_id) || {} - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.add session_id, 0 # so we don't worry about cache miss on #set - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.set session_id, session, expiry - return session_id - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return false - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb deleted file mode 100644 index f6f87408bb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb +++ /dev/null @@ -1,100 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# THANKS: -# apeiros, for session id generation, expiry setup, and threadiness -# sergio, threadiness and bugreps - -require 'rack/session/abstract/id' -require 'thread' - -module Rack - module Session - # Rack::Session::Pool provides simple cookie based session management. - # Session data is stored in a hash held by @pool. - # In the context of a multithreaded environment, sessions being - # committed to the pool is done in a merging manner. - # - # The :drop option is available in rack.session.options if you with to - # explicitly remove the session from the session cache. - # - # Example: - # myapp = MyRackApp.new - # sessioned = Rack::Session::Pool.new(myapp, - # :domain => 'foo.com', - # :expire_after => 2592000 - # ) - # Rack::Handler::WEBrick.run sessioned - - class Pool < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false - - def initialize(app, options={}) - super - @pool = Hash.new - @mutex = Mutex.new - end - - def generate_sid - loop do - sid = super - break sid unless @pool.key? sid - end - end - - def get_session(env, sid) - session = @pool[sid] if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - @pool.store sid, session - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - @mutex.lock if env['rack.multithread'] - session = @pool[session_id] - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.store session_id, 0 - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.store session_id, session - return session_id - rescue - warn "#{new_session.inspect} has been lost." - warn $!.inspect - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb deleted file mode 100644 index 697bc41fdb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb +++ /dev/null @@ -1,349 +0,0 @@ -require 'ostruct' -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowExceptions catches all exceptions raised from the app it - # wraps. It shows a useful backtrace with the sourcefile and - # clickable context, the whole Rack environment and the request - # data. - # - # Be careful when you use this on public-facing sites as it could - # reveal information helpful to attackers. - - class ShowExceptions - CONTEXT = 7 - - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - @app.call(env) - rescue StandardError, LoadError, SyntaxError => e - backtrace = pretty(env, e) - [500, - {"Content-Type" => "text/html", - "Content-Length" => backtrace.join.size.to_s}, - backtrace] - end - - def pretty(env, exception) - req = Rack::Request.new(env) - path = (req.script_name + req.path_info).squeeze("/") - - frames = exception.backtrace.map { |line| - frame = OpenStruct.new - if line =~ /(.*?):(\d+)(:in `(.*)')?/ - frame.filename = $1 - frame.lineno = $2.to_i - frame.function = $4 - - begin - lineno = frame.lineno-1 - lines = ::File.readlines(frame.filename) - frame.pre_context_lineno = [lineno-CONTEXT, 0].max - frame.pre_context = lines[frame.pre_context_lineno...lineno] - frame.context_line = lines[lineno].chomp - frame.post_context_lineno = [lineno+CONTEXT, lines.size].min - frame.post_context = lines[lineno+1..frame.post_context_lineno] - rescue - end - - frame - else - nil - end - }.compact - - env["rack.errors"].puts "#{exception.class}: #{exception.message}" - env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } - env["rack.errors"].flush - - [@template.result(binding)] - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - - <%=h exception.class %> at <%=h path %> - - - - - -
-

<%=h exception.class %> at <%=h path %>

-

<%=h exception.message %>

- - - - - - -
Ruby<%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web<%=h req.request_method %> <%=h(req.host + path)%>
- -

Jump to:

- -
- -
-

Traceback (innermost first)

-
    -<% frames.each { |frame| %> -
  • - <%=h frame.filename %>: in <%=h frame.function %> - - <% if frame.context_line %> -
    - <% if frame.pre_context %> -
      - <% frame.pre_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> - -
      -
    1. <%=h frame.context_line %>...
    - - <% if frame.post_context %> -
      - <% frame.post_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> -
    - <% end %> -
  • -<% } %> -
-
- -
-

Request information

- -

GET

- <% unless req.GET.empty? %> - - - - - - - - - <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No GET data.

- <% end %> - -

POST

- <% unless req.POST.empty? %> - - - - - - - - - <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No POST data.

- <% end %> - - - - <% unless req.cookies.empty? %> - - - - - - - - - <% req.cookies.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No cookie data.

- <% end %> - -

Rack ENV

- - - - - - - - - <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val %>
- -
- -
-

- You're seeing this error because you use Rack::ShowExceptions. -

-
- - - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb deleted file mode 100644 index 28258c7c89..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb +++ /dev/null @@ -1,106 +0,0 @@ -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowStatus catches all empty responses the app it wraps and - # replaces them with a site explaining the error. - # - # Additional details can be put into rack.showstatus.detail - # and will be shown as HTML. If such details exist, the error page - # is always rendered, even if the reply was not empty. - - class ShowStatus - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - empty = headers['Content-Length'].to_i <= 0 - - # client or server error, or explicit message - if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] - req = Rack::Request.new(env) - message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s - detail = env["rack.showstatus.detail"] || message - body = @template.result(binding) - size = Rack::Utils.bytesize(body) - [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] - else - [status, headers, body] - end - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - <%=h message %> at <%=h req.script_name + req.path_info %> - - - - -
-

<%=h message %> (<%= status.to_i %>)

- - - - - - - - - -
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
-
-
-

<%= detail %>

-
- -
-

- You're seeing this error because you use Rack::ShowStatus. -

-
- - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb deleted file mode 100644 index 168e8f83b2..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Rack - - # The Rack::Static middleware intercepts requests for static files - # (javascript files, images, stylesheets, etc) based on the url prefixes - # passed in the options, and serves them using a Rack::File object. This - # allows a Rack stack to serve both static and dynamic content. - # - # Examples: - # use Rack::Static, :urls => ["/media"] - # will serve all requests beginning with /media from the "media" folder - # located in the current directory (ie media/*). - # - # use Rack::Static, :urls => ["/css", "/images"], :root => "public" - # will serve all requests beginning with /css or /images from the folder - # "public" in the current directory (ie public/css/* and public/images/*) - - class Static - - def initialize(app, options={}) - @app = app - @urls = options[:urls] || ["/favicon.ico"] - root = options[:root] || Dir.pwd - @file_server = Rack::File.new(root) - end - - def call(env) - path = env["PATH_INFO"] - can_serve = @urls.any? { |url| path.index(url) == 0 } - - if can_serve - @file_server.call(env) - else - @app.call(env) - end - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb deleted file mode 100644 index 0ff32df181..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - # Rack::URLMap takes a hash mapping urls or paths to apps, and - # dispatches accordingly. Support for HTTP/1.1 host names exists if - # the URLs start with http:// or https://. - # - # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part - # relevant for dispatch is in the SCRIPT_NAME, and the rest in the - # PATH_INFO. This should be taken care of when you need to - # reconstruct the URL in order to create links. - # - # URLMap dispatches in such a way that the longest paths are tried - # first, since they are most specific. - - class URLMap - def initialize(map = {}) - remap(map) - end - - def remap(map) - @mapping = map.map { |location, app| - if location =~ %r{\Ahttps?://(.*?)(/.*)} - host, location = $1, $2 - else - host = nil - end - - unless location[0] == ?/ - raise ArgumentError, "paths need to start with /" - end - location = location.chomp('/') - - [host, location, app] - }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first - end - - def call(env) - path = env["PATH_INFO"].to_s.squeeze("/") - script_name = env['SCRIPT_NAME'] - hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') - @mapping.each { |host, location, app| - next unless (hHost == host || sName == host \ - || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) - next unless location == path[0, location.size] - next unless path[location.size] == nil || path[location.size] == ?/ - - return app.call( - env.merge( - 'SCRIPT_NAME' => (script_name + location), - 'PATH_INFO' => path[location.size..-1])) - } - [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb deleted file mode 100644 index 0a61bce707..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb +++ /dev/null @@ -1,392 +0,0 @@ -require 'set' -require 'tempfile' - -module Rack - # Rack::Utils contains a grab-bag of useful methods for writing web - # applications adopted from all kinds of Ruby libraries. - - module Utils - # Performs URI escaping so that you can construct proper - # query strings faster. Use this rather than the cgi.rb - # version since it's faster. (Stolen from Camping). - def escape(s) - s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { - '%'+$1.unpack('H2'*$1.size).join('%').upcase - }.tr(' ', '+') - end - module_function :escape - - # Unescapes a URI escaped string. (Stolen from Camping). - def unescape(s) - s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ - [$1.delete('%')].pack('H*') - } - end - module_function :unescape - - # Stolen from Mongrel, with some small modifications: - # Parses a query string by breaking it up at the '&' - # and ';' characters. You can also use this to parse - # cookies by changing the characters used in the second - # parameter (which defaults to '&;'). - def parse_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - - if cur = params[k] - if cur.class == Array - params[k] << v - else - params[k] = [cur, v] - end - else - params[k] = v - end - end - - return params - end - module_function :parse_query - - def parse_nested_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - normalize_params(params, k, v) - end - - return params - end - module_function :parse_nested_query - - def normalize_params(params, name, v = nil) - name =~ %r([\[\]]*([^\[\]]+)\]*) - k = $1 || '' - after = $' || '' - - return if k.empty? - - if after == "" - params[k] = v - elsif after == "[]" - params[k] ||= [] - raise TypeError unless params[k].is_a?(Array) - params[k] << v - elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) - child_key = $1 - params[k] ||= [] - raise TypeError unless params[k].is_a?(Array) - if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) - normalize_params(params[k].last, child_key, v) - else - params[k] << normalize_params({}, child_key, v) - end - else - params[k] ||= {} - params[k] = normalize_params(params[k], after, v) - end - - return params - end - module_function :normalize_params - - def build_query(params) - params.map { |k, v| - if v.class == Array - build_query(v.map { |x| [k, x] }) - else - escape(k) + "=" + escape(v) - end - }.join("&") - end - module_function :build_query - - # Escape ampersands, brackets and quotes to their HTML/XML entities. - def escape_html(string) - string.to_s.gsub("&", "&"). - gsub("<", "<"). - gsub(">", ">"). - gsub("'", "'"). - gsub('"', """) - end - module_function :escape_html - - def select_best_encoding(available_encodings, accept_encoding) - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - - expanded_accept_encoding = - accept_encoding.map { |m, q| - if m == "*" - (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } - else - [[m, q]] - end - }.inject([]) { |mem, list| - mem + list - } - - encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } - - unless encoding_candidates.include?("identity") - encoding_candidates.push("identity") - end - - expanded_accept_encoding.find_all { |m, q| - q == 0.0 - }.each { |m, _| - encoding_candidates.delete(m) - } - - return (encoding_candidates & available_encodings)[0] - end - module_function :select_best_encoding - - # Return the bytesize of String; uses String#length under Ruby 1.8 and - # String#bytesize under 1.9. - if ''.respond_to?(:bytesize) - def bytesize(string) - string.bytesize - end - else - def bytesize(string) - string.size - end - end - module_function :bytesize - - # Context allows the use of a compatible middleware at different points - # in a request handling stack. A compatible middleware must define - # #context which should take the arguments env and app. The first of which - # would be the request environment. The second of which would be the rack - # application that the request would be forwarded to. - class Context - attr_reader :for, :app - - def initialize(app_f, app_r) - raise 'running context does not respond to #context' unless app_f.respond_to? :context - @for, @app = app_f, app_r - end - - def call(env) - @for.context(env, @app) - end - - def recontext(app) - self.class.new(@for, app) - end - - def context(env, app=@app) - recontext(app).call(env) - end - end - - # A case-insensitive Hash that preserves the original case of a - # header when set. - class HeaderHash < Hash - def initialize(hash={}) - @names = {} - hash.each { |k, v| self[k] = v } - end - - def to_hash - inject({}) do |hash, (k,v)| - if v.respond_to? :to_ary - hash[k] = v.to_ary.join("\n") - else - hash[k] = v - end - hash - end - end - - def [](k) - super @names[k.downcase] - end - - def []=(k, v) - delete k - @names[k.downcase] = k - super k, v - end - - def delete(k) - super @names.delete(k.downcase) - end - - def include?(k) - @names.has_key? k.downcase - end - - alias_method :has_key?, :include? - alias_method :member?, :include? - alias_method :key?, :include? - - def merge!(other) - other.each { |k, v| self[k] = v } - self - end - - def merge(other) - hash = dup - hash.merge! other - end - end - - # Every standard HTTP code mapped to the appropriate message. - # Stolen from Mongrel. - HTTP_STATUS_CODES = { - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' - } - - # Responses with HTTP status codes that should not have an entity body - STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) - - # A multipart form data parser, adapted from IOWA. - # - # Usually, Rack::Request#POST takes care of calling this. - - module Multipart - EOL = "\r\n" - - def self.parse_multipart(env) - unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n - nil - else - boundary = "--#{$1}" - - params = {} - buf = "" - content_length = env['CONTENT_LENGTH'].to_i - input = env['rack.input'] - - boundary_size = boundary.size + EOL.size - bufsize = 16384 - - content_length -= boundary_size - - status = input.read(boundary_size) - raise EOFError, "bad content body" unless status == boundary + EOL - - rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n - - loop { - head = nil - body = '' - filename = content_type = name = nil - - until head && buf =~ rx - if !head && i = buf.index("\r\n\r\n") - head = buf.slice!(0, i+2) # First \r\n - buf.slice!(0, 2) # Second \r\n - - filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)\r\n/ni, 1] - name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] - - if filename - body = Tempfile.new("RackMultipart") - body.binmode if body.respond_to?(:binmode) - end - - next - end - - # Save the read body part. - if head && (boundary_size+4 < buf.size) - body << buf.slice!(0, buf.size - (boundary_size+4)) - end - - c = input.read(bufsize < content_length ? bufsize : content_length) - raise EOFError, "bad content body" if c.nil? || c.empty? - buf << c - content_length -= c.size - end - - # Save the rest. - if i = buf.index(rx) - body << buf.slice!(0, i) - buf.slice!(0, boundary_size+2) - - content_length = -1 if $1 == "--" - end - - if filename == "" - # filename is blank which means no file has been selected - data = nil - elsif filename - body.rewind - - # Take the basename of the upload's original filename. - # This handles the full Windows paths given by Internet Explorer - # (and perhaps other broken user agents) without affecting - # those which give the lone filename. - filename =~ /^(?:.*[:\\\/])?(.*)/m - filename = $1 - - data = {:filename => filename, :type => content_type, - :name => name, :tempfile => body, :head => head} - else - data = body - end - - Utils.normalize_params(params, name, data) unless data.nil? - - break if buf.empty? || content_length == -1 - } - - begin - input.rewind if input.respond_to?(:rewind) - rescue Errno::ESPIPE - # Handles exceptions raised by input streams that cannot be rewound - # such as when using plain CGI under Apache - end - - params - end - end - end - end -end diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 88b81dc493..6322cfc84a 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -96,7 +96,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest # Ruby CGI doesn't handle multipart/mixed for us. files = params['files'] - assert_kind_of String, files + assert_kind_of Tempfile, files files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) assert_equal 19756, files.size end -- cgit v1.2.3 From 4f412a10b6125831af34d874927f891f586d0101 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 25 Apr 2009 14:04:03 -0500 Subject: Remove RewindableInput middleware since all input MUST be rewindable according to a recent change in the Rack 1.0 SPEC --- .../lib/action_controller/dispatch/middlewares.rb | 1 - actionpack/lib/action_dispatch.rb | 1 - .../action_dispatch/middleware/rewindable_input.rb | 19 ------- .../request/multipart_params_parsing_test.rb | 61 ---------------------- .../request/url_encoded_params_parsing_test.rb | 38 -------------- 5 files changed, 120 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/rewindable_input.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index b62b4f84a1..b5adbae746 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -7,7 +7,6 @@ use "ActionDispatch::Failsafe" use lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options } -use "ActionDispatch::RewindableInput" use "ActionDispatch::ParamsParser" use "Rack::MethodOverride" use "Rack::Head" diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 0c915d9fd5..4f65dcadee 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -43,7 +43,6 @@ module ActionDispatch autoload :Failsafe, 'action_dispatch/middleware/failsafe' autoload :ParamsParser, 'action_dispatch/middleware/params_parser' autoload :Reloader, 'action_dispatch/middleware/reloader' - autoload :RewindableInput, 'action_dispatch/middleware/rewindable_input' autoload :MiddlewareStack, 'action_dispatch/middleware/stack' module Http diff --git a/actionpack/lib/action_dispatch/middleware/rewindable_input.rb b/actionpack/lib/action_dispatch/middleware/rewindable_input.rb deleted file mode 100644 index c818f28cce..0000000000 --- a/actionpack/lib/action_dispatch/middleware/rewindable_input.rb +++ /dev/null @@ -1,19 +0,0 @@ -module ActionDispatch - class RewindableInput - def initialize(app) - @app = app - end - - def call(env) - begin - env['rack.input'].rewind - rescue NoMethodError, Errno::ESPIPE - # Handles exceptions raised by input streams that cannot be rewound - # such as when using plain CGI under Apache - env['rack.input'] = StringIO.new(env['rack.input'].read) - end - - @app.call(env) - end - end -end diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 6322cfc84a..cc81a87cb9 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -133,46 +133,6 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest end end - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "parses unwindable stream" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - params = parse_multipart('large_text_file') - assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] - end - - test "uploads and reads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - - test "passes through rack middleware and uploads file" do - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - - test "passes through rack middleware and uploads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - private def fixture(name) File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| @@ -199,25 +159,4 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest yield end end - - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - env['rack.input'].read - env['rack.input'].rewind - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end end diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 8de4a83d76..7167cdafac 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -126,45 +126,7 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest assert_parses expected, query end - test "passes through rack middleware and parses params" do - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "passes through rack middleware and parses params with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - private - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - env['rack.input'].read - env['rack.input'].rewind - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end - def with_test_routing with_routing do |set| set.draw do |map| -- cgit v1.2.3 From dbbe2e74ff5b6363da74fe63045b043c24041b1a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 10:26:53 -0500 Subject: Create a new file for response tests --- actionpack/test/dispatch/rack_test.rb | 90 ------------------------------- actionpack/test/dispatch/response_test.rb | 83 ++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 90 deletions(-) create mode 100644 actionpack/test/dispatch/response_test.rb (limited to 'actionpack') diff --git a/actionpack/test/dispatch/rack_test.rb b/actionpack/test/dispatch/rack_test.rb index 9fad4b22ee..94eba2a24f 100644 --- a/actionpack/test/dispatch/rack_test.rb +++ b/actionpack/test/dispatch/rack_test.rb @@ -201,93 +201,3 @@ class RackRequestNeedsRewoundTest < BaseRackTest assert_equal 0, request.body.pos end end - -class RackResponseTest < BaseRackTest - def setup - super - @response = ActionDispatch::Response.new - end - - test "simple output" do - @response.body = "Hello, World!" - @response.prepare! - - status, headers, body = @response.to_a - assert_equal 200, status - assert_equal({ - "Content-Type" => "text/html; charset=utf-8", - "Cache-Control" => "private, max-age=0, must-revalidate", - "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"', - "Set-Cookie" => "", - "Content-Length" => "13" - }, headers) - - parts = [] - body.each { |part| parts << part } - assert_equal ["Hello, World!"], parts - end - - def test_utf8_output - @response.body = [1090, 1077, 1089, 1090].pack("U*") - @response.prepare! - - status, headers, body = @response.to_a - assert_equal 200, status - assert_equal({ - "Content-Type" => "text/html; charset=utf-8", - "Cache-Control" => "private, max-age=0, must-revalidate", - "ETag" => '"ebb5e89e8a94e9dd22abf5d915d112b2"', - "Set-Cookie" => "", - "Content-Length" => "8" - }, headers) - end - - def test_streaming_block - @response.body = Proc.new do |response, output| - 5.times { |n| output.write(n) } - end - @response.prepare! - - status, headers, body = @response.to_a - assert_equal 200, status - assert_equal({ - "Content-Type" => "text/html; charset=utf-8", - "Cache-Control" => "no-cache", - "Set-Cookie" => "" - }, headers) - - parts = [] - body.each { |part| parts << part.to_s } - assert_equal ["0", "1", "2", "3", "4"], parts - end -end - -class RackResponseHeadersTest < BaseRackTest - def setup - super - @response = ActionDispatch::Response.new - @response.status = "200 OK" - end - - test "content type" do - [204, 304].each do |c| - @response.status = c.to_s - assert !response_headers.has_key?("Content-Type"), "#{c} should not have Content-Type header" - end - - [200, 302, 404, 500].each do |c| - @response.status = c.to_s - assert response_headers.has_key?("Content-Type"), "#{c} did not have Content-Type header" - end - end - - test "status" do - assert !response_headers.has_key?('Status') - end - - private - def response_headers - @response.prepare! - @response.to_a[1] - end -end diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb new file mode 100644 index 0000000000..fb593a6c31 --- /dev/null +++ b/actionpack/test/dispatch/response_test.rb @@ -0,0 +1,83 @@ +require 'abstract_unit' + +class ResponseTest < ActiveSupport::TestCase + def setup + @response = ActionDispatch::Response.new + end + + test "simple output" do + @response.body = "Hello, World!" + @response.prepare! + + status, headers, body = @response.to_a + assert_equal 200, status + assert_equal({ + "Content-Type" => "text/html; charset=utf-8", + "Cache-Control" => "private, max-age=0, must-revalidate", + "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"', + "Set-Cookie" => "", + "Content-Length" => "13" + }, headers) + + parts = [] + body.each { |part| parts << part } + assert_equal ["Hello, World!"], parts + end + + test "utf8 output" do + @response.body = [1090, 1077, 1089, 1090].pack("U*") + @response.prepare! + + status, headers, body = @response.to_a + assert_equal 200, status + assert_equal({ + "Content-Type" => "text/html; charset=utf-8", + "Cache-Control" => "private, max-age=0, must-revalidate", + "ETag" => '"ebb5e89e8a94e9dd22abf5d915d112b2"', + "Set-Cookie" => "", + "Content-Length" => "8" + }, headers) + end + + test "streaming block" do + @response.body = Proc.new do |response, output| + 5.times { |n| output.write(n) } + end + @response.prepare! + + status, headers, body = @response.to_a + assert_equal 200, status + assert_equal({ + "Content-Type" => "text/html; charset=utf-8", + "Cache-Control" => "no-cache", + "Set-Cookie" => "" + }, headers) + + parts = [] + body.each { |part| parts << part.to_s } + assert_equal ["0", "1", "2", "3", "4"], parts + end + + test "content type" do + [204, 304].each do |c| + @response.status = c.to_s + @response.prepare! + status, headers, body = @response.to_a + assert !headers.has_key?("Content-Type"), "#{c} should not have Content-Type header" + end + + [200, 302, 404, 500].each do |c| + @response.status = c.to_s + @response.prepare! + status, headers, body = @response.to_a + assert headers.has_key?("Content-Type"), "#{c} did not have Content-Type header" + end + end + + test "does not include Status header" do + @response.status = "200 OK" + @response.prepare! + status, headers, body = @response.to_a + assert !headers.has_key?('Status') + end +end -- cgit v1.2.3 From 5352a2417b9f6297d16a6baefd1994be4d1e4a12 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 11:12:33 -0500 Subject: Move useful response test helpers into request --- .../lib/action_controller/testing/integration.rb | 7 ++- .../lib/action_controller/testing/process.rb | 61 +------------------- actionpack/lib/action_dispatch/http/response.rb | 65 +++++++++++++++++++++- actionpack/test/dispatch/response_test.rb | 47 ++++++++++++++++ 4 files changed, 116 insertions(+), 64 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 15d0603ac1..10260d5af2 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -304,8 +304,11 @@ module ActionController @response = @controller.response @controller.send(:set_test_assigns) else - @request = ::Rack::Request.new(env) - @response = response + @request = Request.new(env) + @response = Response.new + @response.status = @status + @response.headers = @headers + @response.body = @body end # Decorate the response with the standard behavior of the diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index f5742af472..05b756fa4d 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -156,54 +156,7 @@ module ActionController #:nodoc: # A refactoring of TestResponse to allow the same behavior to be applied # to the "real" CgiResponse class in integration tests. module TestResponseBehavior #:nodoc: - # The response code of the request - def response_code - status.to_s[0,3].to_i rescue 0 - end - - # Returns a String to ensure compatibility with Net::HTTPResponse - def code - status.to_s.split(' ')[0] - end - - def message - status.to_s.split(' ',2)[1] - end - - # Was the response successful? - def success? - (200..299).include?(response_code) - end - - # Was the URL not found? - def missing? - response_code == 404 - end - - # Were we redirected? - def redirect? - (300..399).include?(response_code) - end - - # Was there a server-side error? - def error? - (500..599).include?(response_code) - end - - alias_method :server_error?, :error? - - # Was there a client client? - def client_error? - (400..499).include?(response_code) - end - - # Returns the redirection location or nil - def redirect_url - headers['Location'] - end - - # Does the redirect location match this regexp pattern? - def redirect_url_match?( pattern ) + def redirect_url_match?(pattern) return false if redirect_url.nil? p = Regexp.new(pattern) if pattern.class == String p = pattern if pattern.class == Regexp @@ -252,18 +205,6 @@ module ActionController #:nodoc: !template_objects[name].nil? end - # Returns the response cookies, converted to a Hash of (name => value) pairs - # - # assert_equal 'AuthorOfNewPage', r.cookies['author'] - def cookies - cookies = {} - Array(headers['Set-Cookie']).each do |cookie| - key, value = cookie.split(";").first.split("=").map {|val| Rack::Utils.unescape(val)} - cookies[key] = value - end - cookies - end - # Returns binary content (downloadable file), converted to a String def binary_content raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index ecf40b8103..7bc9c62e2c 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -37,6 +37,9 @@ module ActionDispatch # :nodoc: attr_accessor :session, :assigns, :template, :layout attr_accessor :redirected_to, :redirected_to_method_params + attr_writer :header + alias_method :headers=, :header= + delegate :default_charset, :to => 'ActionController::Base' def initialize @@ -45,6 +48,47 @@ module ActionDispatch # :nodoc: @session, @assigns = [], [] end + # The response code of the request + def response_code + status.to_s[0,3].to_i rescue 0 + end + + # Returns a String to ensure compatibility with Net::HTTPResponse + def code + status.to_s.split(' ')[0] + end + + def message + status.to_s.split(' ',2)[1] || StatusCodes::STATUS_CODES[response_code] + end + + # Was the response successful? + def success? + (200..299).include?(response_code) + end + + # Was the URL not found? + def missing? + response_code == 404 + end + + # Were we redirected? + def redirect? + (300..399).include?(response_code) + end + + # Was there a server-side error? + def error? + (500..599).include?(response_code) + end + + alias_method :server_error?, :error? + + # Was there a client client? + def client_error? + (400..499).include?(response_code) + end + def body str = '' each { |part| str << part.to_s } @@ -64,9 +108,14 @@ module ActionDispatch # :nodoc: @body end - def location; headers['Location'] end - def location=(url) headers['Location'] = url end + def location + headers['Location'] + end + alias_method :redirect_url, :location + def location=(url) + headers['Location'] = url + end # Sets the HTTP response's content MIME type. For example, in the controller # you could write this: @@ -192,6 +241,18 @@ module ActionDispatch # :nodoc: super(key, value) end + # Returns the response cookies, converted to a Hash of (name => value) pairs + # + # assert_equal 'AuthorOfNewPage', r.cookies['author'] + def cookies + cookies = {} + Array(headers['Set-Cookie']).each do |cookie| + key, value = cookie.split(";").first.split("=").map { |v| Rack::Utils.unescape(v) } + cookies[key] = value + end + cookies + end + private def handle_conditional_get! if etag? || last_modified? diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index fb593a6c31..2ddc6cb2b5 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -80,4 +80,51 @@ class ResponseTest < ActiveSupport::TestCase status, headers, body = @response.to_a assert !headers.has_key?('Status') end + + test "response code" do + @response.status = "200 OK" + assert_equal 200, @response.response_code + + @response.status = "200" + assert_equal 200, @response.response_code + + @response.status = 200 + assert_equal 200, @response.response_code + end + + test "code" do + @response.status = "200 OK" + assert_equal "200", @response.code + + @response.status = "200" + assert_equal "200", @response.code + + @response.status = 200 + assert_equal "200", @response.code + end + + test "message" do + @response.status = "200 OK" + assert_equal "OK", @response.message + + @response.status = "200" + assert_equal "OK", @response.message + + @response.status = 200 + assert_equal "OK", @response.message + end + + test "cookies" do + @response.set_cookie("user_name", :value => "david", :path => "/") + @response.prepare! + status, headers, body = @response.to_a + assert_equal "user_name=david; path=/", headers["Set-Cookie"] + assert_equal({"user_name" => "david"}, @response.cookies) + + @response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5)) + @response.prepare! + status, headers, body = @response.to_a + assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", headers["Set-Cookie"] + assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies) + end end -- cgit v1.2.3 From 5ea8d401569323a10592d68d29b293c1ae131a8b Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 11:16:14 -0500 Subject: Deprecate response.redirect_url_match?, use assert_match instead. --- actionpack/lib/action_controller/testing/process.rb | 1 + actionpack/test/controller/action_pack_assertions_test.rb | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 05b756fa4d..2ad0579a30 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -157,6 +157,7 @@ module ActionController #:nodoc: # to the "real" CgiResponse class in integration tests. module TestResponseBehavior #:nodoc: def redirect_url_match?(pattern) + ::ActiveSupport::Deprecation.warn("response.redirect_url_match? is deprecated. Use assert_match(/foo/, response.redirect_url) instead", caller) return false if redirect_url.nil? p = Regexp.new(pattern) if pattern.class == String p = pattern if pattern.class == Regexp diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 96f7a42c9b..f091f9b87c 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -378,10 +378,12 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_redirect_url_match process :redirect_external assert @response.redirect? - assert @response.redirect_url_match?("rubyonrails") - assert @response.redirect_url_match?(/rubyonrails/) - assert !@response.redirect_url_match?("phpoffrails") - assert !@response.redirect_url_match?(/perloffrails/) + assert_deprecated do + assert @response.redirect_url_match?("rubyonrails") + assert @response.redirect_url_match?(/rubyonrails/) + assert !@response.redirect_url_match?("phpoffrails") + assert !@response.redirect_url_match?(/perloffrails/) + end end # check for a redirection -- cgit v1.2.3 From 82bc768dad761df466e38ee9f1501aef766878c3 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 11:19:42 -0500 Subject: Fix typo in stale session check [#2404 state:resolved] --- actionpack/lib/action_dispatch/middleware/session/abstract_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 6c039cf62d..211d373208 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -74,7 +74,7 @@ module ActionDispatch # Note that the regexp does not allow $1 to end with a ':' $1.constantize rescue LoadError, NameError => const_error - raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n" + raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" end retry -- cgit v1.2.3 From 3cb97aeea8837b9d2b7ed3f9806f5727ceef0e3d Mon Sep 17 00:00:00 2001 From: "Hongli Lai (Phusion)" Date: Sun, 26 Apr 2009 11:23:10 -0500 Subject: Fix environment variable testing code in failsafe.rb. Signed-off-by: Joshua Peek --- actionpack/lib/action_dispatch/middleware/failsafe.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb index b5a3abcc92..5e0c479fdd 100644 --- a/actionpack/lib/action_dispatch/middleware/failsafe.rb +++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb @@ -11,7 +11,7 @@ module ActionDispatch @app.call(env) rescue Exception => exception # Reraise exception in test environment - if defined?(Rails) && Rails.test? + if defined?(Rails) && Rails.env.test? raise exception else failsafe_response(exception) -- cgit v1.2.3 From 6940c0de12eedcff6529ba0dfef533513cbcd389 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 11:37:11 -0500 Subject: Unify functional and integration tests cookie helpers --- .../lib/action_controller/testing/integration.rb | 33 ++++++++-------------- actionpack/test/controller/integration_test.rb | 2 +- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 10260d5af2..be5f216e2b 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -285,37 +285,28 @@ module ActionController app = Rack::Lint.new(@app) status, headers, body = app.call(env) response = ::Rack::MockResponse.new(status, headers, body) + @request_count += 1 + @request = Request.new(env) - @html_document = nil + @response = Response.new + @response.status = @status = response.status + @response.headers = @headers = response.headers + @response.body = @body = response.body - @status = response.status @status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status] - @headers = response.headers - @body = response.body - - (@headers['Set-Cookie'] || "").split("\n").each do |cookie| - name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2] - @cookies[name] = value - end - - if @controller = ActionController::Base.last_instantiation - @request = @controller.request - @response = @controller.response - @controller.send(:set_test_assigns) - else - @request = Request.new(env) - @response = Response.new - @response.status = @status - @response.headers = @headers - @response.body = @body - end + @cookies.merge!(@response.cookies) + @html_document = nil # Decorate the response with the standard behavior of the # TestResponse so that things like assert_response can be # used in integration tests. @response.extend(TestResponseBehavior) + if @controller = ActionController::Base.last_instantiation + @controller.send(:set_test_assigns) + end + return @status end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 9eeaa7b4e1..70fa41aded 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -297,7 +297,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest assert_response 410 assert_response :gone assert_equal "cookie_1=; path=/\ncookie_3=chocolate; path=/", headers["Set-Cookie"] - assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies) + assert_equal({"cookie_1"=>nil, "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies) assert_equal "Gone", response.body end end -- cgit v1.2.3 From c8919f4c7ca13ad78987ea0c8497abe85249975b Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 11:52:45 -0500 Subject: Require an ActionDispatch::Request to use response assertions --- .../testing/assertions/response.rb | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index ca0a9bbf52..c57cbecc44 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -22,6 +22,8 @@ module ActionController # assert_response 401 # def assert_response(type, message = nil) + validate_response! + clean_backtrace do if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") assert_block("") { true } # to count the assertion @@ -30,8 +32,8 @@ module ActionController elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] assert_block("") { true } # to count the assertion else - if @response.error? - exception = @response.template.instance_variable_get(:@exception) + if @controller && @response.error? + exception = @controller.response.template.instance_variable_get(:@exception) exception_message = exception && exception.message assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } else @@ -57,6 +59,8 @@ module ActionController # assert_redirected_to @customer # def assert_redirected_to(options = {}, message=nil) + validate_response! + clean_backtrace do assert_response(:redirect, message) return true if options == @response.redirected_to @@ -89,23 +93,25 @@ module ActionController # assert_template :partial => false # def assert_template(options = {}, message = nil) + validate_response! + clean_backtrace do case options when NilClass, String - rendered = @response.rendered[:template].to_s + rendered = @controller.response.rendered[:template].to_s msg = build_message(message, "expecting but rendering with ", options, rendered) assert_block(msg) do if options.nil? - @response.rendered[:template].blank? + @controller.response.rendered[:template].blank? else rendered.to_s.match(options) end end when Hash if expected_partial = options[:partial] - partials = @response.rendered[:partials] + partials = @controller.response.rendered[:partials] if expected_count = options[:count] found = partials.detect { |p, _| p.to_s.match(expected_partial) } actual_count = found.nil? ? 0 : found.second @@ -120,7 +126,7 @@ module ActionController assert(partials.keys.any? { |p| p.to_s.match(expected_partial) }, msg) end else - assert @response.rendered[:partials].empty?, + assert @controller.response.rendered[:partials].empty?, "Expected no partials to be rendered" end end @@ -145,6 +151,12 @@ module ActionController @request.protocol + @request.host_with_port + after_routing end end + + def validate_response! + unless @request.is_a?(ActionDispatch::Request) + raise ArgumentError, "@request must be an ActionDispatch::Request" + end + end end end end -- cgit v1.2.3 From 04949096797a390105c7ab9fb9b99938d5921dd4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 26 Apr 2009 14:33:57 -0500 Subject: Inherit TestSession from Session::AbstractStore and add indifferent access to Session::AbstractStore. --- actionpack/lib/action_controller/base/base.rb | 10 +-- .../lib/action_controller/testing/process.rb | 78 +++------------------- actionpack/lib/action_dispatch/http/request.rb | 14 +--- actionpack/lib/action_dispatch/http/response.rb | 3 +- .../middleware/session/abstract_store.rb | 28 +++++++- .../middleware/session/cookie_store.rb | 7 +- .../controller/http_digest_authentication_test.rb | 2 - .../test/controller/request/test_request_test.rb | 23 ++++--- .../test/dispatch/session/cookie_store_test.rb | 3 +- .../test/dispatch/session/test_session_test.rb | 24 +++---- 10 files changed, 67 insertions(+), 125 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 3000b3d12f..afb9fb71cb 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -811,14 +811,8 @@ module ActionController #:nodoc: end def assign_shortcuts(request, response) - @_request, @_params = request, request.parameters - - @_response = response - @_response.session = request.session - - @_session = @_response.session - - @_headers = @_response.headers + @_request, @_response, @_params = request, response, request.parameters + @_session, @_headers = @_request.session, @_response.headers end def initialize_current_url diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 2ad0579a30..16275371ad 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -1,8 +1,9 @@ require 'rack/session/abstract/id' + module ActionController #:nodoc: class TestRequest < ActionDispatch::Request #:nodoc: - attr_accessor :cookies, :session_options - attr_accessor :query_parameters, :path, :session + attr_accessor :cookies + attr_accessor :query_parameters, :path attr_accessor :host def self.new(env = {}) @@ -13,18 +14,13 @@ module ActionController #:nodoc: super(Rack::MockRequest.env_for("/").merge(env)) @query_parameters = {} - @session = TestSession.new - default_rack_options = Rack::Session::Abstract::ID::DEFAULT_OPTIONS - @session_options ||= {:id => generate_sid(default_rack_options[:sidbits])}.merge(default_rack_options) + @env['rack.session'] = TestSession.new + @env['rack.session.options'] = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) initialize_default_values initialize_containers end - def reset_session - @session.reset - end - # Wraps raw_post in a StringIO. def body_stream #:nodoc: StringIO.new(raw_post) @@ -124,10 +120,6 @@ module ActionController #:nodoc: end private - def generate_sid(sidbits) - "%0#{sidbits / 4}x" % rand(2**sidbits - 1) - end - def initialize_containers @cookies = {} end @@ -235,62 +227,12 @@ module ActionController #:nodoc: end end - class TestSession < Hash #:nodoc: - attr_accessor :session_id - - def initialize(attributes = nil) - reset_session_id - replace_attributes(attributes) - end - - def reset - reset_session_id - replace_attributes({ }) - end - - def data - to_hash - end - - def [](key) - super(key.to_s) - end - - def []=(key, value) - super(key.to_s, value) - end - - def update(hash = nil) - if hash.nil? - ActiveSupport::Deprecation.warn('use replace instead', caller) - replace({}) - else - super(hash) - end - end - - def delete(key = nil) - if key.nil? - ActiveSupport::Deprecation.warn('use clear instead', caller) - clear - else - super(key.to_s) - end - end - - def close - ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller) - end - - private - - def reset_session_id - @session_id = '' - end + class TestSession < ActionDispatch::Session::AbstractStore::SessionHash #:nodoc: + DEFAULT_OPTIONS = ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS - def replace_attributes(attributes = nil) - attributes ||= {} - replace(attributes.stringify_keys) + def initialize(session = {}) + replace(session.stringify_keys) + @loaded = true end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index ab654b9a50..2602b344ca 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -451,23 +451,15 @@ EOM @env['rack.input'] end - def session - @env['rack.session'] ||= {} + def reset_session + self.session_options.delete(:id) + self.session = {} end def session=(session) #:nodoc: @env['rack.session'] = session end - def reset_session - @env['rack.session.options'].delete(:id) - @env['rack.session'] = {} - end - - def session_options - @env['rack.session.options'] ||= {} - end - def session_options=(options) @env['rack.session.options'] = options end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 7bc9c62e2c..77c2dd0d7a 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -34,12 +34,13 @@ module ActionDispatch # :nodoc: DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request - attr_accessor :session, :assigns, :template, :layout + attr_accessor :assigns, :template, :layout attr_accessor :redirected_to, :redirected_to_method_params attr_writer :header alias_method :headers=, :header= + delegate :session, :to => :request delegate :default_charset, :to => 'ActionController::Base' def initialize diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 211d373208..03761b10bd 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -26,12 +26,12 @@ module ActionDispatch def [](key) load! unless @loaded - super + super(key.to_s) end def []=(key, value) load! unless @loaded - super + super(key.to_s, value) end def to_hash @@ -40,6 +40,24 @@ module ActionDispatch h end + def update(hash = nil) + if hash.nil? + ActiveSupport::Deprecation.warn('use replace instead', caller) + replace({}) + else + super(hash.stringify_keys) + end + end + + def delete(key = nil) + if key.nil? + ActiveSupport::Deprecation.warn('use clear instead', caller) + clear + else + super(key.to_s) + end + end + def data ActiveSupport::Deprecation.warn( "ActionController::Session::AbstractStore::SessionHash#data " + @@ -47,6 +65,10 @@ module ActionDispatch to_hash end + def close + ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller) + end + def inspect load! unless @loaded super @@ -61,7 +83,7 @@ module ActionDispatch stale_session_check! do id, session = @by.send(:load_session, @env) (@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id - replace(session) + replace(session.stringify_keys) @loaded = true end end diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 433c4cc070..547a2d2062 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -143,7 +143,8 @@ module ActionDispatch request = Rack::Request.new(env) session_data = request.cookies[@key] data = unmarshal(session_data) || persistent_session_id!({}) - [data[:session_id], data] + data.stringify_keys! + [data["session_id"], data] end # Marshal a session hash into safe cookie data. Include an integrity hash. @@ -206,12 +207,12 @@ module ActionDispatch end def inject_persistent_session_id(data) - requires_session_id?(data) ? { :session_id => generate_sid } : {} + requires_session_id?(data) ? { "session_id" => generate_sid } : {} end def requires_session_id?(data) if data - data.respond_to?(:key?) && !data.key?(:session_id) + data.respond_to?(:key?) && !data.key?("session_id") else true end diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb index 00789eea38..7bebc8cd2a 100644 --- a/actionpack/test/controller/http_digest_authentication_test.rb +++ b/actionpack/test/controller/http_digest_authentication_test.rb @@ -111,8 +111,6 @@ class HttpDigestAuthenticationTest < ActionController::TestCase test "authentication request with valid credential and nil session" do @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') - # session_id = "" in functional test, but is +nil+ in real life - @request.session.session_id = nil get :display assert_response :success diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb index 81551b4ba7..0a39feb7fe 100644 --- a/actionpack/test/controller/request/test_request_test.rb +++ b/actionpack/test/controller/request/test_request_test.rb @@ -10,26 +10,27 @@ class ActionController::TestRequestTest < ActiveSupport::TestCase def test_test_request_has_session_options_initialized assert @request.session_options end - - Rack::Session::Abstract::ID::DEFAULT_OPTIONS.each_key do |option| - test "test_rack_default_session_options_#{option}_exists_in_session_options_and_is_default" do - assert_equal(Rack::Session::Abstract::ID::DEFAULT_OPTIONS[option], - @request.session_options[option], + + ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option| + test "rack default session options #{option} exists in session options and is default" do + assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option], + @request.session_options[option], "Missing rack session default option #{option} in request.session_options") end - test "test_rack_default_session_options_#{option}_exists_in_session_options" do - assert(@request.session_options.has_key?(option), + + test "rack default session options #{option} exists in session options" do + assert(@request.session_options.has_key?(option), "Missing rack session option #{option} in request.session_options") end end - + def test_session_id_exists_by_default assert_not_nil(@request.session_options[:id]) end - + def test_session_id_different_on_each_call - prev_id = + prev_id = assert_not_equal(@request.session_options[:id], ActionController::TestRequest.new.session_options[:id]) end - + end \ No newline at end of file diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index b9bf8cf411..3090a70244 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -10,8 +10,7 @@ class CookieStoreTest < ActionController::IntegrationTest :key => SessionKey, :secret => SessionSecret) Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1') - - SignedBar = "BAh7BjoIZm9vIghiYXI%3D--fef868465920f415f2c0652d6910d3af288a0367" + SignedBar = Verifier.generate(:foo => "bar", :session_id => ActiveSupport::SecureRandom.hex(16)) class TestController < ActionController::Base def no_session_access diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb index de6539e1cc..0ff93f1c5d 100644 --- a/actionpack/test/dispatch/session/test_session_test.rb +++ b/actionpack/test/dispatch/session/test_session_test.rb @@ -2,37 +2,30 @@ require 'abstract_unit' require 'stringio' class ActionController::TestSessionTest < ActiveSupport::TestCase - def test_calling_delete_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session assert_deprecated(/use clear instead/){ ActionController::TestSession.new.delete } end - + def test_calling_update_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session assert_deprecated(/use replace instead/){ ActionController::TestSession.new.update } end - + def test_calling_close_raises_deprecation_warning assert_deprecated(/sessions should no longer be closed/){ ActionController::TestSession.new.close } end - - def test_defaults - session = ActionController::TestSession.new - assert_equal({}, session.data) - assert_equal('', session.session_id) - end - + def test_ctor_allows_setting session = ActionController::TestSession.new({:one => 'one', :two => 'two'}) assert_equal('one', session[:one]) assert_equal('two', session[:two]) end - + def test_setting_session_item_sets_item session = ActionController::TestSession.new session[:key] = 'value' assert_equal('value', session[:key]) end - + def test_calling_delete_removes_item session = ActionController::TestSession.new session[:key] = 'value' @@ -40,13 +33,13 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase session.delete(:key) assert_nil(session[:key]) end - + def test_calling_update_with_params_passes_to_attributes session = ActionController::TestSession.new() session.update('key' => 'value') assert_equal('value', session[:key]) end - + def test_clear_emptys_session params = {:one => 'one', :two => 'two'} session = ActionController::TestSession.new({:one => 'one', :two => 'two'}) @@ -54,5 +47,4 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase assert_nil(session[:one]) assert_nil(session[:two]) end - -end \ No newline at end of file +end -- cgit v1.2.3 From be7e21a85c487b6f3bfc2e393387ada5cc52290d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 15:05:50 -0700 Subject: Qualify toplevel constant references since we're in a BasicObject --- actionpack/lib/action_view/helpers/prototype_helper.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index fb8122af35..868c8226c4 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -686,7 +686,7 @@ module ActionView # Returns an object whose to_json evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) - ActiveSupport::JSON::Variable.new(code.to_s) + ::ActiveSupport::JSON::Variable.new(code.to_s) end # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be @@ -973,7 +973,7 @@ module ActionView def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{ActiveSupport::JSON.encode(ids.first)})") + "#{method}(#{::ActiveSupport::JSON.encode(ids.first)})") end def page @@ -997,7 +997,7 @@ module ActionView end def javascript_object_for(object) - ActiveSupport::JSON.encode(object) + ::ActiveSupport::JSON.encode(object) end def arguments_for_call(arguments, block = nil) @@ -1139,7 +1139,7 @@ module ActionView class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id - super(generator, "$(#{ActiveSupport::JSON.encode(id)})") + super(generator, "$(#{::ActiveSupport::JSON.encode(id)})") end # Allows access of element attributes through +attribute+. Examples: @@ -1213,7 +1213,7 @@ module ActionView enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block else add_variable_assignment!(variable) - append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});") + append_enumerable_function!("eachSlice(#{::ActiveSupport::JSON.encode(number)});") end end @@ -1234,7 +1234,7 @@ module ActionView def pluck(variable, property) add_variable_assignment!(variable) - append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});") + append_enumerable_function!("pluck(#{::ActiveSupport::JSON.encode(property)});") end def zip(variable, *arguments, &block) @@ -1298,7 +1298,7 @@ module ActionView class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) - super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})") + super(generator, "$$(#{::ActiveSupport::JSON.encode(pattern)})") end end end -- cgit v1.2.3 From 8d64085138b1a2ff36b94267d0236868b287610e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 15:18:33 -0700 Subject: Only Object to_json alias is needed. Prefer nil options. --- actionpack/lib/action_view/helpers/prototype_helper.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 868c8226c4..9cafd17004 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1188,8 +1188,6 @@ module ActionView @variable end - alias to_json rails_to_json - private def append_to_function_chain!(call) @generator << @variable if @empty -- cgit v1.2.3 From c9d9bd7227b687f2162bd485b891aa2c2499adf0 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 16:04:11 -0700 Subject: Check for to_str rather than String --- actionpack/lib/action_dispatch/http/response.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 77c2dd0d7a..c2add1272e 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -98,7 +98,7 @@ module ActionDispatch # :nodoc: def body=(body) @body = - if body.is_a?(String) + if body.respond_to?(:to_str) [body] else body @@ -215,8 +215,6 @@ module ActionDispatch # :nodoc: if @body.respond_to?(:call) @writer = lambda { |x| callback.call(x) } @body.call(self, self) - elsif @body.is_a?(String) - callback.call(@body) else @body.each(&callback) end -- cgit v1.2.3 From 3f632027819ab331187ca58c014458dfcfd57a89 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 16:04:29 -0700 Subject: Don't assume :params is a Hash --- actionpack/lib/action_dispatch/test/mock.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/test/mock.rb b/actionpack/lib/action_dispatch/test/mock.rb index 86269fad01..8dc048af11 100644 --- a/actionpack/lib/action_dispatch/test/mock.rb +++ b/actionpack/lib/action_dispatch/test/mock.rb @@ -21,10 +21,7 @@ module ActionDispatch if method == "POST" && !opts.has_key?(:input) opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - multipart = (opts[:params] || {}).any? do |k, v| - UploadedFile === v - end - + multipart = opts[:params].respond_to?(:any?) && opts[:params].any? { |k, v| UploadedFile === v } if multipart opts[:input] = multipart_body(opts.delete(:params)) opts["CONTENT_LENGTH"] ||= opts[:input].length.to_s -- cgit v1.2.3 From f7d7dc5aa8a5facc357ed291819db23e3f3df9b6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 17:19:14 -0700 Subject: Use session= writer methods --- actionpack/lib/action_controller/testing/process.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 16275371ad..c532a67e78 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -14,8 +14,8 @@ module ActionController #:nodoc: super(Rack::MockRequest.env_for("/").merge(env)) @query_parameters = {} - @env['rack.session'] = TestSession.new - @env['rack.session.options'] = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) + self.session = TestSession.new + self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) initialize_default_values initialize_containers -- cgit v1.2.3 From 1850aea7fc9a1353de8e87adadf5230269b358c1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 18:26:06 -0700 Subject: Not sure why Request#session is missing --- actionpack/lib/action_dispatch/http/request.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 2602b344ca..0b8909ced7 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -451,6 +451,14 @@ EOM @env['rack.input'] end + def session + @env['rack.session'] + end + + def session_options + @env['rack.session.options'] + end + def reset_session self.session_options.delete(:id) self.session = {} -- cgit v1.2.3 From f5b4a9d02bc2292bae59e7b4fc028cce6edb91f7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 18:27:41 -0700 Subject: Array splitting strings on newlines is deprecated --- actionpack/lib/action_dispatch/http/response.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index c2add1272e..6c92fb9713 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -245,9 +245,14 @@ module ActionDispatch # :nodoc: # assert_equal 'AuthorOfNewPage', r.cookies['author'] def cookies cookies = {} - Array(headers['Set-Cookie']).each do |cookie| - key, value = cookie.split(";").first.split("=").map { |v| Rack::Utils.unescape(v) } - cookies[key] = value + if header = headers['Set-Cookie'] + header = header.split("\n") if header.respond_to?(:to_str) + header.each do |cookie| + if pair = cookie.split(';').first + key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) } + cookies[key] = value + end + end end cookies end @@ -305,7 +310,13 @@ module ActionDispatch # :nodoc: end def convert_cookies! - headers['Set-Cookie'] = Array(headers['Set-Cookie']).compact + headers['Set-Cookie'] = + if header = headers['Set-Cookie'] + header = header.split("\n") if header.respond_to?(:to_str) + header.compact + else + [] + end end end end -- cgit v1.2.3 From 5cef0cbad2d1df013c74ab96c16cf7fd84040f46 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 19:08:04 -0700 Subject: Check for to_str rather than String --- actionpack/lib/action_controller/base/render.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 33695cd78e..601c5429c3 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -254,7 +254,7 @@ module ActionController render_for_text(js) elsif json = options[:json] - json = ActiveSupport::JSON.encode(json) unless json.is_a?(String) + json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? response.content_type ||= Mime::JSON render_for_text(json) -- cgit v1.2.3 From 678385d307559b2b5737bb2b07f633d2b9a0802c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 19:59:22 -0700 Subject: Use javascript_object_for --- actionpack/lib/action_view/helpers/prototype_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 9cafd17004..a44c144d53 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -973,7 +973,7 @@ module ActionView def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{::ActiveSupport::JSON.encode(ids.first)})") + "#{method}(#{javascript_object_for(ids.first)})") end def page -- cgit v1.2.3 From ee46ffedb88f812467485167036c7d254d0ce757 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 20:04:47 -0700 Subject: Now that we have a separate internal rails_to_json, use a separate circular reference stack instead of sticking it in the options hash --- actionpack/lib/action_view/helpers/prototype_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index a44c144d53..1fbe012a95 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1180,11 +1180,11 @@ module ActionView # The JSON Encoder calls this to check for the +to_json+ method # Since it's a blank slate object, I suppose it responds to anything. - def respond_to?(method) + def respond_to?(*) true end - def rails_to_json(options = nil) + def rails_to_json(*) @variable end -- cgit v1.2.3 From e44cd416208241cd96f75574d6c454fc2101e789 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 26 Apr 2009 23:59:17 -0700 Subject: Make it clearer that session is nil --- actionpack/test/activerecord/active_record_store_test.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 34f18806a2..663cd259c8 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -13,6 +13,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end def set_session_value + raise "missing session!" unless session session[:foo] = params[:foo] || "bar" head :ok end -- cgit v1.2.3 From a88ddf8cc327279258cd68b0ad4091a5d54e3507 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 27 Apr 2009 00:00:03 -0700 Subject: Don't return bare string as rack body --- actionpack/lib/action_dispatch/middleware/failsafe.rb | 4 ++-- actionpack/test/controller/dispatcher_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb index 5e0c479fdd..836098482c 100644 --- a/actionpack/lib/action_dispatch/middleware/failsafe.rb +++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb @@ -29,9 +29,9 @@ module ActionDispatch def failsafe_response_body error_path = "#{self.class.error_file_path}/500.html" if File.exist?(error_path) - File.read(error_path) + [File.read(error_path)] else - "

500 Internal Server Error

" + ["

500 Internal Server Error

"] end end diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb index 569d698a03..c3bd113b86 100644 --- a/actionpack/test/controller/dispatcher_test.rb +++ b/actionpack/test/controller/dispatcher_test.rb @@ -53,7 +53,7 @@ class DispatcherTest < Test::Unit::TestCase assert_equal [ 500, {"Content-Type" => "text/html"}, - "

500 Internal Server Error

" + ["

500 Internal Server Error

"] ], dispatch end end -- cgit v1.2.3 From c2b4da1c425dd8e1cc6606d49aea53e4f7521b91 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 27 Apr 2009 00:17:02 -0700 Subject: Sufficient to test that multipart/mixed wasn't parsed to a hash --- actionpack/test/dispatch/request/multipart_params_parsing_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index cc81a87cb9..aaf647e45a 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -96,7 +96,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest # Ruby CGI doesn't handle multipart/mixed for us. files = params['files'] - assert_kind_of Tempfile, files + assert_not_kind_of Hash, files files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) assert_equal 19756, files.size end -- cgit v1.2.3 From dde063507ac40fda1a67f06a54c1a57d237f57b2 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 27 Apr 2009 09:29:01 -0700 Subject: Can't please them all --- actionpack/test/dispatch/request/multipart_params_parsing_test.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index aaf647e45a..9e008a9ae8 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -94,9 +94,8 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest assert_equal %w(files foo), params.keys.sort assert_equal 'bar', params['foo'] - # Ruby CGI doesn't handle multipart/mixed for us. + # Rack doesn't handle multipart/mixed for us. files = params['files'] - assert_not_kind_of Hash, files files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) assert_equal 19756, files.size end -- cgit v1.2.3 From 21aa32692caf91f56d1c5c411baae635fa398344 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 27 Apr 2009 13:11:17 -0500 Subject: Delegate controller.session to request.session and deprecate response session --- actionpack/lib/action_controller/base/base.rb | 14 +++++--------- actionpack/lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch/http/request.rb | 8 -------- actionpack/lib/action_dispatch/http/response.rb | 6 +++++- actionpack/test/controller/test_test.rb | 6 ------ 5 files changed, 11 insertions(+), 25 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index afb9fb71cb..1d0738588d 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -238,7 +238,7 @@ module ActionController #:nodoc: cattr_reader :protected_instance_variables # Controller specific instance variables which will not be accessible inside views. @@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller - @action_name @before_filter_chain_aborted @action_cache_path @_session @_headers @_params + @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params @_flash @_response) # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets, @@ -356,7 +356,9 @@ module ActionController #:nodoc: # Holds a hash of objects in the session. Accessed like session[:person] to get the object tied to the "person" # key. The session will hold any type of object as values, but the key should be a string or symbol. - attr_internal :session + def session + request.session + end # Holds a hash of header names and values. Accessed like headers["Cache-Control"] to get the value of the Cache-Control # directive. Values should always be specified as strings. @@ -787,7 +789,6 @@ module ActionController #:nodoc: # Resets the session by clearing out all the objects stored within and initializing a new session object. def reset_session #:doc: request.reset_session - @_session = request.session end private @@ -812,7 +813,7 @@ module ActionController #:nodoc: def assign_shortcuts(request, response) @_request, @_response, @_params = request, response, request.parameters - @_session, @_headers = @_request.session, @_response.headers + @_headers = @_response.headers end def initialize_current_url @@ -888,10 +889,6 @@ module ActionController #:nodoc: "#{request.protocol}#{request.host}#{request.request_uri}" end - def close_session - # @_session.close if @_session && @_session.respond_to?(:close) - end - def default_template(action_name = self.action_name) self.view_paths.find_template(default_template_name(action_name), default_template_format) end @@ -915,7 +912,6 @@ module ActionController #:nodoc: end def process_cleanup - close_session end end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index c532a67e78..d073d06b19 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -165,7 +165,7 @@ module ActionController #:nodoc: # A shortcut to the flash. Returns an empty hash if no session flash exists. def flash - session['flash'] || {} + request.session['flash'] || {} end # Do we have a flash? diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 0b8909ced7..2602b344ca 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -451,14 +451,6 @@ EOM @env['rack.input'] end - def session - @env['rack.session'] - end - - def session_options - @env['rack.session.options'] - end - def reset_session self.session_options.delete(:id) self.session = {} diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 6c92fb9713..ebba4eefa0 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -40,7 +40,11 @@ module ActionDispatch # :nodoc: attr_writer :header alias_method :headers=, :header= - delegate :session, :to => :request + def session + ActiveSupport::Deprecation.warn("response.session has been deprecated. Use request.session instead", caller) + request.session + end + delegate :default_charset, :to => 'ActionController::Base' def initialize diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 124e259ef6..f68ffc7a2a 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -184,12 +184,6 @@ XML assert_equal Hash.new, @controller.session.to_hash end - def test_session_is_cleared_from_response_after_reset_session - process :set_session - process :reset_the_session - assert_equal Hash.new, @response.session.to_hash - end - def test_session_is_cleared_from_request_after_reset_session process :set_session process :reset_the_session -- cgit v1.2.3 From cecafc52ee0a4a53c903ddbaba95683261f88e5f Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 23 Apr 2009 15:58:38 -0700 Subject: Refactor ActionView::Template ActionView::Template is now completely independent from template storage, which allows different back ends such as the database. ActionView::Template's only responsibility is to take in the template source (passed in from ActionView::Path), compile it, and render it. --- actionpack/lib/action_controller/base/base.rb | 20 +- actionpack/lib/action_controller/base/render.rb | 7 +- .../testing/assertions/response.rb | 10 +- actionpack/lib/action_view/base.rb | 4 +- actionpack/lib/action_view/paths.rb | 12 +- actionpack/lib/action_view/render/rendering.rb | 13 +- actionpack/lib/action_view/template/error.rb | 4 +- actionpack/lib/action_view/template/handlers.rb | 2 +- actionpack/lib/action_view/template/path.rb | 68 +++-- actionpack/lib/action_view/template/template.rb | 336 ++++++++++++--------- actionpack/lib/action_view/test_case.rb | 7 +- .../abstract_controller_test.rb | 2 +- actionpack/test/controller/helper_test.rb | 2 +- actionpack/test/controller/layout_test.rb | 24 +- actionpack/test/controller/render_test.rb | 6 +- actionpack/test/controller/view_paths_test.rb | 49 +-- actionpack/test/fixtures/layouts/standard.erb | 1 - actionpack/test/fixtures/layouts/standard.html.erb | 1 + .../test/render_file_with_locals_and_default.erb | 1 + .../test/template/compiled_templates_test.rb | 36 +-- actionpack/test/template/render_test.rb | 14 +- 21 files changed, 338 insertions(+), 281 deletions(-) delete mode 100644 actionpack/test/fixtures/layouts/standard.erb create mode 100644 actionpack/test/fixtures/layouts/standard.html.erb create mode 100644 actionpack/test/fixtures/test/render_file_with_locals_and_default.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 1d0738588d..2063df54b4 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -494,8 +494,18 @@ module ActionController #:nodoc: end protected :filter_parameters end + + @@exempt_from_layout = [ActionView::TemplateHandlers::RJS] + + def exempt_from_layout(*types) + types.each do |type| + @@exempt_from_layout << + ActionView::Template.handler_class_for_extension(type) + end + + @@exempt_from_layout + end - delegate :exempt_from_layout, :to => 'ActionView::Template' end public @@ -856,13 +866,13 @@ module ActionController #:nodoc: return (performed? ? ret : default_render) if called begin - default_render - rescue ActionView::MissingTemplate => e - raise e unless e.action_name == action_name - # If the path is the same as the action_name, the action is completely missing + view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path) + rescue => e raise UnknownAction, "No action responded to #{action_name}. Actions: " + "#{action_methods.sort.to_sentence}", caller end + + default_render end # Returns true if a render or redirect has already been performed. diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 601c5429c3..4286577ec5 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -378,13 +378,14 @@ module ActionController # ==== Arguments # parts:: # Example: ["show", [:html, :xml], "users", false] - def render_for_parts(parts, layout, options = {}) + def render_for_parts(parts, layout_details, options = {}) parts[1] = {:formats => parts[1], :locales => [I18n.locale]} tmp = view_paths.find_by_parts(*parts) - layout = _pick_layout(*layout) unless tmp.exempt_from_layout? - + layout = _pick_layout(*layout_details) unless + self.class.exempt_from_layout.include?(tmp.handler) + render_for_text( @template._render_template_with_layout(tmp, layout, options, parts[3])) end diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index c57cbecc44..574b8d6825 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -98,22 +98,22 @@ module ActionController clean_backtrace do case options when NilClass, String - rendered = @controller.response.rendered[:template].to_s + rendered = (@controller.response.rendered[:template] || []).map { |t| t.identifier } msg = build_message(message, "expecting but rendering with ", - options, rendered) + options, rendered.join(', ')) assert_block(msg) do if options.nil? @controller.response.rendered[:template].blank? else - rendered.to_s.match(options) + rendered.any? { |t| t.match(options) } end end when Hash if expected_partial = options[:partial] partials = @controller.response.rendered[:partials] if expected_count = options[:count] - found = partials.detect { |p, _| p.to_s.match(expected_partial) } + found = partials.detect { |p, _| p.identifier.match(expected_partial) } actual_count = found.nil? ? 0 : found.second msg = build_message(message, "expecting ? to be rendered ? time(s) but rendered ? time(s)", @@ -123,7 +123,7 @@ module ActionController msg = build_message(message, "expecting partial but action rendered ", options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.to_s.match(expected_partial) }, msg) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) end else assert @controller.response.rendered[:partials].empty?, diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index efed19a21d..d087395361 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -196,7 +196,9 @@ module ActionView #:nodoc: delegate :controller_path, :to => :controller, :allow_nil => true delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :action_name, :controller_name, :to => :controller + :flash, :action_name, :controller_name, :to => :controller + + delegate :logger, :to => :controller, :allow_nil => true delegate :find_by_parts, :to => :view_paths diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index e48088f344..f6d021c92a 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -3,7 +3,7 @@ module ActionView #:nodoc: def self.type_cast(obj) if obj.is_a?(String) cache = !Object.const_defined?(:Rails) || Rails.configuration.cache_classes - Template::FileSystemPath.new(obj, :cache => cache) + Template::FileSystemPathWithFallback.new(obj, :cache => cache) else obj end @@ -34,18 +34,18 @@ module ActionView #:nodoc: end def find_by_parts(path, details = {}, prefix = nil, partial = false) - template_path = path.sub(/^\//, '') + # template_path = path.sub(/^\//, '') + template_path = path each do |load_path| if template = load_path.find_by_parts(template_path, details, prefix, partial) return template end end - - Template.new(path, self) - rescue ActionView::MissingTemplate => e + + # TODO: Have a fallback absolute path? extension = details[:formats] || [] - raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}") + raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}") end def find_by_parts?(path, extension = nil, prefix = nil, partial = false) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 4213b09e48..f174053b86 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -46,8 +46,8 @@ module ActionView locals ||= {} if controller && layout - response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response) - logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger + response.layout = layout.identifier if controller.respond_to?(:response) + logger.info("Rendering template within #{layout.identifier}") if logger end begin @@ -76,7 +76,6 @@ module ActionView end end rescue Exception => e - raise e if template.is_a?(InlineTemplate) || !template.filename if TemplateError === e e.sub_template_of(template) raise e @@ -86,7 +85,9 @@ module ActionView end def _render_inline(inline, layout, options) - content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {}) + handler = Template.handler_class_for_extension(options[:type] || "erb") + template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) + content = _render_template(template, options[:locals] || {}) layout ? _render_content_with_layout(content, layout, options[:locals]) : content end @@ -96,7 +97,7 @@ module ActionView def _render_template_with_layout(template, layout = nil, options = {}, partial = false) if controller && logger - logger.info("Rendering #{template.path_without_extension}" + + logger.info("Rendering #{template.identifier}" + (options[:status] ? " (#{options[:status]})" : '')) end @@ -107,7 +108,7 @@ module ActionView _render_template(template, options[:locals] || {}) end - return content unless layout && !template.exempt_from_layout? + return content unless layout _render_content_with_layout(content, layout, options[:locals] || {}) end end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 37cb1c7c6c..a06e80b294 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -12,7 +12,7 @@ module ActionView end def file_name - @template.relative_path + @template.identifier end def message @@ -30,7 +30,7 @@ module ActionView def sub_template_message if @sub_templates "Trace of template inclusion: " + - @sub_templates.collect { |template| template.relative_path }.join(", ") + @sub_templates.collect { |template| template.identifier }.join(", ") else "" end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 448ab6731b..0590372d09 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -46,7 +46,7 @@ module ActionView #:nodoc: end def handler_class_for_extension(extension) - registered_template_handler(extension) || @@default_template_handlers + (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers end end end diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb index 660a7e91a2..478bf96c9a 100644 --- a/actionpack/lib/action_view/template/path.rb +++ b/actionpack/lib/action_view/template/path.rb @@ -1,3 +1,5 @@ +require "pathname" + module ActionView class Template # Abstract super class @@ -26,13 +28,6 @@ module ActionView def find_templates(name, details, prefix, partial) raise NotImplementedError end - - # TODO: Refactor this to abstract out the file system - def initialize_template(file) - t = Template.new(file.split("#{self}/").last, self) - t.load! - t - end def valid_handlers @valid_handlers ||= TemplateHandlers.extensions @@ -44,10 +39,10 @@ module ActionView /\.(?:#{e})$/ end end - + def handler_glob - e = TemplateHandlers.extensions.join(',') - ".{#{e}}" + e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + "{#{e}}" end def formats_glob @@ -69,23 +64,19 @@ module ActionView def initialize(path, options = {}) raise ArgumentError, "path already is a Path class" if path.is_a?(Path) super(options) - @path = path + @path = Pathname.new(path).expand_path end - + # TODO: This is the currently needed API. Make this suck less # ==== attr_reader :path def to_s - if defined?(RAILS_ROOT) - path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') - else - path.to_s - end + path.to_s end def to_str - path.to_str + path.to_s end def ==(path) @@ -97,11 +88,15 @@ module ActionView end # ==== - def find_templates(name, details, prefix, partial) - if glob = parts_to_glob(name, details, prefix, partial) + def find_templates(name, details, prefix, partial, root = "#{@path}/") + if glob = details_to_glob(name, details, prefix, partial, root) cached(glob) do Dir[glob].map do |path| - initialize_template(path) unless File.directory?(path) + next if File.directory?(path) + source = File.read(path) + identifier = Pathname.new(path).expand_path.to_s + + Template.new(source, identifier, *path_to_details(path)) end.compact end end @@ -109,7 +104,8 @@ module ActionView private - def parts_to_glob(name, details, prefix, partial) + # :api: plugin + def details_to_glob(name, details, prefix, partial, root) path = "" path << "#{prefix}/" unless prefix.empty? path << (partial ? "_#{name}" : name) @@ -123,8 +119,34 @@ module ActionView end end - "#{@path}/#{path}#{extensions}#{handler_glob}" + "#{root}#{path}#{extensions}#{handler_glob}" + end + + # TODO: fix me + # :api: plugin + def path_to_details(path) + # [:erb, :format => :html, :locale => :en, :partial => true/false] + if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$') + partial = m[1] == '_' + details = (m[2]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[3]) + + format = Mime[details.last] && details.pop.to_sym + locale = details.last && details.pop.to_sym + + return handler, :format => format, :locale => locale, :partial => partial + end end end + + class FileSystemPathWithFallback < FileSystemPath + + def find_templates(name, details, prefix, partial) + templates = super + return super(name, details, prefix, partial, '') if templates.empty? + templates + end + + end end end \ No newline at end of file diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index e541336613..ce6268729a 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -1,188 +1,230 @@ +# encoding: utf-8 +# This is so that templates compiled in this file are UTF-8 + require 'set' require "action_view/template/path" -module ActionView #:nodoc: +module ActionView class Template extend TemplateHandlers - extend ActiveSupport::Memoizable + attr_reader :source, :identifier, :handler - module Loading - def load! - @cached = true - # freeze - end + def initialize(source, identifier, handler, details) + @source = source + @identifier = identifier + @handler = handler + @details = details end - include Loading - include Renderable - - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - - # Don't render layouts for templates with the given extensions. - def self.exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge(regexps) + def render(view, locals, &blk) + method_name = compile(locals, view) + view.send(method_name, locals, &blk) + end + + # TODO: Figure out how to abstract this + def variable_name + identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym end - attr_accessor :template_path, :filename, :load_path, :base_path - attr_accessor :locale, :name, :format, :extension - delegate :to_s, :to => :path + # TODO: Figure out how to abstract this + def counter_name + "#{variable_name}_counter".to_sym + end + + # TODO: kill hax + def partial? + @details[:partial] + end + + # TODO: Move out of Template + def mime_type + Mime::Type.lookup_by_extension(@details[:format]) if @details[:format] + end + + private - def initialize(template_path, load_paths = []) - template_path = template_path.dup - @load_path, @filename = find_full_path(template_path, load_paths) - @base_path, @name, @locale, @format, @extension = split(template_path) - @base_path.to_s.gsub!(/\/$/, '') # Push to split method + def compile(locals, view) + method_name = build_method_name(locals) + + return method_name if view.respond_to?(method_name) + + locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + + source = <<-end_src + def #{method_name}(local_assigns) + old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)} + ensure + self.output_buffer = old_output_buffer + end + end_src + + begin + ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0) + method_name + rescue Exception => e # errors from template code + if logger = (view && view.logger) + logger.debug "ERROR: compiling #{method_name} RAISED #{e}" + logger.debug "Function body: #{source}" + logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end - # Extend with partial super powers - extend RenderablePartial if @name =~ /^_/ + raise ActionView::TemplateError.new(self, {}, e) + end + end + + def build_method_name(locals) + # TODO: is locals.keys.hash reliably the same? + "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end + end +end + +if false + module ActionView #:nodoc: + class Template + extend TemplateHandlers + extend ActiveSupport::Memoizable - def accessible_paths - paths = [] + module Loading + def load! + @cached = true + # freeze + end + end + include Loading + + include Renderable - if valid_extension?(extension) - paths << path - paths << path_without_extension - if multipart? - formats = format.split(".") - paths << "#{path_without_format_and_extension}.#{formats.first}" - paths << "#{path_without_format_and_extension}.#{formats.second}" + # Templates that are exempt from layouts + @@exempt_from_layout = Set.new([/\.rjs$/]) + + # Don't render layouts for templates with the given extensions. + def self.exempt_from_layout(*extensions) + regexps = extensions.collect do |extension| + extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ end - else - # template without explicit template handler should only be reachable through its exact path - paths << template_path + @@exempt_from_layout.merge(regexps) end - paths - end + attr_accessor :template_path, :filename, :load_path, :base_path + attr_accessor :locale, :name, :format, :extension + delegate :to_s, :to => :path + + def initialize(template_path, load_paths = []) + template_path = template_path.dup + @load_path, @filename = find_full_path(template_path, load_paths) + @name = template_path.to_s.split("/").last.split(".").first + # @base_path, @name, @locale, @format, @extension = split(template_path) + @base_path.to_s.gsub!(/\/$/, '') # Push to split method + + # Extend with partial super powers + extend RenderablePartial if @name =~ /^_/ + end - def relative_path - path = File.expand_path(filename) - path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) - path - end - memoize :relative_path + def accessible_paths + paths = [] + + if valid_extension?(extension) + paths << path + paths << path_without_extension + if multipart? + formats = format.split(".") + paths << "#{path_without_format_and_extension}.#{formats.first}" + paths << "#{path_without_format_and_extension}.#{formats.second}" + end + else + # template without explicit template handler should only be reachable through its exact path + paths << template_path + end + + paths + end - def source - File.read(filename) - end - memoize :source + def relative_path + path = File.expand_path(filename) + path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) + path + end + memoize :relative_path - def exempt_from_layout? - @@exempt_from_layout.any? { |exempted| path =~ exempted } - end + def source + File.read(filename) + end + memoize :source - def path_without_extension - [base_path, [name, locale, format].compact.join('.')].compact.join('/') - end - memoize :path_without_extension + def exempt_from_layout? + @@exempt_from_layout.any? { |exempted| path =~ exempted } + end + + def path_without_extension + [base_path, [name, locale, format].compact.join('.')].compact.join('/') + end + memoize :path_without_extension - def path_without_format_and_extension - [base_path, [name, locale].compact.join('.')].compact.join('/') - end - memoize :path_without_format_and_extension + def path_without_format_and_extension + [base_path, [name, locale].compact.join('.')].compact.join('/') + end + memoize :path_without_format_and_extension - def path - [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') - end - memoize :path + def path + [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') + end + memoize :path - def mime_type - Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) - end - memoize :mime_type + def mime_type + Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) + end + memoize :mime_type - def multipart? - format && format.include?('.') - end + def multipart? + format && format.include?('.') + end - def content_type - format && format.gsub('.', '/') - end + def content_type + format && format.gsub('.', '/') + end - private + private - def format_and_extension - (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions - end - memoize :format_and_extension - - def mtime - File.mtime(filename) - end - memoize :mtime + def format_and_extension + (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions + end + memoize :format_and_extension - def method_segment - relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } - end - memoize :method_segment + def mtime + File.mtime(filename) + end + memoize :mtime - def stale? - File.mtime(filename) > mtime - end + def method_segment + relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } + end + memoize :method_segment - def recompile? - !@cached - end + def stale? + File.mtime(filename) > mtime + end - def valid_extension?(extension) - !Template.registered_template_handler(extension).nil? - end + def recompile? + !@cached + end - def valid_locale?(locale) - I18n.available_locales.include?(locale.to_sym) - end + def valid_extension?(extension) + !Template.registered_template_handler(extension).nil? + end - def find_full_path(path, load_paths) - load_paths = Array(load_paths) + [nil] - load_paths.each do |load_path| - file = load_path ? "#{load_path.to_str}/#{path}" : path - return load_path, file if File.file?(file) + def valid_locale?(locale) + I18n.available_locales.include?(locale.to_sym) end - raise MissingTemplate.new(load_paths, path) - end - # Returns file split into an array - # [base_path, name, locale, format, extension] - def split(file) - if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/) - base_path = m[1] - name = m[2] - extensions = m[3] - else - return - end - - locale = nil - format = nil - extension = nil - - if m = extensions.split(".") - if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three - locale = m[0] - format = m[1] - extension = m[2] - elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats - format = "#{m[0]}.#{m[1]}" - extension = m[2] - elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension - locale = m[0] - extension = m[1] - elsif valid_extension?(m[1]) # format and extension - format = m[0] - extension = m[1] - elsif valid_extension?(m[0]) # Just extension - extension = m[0] - else # No extension - format = m[0] + def find_full_path(path, load_paths) + load_paths = Array(load_paths) + [nil] + load_paths.each do |load_path| + file = load_path ? "#{load_path.to_str}/#{path}" : path + return load_path, file if File.file?(file) end + raise MissingTemplate.new(load_paths, path) end - - [base_path, name, locale, format, extension] end end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index c8f204046b..dddd671812 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -10,9 +10,10 @@ module ActionView alias_method :_render_template_without_template_tracking, :_render_template def _render_template(template, local_assigns = {}) - if template.respond_to?(:path) && !template.is_a?(InlineTemplate) - @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial) - @_rendered[:template] ||= template + if template.respond_to?(:identifier) + @_rendered[:partials][template] += 1 if template.partial? + @_rendered[:template] ||= [] + @_rendered[:template] << template end _render_template_without_template_tracking(template, local_assigns) end diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index f1dcb39ef1..331797afcf 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -139,7 +139,7 @@ module AbstractController private def self.layout(formats) begin - view_paths.find_by_parts(name.underscore, {:formats => formats}t, "layouts") + view_paths.find_by_parts(name.underscore, {:formats => formats}, "layouts") rescue ActionView::MissingTemplate begin view_paths.find_by_parts("application", {:formats => formats}, "layouts") diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 5f36461b89..58addc123d 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -211,7 +211,7 @@ class IsolatedHelpersTest < Test::Unit::TestCase end def test_helper_in_a - assert_raise(NameError) { A.process(@request, @response) } + assert_raise(ActionView::TemplateError) { A.process(@request, @response) } end def test_helper_in_b diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index f2721e274d..11559b4071 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -56,8 +56,8 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase def test_third_party_template_library_auto_discovers_layout @controller = ThirdPartyTemplateLibraryController.new get :hello - assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout(true).to_s - assert_equal 'layouts/third_party_template_library', @response.layout + assert @controller.active_layout(true).identifier.include?('layouts/third_party_template_library.mab') + assert @response.layout.include?('layouts/third_party_template_library') assert_response :success assert_equal 'Mab', @response.body end @@ -72,7 +72,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase def test_namespaced_controllers_auto_detect_layouts @controller = MultipleExtensions.new get :hello - assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout(true).to_s + 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 @@ -116,22 +116,24 @@ class RendersNoLayoutController < LayoutTest end class LayoutSetInResponseTest < ActionController::TestCase + include ActionView::TemplateHandlers + def test_layout_set_when_using_default_layout @controller = DefaultLayoutController.new get :hello - assert_equal 'layouts/layout_test', @response.layout + assert @response.layout.include?('layouts/layout_test') end def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_only_exception_when_included @controller = OnlyLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_only_exception_when_excepted @@ -143,7 +145,7 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_except_exception_when_included @controller = ExceptLayoutController.new get :hello - assert_equal 'layouts/item', @response.layout + assert @response.layout.include?('layouts/item') end def test_layout_except_exception_when_excepted @@ -155,7 +157,7 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_render @controller = SetsLayoutInRenderController.new get :hello - assert_equal 'layouts/third_party_template_library', @response.layout + assert @response.layout.include?('layouts/third_party_template_library') end def test_layout_is_not_set_when_none_rendered @@ -165,14 +167,14 @@ class LayoutSetInResponseTest < ActionController::TestCase end def test_exempt_from_layout_honored_by_render_template - ActionController::Base.exempt_from_layout :rhtml + ActionController::Base.exempt_from_layout :erb @controller = RenderWithTemplateOptionController.new get :hello assert_equal "alt/hello.rhtml", @response.body.strip ensure - ActionController::Base.exempt_from_layout.delete(/\.rhtml$/) + ActionController::Base.exempt_from_layout.delete(ERB) end def test_layout_is_picked_from_the_controller_instances_view_path @@ -232,7 +234,7 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/ @controller = LayoutSymlinkedTest.new get :hello assert_response 200 - assert_equal "layouts/symlinked/symlinked_layout", @response.layout + assert @response.layout.include?("layouts/symlinked/symlinked_layout") end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index af7236ed26..da063710a9 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -773,7 +773,7 @@ class RenderTest < ActionController::TestCase begin get :render_line_offset flunk "the action should have raised an exception" - rescue RuntimeError => exc + rescue StandardError => exc line = exc.backtrace.first assert(line =~ %r{:(\d+):}) assert_equal "1", $1, @@ -1736,7 +1736,7 @@ class RenderingLoggingTest < ActionController::TestCase @controller.logger = MockLogger.new get :layout_test logged = @controller.logger.logged.find_all {|l| l =~ /render/i } - assert_equal "Rendering test/hello_world", logged[0] - assert_equal "Rendering template within layouts/standard", logged[1] + assert logged[0] =~ %r{Rendering.*test/hello_world} + assert logged[1] =~ %r{Rendering template within.*layouts/standard} end end diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index 1539f8f506..0ac10634b2 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -20,7 +20,7 @@ class ViewLoadPathsTest < ActionController::TestCase layout 'test/sub' def hello_world; render(:template => 'test/hello_world'); end end - + def setup TestController.view_paths = nil @@ -42,30 +42,39 @@ class ViewLoadPathsTest < ActionController::TestCase ActiveSupport::Deprecation.behavior = @old_behavior end + def expand(array) + array.map {|x| File.expand_path(x)} + end + + def assert_paths(*paths) + controller = paths.first.is_a?(Class) ? paths.shift : @controller + assert_equal expand(paths), controller.view_paths.map(&:to_s) + end + def test_template_load_path_was_set_correctly - assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH end def test_controller_appends_view_path_correctly @controller.append_view_path 'foo' - assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s) + assert_paths(FIXTURE_LOAD_PATH, "foo") @controller.append_view_path(%w(bar baz)) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) - + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz") + @controller.append_view_path(FIXTURE_LOAD_PATH) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH) end def test_controller_prepends_view_path_correctly @controller.prepend_view_path 'baz' - assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths("baz", FIXTURE_LOAD_PATH) @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH @controller.prepend_view_path(FIXTURE_LOAD_PATH) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH end def test_template_appends_view_path_correctly @@ -73,11 +82,11 @@ class ViewLoadPathsTest < ActionController::TestCase class_view_paths = TestController.view_paths @controller.append_view_path 'foo' - assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s) + assert_paths FIXTURE_LOAD_PATH, "foo" @controller.append_view_path(%w(bar baz)) - assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s) - assert_equal class_view_paths, TestController.view_paths + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz" + assert_paths TestController, *class_view_paths end def test_template_prepends_view_path_correctly @@ -85,11 +94,11 @@ class ViewLoadPathsTest < ActionController::TestCase class_view_paths = TestController.view_paths @controller.prepend_view_path 'baz' - assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) + assert_paths "baz", FIXTURE_LOAD_PATH @controller.prepend_view_path(%w(foo bar)) - assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s) - assert_equal class_view_paths, TestController.view_paths + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH + assert_paths TestController, *class_view_paths end def test_view_paths @@ -130,12 +139,12 @@ class ViewLoadPathsTest < ActionController::TestCase A.view_paths = ['a/path'] - assert_equal ['a/path'], A.view_paths.map(&:to_s) - assert_equal A.view_paths, B.view_paths - assert_equal original_load_paths, C.view_paths - + assert_paths A, "a/path" + assert_paths A, *B.view_paths + assert_paths C, *original_load_paths + C.view_paths = [] assert_nothing_raised { C.view_paths << 'c/path' } - assert_equal ['c/path'], C.view_paths.map(&:to_s) + assert_paths C, "c/path" end end diff --git a/actionpack/test/fixtures/layouts/standard.erb b/actionpack/test/fixtures/layouts/standard.erb deleted file mode 100644 index 368764e6f4..0000000000 --- a/actionpack/test/fixtures/layouts/standard.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @content_for_layout %><%= @variable_for_layout %> \ No newline at end of file diff --git a/actionpack/test/fixtures/layouts/standard.html.erb b/actionpack/test/fixtures/layouts/standard.html.erb new file mode 100644 index 0000000000..368764e6f4 --- /dev/null +++ b/actionpack/test/fixtures/layouts/standard.html.erb @@ -0,0 +1 @@ +<%= @content_for_layout %><%= @variable_for_layout %> \ No newline at end of file diff --git a/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb b/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb new file mode 100644 index 0000000000..9b4900acc5 --- /dev/null +++ b/actionpack/test/fixtures/test/render_file_with_locals_and_default.erb @@ -0,0 +1 @@ +<%= secret ||= 'one' %> \ No newline at end of file diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index c75e29ed9a..b29b03f99d 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -5,37 +5,13 @@ class CompiledTemplatesTest < Test::Unit::TestCase def setup @compiled_templates = ActionView::Base::CompiledTemplates @compiled_templates.instance_methods.each do |m| - @compiled_templates.send(:remove_method, m) if m =~ /^_run_/ + @compiled_templates.send(:remove_method, m) if m =~ /^_render_template_/ end end - - def test_template_gets_compiled - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - assert_equal 1, @compiled_templates.instance_methods.size - end - + def test_template_gets_recompiled_when_using_different_keys_in_local_assigns - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"}) - assert_equal 2, @compiled_templates.instance_methods.size - end - - def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - ActionView::Template.any_instance.expects(:compile!).never - assert_equal "Hello world!", render(:file => "test/hello_world.erb") - end - - def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached - ActionView::Template.any_instance.expects(:recompile?).times(3).returns(true) - assert_equal 0, @compiled_templates.instance_methods.size - assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") - ActionView::Template.any_instance.expects(:compile!).times(3) - 3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") } - assert_equal 1, @compiled_templates.instance_methods.size + assert_equal "one", render(:file => "test/render_file_with_locals_and_default.erb") + assert_equal "two", render(:file => "test/render_file_with_locals_and_default.erb", :locals => { :secret => "two" }) end def test_template_changes_are_not_reflected_with_cached_templates @@ -61,14 +37,12 @@ class CompiledTemplatesTest < Test::Unit::TestCase def render_with_cache(*args) view_paths = ActionController::Base.view_paths - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end def render_without_cache(*args) - path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH) + path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH) view_paths = ActionView::Base.process_view_paths(path) - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 7191df0dfd..71291f009c 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -91,10 +91,6 @@ module RenderTestCases assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar") end - def test_render_has_access_current_template - assert_equal "test/template.erb", @view.render(:file => "test/template.erb") - end - def test_render_update # TODO: You should not have to stub out template because template is self! @view.instance_variable_set(:@template, @view) @@ -240,10 +236,6 @@ module RenderTestCases end end - def test_template_with_malformed_template_handler_is_reachable_through_its_exact_filename - assert_equal "Don't render me!", @view.render(:file => 'test/malformed/malformed.html.erb~') - end - def test_render_with_layout assert_equal %(\nHello world!\n), @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield") @@ -269,7 +261,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase # Ensure view path cache is primed def setup view_paths = ActionController::Base.view_paths - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class + assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class setup_view(view_paths) end end @@ -280,9 +272,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase # Test the same thing as above, but make sure the view path # is not eager loaded def setup - path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH) + path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH) view_paths = ActionView::Base.process_view_paths(path) - assert_equal ActionView::Template::FileSystemPath, view_paths.first.class + assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class setup_view(view_paths) end end -- cgit v1.2.3 From ab83db9d069dea643eeb3588eeee634a780b6735 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 27 Apr 2009 12:34:25 -0700 Subject: Fixes ActionMailer to work with the ActionView refactoring --- actionpack/lib/action_view/template/template.rb | 152 +----------------------- 1 file changed, 1 insertion(+), 151 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index ce6268729a..dcc5006103 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -38,7 +38,7 @@ module ActionView # TODO: Move out of Template def mime_type - Mime::Type.lookup_by_extension(@details[:format]) if @details[:format] + Mime::Type.lookup_by_extension(@details[:format].to_s) if @details[:format] end private @@ -77,154 +77,4 @@ module ActionView "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end end -end - -if false - module ActionView #:nodoc: - class Template - extend TemplateHandlers - extend ActiveSupport::Memoizable - - module Loading - def load! - @cached = true - # freeze - end - end - include Loading - - include Renderable - - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - - # Don't render layouts for templates with the given extensions. - def self.exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge(regexps) - end - - attr_accessor :template_path, :filename, :load_path, :base_path - attr_accessor :locale, :name, :format, :extension - delegate :to_s, :to => :path - - def initialize(template_path, load_paths = []) - template_path = template_path.dup - @load_path, @filename = find_full_path(template_path, load_paths) - @name = template_path.to_s.split("/").last.split(".").first - # @base_path, @name, @locale, @format, @extension = split(template_path) - @base_path.to_s.gsub!(/\/$/, '') # Push to split method - - # Extend with partial super powers - extend RenderablePartial if @name =~ /^_/ - end - - def accessible_paths - paths = [] - - if valid_extension?(extension) - paths << path - paths << path_without_extension - if multipart? - formats = format.split(".") - paths << "#{path_without_format_and_extension}.#{formats.first}" - paths << "#{path_without_format_and_extension}.#{formats.second}" - end - else - # template without explicit template handler should only be reachable through its exact path - paths << template_path - end - - paths - end - - def relative_path - path = File.expand_path(filename) - path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) - path - end - memoize :relative_path - - def source - File.read(filename) - end - memoize :source - - def exempt_from_layout? - @@exempt_from_layout.any? { |exempted| path =~ exempted } - end - - def path_without_extension - [base_path, [name, locale, format].compact.join('.')].compact.join('/') - end - memoize :path_without_extension - - def path_without_format_and_extension - [base_path, [name, locale].compact.join('.')].compact.join('/') - end - memoize :path_without_format_and_extension - - def path - [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') - end - memoize :path - - def mime_type - Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) - end - memoize :mime_type - - def multipart? - format && format.include?('.') - end - - def content_type - format && format.gsub('.', '/') - end - - private - - def format_and_extension - (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions - end - memoize :format_and_extension - - def mtime - File.mtime(filename) - end - memoize :mtime - - def method_segment - relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } - end - memoize :method_segment - - def stale? - File.mtime(filename) > mtime - end - - def recompile? - !@cached - end - - def valid_extension?(extension) - !Template.registered_template_handler(extension).nil? - end - - def valid_locale?(locale) - I18n.available_locales.include?(locale.to_sym) - end - - def find_full_path(path, load_paths) - load_paths = Array(load_paths) + [nil] - load_paths.each do |load_path| - file = load_path ? "#{load_path.to_str}/#{path}" : path - return load_path, file if File.file?(file) - end - raise MissingTemplate.new(load_paths, path) - end - end - end end \ No newline at end of file -- cgit v1.2.3 From afa7d7ff05a0d4787b216d50d609084649f21669 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 28 Apr 2009 16:15:17 -0500 Subject: Fix validate_request method name --- actionpack/lib/action_controller/testing/assertions/response.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index 574b8d6825..a4a3dcdec8 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -22,7 +22,7 @@ module ActionController # assert_response 401 # def assert_response(type, message = nil) - validate_response! + validate_request! clean_backtrace do if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") @@ -59,7 +59,7 @@ module ActionController # assert_redirected_to @customer # def assert_redirected_to(options = {}, message=nil) - validate_response! + validate_request! clean_backtrace do assert_response(:redirect, message) @@ -93,7 +93,7 @@ module ActionController # assert_template :partial => false # def assert_template(options = {}, message = nil) - validate_response! + validate_request! clean_backtrace do case options @@ -152,7 +152,7 @@ module ActionController end end - def validate_response! + def validate_request! unless @request.is_a?(ActionDispatch::Request) raise ArgumentError, "@request must be an ActionDispatch::Request" end -- cgit v1.2.3 From d63b42da362d696398fd371815734cb0caed48df Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 28 Apr 2009 16:25:04 -0500 Subject: Move header injection back into integration tests --- actionpack/lib/action_controller/testing/integration.rb | 7 ++++++- actionpack/lib/action_dispatch/test/mock.rb | 12 +----------- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index be5f216e2b..037463e489 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -263,7 +263,6 @@ module ActionController opts = { :method => method.to_s.upcase, :params => parameters, - :headers => headers, "SERVER_NAME" => host, "SERVER_PORT" => (https? ? "443" : "80"), @@ -282,6 +281,12 @@ module ActionController } env = ActionDispatch::Test::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_/ + env[key] = value + end + app = Rack::Lint.new(@app) status, headers, body = app.call(env) response = ::Rack::MockResponse.new(status, headers, body) diff --git a/actionpack/lib/action_dispatch/test/mock.rb b/actionpack/lib/action_dispatch/test/mock.rb index 8dc048af11..4042f9fbc8 100644 --- a/actionpack/lib/action_dispatch/test/mock.rb +++ b/actionpack/lib/action_dispatch/test/mock.rb @@ -5,8 +5,6 @@ module ActionDispatch class << self def env_for(path, opts) - headers = opts.delete(:headers) - method = (opts[:method] || opts["REQUEST_METHOD"]).to_s.upcase opts[:method] = opts["REQUEST_METHOD"] = method @@ -48,15 +46,7 @@ module ActionDispatch uri.query = requestify(params) end - env = ::Rack::MockRequest.env_for(uri.to_s, opts) - - (headers || {}).each do |key, value| - key = key.to_s.upcase.gsub(/-/, "_") - key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/ - env[key] = value - end - - env + ::Rack::MockRequest.env_for(uri.to_s, opts) end private -- cgit v1.2.3 From 8925e89c6307b8b7c8aeb0277ae5e059904b2fc6 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 28 Apr 2009 16:32:26 -0500 Subject: Deprecate response.assigns --- actionpack/lib/action_dispatch/http/response.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index ebba4eefa0..f570b8e8ed 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -34,7 +34,7 @@ module ActionDispatch # :nodoc: DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request - attr_accessor :assigns, :template, :layout + attr_accessor :template, :layout attr_accessor :redirected_to, :redirected_to_method_params attr_writer :header @@ -45,12 +45,16 @@ module ActionDispatch # :nodoc: request.session end + def assigns + ActiveSupport::Deprecation.warn("response.assigns has been deprecated. Use controller.assigns instead", caller) + template.assigns + end + delegate :default_charset, :to => 'ActionController::Base' def initialize super @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS) - @session, @assigns = [], [] end # The response code of the request -- cgit v1.2.3 From c0a372ba87f556769b98a6d06e8c684c3c3156df Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 28 Apr 2009 23:29:29 -0500 Subject: Deprecate template, session, assigns, and layout accessors on response object. Instead access them through the controller instance. This mainly affects functional test assertions. --- actionpack/lib/action_controller/base/base.rb | 4 +- .../lib/action_controller/base/mime_responds.rb | 2 +- .../lib/action_controller/caching/actions.rb | 2 +- .../testing/assertions/response.rb | 10 +- .../lib/action_controller/testing/process.rb | 13 +- actionpack/lib/action_dispatch/http/response.rb | 16 +- actionpack/lib/action_view/base.rb | 2 +- actionpack/lib/action_view/render/rendering.rb | 2 +- actionpack/lib/action_view/test_case.rb | 5 +- .../test/controller/action_pack_assertions_test.rb | 12 +- actionpack/test/controller/filters_test.rb | 177 +++++++++++++-------- actionpack/test/controller/flash_test.rb | 48 +++--- actionpack/test/controller/layout_test.rb | 24 +-- actionpack/test/template/body_parts_test.rb | 2 +- actionpack/test/template/output_buffer_test.rb | 18 +-- 15 files changed, 195 insertions(+), 142 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 2063df54b4..14c4339c94 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -367,6 +367,8 @@ module ActionController #:nodoc: # Returns the name of the action this controller is processing. attr_accessor :action_name + attr_reader :template + class << self def call(env) # HACK: For global rescue to have access to the original request and response @@ -816,7 +818,7 @@ module ActionController #:nodoc: def initialize_template_class(response) @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats) - response.template.helpers.send :include, self.class.master_helper_module + @template.helpers.send :include, self.class.master_helper_module response.redirected_to = nil @performed_render = @performed_redirect = false end diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb index bac225ab2a..1003e61a0b 100644 --- a/actionpack/lib/action_controller/base/mime_responds.rb +++ b/actionpack/lib/action_controller/base/mime_responds.rb @@ -127,7 +127,7 @@ module ActionController #:nodoc: @order << mime_type @responses[mime_type] ||= Proc.new do - @response.template.formats = [mime_type.to_sym] + @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 diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index b99feddf77..d95a346862 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -121,7 +121,7 @@ module ActionController #:nodoc: end def content_for_layout(controller) - controller.response.layout && controller.response.template.instance_variable_get('@cached_content_for_layout') + controller.template.layout && controller.template.instance_variable_get('@cached_content_for_layout') end end diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index a4a3dcdec8..684fe1ffe0 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -33,7 +33,7 @@ module ActionController assert_block("") { true } # to count the assertion else if @controller && @response.error? - exception = @controller.response.template.instance_variable_get(:@exception) + exception = @controller.template.instance_variable_get(:@exception) exception_message = exception && exception.message assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } else @@ -98,20 +98,20 @@ module ActionController clean_backtrace do case options when NilClass, String - rendered = (@controller.response.rendered[:template] || []).map { |t| t.identifier } + rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } msg = build_message(message, "expecting but rendering with ", options, rendered.join(', ')) assert_block(msg) do if options.nil? - @controller.response.rendered[:template].blank? + @controller.template.rendered[:template].blank? else rendered.any? { |t| t.match(options) } end end when Hash if expected_partial = options[:partial] - partials = @controller.response.rendered[:partials] + partials = @controller.template.rendered[:partials] if expected_count = options[:count] found = partials.detect { |p, _| p.identifier.match(expected_partial) } actual_count = found.nil? ? 0 : found.second @@ -126,7 +126,7 @@ module ActionController assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) end else - assert @controller.response.rendered[:partials].empty?, + assert @controller.template.rendered[:partials].empty?, "Expected no partials to be rendered" end end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index d073d06b19..16a8f66bc4 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -160,7 +160,8 @@ module ActionController #:nodoc: # Returns the template of the file which was used to # render this response (or nil) def rendered - template.instance_variable_get(:@_rendered) + ActiveSupport::Deprecation.warn("response.rendered has been deprecated. Use tempate.rendered instead", caller) + @template.instance_variable_get(:@_rendered) end # A shortcut to the flash. Returns an empty hash if no session flash exists. @@ -190,11 +191,13 @@ module ActionController #:nodoc: # A shortcut to the template.assigns def template_objects - template.assigns || {} + ActiveSupport::Deprecation.warn("response.template_objects has been deprecated. Use tempate.assigns instead", caller) + @template.assigns || {} end # Does the specified template object exist? def has_template_object?(name=nil) + ActiveSupport::Deprecation.warn("response.has_template_object? has been deprecated. Use tempate.assigns[name].nil? instead", caller) !template_objects[name].nil? end @@ -317,9 +320,9 @@ module ActionController #:nodoc: def assigns(key = nil) if key.nil? - @response.template.assigns + @controller.template.assigns else - @response.template.assigns[key.to_s] + @controller.template.assigns[key.to_s] end end @@ -431,7 +434,7 @@ module ActionController #:nodoc: (instance_variable_names - self.class.protected_instance_variables).each do |var| name, value = var[1..-1], instance_variable_get(var) @assigns[name] = value - response.template.assigns[name] = value if response + @template.assigns[name] = value if response end end end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index f570b8e8ed..d104dcb8a0 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -34,20 +34,30 @@ module ActionDispatch # :nodoc: DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request - attr_accessor :template, :layout attr_accessor :redirected_to, :redirected_to_method_params attr_writer :header alias_method :headers=, :header= + def template + ActiveSupport::Deprecation.warn("response.template has been deprecated. Use controller.template instead", caller) + @template + end + attr_writer :template + def session ActiveSupport::Deprecation.warn("response.session has been deprecated. Use request.session instead", caller) - request.session + @request.session end def assigns ActiveSupport::Deprecation.warn("response.assigns has been deprecated. Use controller.assigns instead", caller) - template.assigns + @template.controller.assigns + end + + def layout + ActiveSupport::Deprecation.warn("response.layout has been deprecated. Use template.layout instead", caller) + @template.layout end delegate :default_charset, :to => 'ActionController::Base' diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index d087395361..44bd401631 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -191,7 +191,7 @@ module ActionView #:nodoc: ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading) end - attr_internal :request + attr_internal :request, :layout delegate :controller_path, :to => :controller, :allow_nil => true diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index f174053b86..6e368f27eb 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -46,7 +46,7 @@ module ActionView locals ||= {} if controller && layout - response.layout = layout.identifier if controller.respond_to?(:response) + @_layout = layout.identifier logger.info("Rendering template within #{layout.identifier}") if logger end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index dddd671812..50bed67f7d 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -7,7 +7,8 @@ module ActionView @_rendered = { :template => nil, :partials => Hash.new(0) } initialize_without_template_tracking(*args) end - + + attr_internal :rendered alias_method :_render_template_without_template_tracking, :_render_template def _render_template(template, local_assigns = {}) if template.respond_to?(:identifier) @@ -16,7 +17,7 @@ module ActionView @_rendered[:template] << template end _render_template_without_template_tracking(template, local_assigns) - end + end end class TestCase < ActiveSupport::TestCase diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index f091f9b87c..dd59999a0c 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -292,14 +292,14 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # make sure that the template objects exist def test_template_objects_alive process :assign_this - assert !@response.has_template_object?('hi') - assert @response.has_template_object?('howdy') + assert !@controller.template.assigns['hi'] + assert @controller.template.assigns['howdy'] end # make sure we don't have template objects when we shouldn't def test_template_object_missing process :nothing - assert_nil @response.template_objects['howdy'] + assert_nil @controller.template.assigns['howdy'] end # check the empty flashing @@ -328,11 +328,11 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # check if we were rendered by a file-based template? def test_rendered_action process :nothing - assert_nil @response.rendered[:template] + assert_nil @controller.template.rendered[:template] process :hello_world - assert @response.rendered[:template] - assert 'hello_world', @response.rendered[:template].to_s + assert @controller.template.rendered[:template] + assert 'hello_world', @controller.template.rendered[:template].to_s end # check the redirection location diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index e83fde2349..aca7a821c8 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -165,11 +165,11 @@ class FilterTest < Test::Unit::TestCase def index render :text => 'ok' end - + def public end end - + class SkippingAndReorderingController < TestController skip_before_filter :ensure_login before_filter :find_record @@ -450,7 +450,8 @@ class FilterTest < Test::Unit::TestCase def test_empty_filter_chain assert_equal 0, EmptyFilterChainController.filter_chain.size - assert test_process(EmptyFilterChainController).template.assigns['action_executed'] + test_process(EmptyFilterChainController) + assert @controller.template.assigns['action_executed'] end def test_added_filter_to_inheritance_graph @@ -466,88 +467,109 @@ class FilterTest < Test::Unit::TestCase end def test_running_filters - assert_equal %w( wonderful_life ensure_login ), test_process(PrependingController).template.assigns["ran_filter"] + test_process(PrependingController) + assert_equal %w( wonderful_life ensure_login ), @controller.template.assigns["ran_filter"] end def test_running_filters_with_proc - assert test_process(ProcController).template.assigns["ran_proc_filter"] + test_process(ProcController) + assert @controller.template.assigns["ran_proc_filter"] end def test_running_filters_with_implicit_proc - assert test_process(ImplicitProcController).template.assigns["ran_proc_filter"] + test_process(ImplicitProcController) + assert @controller.template.assigns["ran_proc_filter"] end def test_running_filters_with_class - assert test_process(AuditController).template.assigns["was_audited"] + test_process(AuditController) + assert @controller.template.assigns["was_audited"] end def test_running_anomolous_yet_valid_condition_filters - response = test_process(AnomolousYetValidConditionController) - assert_equal %w( ensure_login ), response.template.assigns["ran_filter"] - assert response.template.assigns["ran_class_filter"] - assert response.template.assigns["ran_proc_filter1"] - assert response.template.assigns["ran_proc_filter2"] + test_process(AnomolousYetValidConditionController) + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert @controller.template.assigns["ran_class_filter"] + assert @controller.template.assigns["ran_proc_filter1"] + assert @controller.template.assigns["ran_proc_filter2"] - response = test_process(AnomolousYetValidConditionController, "show_without_filter") - assert_equal nil, response.template.assigns["ran_filter"] - assert !response.template.assigns["ran_class_filter"] - assert !response.template.assigns["ran_proc_filter1"] - assert !response.template.assigns["ran_proc_filter2"] + test_process(AnomolousYetValidConditionController, "show_without_filter") + assert_equal nil, @controller.template.assigns["ran_filter"] + assert !@controller.template.assigns["ran_class_filter"] + assert !@controller.template.assigns["ran_proc_filter1"] + assert !@controller.template.assigns["ran_proc_filter2"] end def test_running_conditional_options - response = test_process(ConditionalOptionsFilter) - assert_equal %w( ensure_login ), response.template.assigns["ran_filter"] + test_process(ConditionalOptionsFilter) + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] end def test_running_collection_condition_filters - assert_equal %w( ensure_login ), test_process(ConditionalCollectionFilterController).template.assigns["ran_filter"] - assert_equal nil, test_process(ConditionalCollectionFilterController, "show_without_filter").template.assigns["ran_filter"] - assert_equal nil, test_process(ConditionalCollectionFilterController, "another_action").template.assigns["ran_filter"] + test_process(ConditionalCollectionFilterController) + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + test_process(ConditionalCollectionFilterController, "show_without_filter") + assert_equal nil, @controller.template.assigns["ran_filter"] + test_process(ConditionalCollectionFilterController, "another_action") + assert_equal nil, @controller.template.assigns["ran_filter"] end def test_running_only_condition_filters - assert_equal %w( ensure_login ), test_process(OnlyConditionSymController).template.assigns["ran_filter"] - assert_equal nil, test_process(OnlyConditionSymController, "show_without_filter").template.assigns["ran_filter"] + test_process(OnlyConditionSymController) + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + test_process(OnlyConditionSymController, "show_without_filter") + assert_equal nil, @controller.template.assigns["ran_filter"] - assert test_process(OnlyConditionProcController).template.assigns["ran_proc_filter"] - assert !test_process(OnlyConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"] + test_process(OnlyConditionProcController) + assert @controller.template.assigns["ran_proc_filter"] + test_process(OnlyConditionProcController, "show_without_filter") + assert !@controller.template.assigns["ran_proc_filter"] - assert test_process(OnlyConditionClassController).template.assigns["ran_class_filter"] - assert !test_process(OnlyConditionClassController, "show_without_filter").template.assigns["ran_class_filter"] + test_process(OnlyConditionClassController) + assert @controller.template.assigns["ran_class_filter"] + test_process(OnlyConditionClassController, "show_without_filter") + assert !@controller.template.assigns["ran_class_filter"] end def test_running_except_condition_filters - assert_equal %w( ensure_login ), test_process(ExceptConditionSymController).template.assigns["ran_filter"] - assert_equal nil, test_process(ExceptConditionSymController, "show_without_filter").template.assigns["ran_filter"] + test_process(ExceptConditionSymController) + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + test_process(ExceptConditionSymController, "show_without_filter") + assert_equal nil, @controller.template.assigns["ran_filter"] - assert test_process(ExceptConditionProcController).template.assigns["ran_proc_filter"] - assert !test_process(ExceptConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"] + test_process(ExceptConditionProcController) + assert @controller.template.assigns["ran_proc_filter"] + test_process(ExceptConditionProcController, "show_without_filter") + assert !@controller.template.assigns["ran_proc_filter"] - assert test_process(ExceptConditionClassController).template.assigns["ran_class_filter"] - assert !test_process(ExceptConditionClassController, "show_without_filter").template.assigns["ran_class_filter"] + test_process(ExceptConditionClassController) + assert @controller.template.assigns["ran_class_filter"] + test_process(ExceptConditionClassController, "show_without_filter") + assert !@controller.template.assigns["ran_class_filter"] end def test_running_before_and_after_condition_filters - assert_equal %w( ensure_login clean_up_tmp), test_process(BeforeAndAfterConditionController).template.assigns["ran_filter"] - assert_equal nil, test_process(BeforeAndAfterConditionController, "show_without_filter").template.assigns["ran_filter"] + test_process(BeforeAndAfterConditionController) + assert_equal %w( ensure_login clean_up_tmp), @controller.template.assigns["ran_filter"] + test_process(BeforeAndAfterConditionController, "show_without_filter") + assert_equal nil, @controller.template.assigns["ran_filter"] end def test_around_filter - controller = test_process(AroundFilterController) - assert controller.template.assigns["before_ran"] - assert controller.template.assigns["after_ran"] + test_process(AroundFilterController) + assert @controller.template.assigns["before_ran"] + assert @controller.template.assigns["after_ran"] end def test_before_after_class_filter - controller = test_process(BeforeAfterClassFilterController) - assert controller.template.assigns["before_ran"] - assert controller.template.assigns["after_ran"] + test_process(BeforeAfterClassFilterController) + assert @controller.template.assigns["before_ran"] + assert @controller.template.assigns["after_ran"] end def test_having_properties_in_around_filter - controller = test_process(AroundFilterController) - assert_equal "before and after", controller.template.assigns["execution_log"] + test_process(AroundFilterController) + assert_equal "before and after", @controller.template.assigns["execution_log"] end def test_prepending_and_appending_around_filter @@ -560,7 +582,7 @@ class FilterTest < Test::Unit::TestCase def test_rendering_breaks_filtering_chain response = test_process(RenderingController) assert_equal "something else", response.body - assert !response.template.assigns["ran_action"] + assert !@controller.template.assigns["ran_action"] end def test_filters_with_mixed_specialization_run_in_order @@ -586,40 +608,53 @@ class FilterTest < Test::Unit::TestCase def test_running_prepended_before_and_after_filter assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length - response = test_process(PrependingBeforeAndAfterController) - assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"] + test_process(PrependingBeforeAndAfterController) + assert_equal %w( before_all between_before_all_and_after_all after_all ), @controller.template.assigns["ran_filter"] end - + def test_skipping_and_limiting_controller - assert_equal %w( ensure_login ), test_process(SkippingAndLimitedController, "index").template.assigns["ran_filter"] - assert_nil test_process(SkippingAndLimitedController, "public").template.assigns["ran_filter"] + test_process(SkippingAndLimitedController, "index") + assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + test_process(SkippingAndLimitedController, "public") + assert_nil @controller.template.assigns["ran_filter"] end def test_skipping_and_reordering_controller - assert_equal %w( find_record ensure_login ), test_process(SkippingAndReorderingController, "index").template.assigns["ran_filter"] + test_process(SkippingAndReorderingController, "index") + assert_equal %w( find_record ensure_login ), @controller.template.assigns["ran_filter"] end def test_conditional_skipping_of_filters - assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"] - assert_equal %w( ensure_login find_user ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"] + test_process(ConditionalSkippingController, "login") + assert_nil @controller.template.assigns["ran_filter"] + test_process(ConditionalSkippingController, "change_password") + assert_equal %w( ensure_login find_user ), @controller.template.assigns["ran_filter"] - assert_nil test_process(ConditionalSkippingController, "login").template.controller.instance_variable_get("@ran_after_filter") - assert_equal %w( clean_up ), test_process(ConditionalSkippingController, "change_password").template.controller.instance_variable_get("@ran_after_filter") + test_process(ConditionalSkippingController, "login") + assert_nil @controller.template.controller.instance_variable_get("@ran_after_filter") + test_process(ConditionalSkippingController, "change_password") + assert_equal %w( clean_up ), @controller.template.controller.instance_variable_get("@ran_after_filter") end def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional - assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'] - assert_nil test_process(ChildOfConditionalParentController, 'another_action').template.assigns['ran_filter'] + test_process(ChildOfConditionalParentController) + assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'] + test_process(ChildOfConditionalParentController, 'another_action') + assert_nil @controller.template.assigns['ran_filter'] end def test_condition_skipping_of_filters_when_siblings_also_have_conditions - assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'], "1" - assert_equal nil, test_process(AnotherChildOfConditionalParentController).template.assigns['ran_filter'] - assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'] + test_process(ChildOfConditionalParentController) + assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'], "1" + test_process(AnotherChildOfConditionalParentController) + assert_equal nil, @controller.template.assigns['ran_filter'] + test_process(ChildOfConditionalParentController) + assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'] end def test_changing_the_requirements - assert_equal nil, test_process(ChangingTheRequirementsController, "go_wild").template.assigns['ran_filter'] + test_process(ChangingTheRequirementsController, "go_wild") + assert_equal nil, @controller.template.assigns['ran_filter'] end def test_a_rescuing_around_filter @@ -638,7 +673,8 @@ class FilterTest < Test::Unit::TestCase request = ActionController::TestRequest.new request.action = action controller = controller.new if controller.is_a?(Class) - controller.process_with_test(request, ActionController::TestResponse.new) + @controller = controller + @controller.process_with_test(request, ActionController::TestResponse.new) end end @@ -819,9 +855,9 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase end def test_with_proc - controller = test_process(ControllerWithProcFilter,'no_raise') - assert controller.template.assigns['before'] - assert controller.template.assigns['after'] + test_process(ControllerWithProcFilter,'no_raise') + assert @controller.template.assigns['before'] + assert @controller.template.assigns['after'] end def test_nested_filters @@ -841,13 +877,13 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase end def test_filter_order_with_all_filter_types - controller = test_process(ControllerWithAllTypesOfFilters,'no_raise') - assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after',controller.template.assigns['ran_filter'].join(' ') + test_process(ControllerWithAllTypesOfFilters,'no_raise') + assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after', @controller.template.assigns['ran_filter'].join(' ') end def test_filter_order_with_skip_filter_method - controller = test_process(ControllerWithTwoLessFilters,'no_raise') - assert_equal 'before around (before yield) around (after yield)',controller.template.assigns['ran_filter'].join(' ') + test_process(ControllerWithTwoLessFilters,'no_raise') + assert_equal 'before around (before yield) around (after yield)', @controller.template.assigns['ran_filter'].join(' ') end def test_first_filter_in_multiple_before_filter_chain_halts @@ -880,6 +916,7 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase request = ActionController::TestRequest.new request.action = action controller = controller.new if controller.is_a?(Class) - controller.process_with_test(request, ActionController::TestResponse.new) + @controller = controller + @controller.process_with_test(request, ActionController::TestResponse.new) end end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index d8a892811e..ef60cae0ff 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -79,64 +79,64 @@ class FlashTest < ActionController::TestCase get :set_flash get :use_flash - assert_equal "hello", @response.template.assigns["flash_copy"]["that"] - assert_equal "hello", @response.template.assigns["flashy"] + assert_equal "hello", @controller.template.assigns["flash_copy"]["that"] + assert_equal "hello", @controller.template.assigns["flashy"] get :use_flash - assert_nil @response.template.assigns["flash_copy"]["that"], "On second flash" + assert_nil @controller.template.assigns["flash_copy"]["that"], "On second flash" end def test_keep_flash get :set_flash get :use_flash_and_keep_it - assert_equal "hello", @response.template.assigns["flash_copy"]["that"] - assert_equal "hello", @response.template.assigns["flashy"] + assert_equal "hello", @controller.template.assigns["flash_copy"]["that"] + assert_equal "hello", @controller.template.assigns["flashy"] get :use_flash - assert_equal "hello", @response.template.assigns["flash_copy"]["that"], "On second flash" + assert_equal "hello", @controller.template.assigns["flash_copy"]["that"], "On second flash" get :use_flash - assert_nil @response.template.assigns["flash_copy"]["that"], "On third flash" + assert_nil @controller.template.assigns["flash_copy"]["that"], "On third flash" end def test_flash_now get :set_flash_now - assert_equal "hello", @response.template.assigns["flash_copy"]["that"] - assert_equal "bar" , @response.template.assigns["flash_copy"]["foo"] - assert_equal "hello", @response.template.assigns["flashy"] + 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"] get :attempt_to_use_flash_now - assert_nil @response.template.assigns["flash_copy"]["that"] - assert_nil @response.template.assigns["flash_copy"]["foo"] - assert_nil @response.template.assigns["flashy"] + assert_nil @controller.template.assigns["flash_copy"]["that"] + assert_nil @controller.template.assigns["flash_copy"]["foo"] + assert_nil @controller.template.assigns["flashy"] end def test_update_flash get :set_flash get :use_flash_and_update_it - assert_equal "hello", @response.template.assigns["flash_copy"]["that"] - assert_equal "hello again", @response.template.assigns["flash_copy"]["this"] + assert_equal "hello", @controller.template.assigns["flash_copy"]["that"] + assert_equal "hello again", @controller.template.assigns["flash_copy"]["this"] get :use_flash - assert_nil @response.template.assigns["flash_copy"]["that"], "On second flash" - assert_equal "hello again", @response.template.assigns["flash_copy"]["this"], "On second 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" end def test_flash_after_reset_session get :use_flash_after_reset_session - assert_equal "hello", @response.template.assigns["flashy_that"] - assert_equal "good-bye", @response.template.assigns["flashy_this"] - assert_nil @response.template.assigns["flashy_that_reset"] + 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"] end def test_sweep_after_halted_filter_chain get :std_action - assert_nil @response.template.assigns["flash_copy"]["foo"] + assert_nil @controller.template.assigns["flash_copy"]["foo"] get :filter_halting_action - assert_equal "bar", @response.template.assigns["flash_copy"]["foo"] + assert_equal "bar", @controller.template.assigns["flash_copy"]["foo"] get :std_action # follow redirection - assert_equal "bar", @response.template.assigns["flash_copy"]["foo"] + assert_equal "bar", @controller.template.assigns["flash_copy"]["foo"] get :std_action - assert_nil @response.template.assigns["flash_copy"]["foo"] + assert_nil @controller.template.assigns["flash_copy"]["foo"] end end diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 11559b4071..da3f7b0cb8 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -57,7 +57,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase @controller = ThirdPartyTemplateLibraryController.new get :hello assert @controller.active_layout(true).identifier.include?('layouts/third_party_template_library.mab') - assert @response.layout.include?('layouts/third_party_template_library') + assert @controller.template.layout.include?('layouts/third_party_template_library') assert_response :success assert_equal 'Mab', @response.body end @@ -121,49 +121,49 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_default_layout @controller = DefaultLayoutController.new get :hello - assert @response.layout.include?('layouts/layout_test') + assert @controller.template.layout.include?('layouts/layout_test') end def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello - assert @response.layout.include?('layouts/item') + assert @controller.template.layout.include?('layouts/item') end def test_layout_only_exception_when_included @controller = OnlyLayoutController.new get :hello - assert @response.layout.include?('layouts/item') + assert @controller.template.layout.include?('layouts/item') end def test_layout_only_exception_when_excepted @controller = OnlyLayoutController.new get :goodbye - assert_equal nil, @response.layout + assert_equal nil, @controller.template.layout end def test_layout_except_exception_when_included @controller = ExceptLayoutController.new get :hello - assert @response.layout.include?('layouts/item') + assert @controller.template.layout.include?('layouts/item') end def test_layout_except_exception_when_excepted @controller = ExceptLayoutController.new get :goodbye - assert_equal nil, @response.layout + assert_equal nil, @controller.template.layout end def test_layout_set_when_using_render @controller = SetsLayoutInRenderController.new get :hello - assert @response.layout.include?('layouts/third_party_template_library') + assert @controller.template.layout.include?('layouts/third_party_template_library') end def test_layout_is_not_set_when_none_rendered @controller = RendersNoLayoutController.new get :hello - assert_nil @response.layout + assert_nil @controller.template.layout end def test_exempt_from_layout_honored_by_render_template @@ -181,7 +181,7 @@ class LayoutSetInResponseTest < ActionController::TestCase pending do @controller = PrependsViewPathController.new get :hello - assert_equal 'layouts/alt', @response.layout + assert_equal 'layouts/alt', @controller.template.layout end end @@ -206,7 +206,7 @@ class LayoutExceptionRaised < ActionController::TestCase def test_exception_raised_when_layout_file_not_found @controller = SetsNonExistentLayoutFile.new get :hello - assert_kind_of ActionView::MissingTemplate, @response.template.instance_eval { @exception } + assert_kind_of ActionView::MissingTemplate, @controller.template.instance_eval { @exception } end end @@ -234,7 +234,7 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/ @controller = LayoutSymlinkedTest.new get :hello assert_response 200 - assert @response.layout.include?("layouts/symlinked/symlinked_layout") + assert @controller.template.layout.include?("layouts/symlinked/symlinked_layout") end end end diff --git a/actionpack/test/template/body_parts_test.rb b/actionpack/test/template/body_parts_test.rb index 4c82b75cdc..5be8533293 100644 --- a/actionpack/test/template/body_parts_test.rb +++ b/actionpack/test/template/body_parts_test.rb @@ -6,7 +6,7 @@ class BodyPartsTest < ActionController::TestCase class TestController < ActionController::Base def index RENDERINGS.each do |rendering| - response.template.punctuate_body! rendering + @template.punctuate_body! rendering end @performed_render = true end diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index 6d8eab63dc..bc17f36783 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -13,23 +13,23 @@ class OutputBufferTest < ActionController::TestCase # Start with the default body parts get :index assert_equal ['foo'], @response.body_parts - assert_nil @response.template.output_buffer + assert_nil @controller.template.output_buffer # Nil output buffer is skipped - @response.template.flush_output_buffer - assert_nil @response.template.output_buffer + @controller.template.flush_output_buffer + assert_nil @controller.template.output_buffer assert_equal ['foo'], @response.body_parts # Empty output buffer is skipped - @response.template.output_buffer = '' - @response.template.flush_output_buffer - assert_equal '', @response.template.output_buffer + @controller.template.output_buffer = '' + @controller.template.flush_output_buffer + assert_equal '', @controller.template.output_buffer assert_equal ['foo'], @response.body_parts # Flushing appends the output buffer to the body parts - @response.template.output_buffer = 'bar' - @response.template.flush_output_buffer - assert_equal '', @response.template.output_buffer + @controller.template.output_buffer = 'bar' + @controller.template.flush_output_buffer + assert_equal '', @controller.template.output_buffer assert_equal ['foo', 'bar'], @response.body_parts end end -- cgit v1.2.3 From 7eef11eb657e6efb54dfe782ca2531df93654f83 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 29 Apr 2009 23:29:11 -0700 Subject: Convert params keys to strings --- actionpack/lib/action_dispatch/test/mock.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/test/mock.rb b/actionpack/lib/action_dispatch/test/mock.rb index 4042f9fbc8..68e5b108b4 100644 --- a/actionpack/lib/action_dispatch/test/mock.rb +++ b/actionpack/lib/action_dispatch/test/mock.rb @@ -42,6 +42,7 @@ module ActionDispatch opts[:input] = params end else + params.stringify_keys! params.update(::Rack::Utils.parse_query(uri.query)) uri.query = requestify(params) end -- cgit v1.2.3 From 988513ac7a0cbd820c9486088256b8ab4e8acf74 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 11:40:29 -0500 Subject: Framework backtrace cleaning is handled by ActiveSupport now --- .../action_controller/testing/assertions/dom.rb | 20 ++-- .../action_controller/testing/assertions/model.rb | 4 +- .../testing/assertions/response.rb | 108 ++++++++++----------- .../testing/assertions/routing.rb | 42 ++++---- .../action_controller/testing/assertions/tag.rb | 16 ++- .../lib/action_controller/testing/test_case.rb | 8 -- actionpack/test/controller/test_test.rb | 27 ------ 7 files changed, 85 insertions(+), 140 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/assertions/dom.rb b/actionpack/lib/action_controller/testing/assertions/dom.rb index 5ffe5f1883..c0e6c68fcd 100644 --- a/actionpack/lib/action_controller/testing/assertions/dom.rb +++ b/actionpack/lib/action_controller/testing/assertions/dom.rb @@ -9,13 +9,11 @@ module ActionController # assert_dom_equal 'Apples', link_to("Apples", "http://www.example.com") # def assert_dom_equal(expected, actual, message = "") - clean_backtrace do - expected_dom = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - full_message = build_message(message, " expected to be == to\n.", expected_dom.to_s, actual_dom.to_s) + expected_dom = HTML::Document.new(expected).root + actual_dom = HTML::Document.new(actual).root + full_message = build_message(message, " expected to be == to\n.", expected_dom.to_s, actual_dom.to_s) - assert_block(full_message) { expected_dom == actual_dom } - end + assert_block(full_message) { expected_dom == actual_dom } end # The negated form of +assert_dom_equivalent+. @@ -26,13 +24,11 @@ module ActionController # assert_dom_not_equal 'Apples', link_to("Oranges", "http://www.example.com") # def assert_dom_not_equal(expected, actual, message = "") - clean_backtrace do - expected_dom = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - full_message = build_message(message, " expected to be != to\n.", expected_dom.to_s, actual_dom.to_s) + expected_dom = HTML::Document.new(expected).root + actual_dom = HTML::Document.new(actual).root + full_message = build_message(message, " expected to be != to\n.", expected_dom.to_s, actual_dom.to_s) - assert_block(full_message) { expected_dom != actual_dom } - end + assert_block(full_message) { expected_dom != actual_dom } end end end diff --git a/actionpack/lib/action_controller/testing/assertions/model.rb b/actionpack/lib/action_controller/testing/assertions/model.rb index 3a7b39b106..93e3bcf456 100644 --- a/actionpack/lib/action_controller/testing/assertions/model.rb +++ b/actionpack/lib/action_controller/testing/assertions/model.rb @@ -12,9 +12,7 @@ module ActionController # def assert_valid(record) ::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller) - clean_backtrace do - assert record.valid?, record.errors.full_messages.join("\n") - end + assert record.valid?, record.errors.full_messages.join("\n") end end end diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb index 684fe1ffe0..7b2936e26c 100644 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ b/actionpack/lib/action_controller/testing/assertions/response.rb @@ -24,21 +24,19 @@ module ActionController def assert_response(type, message = nil) validate_request! - clean_backtrace do - if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") - assert_block("") { true } # to count the assertion - elsif type.is_a?(Fixnum) && @response.response_code == type - assert_block("") { true } # to count the assertion - elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] - assert_block("") { true } # to count the assertion + if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") + assert_block("") { true } # to count the assertion + elsif type.is_a?(Fixnum) && @response.response_code == type + assert_block("") { true } # to count the assertion + elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] + assert_block("") { true } # to count the assertion + else + if @controller && @response.error? + exception = @controller.template.instance_variable_get(:@exception) + exception_message = exception && exception.message + assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } else - if @controller && @response.error? - exception = @controller.template.instance_variable_get(:@exception) - exception_message = exception && exception.message - assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } - else - assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } - end + assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } end end end @@ -61,21 +59,19 @@ module ActionController def assert_redirected_to(options = {}, message=nil) validate_request! - clean_backtrace do - assert_response(:redirect, message) - return true if options == @response.redirected_to + assert_response(:redirect, message) + return true if options == @response.redirected_to - # Support partial arguments for hash redirections - if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) - return true if options.all? {|(key, value)| @response.redirected_to[key] == value} - end + # Support partial arguments for hash redirections + if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) + return true if options.all? {|(key, value)| @response.redirected_to[key] == value} + end - redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) - options_after_normalisation = normalize_argument_to_redirection(options) + redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) + options_after_normalisation = normalize_argument_to_redirection(options) - if redirected_to_after_normalisation != options_after_normalisation - flunk "Expected response to be a redirect to <#{options_after_normalisation}> but was a redirect to <#{redirected_to_after_normalisation}>" - end + if redirected_to_after_normalisation != options_after_normalisation + flunk "Expected response to be a redirect to <#{options_after_normalisation}> but was a redirect to <#{redirected_to_after_normalisation}>" end end @@ -95,40 +91,38 @@ module ActionController def assert_template(options = {}, message = nil) validate_request! - clean_backtrace do - case options - when NilClass, String - rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting but rendering with ", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - @controller.template.rendered[:template].blank? - else - rendered.any? { |t| t.match(options) } - end + case options + when NilClass, String + rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } + msg = build_message(message, + "expecting but rendering with ", + options, rendered.join(', ')) + assert_block(msg) do + if options.nil? + @controller.template.rendered[:template].blank? + else + rendered.any? { |t| t.match(options) } end - when Hash - if expected_partial = options[:partial] - partials = @controller.template.rendered[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found.second - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial but action rendered ", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end + end + when Hash + if expected_partial = options[:partial] + partials = @controller.template.rendered[:partials] + if expected_count = options[:count] + found = partials.detect { |p, _| p.identifier.match(expected_partial) } + actual_count = found.nil? ? 0 : found.second + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) else - assert @controller.template.rendered[:partials].empty?, - "Expected no partials to be rendered" + msg = build_message(message, + "expecting partial but action rendered ", + options[:partial], partials.keys) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) end + else + assert @controller.template.rendered[:partials].empty?, + "Expected no partials to be rendered" end end end diff --git a/actionpack/lib/action_controller/testing/assertions/routing.rb b/actionpack/lib/action_controller/testing/assertions/routing.rb index 5101751cea..f3f4f54fe3 100644 --- a/actionpack/lib/action_controller/testing/assertions/routing.rb +++ b/actionpack/lib/action_controller/testing/assertions/routing.rb @@ -44,19 +44,17 @@ module ActionController request_method = nil end - clean_backtrace do - ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? - request = recognized_request_for(path, request_method) + ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? + request = recognized_request_for(path, request_method) - expected_options = expected_options.clone - extras.each_key { |key| expected_options.delete key } unless extras.nil? + expected_options = expected_options.clone + extras.each_key { |key| expected_options.delete key } unless extras.nil? - expected_options.stringify_keys! - routing_diff = expected_options.diff(request.path_parameters) - msg = build_message(message, "The recognized options did not match , difference: ", - request.path_parameters, expected_options, expected_options.diff(request.path_parameters)) - assert_block(msg) { request.path_parameters == expected_options } - end + expected_options.stringify_keys! + routing_diff = expected_options.diff(request.path_parameters) + msg = build_message(message, "The recognized options did not match , difference: ", + request.path_parameters, expected_options, expected_options.diff(request.path_parameters)) + assert_block(msg) { request.path_parameters == expected_options } end # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+. @@ -78,21 +76,19 @@ module ActionController # # Asserts that the generated route gives us our custom route # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) - clean_backtrace do - expected_path = "/#{expected_path}" unless expected_path[0] == ?/ - # Load routes.rb if it hasn't been loaded. - ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? + expected_path = "/#{expected_path}" unless expected_path[0] == ?/ + # Load routes.rb if it hasn't been loaded. + ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? - generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults) - found_extras = options.reject {|k, v| ! extra_keys.include? k} + generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults) + found_extras = options.reject {|k, v| ! extra_keys.include? k} - msg = build_message(message, "found extras , not ", found_extras, extras) - assert_block(msg) { found_extras == extras } + msg = build_message(message, "found extras , not ", found_extras, extras) + assert_block(msg) { found_extras == extras } - msg = build_message(message, "The generated path did not match ", generated_path, - expected_path) - assert_block(msg) { expected_path == generated_path } - end + msg = build_message(message, "The generated path did not match ", generated_path, + expected_path) + assert_block(msg) { expected_path == generated_path } end # Asserts that path and options match both ways; in other words, it verifies that path generates diff --git a/actionpack/lib/action_controller/testing/assertions/tag.rb b/actionpack/lib/action_controller/testing/assertions/tag.rb index 80249e0e83..d9197b7855 100644 --- a/actionpack/lib/action_controller/testing/assertions/tag.rb +++ b/actionpack/lib/action_controller/testing/assertions/tag.rb @@ -94,11 +94,9 @@ module ActionController # that allow optional closing tags (p, li, td). You must explicitly # close all of your tags to use these assertions. def assert_tag(*opts) - clean_backtrace do - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}" - end + opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first + tag = find_tag(opts) + assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}" end # Identical to +assert_tag+, but asserts that a matching tag does _not_ @@ -116,11 +114,9 @@ module ActionController # assert_no_tag :tag => "p", # :children => { :count => 1..3, :only => { :tag => "img" } } def assert_no_tag(*opts) - clean_backtrace do - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}" - end + opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first + tag = find_tag(opts) + assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}" end end end diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb index b020b755a0..a80488e13e 100644 --- a/actionpack/lib/action_controller/testing/test_case.rb +++ b/actionpack/lib/action_controller/testing/test_case.rb @@ -109,14 +109,6 @@ module ActionController %w(response selector tag dom routing model).each do |kind| include ActionController::Assertions.const_get("#{kind.camelize}Assertions") end - - def clean_backtrace(&block) - yield - rescue ActiveSupport::TestCase::Assertion => error - framework_path = Regexp.new(File.expand_path("#{File.dirname(__FILE__)}/assertions")) - error.backtrace.reject! { |line| File.expand_path(line) =~ framework_path } - raise - end end include Assertions diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index f68ffc7a2a..b372980242 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -629,33 +629,6 @@ XML end end -class CleanBacktraceTest < ActionController::TestCase - def test_should_reraise_the_same_object - exception = ActiveSupport::TestCase::Assertion.new('message') - clean_backtrace { raise exception } - rescue Exception => caught - assert_equal exception.object_id, caught.object_id - assert_equal exception.message, caught.message - end - - def test_should_clean_assertion_lines_from_backtrace - path = File.expand_path("#{File.dirname(__FILE__)}/../../lib/action_controller/testing") - exception = ActiveSupport::TestCase::Assertion.new('message') - exception.set_backtrace ["#{path}/abc", "#{path}/assertions/def"] - clean_backtrace { raise exception } - rescue Exception => caught - assert_equal ["#{path}/abc"], caught.backtrace - end - - def test_should_only_clean_assertion_failure_errors - clean_backtrace do - raise "can't touch this", [File.expand_path("#{File.dirname(__FILE__)}/../../lib/action_controller/assertions/abc")] - end - rescue => caught - assert !caught.backtrace.empty? - end -end - class InferringClassNameTest < ActionController::TestCase def test_determine_controller_class assert_equal ContentController, determine_class("ContentControllerTest") -- cgit v1.2.3 From 98dd726687259b96fad15cc073c610fda7fc1023 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 11:41:43 -0500 Subject: Test::Unit work arounds are handled by ActiveSupport --- .../lib/action_controller/testing/integration.rb | 49 ---------------------- 1 file changed, 49 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 037463e489..f960698566 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -508,54 +508,5 @@ module ActionController # end class IntegrationTest < ActiveSupport::TestCase include Integration::Runner - - # Work around a bug in test/unit caused by the default test being named - # as a symbol (:default_test), which causes regex test filters - # (like "ruby test.rb -n /foo/") to fail because =~ doesn't work on - # symbols. - def initialize(name) #:nodoc: - super(name.to_s) - end - - # Work around test/unit's requirement that every subclass of TestCase have - # at least one test method. Note that this implementation extends to all - # subclasses, as well, so subclasses of IntegrationTest may also exist - # without any test methods. - def run(*args) #:nodoc: - return if @method_name == "default_test" - super - end - - # Because of how use_instantiated_fixtures and use_transactional_fixtures - # are defined, we need to treat them as special cases. Otherwise, users - # would potentially have to set their values for both Test::Unit::TestCase - # ActionController::IntegrationTest, since by the time the value is set on - # TestCase, IntegrationTest has already been defined and cannot inherit - # changes to those variables. So, we make those two attributes - # copy-on-write. - - class << self - def use_transactional_fixtures=(flag) #:nodoc: - @_use_transactional_fixtures = true - @use_transactional_fixtures = flag - end - - def use_instantiated_fixtures=(flag) #:nodoc: - @_use_instantiated_fixtures = true - @use_instantiated_fixtures = flag - end - - def use_transactional_fixtures #:nodoc: - @_use_transactional_fixtures ? - @use_transactional_fixtures : - superclass.use_transactional_fixtures - end - - def use_instantiated_fixtures #:nodoc: - @_use_instantiated_fixtures ? - @use_instantiated_fixtures : - superclass.use_instantiated_fixtures - end - end end end -- cgit v1.2.3 From 7b3b7cb2ab1ccf96d4c8a1bafd87dbfbd2ac8c84 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 11:55:53 -0500 Subject: Move generic assertions into ActionDispatch --- .../action_controller/testing/assertions/dom.rb | 35 -- .../action_controller/testing/assertions/model.rb | 19 - .../testing/assertions/response.rb | 156 ----- .../testing/assertions/routing.rb | 142 ----- .../testing/assertions/selector.rb | 632 --------------------- .../action_controller/testing/assertions/tag.rb | 123 ---- .../lib/action_controller/testing/integration.rb | 2 +- .../lib/action_controller/testing/test_case.rb | 7 +- actionpack/lib/action_dispatch.rb | 2 + .../lib/action_dispatch/testing/assertions.rb | 8 + .../lib/action_dispatch/testing/assertions/dom.rb | 35 ++ .../action_dispatch/testing/assertions/model.rb | 19 + .../action_dispatch/testing/assertions/response.rb | 156 +++++ .../action_dispatch/testing/assertions/routing.rb | 142 +++++ .../action_dispatch/testing/assertions/selector.rb | 632 +++++++++++++++++++++ .../lib/action_dispatch/testing/assertions/tag.rb | 123 ++++ actionpack/lib/action_view/test_case.rb | 2 +- 17 files changed, 1120 insertions(+), 1115 deletions(-) delete mode 100644 actionpack/lib/action_controller/testing/assertions/dom.rb delete mode 100644 actionpack/lib/action_controller/testing/assertions/model.rb delete mode 100644 actionpack/lib/action_controller/testing/assertions/response.rb delete mode 100644 actionpack/lib/action_controller/testing/assertions/routing.rb delete mode 100644 actionpack/lib/action_controller/testing/assertions/selector.rb delete mode 100644 actionpack/lib/action_controller/testing/assertions/tag.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/dom.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/model.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/response.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/routing.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/selector.rb create mode 100644 actionpack/lib/action_dispatch/testing/assertions/tag.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/assertions/dom.rb b/actionpack/lib/action_controller/testing/assertions/dom.rb deleted file mode 100644 index c0e6c68fcd..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/dom.rb +++ /dev/null @@ -1,35 +0,0 @@ -module ActionController - module Assertions - module DomAssertions - # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) - # - # ==== Examples - # - # # assert that the referenced method generates the appropriate HTML string - # assert_dom_equal 'Apples', link_to("Apples", "http://www.example.com") - # - def assert_dom_equal(expected, actual, message = "") - expected_dom = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - full_message = build_message(message, " expected to be == to\n.", expected_dom.to_s, actual_dom.to_s) - - assert_block(full_message) { expected_dom == actual_dom } - end - - # The negated form of +assert_dom_equivalent+. - # - # ==== Examples - # - # # assert that the referenced method does not generate the specified HTML string - # assert_dom_not_equal 'Apples', link_to("Oranges", "http://www.example.com") - # - def assert_dom_not_equal(expected, actual, message = "") - expected_dom = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - full_message = build_message(message, " expected to be != to\n.", expected_dom.to_s, actual_dom.to_s) - - assert_block(full_message) { expected_dom != actual_dom } - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/assertions/model.rb b/actionpack/lib/action_controller/testing/assertions/model.rb deleted file mode 100644 index 93e3bcf456..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/model.rb +++ /dev/null @@ -1,19 +0,0 @@ -module ActionController - module Assertions - module ModelAssertions - # Ensures that the passed record is valid by Active Record standards and - # returns any error messages if it is not. - # - # ==== Examples - # - # # assert that a newly created record is valid - # model = Model.new - # assert_valid(model) - # - def assert_valid(record) - ::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller) - assert record.valid?, record.errors.full_messages.join("\n") - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/assertions/response.rb b/actionpack/lib/action_controller/testing/assertions/response.rb deleted file mode 100644 index 7b2936e26c..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/response.rb +++ /dev/null @@ -1,156 +0,0 @@ -module ActionController - module Assertions - # A small suite of assertions that test responses from Rails applications. - module ResponseAssertions - # Asserts that the response is one of the following types: - # - # * :success - Status code was 200 - # * :redirect - Status code was in the 300-399 range - # * :missing - Status code was 404 - # * :error - Status code was in the 500-599 range - # - # You can also pass an explicit status number like assert_response(501) - # or its symbolic equivalent assert_response(:not_implemented). - # See ActionDispatch::StatusCodes for a full list. - # - # ==== Examples - # - # # assert that the response was a redirection - # assert_response :redirect - # - # # assert that the response code was status code 401 (unauthorized) - # assert_response 401 - # - def assert_response(type, message = nil) - validate_request! - - if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") - assert_block("") { true } # to count the assertion - elsif type.is_a?(Fixnum) && @response.response_code == type - assert_block("") { true } # to count the assertion - elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] - assert_block("") { true } # to count the assertion - else - if @controller && @response.error? - exception = @controller.template.instance_variable_get(:@exception) - exception_message = exception && exception.message - assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } - else - assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } - end - end - end - - # Assert that the redirection options passed in match those of the redirect called in the latest action. - # This match can be partial, such that assert_redirected_to(:controller => "weblog") will also - # match the redirection of redirect_to(:controller => "weblog", :action => "show") and so on. - # - # ==== Examples - # - # # assert that the redirection was to the "index" action on the WeblogController - # assert_redirected_to :controller => "weblog", :action => "index" - # - # # assert that the redirection was to the named route login_url - # assert_redirected_to login_url - # - # # assert that the redirection was to the url for @customer - # assert_redirected_to @customer - # - def assert_redirected_to(options = {}, message=nil) - validate_request! - - assert_response(:redirect, message) - return true if options == @response.redirected_to - - # Support partial arguments for hash redirections - if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) - return true if options.all? {|(key, value)| @response.redirected_to[key] == value} - end - - redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) - options_after_normalisation = normalize_argument_to_redirection(options) - - if redirected_to_after_normalisation != options_after_normalisation - flunk "Expected response to be a redirect to <#{options_after_normalisation}> but was a redirect to <#{redirected_to_after_normalisation}>" - end - end - - # Asserts that the request was rendered with the appropriate template file or partials - # - # ==== Examples - # - # # assert that the "new" view template was rendered - # assert_template "new" - # - # # assert that the "_customer" partial was rendered twice - # assert_template :partial => '_customer', :count => 2 - # - # # assert that no partials were rendered - # assert_template :partial => false - # - def assert_template(options = {}, message = nil) - validate_request! - - case options - when NilClass, String - rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting but rendering with ", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - @controller.template.rendered[:template].blank? - else - rendered.any? { |t| t.match(options) } - end - end - when Hash - if expected_partial = options[:partial] - partials = @controller.template.rendered[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found.second - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial but action rendered ", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end - else - assert @controller.template.rendered[:partials].empty?, - "Expected no partials to be rendered" - end - end - end - - private - # Proxy to to_param if the object will respond to it. - def parameterize(value) - value.respond_to?(:to_param) ? value.to_param : value - end - - def normalize_argument_to_redirection(fragment) - after_routing = @controller.url_for(fragment) - if after_routing =~ %r{^\w+://.*} - after_routing - else - # FIXME - this should probably get removed. - if after_routing.first != '/' - after_routing = '/' + after_routing - end - @request.protocol + @request.host_with_port + after_routing - end - end - - def validate_request! - unless @request.is_a?(ActionDispatch::Request) - raise ArgumentError, "@request must be an ActionDispatch::Request" - end - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/assertions/routing.rb b/actionpack/lib/action_controller/testing/assertions/routing.rb deleted file mode 100644 index f3f4f54fe3..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/routing.rb +++ /dev/null @@ -1,142 +0,0 @@ -module ActionController - module Assertions - # Suite of assertions to test routes generated by Rails and the handling of requests made to them. - module RoutingAssertions - # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash) - # match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+. - # - # Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes - # requiring a specific HTTP method. The hash should contain a :path with the incoming request path - # and a :method containing the required HTTP verb. - # - # # assert that POSTing to /items will call the create action on ItemsController - # assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post} - # - # You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used - # to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the - # extras argument, appending the query string on the path directly will not work. For example: - # - # # assert that a path of '/items/list/1?view=print' returns the correct options - # assert_recognizes {:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" } - # - # The +message+ parameter allows you to pass in an error message that is displayed upon failure. - # - # ==== Examples - # # Check the default route (i.e., the index action) - # assert_recognizes {:controller => 'items', :action => 'index'}, 'items' - # - # # Test a specific action - # assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list' - # - # # Test an action with a parameter - # assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1' - # - # # Test a custom route - # assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1' - # - # # Check a Simply RESTful generated route - # assert_recognizes list_items_url, 'items/list' - def assert_recognizes(expected_options, path, extras={}, message=nil) - if path.is_a? Hash - request_method = path[:method] - path = path[:path] - else - request_method = nil - end - - ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? - request = recognized_request_for(path, request_method) - - expected_options = expected_options.clone - extras.each_key { |key| expected_options.delete key } unless extras.nil? - - expected_options.stringify_keys! - routing_diff = expected_options.diff(request.path_parameters) - msg = build_message(message, "The recognized options did not match , difference: ", - request.path_parameters, expected_options, expected_options.diff(request.path_parameters)) - assert_block(msg) { request.path_parameters == expected_options } - end - - # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+. - # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in - # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures. - # - # The +defaults+ parameter is unused. - # - # ==== Examples - # # Asserts that the default action is generated for a route with no action - # assert_generates "/items", :controller => "items", :action => "index" - # - # # Tests that the list action is properly routed - # assert_generates "/items/list", :controller => "items", :action => "list" - # - # # Tests the generation of a route with a parameter - # assert_generates "/items/list/1", { :controller => "items", :action => "list", :id => "1" } - # - # # Asserts that the generated route gives us our custom route - # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } - def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) - expected_path = "/#{expected_path}" unless expected_path[0] == ?/ - # Load routes.rb if it hasn't been loaded. - ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? - - generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults) - found_extras = options.reject {|k, v| ! extra_keys.include? k} - - msg = build_message(message, "found extras , not ", found_extras, extras) - assert_block(msg) { found_extras == extras } - - msg = build_message(message, "The generated path did not match ", generated_path, - expected_path) - assert_block(msg) { expected_path == generated_path } - end - - # Asserts that path and options match both ways; in other words, it verifies that path generates - # options and then that options generates path. This essentially combines +assert_recognizes+ - # and +assert_generates+ into one step. - # - # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The - # +message+ parameter allows you to specify a custom error message to display upon failure. - # - # ==== Examples - # # Assert a basic route: a controller with the default action (index) - # assert_routing '/home', :controller => 'home', :action => 'index' - # - # # Test a route generated with a specific controller, action, and parameter (id) - # assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', id => 23 - # - # # Assert a basic route (controller + default action), with an error message if it fails - # assert_routing '/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly' - # - # # Tests a route, providing a defaults hash - # assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"} - # - # # Tests a route with a HTTP method - # assert_routing { :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" } - def assert_routing(path, options, defaults={}, extras={}, message=nil) - assert_recognizes(options, path, extras, message) - - controller, default_controller = options[:controller], defaults[:controller] - if controller && controller.include?(?/) && default_controller && default_controller.include?(?/) - options[:controller] = "/#{controller}" - end - - assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message) - end - - private - # Recognizes the route for a given path. - def recognized_request_for(path, request_method = nil) - path = "/#{path}" unless path.first == '/' - - # Assume given controller - request = ActionController::TestRequest.new - request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method - request.path = path - - ActionController::Routing::Routes.recognize(request) - request - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/assertions/selector.rb b/actionpack/lib/action_controller/testing/assertions/selector.rb deleted file mode 100644 index 0d56ea5ef7..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/selector.rb +++ /dev/null @@ -1,632 +0,0 @@ -#-- -# Copyright (c) 2006 Assaf Arkin (http://labnotes.org) -# Under MIT and/or CC By license. -#++ - -module ActionController - module Assertions - unless const_defined?(:NO_STRIP) - NO_STRIP = %w{pre script style textarea} - end - - # Adds the +assert_select+ method for use in Rails functional - # test cases, which can be used to make assertions on the response HTML of a controller - # action. You can also call +assert_select+ within another +assert_select+ to - # make assertions on elements selected by the enclosing assertion. - # - # Use +css_select+ to select elements without making an assertions, either - # from the response HTML or elements selected by the enclosing assertion. - # - # In addition to HTML responses, you can make the following assertions: - # * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations. - # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions. - # * +assert_select_email+ - Assertions on the HTML body of an e-mail. - # - # Also see HTML::Selector to learn how to use selectors. - module SelectorAssertions - # :call-seq: - # css_select(selector) => array - # css_select(element, selector) => array - # - # Select and return all matching elements. - # - # If called with a single argument, uses that argument as a selector - # to match all elements of the current page. Returns an empty array - # if no match is found. - # - # If called with two arguments, uses the first argument as the base - # element and the second argument as the selector. Attempts to match the - # base element and any of its children. Returns an empty array if no - # match is found. - # - # The selector may be a CSS selector expression (String), an expression - # with substitution values (Array) or an HTML::Selector object. - # - # ==== Examples - # # Selects all div tags - # divs = css_select("div") - # - # # Selects all paragraph tags and does something interesting - # pars = css_select("p") - # pars.each do |par| - # # Do something fun with paragraphs here... - # end - # - # # Selects all list items in unordered lists - # items = css_select("ul>li") - # - # # Selects all form tags and then all inputs inside the form - # forms = css_select("form") - # forms.each do |form| - # inputs = css_select(form, "input") - # ... - # end - # - def css_select(*args) - # See assert_select to understand what's going on here. - arg = args.shift - - if arg.is_a?(HTML::Node) - root = arg - arg = args.shift - elsif arg == nil - raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?" - elsif @selected - matches = [] - - @selected.each do |selected| - subset = css_select(selected, HTML::Selector.new(arg.dup, args.dup)) - subset.each do |match| - matches << match unless matches.any? { |m| m.equal?(match) } - end - end - - return matches - else - root = response_from_page_or_rjs - end - - case arg - when String - selector = HTML::Selector.new(arg, args) - when Array - selector = HTML::Selector.new(*arg) - when HTML::Selector - selector = arg - else raise ArgumentError, "Expecting a selector as the first argument" - end - - selector.select(root) - end - - # :call-seq: - # assert_select(selector, equality?, message?) - # assert_select(element, selector, equality?, message?) - # - # An assertion that selects elements and makes one or more equality tests. - # - # If the first argument is an element, selects all matching elements - # starting from (and including) that element and all its children in - # depth-first order. - # - # If no element if specified, calling +assert_select+ selects from the - # response HTML unless +assert_select+ is called from within an +assert_select+ block. - # - # When called with a block +assert_select+ passes an array of selected elements - # to the block. Calling +assert_select+ from the block, with no element specified, - # runs the assertion on the complete set of elements selected by the enclosing assertion. - # Alternatively the array may be iterated through so that +assert_select+ can be called - # separately for each element. - # - # - # ==== Example - # If the response contains two ordered lists, each with four list elements then: - # assert_select "ol" do |elements| - # elements.each do |element| - # assert_select element, "li", 4 - # end - # end - # - # will pass, as will: - # assert_select "ol" do - # assert_select "li", 8 - # end - # - # The selector may be a CSS selector expression (String), an expression - # with substitution values, or an HTML::Selector object. - # - # === Equality Tests - # - # The equality test may be one of the following: - # * true - Assertion is true if at least one element selected. - # * false - Assertion is true if no element selected. - # * String/Regexp - Assertion is true if the text value of at least - # one element matches the string or regular expression. - # * Integer - Assertion is true if exactly that number of - # elements are selected. - # * Range - Assertion is true if the number of selected - # elements fit the range. - # If no equality test specified, the assertion is true if at least one - # element selected. - # - # To perform more than one equality tests, use a hash with the following keys: - # * :text - Narrow the selection to elements that have this text - # value (string or regexp). - # * :html - Narrow the selection to elements that have this HTML - # content (string or regexp). - # * :count - Assertion is true if the number of selected elements - # is equal to this value. - # * :minimum - Assertion is true if the number of selected - # elements is at least this value. - # * :maximum - Assertion is true if the number of selected - # elements is at most this value. - # - # If the method is called with a block, once all equality tests are - # evaluated the block is called with an array of all matched elements. - # - # ==== Examples - # - # # At least one form element - # assert_select "form" - # - # # Form element includes four input fields - # assert_select "form input", 4 - # - # # Page title is "Welcome" - # assert_select "title", "Welcome" - # - # # Page title is "Welcome" and there is only one title element - # assert_select "title", {:count=>1, :text=>"Welcome"}, - # "Wrong title or more than one title element" - # - # # Page contains no forms - # assert_select "form", false, "This page must contain no forms" - # - # # Test the content and style - # assert_select "body div.header ul.menu" - # - # # Use substitution values - # assert_select "ol>li#?", /item-\d+/ - # - # # All input fields in the form have a name - # assert_select "form input" do - # assert_select "[name=?]", /.+/ # Not empty - # end - def assert_select(*args, &block) - # Start with optional element followed by mandatory selector. - arg = args.shift - - if arg.is_a?(HTML::Node) - # First argument is a node (tag or text, but also HTML root), - # so we know what we're selecting from. - root = arg - arg = args.shift - elsif arg == nil - # This usually happens when passing a node/element that - # happens to be nil. - raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?" - elsif @selected - root = HTML::Node.new(nil) - root.children.concat @selected - else - # Otherwise just operate on the response document. - root = response_from_page_or_rjs - end - - # First or second argument is the selector: string and we pass - # all remaining arguments. Array and we pass the argument. Also - # accepts selector itself. - case arg - when String - selector = HTML::Selector.new(arg, args) - when Array - selector = HTML::Selector.new(*arg) - when HTML::Selector - selector = arg - else raise ArgumentError, "Expecting a selector as the first argument" - end - - # Next argument is used for equality tests. - equals = {} - case arg = args.shift - when Hash - equals = arg - when String, Regexp - equals[:text] = arg - when Integer - equals[:count] = arg - when Range - equals[:minimum] = arg.begin - equals[:maximum] = arg.end - when FalseClass - equals[:count] = 0 - when NilClass, TrueClass - equals[:minimum] = 1 - else raise ArgumentError, "I don't understand what you're trying to match" - end - - # By default we're looking for at least one match. - if equals[:count] - equals[:minimum] = equals[:maximum] = equals[:count] - else - equals[:minimum] = 1 unless equals[:minimum] - end - - # Last argument is the message we use if the assertion fails. - message = args.shift - #- message = "No match made with selector #{selector.inspect}" unless message - if args.shift - raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" - end - - matches = selector.select(root) - # If text/html, narrow down to those elements that match it. - content_mismatch = nil - if match_with = equals[:text] - matches.delete_if do |match| - text = "" - text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding) - stack = match.children.reverse - while node = stack.pop - if node.tag? - stack.concat node.children.reverse - else - content = node.content - content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding) - text << content - end - end - text.strip! unless NO_STRIP.include?(match.name) - unless match_with.is_a?(Regexp) ? (text =~ match_with) : (text == match_with.to_s) - content_mismatch ||= build_message(message, " expected but was\n.", match_with, text) - true - end - end - elsif match_with = equals[:html] - matches.delete_if do |match| - html = match.children.map(&:to_s).join - html.strip! unless NO_STRIP.include?(match.name) - unless match_with.is_a?(Regexp) ? (html =~ match_with) : (html == match_with.to_s) - content_mismatch ||= build_message(message, " expected but was\n.", match_with, html) - true - end - end - end - # Expecting foo found bar element only if found zero, not if - # found one but expecting two. - message ||= content_mismatch if matches.empty? - # Test minimum/maximum occurrence. - min, max = equals[:minimum], equals[:maximum] - message = message || %(Expected #{count_description(min, max)} matching "#{selector.to_s}", found #{matches.size}.) - assert matches.size >= min, message if min - assert matches.size <= max, message if max - - # If a block is given call that block. Set @selected to allow - # nested assert_select, which can be nested several levels deep. - if block_given? && !matches.empty? - begin - in_scope, @selected = @selected, matches - yield matches - ensure - @selected = in_scope - end - end - - # Returns all matches elements. - matches - end - - def count_description(min, max) #:nodoc: - pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')} - - if min && max && (max != min) - "between #{min} and #{max} elements" - elsif min && !(min == 1 && max == 1) - "at least #{min} #{pluralize['element', min]}" - elsif max - "at most #{max} #{pluralize['element', max]}" - end - end - - # :call-seq: - # assert_select_rjs(id?) { |elements| ... } - # assert_select_rjs(statement, id?) { |elements| ... } - # assert_select_rjs(:insert, position, id?) { |elements| ... } - # - # Selects content from the RJS response. - # - # === Narrowing down - # - # With no arguments, asserts that one or more elements are updated or - # inserted by RJS statements. - # - # Use the +id+ argument to narrow down the assertion to only statements - # that update or insert an element with that identifier. - # - # Use the first argument to narrow down assertions to only statements - # of that type. Possible values are :replace, :replace_html, - # :show, :hide, :toggle, :remove and - # :insert_html. - # - # Use the argument :insert followed by an insertion position to narrow - # down the assertion to only statements that insert elements in that - # position. Possible values are :top, :bottom, :before - # and :after. - # - # Using the :remove statement, you will be able to pass a block, but it will - # be ignored as there is no HTML passed for this statement. - # - # === Using blocks - # - # Without a block, +assert_select_rjs+ merely asserts that the response - # contains one or more RJS statements that replace or update content. - # - # With a block, +assert_select_rjs+ also selects all elements used in - # these statements and passes them to the block. Nested assertions are - # supported. - # - # Calling +assert_select_rjs+ with no arguments and using nested asserts - # asserts that the HTML content is returned by one or more RJS statements. - # Using +assert_select+ directly makes the same assertion on the content, - # but without distinguishing whether the content is returned in an HTML - # or JavaScript. - # - # ==== Examples - # - # # Replacing the element foo. - # # page.replace 'foo', ... - # assert_select_rjs :replace, "foo" - # - # # Replacing with the chained RJS proxy. - # # page[:foo].replace ... - # assert_select_rjs :chained_replace, 'foo' - # - # # Inserting into the element bar, top position. - # assert_select_rjs :insert, :top, "bar" - # - # # Remove the element bar - # assert_select_rjs :remove, "bar" - # - # # Changing the element foo, with an image. - # assert_select_rjs "foo" do - # assert_select "img[src=/images/logo.gif"" - # end - # - # # RJS inserts or updates a list with four items. - # assert_select_rjs do - # assert_select "ol>li", 4 - # end - # - # # The same, but shorter. - # assert_select "ol>li", 4 - def assert_select_rjs(*args, &block) - rjs_type = args.first.is_a?(Symbol) ? args.shift : nil - id = args.first.is_a?(String) ? args.shift : nil - - # If the first argument is a symbol, it's the type of RJS statement we're looking - # for (update, replace, insertion, etc). Otherwise, we're looking for just about - # any RJS statement. - if rjs_type - if rjs_type == :insert - position = args.shift - id = args.shift - insertion = "insert_#{position}".to_sym - raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion] - statement = "(#{RJS_STATEMENTS[insertion]})" - else - raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type] - statement = "(#{RJS_STATEMENTS[rjs_type]})" - end - else - statement = "#{RJS_STATEMENTS[:any]}" - end - - # Next argument we're looking for is the element identifier. If missing, we pick - # any element, otherwise we replace it in the statement. - pattern = Regexp.new( - id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement - ) - - # Duplicate the body since the next step involves destroying it. - matches = nil - case rjs_type - when :remove, :show, :hide, :toggle - matches = @response.body.match(pattern) - else - @response.body.gsub(pattern) do |match| - html = unescape_rjs(match) - matches ||= [] - matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? } - "" - end - end - - if matches - assert_block("") { true } # to count the assertion - if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type) - begin - in_scope, @selected = @selected, matches - yield matches - ensure - @selected = in_scope - end - end - matches - else - # RJS statement not found. - case rjs_type - when :remove, :show, :hide, :toggle - flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered." - else - flunk_message = "No RJS statement that replaces or inserts HTML content." - end - flunk args.shift || flunk_message - end - end - - # :call-seq: - # assert_select_encoded(element?) { |elements| ... } - # - # Extracts the content of an element, treats it as encoded HTML and runs - # nested assertion on it. - # - # You typically call this method within another assertion to operate on - # all currently selected elements. You can also pass an element or array - # of elements. - # - # The content of each element is un-encoded, and wrapped in the root - # element +encoded+. It then calls the block with all un-encoded elements. - # - # ==== Examples - # # Selects all bold tags from within the title of an ATOM feed's entries (perhaps to nab a section name prefix) - # assert_select_feed :atom, 1.0 do - # # Select each entry item and then the title item - # assert_select "entry>title" do - # # Run assertions on the encoded title elements - # assert_select_encoded do - # assert_select "b" - # end - # end - # end - # - # - # # Selects all paragraph tags from within the description of an RSS feed - # assert_select_feed :rss, 2.0 do - # # Select description element of each feed item. - # assert_select "channel>item>description" do - # # Run assertions on the encoded elements. - # assert_select_encoded do - # assert_select "p" - # end - # end - # end - def assert_select_encoded(element = nil, &block) - case element - when Array - elements = element - when HTML::Node - elements = [element] - when nil - unless elements = @selected - raise ArgumentError, "First argument is optional, but must be called from a nested assert_select" - end - else - raise ArgumentError, "Argument is optional, and may be node or array of nodes" - end - - fix_content = lambda do |node| - # Gets around a bug in the Rails 1.1 HTML parser. - node.content.gsub(/)?/m) { CGI.escapeHTML($1) } - end - - selected = elements.map do |element| - text = element.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join - root = HTML::Document.new(CGI.unescapeHTML("#{text}")).root - css_select(root, "encoded:root", &block)[0] - end - - begin - old_selected, @selected = @selected, selected - assert_select ":root", &block - ensure - @selected = old_selected - end - end - - # :call-seq: - # assert_select_email { } - # - # Extracts the body of an email and runs nested assertions on it. - # - # You must enable deliveries for this assertion to work, use: - # ActionMailer::Base.perform_deliveries = true - # - # ==== Examples - # - # assert_select_email do - # assert_select "h1", "Email alert" - # end - # - # assert_select_email do - # items = assert_select "ol>li" - # items.each do - # # Work with items here... - # end - # end - # - def assert_select_email(&block) - deliveries = ActionMailer::Base.deliveries - assert !deliveries.empty?, "No e-mail in delivery list" - - for delivery in deliveries - for part in delivery.parts - if part["Content-Type"].to_s =~ /^text\/html\W/ - root = HTML::Document.new(part.body).root - assert_select root, ":root", &block - end - end - end - end - - protected - unless const_defined?(:RJS_STATEMENTS) - RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\"" - RJS_ANY_ID = "\"([^\"])*\"" - RJS_STATEMENTS = { - :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)", - :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)", - :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)", - :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)" - } - [:remove, :show, :hide, :toggle].each do |action| - RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)" - end - RJS_INSERTIONS = ["top", "bottom", "before", "after"] - RJS_INSERTIONS.each do |insertion| - RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)" - end - RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)" - RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})") - RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ - end - - # +assert_select+ and +css_select+ call this to obtain the content in the HTML - # page, or from all the RJS statements, depending on the type of response. - def response_from_page_or_rjs() - content_type = @response.content_type - - if content_type && Mime::JS =~ content_type - body = @response.body.dup - root = HTML::Node.new(nil) - - while true - next if body.sub!(RJS_STATEMENTS[:any]) do |match| - html = unescape_rjs(match) - matches = HTML::Document.new(html).root.children.select { |n| n.tag? } - root.children.concat matches - "" - end - break - end - - root - else - html_document.root - end - end - - # Unescapes a RJS string. - def unescape_rjs(rjs_string) - # RJS encodes double quotes and line breaks. - unescaped= rjs_string.gsub('\"', '"') - unescaped.gsub!(/\\\//, '/') - unescaped.gsub!('\n', "\n") - unescaped.gsub!('\076', '>') - unescaped.gsub!('\074', '<') - # RJS encodes non-ascii characters. - unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')} - unescaped - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/assertions/tag.rb b/actionpack/lib/action_controller/testing/assertions/tag.rb deleted file mode 100644 index d9197b7855..0000000000 --- a/actionpack/lib/action_controller/testing/assertions/tag.rb +++ /dev/null @@ -1,123 +0,0 @@ -module ActionController - module Assertions - # Pair of assertions to testing elements in the HTML output of the response. - module TagAssertions - # Asserts that there is a tag/node/element in the body of the response - # that meets all of the given conditions. The +conditions+ parameter must - # be a hash of any of the following keys (all are optional): - # - # * :tag: the node type must match the corresponding value - # * :attributes: a hash. The node's attributes must match the - # corresponding values in the hash. - # * :parent: a hash. The node's parent must match the - # corresponding hash. - # * :child: a hash. At least one of the node's immediate children - # must meet the criteria described by the hash. - # * :ancestor: a hash. At least one of the node's ancestors must - # meet the criteria described by the hash. - # * :descendant: a hash. At least one of the node's descendants - # must meet the criteria described by the hash. - # * :sibling: a hash. At least one of the node's siblings must - # meet the criteria described by the hash. - # * :after: a hash. The node must be after any sibling meeting - # the criteria described by the hash, and at least one sibling must match. - # * :before: a hash. The node must be before any sibling meeting - # the criteria described by the hash, and at least one sibling must match. - # * :children: a hash, for counting children of a node. Accepts - # the keys: - # * :count: either a number or a range which must equal (or - # include) the number of children that match. - # * :less_than: the number of matching children must be less - # than this number. - # * :greater_than: the number of matching children must be - # greater than this number. - # * :only: another hash consisting of the keys to use - # to match on the children, and only matching children will be - # counted. - # * :content: the textual content of the node must match the - # given value. This will not match HTML tags in the body of a - # tag--only text. - # - # Conditions are matched using the following algorithm: - # - # * if the condition is a string, it must be a substring of the value. - # * if the condition is a regexp, it must match the value. - # * if the condition is a number, the value must match number.to_s. - # * if the condition is +true+, the value must not be +nil+. - # * if the condition is +false+ or +nil+, the value must be +nil+. - # - # === Examples - # - # # Assert that there is a "span" tag - # assert_tag :tag => "span" - # - # # Assert that there is a "span" tag with id="x" - # assert_tag :tag => "span", :attributes => { :id => "x" } - # - # # Assert that there is a "span" tag using the short-hand - # assert_tag :span - # - # # Assert that there is a "span" tag with id="x" using the short-hand - # assert_tag :span, :attributes => { :id => "x" } - # - # # Assert that there is a "span" inside of a "div" - # assert_tag :tag => "span", :parent => { :tag => "div" } - # - # # Assert that there is a "span" somewhere inside a table - # assert_tag :tag => "span", :ancestor => { :tag => "table" } - # - # # Assert that there is a "span" with at least one "em" child - # assert_tag :tag => "span", :child => { :tag => "em" } - # - # # Assert that there is a "span" containing a (possibly nested) - # # "strong" tag. - # assert_tag :tag => "span", :descendant => { :tag => "strong" } - # - # # Assert that there is a "span" containing between 2 and 4 "em" tags - # # as immediate children - # assert_tag :tag => "span", - # :children => { :count => 2..4, :only => { :tag => "em" } } - # - # # Get funky: assert that there is a "div", with an "ul" ancestor - # # and an "li" parent (with "class" = "enum"), and containing a - # # "span" descendant that contains text matching /hello world/ - # assert_tag :tag => "div", - # :ancestor => { :tag => "ul" }, - # :parent => { :tag => "li", - # :attributes => { :class => "enum" } }, - # :descendant => { :tag => "span", - # :child => /hello world/ } - # - # Please note: +assert_tag+ and +assert_no_tag+ only work - # with well-formed XHTML. They recognize a few tags as implicitly self-closing - # (like br and hr and such) but will not work correctly with tags - # that allow optional closing tags (p, li, td). You must explicitly - # close all of your tags to use these assertions. - def assert_tag(*opts) - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}" - end - - # Identical to +assert_tag+, but asserts that a matching tag does _not_ - # exist. (See +assert_tag+ for a full discussion of the syntax.) - # - # === Examples - # # Assert that there is not a "div" containing a "p" - # assert_no_tag :tag => "div", :descendant => { :tag => "p" } - # - # # Assert that an unordered list is empty - # assert_no_tag :tag => "ul", :descendant => { :tag => "li" } - # - # # Assert that there is not a "p" tag with between 1 to 3 "img" tags - # # as immediate children - # assert_no_tag :tag => "p", - # :children => { :count => 1..3, :only => { :tag => "img" } } - def assert_no_tag(*opts) - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}" - end - end - end -end diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index f960698566..7fa1fd93bf 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -14,7 +14,7 @@ module ActionController # Integration::Session directly. class Session include Test::Unit::Assertions - include ActionController::TestCase::Assertions + include ActionDispatch::Assertions include ActionController::TestProcess # The integer HTTP status code of the last request. diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb index a80488e13e..7b4eda58e5 100644 --- a/actionpack/lib/action_controller/testing/test_case.rb +++ b/actionpack/lib/action_controller/testing/test_case.rb @@ -105,12 +105,7 @@ module ActionController class TestCase < ActiveSupport::TestCase include TestProcess - module Assertions - %w(response selector tag dom routing model).each do |kind| - include ActionController::Assertions.const_get("#{kind.camelize}Assertions") - end - end - include Assertions + include ActionDispatch::Assertions # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 4f65dcadee..8b8a1774e4 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -45,6 +45,8 @@ module ActionDispatch autoload :Reloader, 'action_dispatch/middleware/reloader' autoload :MiddlewareStack, 'action_dispatch/middleware/stack' + autoload :Assertions, 'action_dispatch/testing/assertions' + module Http autoload :Headers, 'action_dispatch/http/headers' end diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb new file mode 100644 index 0000000000..96f08f2355 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -0,0 +1,8 @@ +module ActionDispatch + module Assertions + %w(response selector tag dom routing model).each do |kind| + require "action_dispatch/testing/assertions/#{kind}" + include const_get("#{kind.camelize}Assertions") + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb new file mode 100644 index 0000000000..9a917f704a --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -0,0 +1,35 @@ +module ActionDispatch + module Assertions + module DomAssertions + # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) + # + # ==== Examples + # + # # assert that the referenced method generates the appropriate HTML string + # assert_dom_equal 'Apples', link_to("Apples", "http://www.example.com") + # + def assert_dom_equal(expected, actual, message = "") + expected_dom = HTML::Document.new(expected).root + actual_dom = HTML::Document.new(actual).root + full_message = build_message(message, " expected to be == to\n.", expected_dom.to_s, actual_dom.to_s) + + assert_block(full_message) { expected_dom == actual_dom } + end + + # The negated form of +assert_dom_equivalent+. + # + # ==== Examples + # + # # assert that the referenced method does not generate the specified HTML string + # assert_dom_not_equal 'Apples', link_to("Oranges", "http://www.example.com") + # + def assert_dom_not_equal(expected, actual, message = "") + expected_dom = HTML::Document.new(expected).root + actual_dom = HTML::Document.new(actual).root + full_message = build_message(message, " expected to be != to\n.", expected_dom.to_s, actual_dom.to_s) + + assert_block(full_message) { expected_dom != actual_dom } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/model.rb b/actionpack/lib/action_dispatch/testing/assertions/model.rb new file mode 100644 index 0000000000..46714418c6 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/model.rb @@ -0,0 +1,19 @@ +module ActionDispatch + module Assertions + module ModelAssertions + # Ensures that the passed record is valid by Active Record standards and + # returns any error messages if it is not. + # + # ==== Examples + # + # # assert that a newly created record is valid + # model = Model.new + # assert_valid(model) + # + def assert_valid(record) + ::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller) + assert record.valid?, record.errors.full_messages.join("\n") + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb new file mode 100644 index 0000000000..a72ce9084f --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -0,0 +1,156 @@ +module ActionDispatch + module Assertions + # A small suite of assertions that test responses from Rails applications. + module ResponseAssertions + # Asserts that the response is one of the following types: + # + # * :success - Status code was 200 + # * :redirect - Status code was in the 300-399 range + # * :missing - Status code was 404 + # * :error - Status code was in the 500-599 range + # + # You can also pass an explicit status number like assert_response(501) + # or its symbolic equivalent assert_response(:not_implemented). + # See ActionDispatch::StatusCodes for a full list. + # + # ==== Examples + # + # # assert that the response was a redirection + # assert_response :redirect + # + # # assert that the response code was status code 401 (unauthorized) + # assert_response 401 + # + def assert_response(type, message = nil) + validate_request! + + if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") + assert_block("") { true } # to count the assertion + elsif type.is_a?(Fixnum) && @response.response_code == type + assert_block("") { true } # to count the assertion + elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] + assert_block("") { true } # to count the assertion + else + if @controller && @response.error? + exception = @controller.template.instance_variable_get(:@exception) + exception_message = exception && exception.message + assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } + else + assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } + end + end + end + + # Assert that the redirection options passed in match those of the redirect called in the latest action. + # This match can be partial, such that assert_redirected_to(:controller => "weblog") will also + # match the redirection of redirect_to(:controller => "weblog", :action => "show") and so on. + # + # ==== Examples + # + # # assert that the redirection was to the "index" action on the WeblogController + # assert_redirected_to :controller => "weblog", :action => "index" + # + # # assert that the redirection was to the named route login_url + # assert_redirected_to login_url + # + # # assert that the redirection was to the url for @customer + # assert_redirected_to @customer + # + def assert_redirected_to(options = {}, message=nil) + validate_request! + + assert_response(:redirect, message) + return true if options == @response.redirected_to + + # Support partial arguments for hash redirections + if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) + return true if options.all? {|(key, value)| @response.redirected_to[key] == value} + end + + redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) + options_after_normalisation = normalize_argument_to_redirection(options) + + if redirected_to_after_normalisation != options_after_normalisation + flunk "Expected response to be a redirect to <#{options_after_normalisation}> but was a redirect to <#{redirected_to_after_normalisation}>" + end + end + + # Asserts that the request was rendered with the appropriate template file or partials + # + # ==== Examples + # + # # assert that the "new" view template was rendered + # assert_template "new" + # + # # assert that the "_customer" partial was rendered twice + # assert_template :partial => '_customer', :count => 2 + # + # # assert that no partials were rendered + # assert_template :partial => false + # + def assert_template(options = {}, message = nil) + validate_request! + + case options + when NilClass, String + rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier } + msg = build_message(message, + "expecting but rendering with ", + options, rendered.join(', ')) + assert_block(msg) do + if options.nil? + @controller.template.rendered[:template].blank? + else + rendered.any? { |t| t.match(options) } + end + end + when Hash + if expected_partial = options[:partial] + partials = @controller.template.rendered[:partials] + if expected_count = options[:count] + found = partials.detect { |p, _| p.identifier.match(expected_partial) } + actual_count = found.nil? ? 0 : found.second + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) + else + msg = build_message(message, + "expecting partial but action rendered ", + options[:partial], partials.keys) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) + end + else + assert @controller.template.rendered[:partials].empty?, + "Expected no partials to be rendered" + end + end + end + + private + # Proxy to to_param if the object will respond to it. + def parameterize(value) + value.respond_to?(:to_param) ? value.to_param : value + end + + def normalize_argument_to_redirection(fragment) + after_routing = @controller.url_for(fragment) + if after_routing =~ %r{^\w+://.*} + after_routing + else + # FIXME - this should probably get removed. + if after_routing.first != '/' + after_routing = '/' + after_routing + end + @request.protocol + @request.host_with_port + after_routing + end + end + + def validate_request! + unless @request.is_a?(ActionDispatch::Request) + raise ArgumentError, "@request must be an ActionDispatch::Request" + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb new file mode 100644 index 0000000000..89d1a49403 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -0,0 +1,142 @@ +module ActionDispatch + module Assertions + # Suite of assertions to test routes generated by Rails and the handling of requests made to them. + module RoutingAssertions + # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash) + # match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+. + # + # Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes + # requiring a specific HTTP method. The hash should contain a :path with the incoming request path + # and a :method containing the required HTTP verb. + # + # # assert that POSTing to /items will call the create action on ItemsController + # assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post} + # + # You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used + # to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the + # extras argument, appending the query string on the path directly will not work. For example: + # + # # assert that a path of '/items/list/1?view=print' returns the correct options + # assert_recognizes {:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" } + # + # The +message+ parameter allows you to pass in an error message that is displayed upon failure. + # + # ==== Examples + # # Check the default route (i.e., the index action) + # assert_recognizes {:controller => 'items', :action => 'index'}, 'items' + # + # # Test a specific action + # assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list' + # + # # Test an action with a parameter + # assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1' + # + # # Test a custom route + # assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1' + # + # # Check a Simply RESTful generated route + # assert_recognizes list_items_url, 'items/list' + def assert_recognizes(expected_options, path, extras={}, message=nil) + if path.is_a? Hash + request_method = path[:method] + path = path[:path] + else + request_method = nil + end + + ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? + request = recognized_request_for(path, request_method) + + expected_options = expected_options.clone + extras.each_key { |key| expected_options.delete key } unless extras.nil? + + expected_options.stringify_keys! + routing_diff = expected_options.diff(request.path_parameters) + msg = build_message(message, "The recognized options did not match , difference: ", + request.path_parameters, expected_options, expected_options.diff(request.path_parameters)) + assert_block(msg) { request.path_parameters == expected_options } + end + + # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+. + # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in + # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures. + # + # The +defaults+ parameter is unused. + # + # ==== Examples + # # Asserts that the default action is generated for a route with no action + # assert_generates "/items", :controller => "items", :action => "index" + # + # # Tests that the list action is properly routed + # assert_generates "/items/list", :controller => "items", :action => "list" + # + # # Tests the generation of a route with a parameter + # assert_generates "/items/list/1", { :controller => "items", :action => "list", :id => "1" } + # + # # Asserts that the generated route gives us our custom route + # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } + def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) + expected_path = "/#{expected_path}" unless expected_path[0] == ?/ + # Load routes.rb if it hasn't been loaded. + ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? + + generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults) + found_extras = options.reject {|k, v| ! extra_keys.include? k} + + msg = build_message(message, "found extras , not ", found_extras, extras) + assert_block(msg) { found_extras == extras } + + msg = build_message(message, "The generated path did not match ", generated_path, + expected_path) + assert_block(msg) { expected_path == generated_path } + end + + # Asserts that path and options match both ways; in other words, it verifies that path generates + # options and then that options generates path. This essentially combines +assert_recognizes+ + # and +assert_generates+ into one step. + # + # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The + # +message+ parameter allows you to specify a custom error message to display upon failure. + # + # ==== Examples + # # Assert a basic route: a controller with the default action (index) + # assert_routing '/home', :controller => 'home', :action => 'index' + # + # # Test a route generated with a specific controller, action, and parameter (id) + # assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', id => 23 + # + # # Assert a basic route (controller + default action), with an error message if it fails + # assert_routing '/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly' + # + # # Tests a route, providing a defaults hash + # assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"} + # + # # Tests a route with a HTTP method + # assert_routing { :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" } + def assert_routing(path, options, defaults={}, extras={}, message=nil) + assert_recognizes(options, path, extras, message) + + controller, default_controller = options[:controller], defaults[:controller] + if controller && controller.include?(?/) && default_controller && default_controller.include?(?/) + options[:controller] = "/#{controller}" + end + + assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message) + end + + private + # Recognizes the route for a given path. + def recognized_request_for(path, request_method = nil) + path = "/#{path}" unless path.first == '/' + + # Assume given controller + request = ActionController::TestRequest.new + request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method + request.path = path + + ActionController::Routing::Routes.recognize(request) + request + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb new file mode 100644 index 0000000000..dd75cda6b9 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -0,0 +1,632 @@ +#-- +# Copyright (c) 2006 Assaf Arkin (http://labnotes.org) +# Under MIT and/or CC By license. +#++ + +module ActionDispatch + module Assertions + unless const_defined?(:NO_STRIP) + NO_STRIP = %w{pre script style textarea} + end + + # Adds the +assert_select+ method for use in Rails functional + # test cases, which can be used to make assertions on the response HTML of a controller + # action. You can also call +assert_select+ within another +assert_select+ to + # make assertions on elements selected by the enclosing assertion. + # + # Use +css_select+ to select elements without making an assertions, either + # from the response HTML or elements selected by the enclosing assertion. + # + # In addition to HTML responses, you can make the following assertions: + # * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations. + # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions. + # * +assert_select_email+ - Assertions on the HTML body of an e-mail. + # + # Also see HTML::Selector to learn how to use selectors. + module SelectorAssertions + # :call-seq: + # css_select(selector) => array + # css_select(element, selector) => array + # + # Select and return all matching elements. + # + # If called with a single argument, uses that argument as a selector + # to match all elements of the current page. Returns an empty array + # if no match is found. + # + # If called with two arguments, uses the first argument as the base + # element and the second argument as the selector. Attempts to match the + # base element and any of its children. Returns an empty array if no + # match is found. + # + # The selector may be a CSS selector expression (String), an expression + # with substitution values (Array) or an HTML::Selector object. + # + # ==== Examples + # # Selects all div tags + # divs = css_select("div") + # + # # Selects all paragraph tags and does something interesting + # pars = css_select("p") + # pars.each do |par| + # # Do something fun with paragraphs here... + # end + # + # # Selects all list items in unordered lists + # items = css_select("ul>li") + # + # # Selects all form tags and then all inputs inside the form + # forms = css_select("form") + # forms.each do |form| + # inputs = css_select(form, "input") + # ... + # end + # + def css_select(*args) + # See assert_select to understand what's going on here. + arg = args.shift + + if arg.is_a?(HTML::Node) + root = arg + arg = args.shift + elsif arg == nil + raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?" + elsif @selected + matches = [] + + @selected.each do |selected| + subset = css_select(selected, HTML::Selector.new(arg.dup, args.dup)) + subset.each do |match| + matches << match unless matches.any? { |m| m.equal?(match) } + end + end + + return matches + else + root = response_from_page_or_rjs + end + + case arg + when String + selector = HTML::Selector.new(arg, args) + when Array + selector = HTML::Selector.new(*arg) + when HTML::Selector + selector = arg + else raise ArgumentError, "Expecting a selector as the first argument" + end + + selector.select(root) + end + + # :call-seq: + # assert_select(selector, equality?, message?) + # assert_select(element, selector, equality?, message?) + # + # An assertion that selects elements and makes one or more equality tests. + # + # If the first argument is an element, selects all matching elements + # starting from (and including) that element and all its children in + # depth-first order. + # + # If no element if specified, calling +assert_select+ selects from the + # response HTML unless +assert_select+ is called from within an +assert_select+ block. + # + # When called with a block +assert_select+ passes an array of selected elements + # to the block. Calling +assert_select+ from the block, with no element specified, + # runs the assertion on the complete set of elements selected by the enclosing assertion. + # Alternatively the array may be iterated through so that +assert_select+ can be called + # separately for each element. + # + # + # ==== Example + # If the response contains two ordered lists, each with four list elements then: + # assert_select "ol" do |elements| + # elements.each do |element| + # assert_select element, "li", 4 + # end + # end + # + # will pass, as will: + # assert_select "ol" do + # assert_select "li", 8 + # end + # + # The selector may be a CSS selector expression (String), an expression + # with substitution values, or an HTML::Selector object. + # + # === Equality Tests + # + # The equality test may be one of the following: + # * true - Assertion is true if at least one element selected. + # * false - Assertion is true if no element selected. + # * String/Regexp - Assertion is true if the text value of at least + # one element matches the string or regular expression. + # * Integer - Assertion is true if exactly that number of + # elements are selected. + # * Range - Assertion is true if the number of selected + # elements fit the range. + # If no equality test specified, the assertion is true if at least one + # element selected. + # + # To perform more than one equality tests, use a hash with the following keys: + # * :text - Narrow the selection to elements that have this text + # value (string or regexp). + # * :html - Narrow the selection to elements that have this HTML + # content (string or regexp). + # * :count - Assertion is true if the number of selected elements + # is equal to this value. + # * :minimum - Assertion is true if the number of selected + # elements is at least this value. + # * :maximum - Assertion is true if the number of selected + # elements is at most this value. + # + # If the method is called with a block, once all equality tests are + # evaluated the block is called with an array of all matched elements. + # + # ==== Examples + # + # # At least one form element + # assert_select "form" + # + # # Form element includes four input fields + # assert_select "form input", 4 + # + # # Page title is "Welcome" + # assert_select "title", "Welcome" + # + # # Page title is "Welcome" and there is only one title element + # assert_select "title", {:count=>1, :text=>"Welcome"}, + # "Wrong title or more than one title element" + # + # # Page contains no forms + # assert_select "form", false, "This page must contain no forms" + # + # # Test the content and style + # assert_select "body div.header ul.menu" + # + # # Use substitution values + # assert_select "ol>li#?", /item-\d+/ + # + # # All input fields in the form have a name + # assert_select "form input" do + # assert_select "[name=?]", /.+/ # Not empty + # end + def assert_select(*args, &block) + # Start with optional element followed by mandatory selector. + arg = args.shift + + if arg.is_a?(HTML::Node) + # First argument is a node (tag or text, but also HTML root), + # so we know what we're selecting from. + root = arg + arg = args.shift + elsif arg == nil + # This usually happens when passing a node/element that + # happens to be nil. + raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?" + elsif @selected + root = HTML::Node.new(nil) + root.children.concat @selected + else + # Otherwise just operate on the response document. + root = response_from_page_or_rjs + end + + # First or second argument is the selector: string and we pass + # all remaining arguments. Array and we pass the argument. Also + # accepts selector itself. + case arg + when String + selector = HTML::Selector.new(arg, args) + when Array + selector = HTML::Selector.new(*arg) + when HTML::Selector + selector = arg + else raise ArgumentError, "Expecting a selector as the first argument" + end + + # Next argument is used for equality tests. + equals = {} + case arg = args.shift + when Hash + equals = arg + when String, Regexp + equals[:text] = arg + when Integer + equals[:count] = arg + when Range + equals[:minimum] = arg.begin + equals[:maximum] = arg.end + when FalseClass + equals[:count] = 0 + when NilClass, TrueClass + equals[:minimum] = 1 + else raise ArgumentError, "I don't understand what you're trying to match" + end + + # By default we're looking for at least one match. + if equals[:count] + equals[:minimum] = equals[:maximum] = equals[:count] + else + equals[:minimum] = 1 unless equals[:minimum] + end + + # Last argument is the message we use if the assertion fails. + message = args.shift + #- message = "No match made with selector #{selector.inspect}" unless message + if args.shift + raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" + end + + matches = selector.select(root) + # If text/html, narrow down to those elements that match it. + content_mismatch = nil + if match_with = equals[:text] + matches.delete_if do |match| + text = "" + text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding) + stack = match.children.reverse + while node = stack.pop + if node.tag? + stack.concat node.children.reverse + else + content = node.content + content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding) + text << content + end + end + text.strip! unless NO_STRIP.include?(match.name) + unless match_with.is_a?(Regexp) ? (text =~ match_with) : (text == match_with.to_s) + content_mismatch ||= build_message(message, " expected but was\n.", match_with, text) + true + end + end + elsif match_with = equals[:html] + matches.delete_if do |match| + html = match.children.map(&:to_s).join + html.strip! unless NO_STRIP.include?(match.name) + unless match_with.is_a?(Regexp) ? (html =~ match_with) : (html == match_with.to_s) + content_mismatch ||= build_message(message, " expected but was\n.", match_with, html) + true + end + end + end + # Expecting foo found bar element only if found zero, not if + # found one but expecting two. + message ||= content_mismatch if matches.empty? + # Test minimum/maximum occurrence. + min, max = equals[:minimum], equals[:maximum] + message = message || %(Expected #{count_description(min, max)} matching "#{selector.to_s}", found #{matches.size}.) + assert matches.size >= min, message if min + assert matches.size <= max, message if max + + # If a block is given call that block. Set @selected to allow + # nested assert_select, which can be nested several levels deep. + if block_given? && !matches.empty? + begin + in_scope, @selected = @selected, matches + yield matches + ensure + @selected = in_scope + end + end + + # Returns all matches elements. + matches + end + + def count_description(min, max) #:nodoc: + pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')} + + if min && max && (max != min) + "between #{min} and #{max} elements" + elsif min && !(min == 1 && max == 1) + "at least #{min} #{pluralize['element', min]}" + elsif max + "at most #{max} #{pluralize['element', max]}" + end + end + + # :call-seq: + # assert_select_rjs(id?) { |elements| ... } + # assert_select_rjs(statement, id?) { |elements| ... } + # assert_select_rjs(:insert, position, id?) { |elements| ... } + # + # Selects content from the RJS response. + # + # === Narrowing down + # + # With no arguments, asserts that one or more elements are updated or + # inserted by RJS statements. + # + # Use the +id+ argument to narrow down the assertion to only statements + # that update or insert an element with that identifier. + # + # Use the first argument to narrow down assertions to only statements + # of that type. Possible values are :replace, :replace_html, + # :show, :hide, :toggle, :remove and + # :insert_html. + # + # Use the argument :insert followed by an insertion position to narrow + # down the assertion to only statements that insert elements in that + # position. Possible values are :top, :bottom, :before + # and :after. + # + # Using the :remove statement, you will be able to pass a block, but it will + # be ignored as there is no HTML passed for this statement. + # + # === Using blocks + # + # Without a block, +assert_select_rjs+ merely asserts that the response + # contains one or more RJS statements that replace or update content. + # + # With a block, +assert_select_rjs+ also selects all elements used in + # these statements and passes them to the block. Nested assertions are + # supported. + # + # Calling +assert_select_rjs+ with no arguments and using nested asserts + # asserts that the HTML content is returned by one or more RJS statements. + # Using +assert_select+ directly makes the same assertion on the content, + # but without distinguishing whether the content is returned in an HTML + # or JavaScript. + # + # ==== Examples + # + # # Replacing the element foo. + # # page.replace 'foo', ... + # assert_select_rjs :replace, "foo" + # + # # Replacing with the chained RJS proxy. + # # page[:foo].replace ... + # assert_select_rjs :chained_replace, 'foo' + # + # # Inserting into the element bar, top position. + # assert_select_rjs :insert, :top, "bar" + # + # # Remove the element bar + # assert_select_rjs :remove, "bar" + # + # # Changing the element foo, with an image. + # assert_select_rjs "foo" do + # assert_select "img[src=/images/logo.gif"" + # end + # + # # RJS inserts or updates a list with four items. + # assert_select_rjs do + # assert_select "ol>li", 4 + # end + # + # # The same, but shorter. + # assert_select "ol>li", 4 + def assert_select_rjs(*args, &block) + rjs_type = args.first.is_a?(Symbol) ? args.shift : nil + id = args.first.is_a?(String) ? args.shift : nil + + # If the first argument is a symbol, it's the type of RJS statement we're looking + # for (update, replace, insertion, etc). Otherwise, we're looking for just about + # any RJS statement. + if rjs_type + if rjs_type == :insert + position = args.shift + id = args.shift + insertion = "insert_#{position}".to_sym + raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion] + statement = "(#{RJS_STATEMENTS[insertion]})" + else + raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type] + statement = "(#{RJS_STATEMENTS[rjs_type]})" + end + else + statement = "#{RJS_STATEMENTS[:any]}" + end + + # Next argument we're looking for is the element identifier. If missing, we pick + # any element, otherwise we replace it in the statement. + pattern = Regexp.new( + id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement + ) + + # Duplicate the body since the next step involves destroying it. + matches = nil + case rjs_type + when :remove, :show, :hide, :toggle + matches = @response.body.match(pattern) + else + @response.body.gsub(pattern) do |match| + html = unescape_rjs(match) + matches ||= [] + matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? } + "" + end + end + + if matches + assert_block("") { true } # to count the assertion + if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type) + begin + in_scope, @selected = @selected, matches + yield matches + ensure + @selected = in_scope + end + end + matches + else + # RJS statement not found. + case rjs_type + when :remove, :show, :hide, :toggle + flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered." + else + flunk_message = "No RJS statement that replaces or inserts HTML content." + end + flunk args.shift || flunk_message + end + end + + # :call-seq: + # assert_select_encoded(element?) { |elements| ... } + # + # Extracts the content of an element, treats it as encoded HTML and runs + # nested assertion on it. + # + # You typically call this method within another assertion to operate on + # all currently selected elements. You can also pass an element or array + # of elements. + # + # The content of each element is un-encoded, and wrapped in the root + # element +encoded+. It then calls the block with all un-encoded elements. + # + # ==== Examples + # # Selects all bold tags from within the title of an ATOM feed's entries (perhaps to nab a section name prefix) + # assert_select_feed :atom, 1.0 do + # # Select each entry item and then the title item + # assert_select "entry>title" do + # # Run assertions on the encoded title elements + # assert_select_encoded do + # assert_select "b" + # end + # end + # end + # + # + # # Selects all paragraph tags from within the description of an RSS feed + # assert_select_feed :rss, 2.0 do + # # Select description element of each feed item. + # assert_select "channel>item>description" do + # # Run assertions on the encoded elements. + # assert_select_encoded do + # assert_select "p" + # end + # end + # end + def assert_select_encoded(element = nil, &block) + case element + when Array + elements = element + when HTML::Node + elements = [element] + when nil + unless elements = @selected + raise ArgumentError, "First argument is optional, but must be called from a nested assert_select" + end + else + raise ArgumentError, "Argument is optional, and may be node or array of nodes" + end + + fix_content = lambda do |node| + # Gets around a bug in the Rails 1.1 HTML parser. + node.content.gsub(/)?/m) { CGI.escapeHTML($1) } + end + + selected = elements.map do |element| + text = element.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join + root = HTML::Document.new(CGI.unescapeHTML("#{text}")).root + css_select(root, "encoded:root", &block)[0] + end + + begin + old_selected, @selected = @selected, selected + assert_select ":root", &block + ensure + @selected = old_selected + end + end + + # :call-seq: + # assert_select_email { } + # + # Extracts the body of an email and runs nested assertions on it. + # + # You must enable deliveries for this assertion to work, use: + # ActionMailer::Base.perform_deliveries = true + # + # ==== Examples + # + # assert_select_email do + # assert_select "h1", "Email alert" + # end + # + # assert_select_email do + # items = assert_select "ol>li" + # items.each do + # # Work with items here... + # end + # end + # + def assert_select_email(&block) + deliveries = ActionMailer::Base.deliveries + assert !deliveries.empty?, "No e-mail in delivery list" + + for delivery in deliveries + for part in delivery.parts + if part["Content-Type"].to_s =~ /^text\/html\W/ + root = HTML::Document.new(part.body).root + assert_select root, ":root", &block + end + end + end + end + + protected + unless const_defined?(:RJS_STATEMENTS) + RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\"" + RJS_ANY_ID = "\"([^\"])*\"" + RJS_STATEMENTS = { + :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)", + :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)", + :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)", + :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)" + } + [:remove, :show, :hide, :toggle].each do |action| + RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)" + end + RJS_INSERTIONS = ["top", "bottom", "before", "after"] + RJS_INSERTIONS.each do |insertion| + RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)" + end + RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)" + RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})") + RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ + end + + # +assert_select+ and +css_select+ call this to obtain the content in the HTML + # page, or from all the RJS statements, depending on the type of response. + def response_from_page_or_rjs() + content_type = @response.content_type + + if content_type && Mime::JS =~ content_type + body = @response.body.dup + root = HTML::Node.new(nil) + + while true + next if body.sub!(RJS_STATEMENTS[:any]) do |match| + html = unescape_rjs(match) + matches = HTML::Document.new(html).root.children.select { |n| n.tag? } + root.children.concat matches + "" + end + break + end + + root + else + html_document.root + end + end + + # Unescapes a RJS string. + def unescape_rjs(rjs_string) + # RJS encodes double quotes and line breaks. + unescaped= rjs_string.gsub('\"', '"') + unescaped.gsub!(/\\\//, '/') + unescaped.gsub!('\n', "\n") + unescaped.gsub!('\076', '>') + unescaped.gsub!('\074', '<') + # RJS encodes non-ascii characters. + unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')} + unescaped + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb new file mode 100644 index 0000000000..ef6867576e --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb @@ -0,0 +1,123 @@ +module ActionDispatch + module Assertions + # Pair of assertions to testing elements in the HTML output of the response. + module TagAssertions + # Asserts that there is a tag/node/element in the body of the response + # that meets all of the given conditions. The +conditions+ parameter must + # be a hash of any of the following keys (all are optional): + # + # * :tag: the node type must match the corresponding value + # * :attributes: a hash. The node's attributes must match the + # corresponding values in the hash. + # * :parent: a hash. The node's parent must match the + # corresponding hash. + # * :child: a hash. At least one of the node's immediate children + # must meet the criteria described by the hash. + # * :ancestor: a hash. At least one of the node's ancestors must + # meet the criteria described by the hash. + # * :descendant: a hash. At least one of the node's descendants + # must meet the criteria described by the hash. + # * :sibling: a hash. At least one of the node's siblings must + # meet the criteria described by the hash. + # * :after: a hash. The node must be after any sibling meeting + # the criteria described by the hash, and at least one sibling must match. + # * :before: a hash. The node must be before any sibling meeting + # the criteria described by the hash, and at least one sibling must match. + # * :children: a hash, for counting children of a node. Accepts + # the keys: + # * :count: either a number or a range which must equal (or + # include) the number of children that match. + # * :less_than: the number of matching children must be less + # than this number. + # * :greater_than: the number of matching children must be + # greater than this number. + # * :only: another hash consisting of the keys to use + # to match on the children, and only matching children will be + # counted. + # * :content: the textual content of the node must match the + # given value. This will not match HTML tags in the body of a + # tag--only text. + # + # Conditions are matched using the following algorithm: + # + # * if the condition is a string, it must be a substring of the value. + # * if the condition is a regexp, it must match the value. + # * if the condition is a number, the value must match number.to_s. + # * if the condition is +true+, the value must not be +nil+. + # * if the condition is +false+ or +nil+, the value must be +nil+. + # + # === Examples + # + # # Assert that there is a "span" tag + # assert_tag :tag => "span" + # + # # Assert that there is a "span" tag with id="x" + # assert_tag :tag => "span", :attributes => { :id => "x" } + # + # # Assert that there is a "span" tag using the short-hand + # assert_tag :span + # + # # Assert that there is a "span" tag with id="x" using the short-hand + # assert_tag :span, :attributes => { :id => "x" } + # + # # Assert that there is a "span" inside of a "div" + # assert_tag :tag => "span", :parent => { :tag => "div" } + # + # # Assert that there is a "span" somewhere inside a table + # assert_tag :tag => "span", :ancestor => { :tag => "table" } + # + # # Assert that there is a "span" with at least one "em" child + # assert_tag :tag => "span", :child => { :tag => "em" } + # + # # Assert that there is a "span" containing a (possibly nested) + # # "strong" tag. + # assert_tag :tag => "span", :descendant => { :tag => "strong" } + # + # # Assert that there is a "span" containing between 2 and 4 "em" tags + # # as immediate children + # assert_tag :tag => "span", + # :children => { :count => 2..4, :only => { :tag => "em" } } + # + # # Get funky: assert that there is a "div", with an "ul" ancestor + # # and an "li" parent (with "class" = "enum"), and containing a + # # "span" descendant that contains text matching /hello world/ + # assert_tag :tag => "div", + # :ancestor => { :tag => "ul" }, + # :parent => { :tag => "li", + # :attributes => { :class => "enum" } }, + # :descendant => { :tag => "span", + # :child => /hello world/ } + # + # Please note: +assert_tag+ and +assert_no_tag+ only work + # with well-formed XHTML. They recognize a few tags as implicitly self-closing + # (like br and hr and such) but will not work correctly with tags + # that allow optional closing tags (p, li, td). You must explicitly + # close all of your tags to use these assertions. + def assert_tag(*opts) + opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first + tag = find_tag(opts) + assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}" + end + + # Identical to +assert_tag+, but asserts that a matching tag does _not_ + # exist. (See +assert_tag+ for a full discussion of the syntax.) + # + # === Examples + # # Assert that there is not a "div" containing a "p" + # assert_no_tag :tag => "div", :descendant => { :tag => "p" } + # + # # Assert that an unordered list is empty + # assert_no_tag :tag => "ul", :descendant => { :tag => "li" } + # + # # Assert that there is not a "p" tag with between 1 to 3 "img" tags + # # as immediate children + # assert_no_tag :tag => "p", + # :children => { :count => 1..3, :only => { :tag => "img" } } + def assert_no_tag(*opts) + opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first + tag = find_tag(opts) + assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}" + end + end + end +end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 50bed67f7d..22adf97304 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -21,7 +21,7 @@ module ActionView end class TestCase < ActiveSupport::TestCase - include ActionController::TestCase::Assertions + include ActionDispatch::Assertions include ActionController::TestProcess class_inheritable_accessor :helper_class -- cgit v1.2.3 From ba9887c9c02a3671c3d1d893cbee9f360ea2df2d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 13:45:12 -0500 Subject: Switch to action_dispatch rack namespace --- actionpack/lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch/http/request.rb | 4 ++-- actionpack/lib/action_dispatch/middleware/params_parser.rb | 2 +- actionpack/test/dispatch/request_test.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 16a8f66bc4..a2bb9afaa5 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -109,7 +109,7 @@ module ActionController #:nodoc: end def recycle! - @env["action_controller.request.request_parameters"] = {} + @env["action_dispatch.request.request_parameters"] = {} self.query_parameters = {} self.path_parameters = {} @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 2602b344ca..9f0361a874 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -437,13 +437,13 @@ EOM # Override Rack's GET method to support indifferent access def GET - @env["action_controller.request.query_parameters"] ||= normalize_parameters(super) + @env["action_dispatch.request.query_parameters"] ||= normalize_parameters(super) end alias_method :query_parameters, :GET # Override Rack's POST method to support indifferent access def POST - @env["action_controller.request.request_parameters"] ||= normalize_parameters(super) + @env["action_dispatch.request.request_parameters"] ||= normalize_parameters(super) end alias_method :request_parameters, :POST diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index abaee2829e..58d527a6e7 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -11,7 +11,7 @@ module ActionDispatch def call(env) if params = parse_formatted_parameters(env) - env["action_controller.request.request_parameters"] = params + env["action_dispatch.request.request_parameters"] = params end @app.call(env) diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index d57a2a611f..3a85db8aa5 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -307,7 +307,7 @@ class RequestTest < ActiveSupport::TestCase test "restrict method hacking" do [:get, :put, :delete].each do |method| request = stub_request 'REQUEST_METHOD' => method.to_s.upcase, - 'action_controller.request.request_parameters' => { :_method => 'put' } + 'action_dispatch.request.request_parameters' => { :_method => 'put' } assert_equal method, request.method end end -- cgit v1.2.3 From 9bac470c7ac7bc15830a66f416358d8efc74a39d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 14:28:42 -0500 Subject: Group integration test helpers and delegate other helpers to request and response objects --- .../lib/action_controller/testing/integration.rb | 273 ++++++++++----------- actionpack/lib/action_dispatch/http/response.rb | 9 + actionpack/test/controller/integration_test.rb | 12 +- 3 files changed, 136 insertions(+), 158 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 7fa1fd93bf..f088e91de4 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -4,6 +4,114 @@ require 'active_support/test_case' module ActionController module Integration #:nodoc: + module RequestHelpers + # Performs a GET request with the given parameters. + # + # - +path+: The URI (as a String) on which you want to perform a GET + # request. + # - +parameters+: The HTTP parameters that you want to pass. This may + # be +nil+, + # a Hash, or a String that is appropriately encoded + # (application/x-www-form-urlencoded or + # multipart/form-data). + # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will + # automatically be upcased, with the prefix 'HTTP_' added if needed. + # + # This method returns an Response object, which one can use to + # inspect the details of the response. Furthermore, if this method was + # called from an ActionController::IntegrationTest object, then that + # object's @response instance variable will point to the same + # response object. + # + # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, + # +put+, +delete+, and +head+. + def get(path, parameters = nil, headers = nil) + process :get, path, parameters, headers + end + + # Performs a POST request with the given parameters. See get() for more + # details. + def post(path, parameters = nil, headers = nil) + process :post, path, parameters, headers + end + + # Performs a PUT request with the given parameters. See get() for more + # details. + def put(path, parameters = nil, headers = nil) + process :put, path, parameters, headers + end + + # Performs a DELETE request with the given parameters. See get() for + # more details. + def delete(path, parameters = nil, headers = nil) + process :delete, path, parameters, headers + end + + # Performs a HEAD request with the given parameters. See get() for more + # details. + def head(path, parameters = nil, headers = nil) + process :head, path, parameters, headers + end + + # Performs an XMLHttpRequest request with the given parameters, mirroring + # a request from the Prototype library. + # + # The request_method is :get, :post, :put, :delete or :head; the + # parameters are +nil+, a hash, or a url-encoded or multipart string; + # the headers are a hash. Keys are automatically upcased and prefixed + # 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(', ') + process(request_method, path, parameters, headers) + end + alias xhr :xml_http_request + + # Follow a single redirect response. If the last response was not a + # redirect, an exception will be raised. Otherwise, the redirect is + # performed on the location header. + def follow_redirect! + raise "not a redirect! #{status} #{status_message}" unless redirect? + get(response.location) + status + end + + # Performs a request using the specified method, following any subsequent + # redirect. Note that the redirects are followed until the response is + # not a redirect--this means you may run into an infinite loop if your + # redirect loops back to itself. + def request_via_redirect(http_method, path, parameters = nil, headers = nil) + process(http_method, path, parameters, headers) + follow_redirect! while redirect? + status + end + + # Performs a GET request, following any subsequent redirect. + # See +request_via_redirect+ for more information. + def get_via_redirect(path, parameters = nil, headers = nil) + request_via_redirect(:get, path, parameters, headers) + end + + # Performs a POST request, following any subsequent redirect. + # See +request_via_redirect+ for more information. + def post_via_redirect(path, parameters = nil, headers = nil) + request_via_redirect(:post, path, parameters, headers) + end + + # Performs a PUT request, following any subsequent redirect. + # See +request_via_redirect+ for more information. + def put_via_redirect(path, parameters = nil, headers = nil) + request_via_redirect(:put, path, parameters, headers) + end + + # Performs a DELETE request, following any subsequent redirect. + # See +request_via_redirect+ for more information. + def delete_via_redirect(path, parameters = nil, headers = nil) + request_via_redirect(:delete, path, parameters, headers) + end + end + # An integration Session instance represents a set of requests and responses # performed sequentially by some virtual user. Because you can instantiate # multiple sessions and run them side-by-side, you can also mimic (to some @@ -16,18 +124,15 @@ module ActionController include Test::Unit::Assertions include ActionDispatch::Assertions include ActionController::TestProcess + include RequestHelpers - # The integer HTTP status code of the last request. - attr_reader :status - - # The status message that accompanied the status code of the last request. - attr_reader :status_message - - # The body of the last request. - attr_reader :body + %w( status status_message headers body redirect? ).each do |method| + delegate method, :to => :response, :allow_nil => true + end - # The URI of the last request. - attr_reader :path + %w( path ).each do |method| + delegate method, :to => :request, :allow_nil => true + end # The hostname used in the last request. attr_accessor :host @@ -42,9 +147,6 @@ module ActionController # sent with the next request. attr_reader :cookies - # A map of the headers returned by the last response. - attr_reader :headers - # A reference to the controller instance used by the last request. attr_reader :controller @@ -69,8 +171,6 @@ module ActionController # # session.reset! def reset! - @status = @path = @headers = nil - @result = @status_message = nil @https = false @cookies = {} @controller = @request = @response = nil @@ -118,117 +218,6 @@ module ActionController @host = name end - # Follow a single redirect response. If the last response was not a - # redirect, an exception will be raised. Otherwise, the redirect is - # performed on the location header. - def follow_redirect! - raise "not a redirect! #{@status} #{@status_message}" unless redirect? - get(interpret_uri(headers['location'])) - status - end - - # Performs a request using the specified method, following any subsequent - # redirect. Note that the redirects are followed until the response is - # not a redirect--this means you may run into an infinite loop if your - # redirect loops back to itself. - def request_via_redirect(http_method, path, parameters = nil, headers = nil) - send(http_method, path, parameters, headers) - follow_redirect! while redirect? - status - end - - # Performs a GET request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def get_via_redirect(path, parameters = nil, headers = nil) - request_via_redirect(:get, path, parameters, headers) - end - - # Performs a POST request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def post_via_redirect(path, parameters = nil, headers = nil) - request_via_redirect(:post, path, parameters, headers) - end - - # Performs a PUT request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def put_via_redirect(path, parameters = nil, headers = nil) - request_via_redirect(:put, path, parameters, headers) - end - - # Performs a DELETE request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def delete_via_redirect(path, parameters = nil, headers = nil) - request_via_redirect(:delete, path, parameters, headers) - end - - # Returns +true+ if the last response was a redirect. - def redirect? - status/100 == 3 - end - - # Performs a GET request with the given parameters. - # - # - +path+: The URI (as a String) on which you want to perform a GET - # request. - # - +parameters+: The HTTP parameters that you want to pass. This may - # be +nil+, - # a Hash, or a String that is appropriately encoded - # (application/x-www-form-urlencoded or - # multipart/form-data). - # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will - # automatically be upcased, with the prefix 'HTTP_' added if needed. - # - # This method returns an Response object, which one can use to - # inspect the details of the response. Furthermore, if this method was - # called from an ActionController::IntegrationTest object, then that - # object's @response instance variable will point to the same - # response object. - # - # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, - # +put+, +delete+, and +head+. - def get(path, parameters = nil, headers = nil) - process :get, path, parameters, headers - end - - # Performs a POST request with the given parameters. See get() for more - # details. - def post(path, parameters = nil, headers = nil) - process :post, path, parameters, headers - end - - # Performs a PUT request with the given parameters. See get() for more - # details. - def put(path, parameters = nil, headers = nil) - process :put, path, parameters, headers - end - - # Performs a DELETE request with the given parameters. See get() for - # more details. - def delete(path, parameters = nil, headers = nil) - process :delete, path, parameters, headers - end - - # Performs a HEAD request with the given parameters. See get() for more - # details. - def head(path, parameters = nil, headers = nil) - process :head, path, parameters, headers - end - - # Performs an XMLHttpRequest request with the given parameters, mirroring - # a request from the Prototype library. - # - # The request_method is :get, :post, :put, :delete or :head; the - # parameters are +nil+, a hash, or a url-encoded or multipart string; - # the headers are a hash. Keys are automatically upcased and prefixed - # 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(', ') - process(request_method, path, parameters, headers) - end - alias xhr :xml_http_request - # Returns the URL for the given options, according to the rules specified # in the application's routes. def url_for(options) @@ -238,19 +227,14 @@ module ActionController end private - # Tailors the session based on the given URI, setting the HTTPS value - # and the hostname. - def interpret_uri(path) - location = URI.parse(path) - https! URI::HTTPS === location if location.scheme - host! location.host if location.host - location.query ? "#{location.path}?#{location.query}" : location.path - end - # Performs the actual request. def process(method, path, parameters = nil, headers = nil) - path = interpret_uri(path) if path =~ %r{://} - @path = path + if path =~ %r{://} + location = URI.parse(path) + https! URI::HTTPS === location if location.scheme + host! location.host if location.host + path = location.query ? "#{location.path}?#{location.query}" : location.path + end [ControllerCapture, ActionController::ProcessWithTest].each do |mod| unless ActionController::Base < mod @@ -279,7 +263,7 @@ module ActionController string << "#{name}=#{value}; " } } - env = ActionDispatch::Test::MockRequest.env_for(@path, opts) + env = ActionDispatch::Test::MockRequest.env_for(path, opts) (headers || {}).each do |key, value| key = key.to_s.upcase.gsub(/-/, "_") @@ -289,17 +273,12 @@ module ActionController app = Rack::Lint.new(@app) status, headers, body = app.call(env) - response = ::Rack::MockResponse.new(status, headers, body) + mock_response = ::Rack::MockResponse.new(status, headers, body) @request_count += 1 - @request = Request.new(env) - - @response = Response.new - @response.status = @status = response.status - @response.headers = @headers = response.headers - @response.body = @body = response.body + @request = Request.new(env) + @response = Response.from_response(mock_response) - @status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status] @cookies.merge!(@response.cookies) @html_document = nil @@ -312,7 +291,7 @@ module ActionController @controller.send(:set_test_assigns) end - return @status + return response.status end # Get a temporary URL writer object diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index d104dcb8a0..1b12308cc9 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -31,6 +31,14 @@ module ActionDispatch # :nodoc: # end # end class Response < Rack::Response + def self.from_response(response) + new.tap do |resp| + resp.status = response.status + resp.headers = response.headers + resp.body = response.body + end + end + DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request @@ -80,6 +88,7 @@ module ActionDispatch # :nodoc: def message status.to_s.split(' ',2)[1] || StatusCodes::STATUS_CODES[response_code] end + alias_method :status_message, :message # Was the response successful? def success? diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 70fa41aded..c616107324 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -30,7 +30,7 @@ class SessionTest < Test::Unit::TestCase def test_request_via_redirect_uses_given_method path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} - @session.expects(:put).with(path, args, headers) + @session.expects(:process).with(:put, path, args, headers) @session.stubs(:redirect?).returns(false) @session.request_via_redirect(:put, path, args, headers) end @@ -90,16 +90,6 @@ class SessionTest < Test::Unit::TestCase assert_equal '/show', @session.url_for(options) end - def test_redirect_bool_with_status_in_300s - @session.stubs(:status).returns 301 - assert @session.redirect? - end - - def test_redirect_bool_with_status_in_200s - @session.stubs(:status).returns 200 - assert !@session.redirect? - end - def test_get path = "/index"; params = "blah"; headers = {:location => 'blah'} @session.expects(:process).with(:get,path,params,headers) -- cgit v1.2.3 From 64e66cf161ee8db0bdbccb1be18fb760f5a9d24e Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 14:40:46 -0500 Subject: Vendor new Rack::Mock changes --- .../lib/action_controller/testing/integration.rb | 2 +- .../lib/action_controller/testing/process.rb | 2 +- actionpack/lib/action_dispatch.rb | 6 +- actionpack/lib/action_dispatch/extensions/rack.rb | 5 + .../lib/action_dispatch/extensions/rack/mock.rb | 65 +++++ .../lib/action_dispatch/extensions/rack/utils.rb | 262 +++++++++++++++++++++ actionpack/lib/action_dispatch/test/mock.rb | 115 --------- .../lib/action_dispatch/test/uploaded_file.rb | 33 --- 8 files changed, 335 insertions(+), 155 deletions(-) create mode 100644 actionpack/lib/action_dispatch/extensions/rack.rb create mode 100644 actionpack/lib/action_dispatch/extensions/rack/mock.rb create mode 100644 actionpack/lib/action_dispatch/extensions/rack/utils.rb delete mode 100644 actionpack/lib/action_dispatch/test/mock.rb delete mode 100644 actionpack/lib/action_dispatch/test/uploaded_file.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index f088e91de4..ce161ef846 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -263,7 +263,7 @@ module ActionController string << "#{name}=#{value}; " } } - env = ActionDispatch::Test::MockRequest.env_for(path, opts) + env = Rack::MockRequest.env_for(path, opts) (headers || {}).each do |key, value| key = key.to_s.upcase.gsub(/-/, "_") diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index a2bb9afaa5..3a7445f890 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -250,7 +250,7 @@ module ActionController #:nodoc: # # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows): # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary) - TestUploadedFile = ActionDispatch::Test::UploadedFile + TestUploadedFile = Rack::Utils::Multipart::UploadedFile module TestProcess def self.included(base) diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 8b8a1774e4..078e631be4 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -34,6 +34,7 @@ require 'active_support/core/all' gem 'rack', '~> 1.0.0' require 'rack' +require 'action_dispatch/extensions/rack' module ActionDispatch autoload :Request, 'action_dispatch/http/request' @@ -56,11 +57,6 @@ module ActionDispatch autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store' autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store' end - - module Test - autoload :UploadedFile, 'action_dispatch/test/uploaded_file' - autoload :MockRequest, 'action_dispatch/test/mock' - end end autoload :Mime, 'action_dispatch/http/mime_type' diff --git a/actionpack/lib/action_dispatch/extensions/rack.rb b/actionpack/lib/action_dispatch/extensions/rack.rb new file mode 100644 index 0000000000..8a543e2110 --- /dev/null +++ b/actionpack/lib/action_dispatch/extensions/rack.rb @@ -0,0 +1,5 @@ +# Monkey patch in new test helper methods +unless Rack::Utils.respond_to?(:build_nested_query) + require 'action_dispatch/extensions/rack/mock' + require 'action_dispatch/extensions/rack/utils' +end diff --git a/actionpack/lib/action_dispatch/extensions/rack/mock.rb b/actionpack/lib/action_dispatch/extensions/rack/mock.rb new file mode 100644 index 0000000000..d773a74244 --- /dev/null +++ b/actionpack/lib/action_dispatch/extensions/rack/mock.rb @@ -0,0 +1,65 @@ +require 'rack/mock' + +module Rack + class MockRequest + # Return the Rack environment used for a request to +uri+. + def self.env_for(uri="", opts={}) + uri = URI(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + + env = DEFAULT_ENV.dup + + env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" + env["SERVER_NAME"] = uri.host || "example.org" + env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" + env["QUERY_STRING"] = uri.query.to_s + env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path + env["rack.url_scheme"] = uri.scheme || "http" + env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" + + env["SCRIPT_NAME"] = opts[:script_name] || "" + + if opts[:fatal] + env["rack.errors"] = FatalWarner.new + else + env["rack.errors"] = StringIO.new + end + + if params = opts[:params] + if env["REQUEST_METHOD"] == "GET" + params = Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Utils.parse_nested_query(env["QUERY_STRING"])) + env["QUERY_STRING"] = Utils.build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Utils::Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = Utils.build_nested_query(params) + end + else + opts[:input] = params + end + end + end + + opts[:input] ||= "" + if String === opts[:input] + env["rack.input"] = StringIO.new(opts[:input]) + else + env["rack.input"] = opts[:input] + end + + env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s + + opts.each { |field, value| + env[field] = value if String === field + } + + env + end + end +end diff --git a/actionpack/lib/action_dispatch/extensions/rack/utils.rb b/actionpack/lib/action_dispatch/extensions/rack/utils.rb new file mode 100644 index 0000000000..1a46f8a4db --- /dev/null +++ b/actionpack/lib/action_dispatch/extensions/rack/utils.rb @@ -0,0 +1,262 @@ +# -*- encoding: binary -*- + +require 'rack/utils' + +module Rack + module Utils + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + params[k] = v + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + module_function :normalize_params + + def build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{escape(value)}" + else + prefix + end + end + module_function :build_nested_query + + module Multipart + 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 + + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" + + def self.parse_multipart(env) + unless env['CONTENT_TYPE'] =~ + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n + nil + else + boundary = "--#{$1}" + + params = {} + buf = "" + content_length = env['CONTENT_LENGTH'].to_i + input = env['rack.input'] + input.rewind + + boundary_size = Utils.bytesize(boundary) + EOL.size + bufsize = 16384 + + content_length -= boundary_size + + read_buffer = '' + + status = input.read(boundary_size, read_buffer) + raise EOFError, "bad content body" unless status == boundary + EOL + + rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n + + loop { + head = nil + body = '' + filename = content_type = name = nil + + until head && buf =~ rx + if !head && i = buf.index(EOL+EOL) + head = buf.slice!(0, i+2) # First \r\n + buf.slice!(0, 2) # Second \r\n + + filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] + + if content_type || filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end + + next + end + + # Save the read body part. + if head && (boundary_size+4 < buf.size) + body << buf.slice!(0, buf.size - (boundary_size+4)) + end + + c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) + raise EOFError, "bad content body" if c.nil? || c.empty? + buf << c + content_length -= c.size + end + + # Save the rest. + if i = buf.index(rx) + body << buf.slice!(0, i) + buf.slice!(0, boundary_size+2) + + content_length = -1 if $1 == "--" + end + + if filename == "" + # filename is blank which means no file has been selected + data = nil + elsif filename + body.rewind + + # Take the basename of the upload's original filename. + # This handles the full Windows paths given by Internet Explorer + # (and perhaps other broken user agents) without affecting + # those which give the lone filename. + filename =~ /^(?:.*[:\\\/])?(.*)/m + filename = $1 + + data = {:filename => filename, :type => content_type, + :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} + else + data = body + end + + Utils.normalize_params(params, name, data) unless data.nil? + + break if buf.empty? || content_length == -1 + } + + input.rewind + + params + end + end + + def self.build_multipart(params, first = true) + if first + unless params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + + multipart = false + query = lambda { |value| + case value + when Array + value.each(&query) + when Hash + value.values.each(&query) + when UploadedFile + multipart = true + end + } + params.values.each(&query) + return nil unless multipart + end + + flattened_params = Hash.new + + params.each do |key, value| + k = first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + build_multipart(v, false).each { |subkey, subvalue| + flattened_params["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + build_multipart(value, false).each { |subkey, subvalue| + flattened_params[k + subkey] = subvalue + } + else + flattened_params[k] = value + end + end + + if first + flattened_params.map { |name, file| + if file.respond_to?(:original_filename) + ::File.open(file.path, "rb") do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r +Content-Type: #{file.content_type}\r +Content-Length: #{::File.stat(file.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + }.join + "--#{MULTIPART_BOUNDARY}--\r" + else + flattened_params + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/test/mock.rb b/actionpack/lib/action_dispatch/test/mock.rb deleted file mode 100644 index 68e5b108b4..0000000000 --- a/actionpack/lib/action_dispatch/test/mock.rb +++ /dev/null @@ -1,115 +0,0 @@ -module ActionDispatch - module Test - class MockRequest < Rack::MockRequest - MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1" - - class << self - def env_for(path, opts) - method = (opts[:method] || opts["REQUEST_METHOD"]).to_s.upcase - opts[:method] = opts["REQUEST_METHOD"] = method - - path = "/#{path}" unless path[0] == ?/ - uri = URI.parse(path) - uri.host ||= "example.org" - - if URI::HTTPS === uri - opts.update("SERVER_PORT" => "443", "HTTPS" => "on") - end - - if method == "POST" && !opts.has_key?(:input) - opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - - multipart = opts[:params].respond_to?(:any?) && opts[:params].any? { |k, v| UploadedFile === v } - if multipart - opts[:input] = multipart_body(opts.delete(:params)) - opts["CONTENT_LENGTH"] ||= opts[:input].length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}" - else - params = opts.delete(:params) - opts[:input] = case params - when Hash then requestify(params) - when nil then "" - else params - end - end - end - - params = opts[:params] || {} - if params.is_a?(String) - if method == "GET" - uri.query = params - else - opts[:input] = params - end - else - params.stringify_keys! - params.update(::Rack::Utils.parse_query(uri.query)) - uri.query = requestify(params) - end - - ::Rack::MockRequest.env_for(uri.to_s, opts) - end - - private - 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}[#{::Rack::Utils.escape(k)}]" : ::Rack::Utils.escape(k)) - end.join("&") - else - "#{prefix}=#{::Rack::Utils.escape(value)}" - end - end - - 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 - - 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="#{::Rack::Utils.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 - end - end - end -end diff --git a/actionpack/lib/action_dispatch/test/uploaded_file.rb b/actionpack/lib/action_dispatch/test/uploaded_file.rb deleted file mode 100644 index 0ac7db4863..0000000000 --- a/actionpack/lib/action_dispatch/test/uploaded_file.rb +++ /dev/null @@ -1,33 +0,0 @@ -require "tempfile" - -module ActionDispatch - 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 -- cgit v1.2.3 From 00d1a57e9f99a1b2439281cb741fd82ef47a5c55 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 17:26:03 -0500 Subject: Start moving TestRequest and TestResponse into ActionDispatch --- actionpack/lib/action_controller/base/base.rb | 3 +- .../lib/action_controller/testing/integration.rb | 11 +- .../lib/action_controller/testing/process.rb | 170 ++------------------- actionpack/lib/action_dispatch.rb | 2 + .../lib/action_dispatch/extensions/rack/utils.rb | 1 - actionpack/lib/action_dispatch/http/request.rb | 36 +++-- actionpack/lib/action_dispatch/http/response.rb | 56 ------- .../lib/action_dispatch/testing/test_request.rb | 56 +++++++ .../lib/action_dispatch/testing/test_response.rb | 131 ++++++++++++++++ .../test/controller/action_pack_assertions_test.rb | 22 ++- actionpack/test/controller/caching_test.rb | 2 +- actionpack/test/controller/routing_test.rb | 8 +- actionpack/test/controller/test_test.rb | 4 +- actionpack/test/dispatch/test_request_test.rb | 30 ++++ 14 files changed, 279 insertions(+), 253 deletions(-) create mode 100644 actionpack/lib/action_dispatch/testing/test_request.rb create mode 100644 actionpack/lib/action_dispatch/testing/test_response.rb create mode 100644 actionpack/test/dispatch/test_request_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 14c4339c94..99b5963891 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -817,7 +817,8 @@ module ActionController #:nodoc: end def initialize_template_class(response) - @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats) + @template = ActionView::Base.new(self.class.view_paths, {}, self, formats) + response.template = @template if response.respond_to?(:template=) @template.helpers.send :include, self.class.master_helper_module response.redirected_to = nil @performed_render = @performed_redirect = false diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index ce161ef846..4f39ee6a01 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -245,7 +245,7 @@ module ActionController ActionController::Base.clear_last_instantiation! opts = { - :method => method.to_s.upcase, + :method => method, :params => parameters, "SERVER_NAME" => host, @@ -276,17 +276,12 @@ module ActionController mock_response = ::Rack::MockResponse.new(status, headers, body) @request_count += 1 - @request = Request.new(env) - @response = Response.from_response(mock_response) + @request = ActionDispatch::Request.new(env) + @response = ActionDispatch::TestResponse.from_response(mock_response) @cookies.merge!(@response.cookies) @html_document = nil - # Decorate the response with the standard behavior of the - # TestResponse so that things like assert_response can be - # used in integration tests. - @response.extend(TestResponseBehavior) - if @controller = ActionController::Base.last_instantiation @controller.send(:set_test_assigns) end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 3a7445f890..e0f8f026fd 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -1,24 +1,19 @@ require 'rack/session/abstract/id' module ActionController #:nodoc: - class TestRequest < ActionDispatch::Request #:nodoc: + class TestRequest < ActionDispatch::TestRequest #:nodoc: attr_accessor :cookies - attr_accessor :query_parameters, :path - attr_accessor :host - - def self.new(env = {}) - super - end + attr_accessor :query_parameters def initialize(env = {}) - super(Rack::MockRequest.env_for("/").merge(env)) + super - @query_parameters = {} + @query_parameters = {} self.session = TestSession.new self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) - initialize_default_values - initialize_containers + @request_uri = "/" + @cookies = {} end # Wraps raw_post in a StringIO. @@ -36,55 +31,8 @@ module ActionController #:nodoc: end end - def port=(number) - @env["SERVER_PORT"] = number.to_i - end - def action=(action_name) - @query_parameters.update({ "action" => action_name }) - @parameters = nil - end - - # Used to check AbstractRequest's request_uri functionality. - # Disables the use of @path and @request_uri so superclass can handle those. - def set_REQUEST_URI(value) - @env["REQUEST_URI"] = value - @request_uri = nil - @path = nil - end - - def request_uri=(uri) - @request_uri = uri - @path = uri.split("?").first - end - - def request_method=(method) - @request_method = method - end - - def accept=(mime_types) - @env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") - @accepts = nil - end - - def if_modified_since=(last_modified) - @env["HTTP_IF_MODIFIED_SINCE"] = last_modified - end - - def if_none_match=(etag) - @env["HTTP_IF_NONE_MATCH"] = etag - end - - def remote_addr=(addr) - @env['REMOTE_ADDR'] = addr - end - - def request_uri(*args) - @request_uri || super() - end - - def path(*args) - @path || super() + query_parameters.update({ "action" => action_name }) end def assign_parameters(controller_path, action, parameters) @@ -105,34 +53,15 @@ module ActionController #:nodoc: end end raw_post # populate env['RAW_POST_DATA'] - @parameters = nil # reset TestRequest#parameters to use the new path_parameters end def recycle! - @env["action_dispatch.request.request_parameters"] = {} - self.query_parameters = {} - self.path_parameters = {} - @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil - end - - def user_agent=(user_agent) - @env['HTTP_USER_AGENT'] = user_agent + @env.delete_if { |k, v| k =~ /^action_dispatch\.request/ } + self.query_parameters = {} + @headers = nil end private - def initialize_containers - @cookies = {} - end - - def initialize_default_values - @host = "test.host" - @request_uri = "/" - @env['HTTP_USER_AGENT'] = "Rails Testing" - @env['REMOTE_ADDR'] = "0.0.0.0" - @env["SERVER_PORT"] = 80 - @env['REQUEST_METHOD'] = "GET" - end - def url_encoded_request_parameters params = self.request_parameters.dup @@ -145,84 +74,13 @@ module ActionController #:nodoc: end end - # A refactoring of TestResponse to allow the same behavior to be applied - # to the "real" CgiResponse class in integration tests. - module TestResponseBehavior #:nodoc: - def redirect_url_match?(pattern) - ::ActiveSupport::Deprecation.warn("response.redirect_url_match? is deprecated. Use assert_match(/foo/, response.redirect_url) instead", caller) - return false if redirect_url.nil? - p = Regexp.new(pattern) if pattern.class == String - p = pattern if pattern.class == Regexp - return false if p.nil? - p.match(redirect_url) != nil - end - - # Returns the template of the file which was used to - # render this response (or nil) - def rendered - ActiveSupport::Deprecation.warn("response.rendered has been deprecated. Use tempate.rendered instead", caller) - @template.instance_variable_get(:@_rendered) - end - - # A shortcut to the flash. Returns an empty hash if no session flash exists. - def flash - request.session['flash'] || {} - end - - # Do we have a flash? - def has_flash? - !flash.empty? - end - - # Do we have a flash that has contents? - def has_flash_with_contents? - !flash.empty? - end - - # Does the specified flash object exist? - def has_flash_object?(name=nil) - !flash[name].nil? - end - - # Does the specified object exist in the session? - def has_session_object?(name=nil) - !session[name].nil? - end - - # A shortcut to the template.assigns - def template_objects - ActiveSupport::Deprecation.warn("response.template_objects has been deprecated. Use tempate.assigns instead", caller) - @template.assigns || {} - end - - # Does the specified template object exist? - def has_template_object?(name=nil) - ActiveSupport::Deprecation.warn("response.has_template_object? has been deprecated. Use tempate.assigns[name].nil? instead", caller) - !template_objects[name].nil? - end - - # Returns binary content (downloadable file), converted to a String - def binary_content - raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc) - require 'stringio' - - sio = StringIO.new - body_parts.call(self, sio) - - sio.rewind - sio.read - end - end - # Integration test methods such as ActionController::Integration::Session#get # and ActionController::Integration::Session#post return objects of class # TestResponse, which represent the HTTP response results of the requested # controller actions. # # See Response for more information on controller response objects. - class TestResponse < ActionDispatch::Response - include TestResponseBehavior - + class TestResponse < ActionDispatch::TestResponse def recycle! body_parts.clear headers.delete('ETag') @@ -293,7 +151,7 @@ module ActionController #:nodoc: @response.recycle! @html_document = nil - @request.env['REQUEST_METHOD'] = http_method + @request.request_method = http_method @request.action = action.to_s @@ -331,7 +189,7 @@ module ActionController #:nodoc: end def flash - @response.flash + @request.flash end def cookies @@ -348,7 +206,7 @@ module ActionController #:nodoc: options.update(:only_path => true, :action => action) url = ActionController::UrlRewriter.new(@request, parameters) - @request.set_REQUEST_URI(url.rewrite(options)) + @request.request_uri = url.rewrite(options) end end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 078e631be4..53368b3d1d 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -47,6 +47,8 @@ module ActionDispatch autoload :MiddlewareStack, 'action_dispatch/middleware/stack' autoload :Assertions, 'action_dispatch/testing/assertions' + autoload :TestRequest, 'action_dispatch/testing/test_request' + autoload :TestResponse, 'action_dispatch/testing/test_response' module Http autoload :Headers, 'action_dispatch/http/headers' diff --git a/actionpack/lib/action_dispatch/extensions/rack/utils.rb b/actionpack/lib/action_dispatch/extensions/rack/utils.rb index 1a46f8a4db..8e4b94eda0 100644 --- a/actionpack/lib/action_dispatch/extensions/rack/utils.rb +++ b/actionpack/lib/action_dispatch/extensions/rack/utils.rb @@ -83,7 +83,6 @@ module Rack end end - EOL = "\r\n" MULTIPART_BOUNDARY = "AaB03x" def self.parse_multipart(env) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 9f0361a874..c28f59dbd6 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -31,7 +31,7 @@ module ActionDispatch # :get. If the request \method is not listed in the HTTP_METHODS # constant above, an UnknownHttpMethod exception is raised. def request_method - @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") + HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") end # Returns the HTTP request \method used for action processing as a @@ -85,7 +85,7 @@ module ActionDispatch # For backward compatibility, the post \format is extracted from the # X-Post-Data-Format HTTP header if present. def content_type - @content_type ||= begin + @env["action_dispatch.request.content_type"] ||= begin if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/ Mime::Type.lookup($1.strip.downcase) else @@ -100,7 +100,7 @@ module ActionDispatch # Returns the accepted MIME type for the request. def accepts - @accepts ||= begin + @env["action_dispatch.request.accepts"] ||= begin header = @env['HTTP_ACCEPT'].to_s.strip fallback = xhr? ? Mime::JS : Mime::HTML @@ -160,7 +160,7 @@ module ActionDispatch # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of ActionController::Base.use_accept_header def format(view_path = []) - @format ||= + @env["action_dispatch.request.format"] ||= if parameters[:format] Mime[parameters[:format]] elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL) @@ -171,12 +171,11 @@ module ActionDispatch end def formats - @formats = - if ActionController::Base.use_accept_header - Array(Mime[parameters[:format]] || accepts) - else - [format] - end + if ActionController::Base.use_accept_header + Array(Mime[parameters[:format]] || accepts) + else + [format] + end end # Sets the \format by string extension, which can be used to force custom formats @@ -192,7 +191,7 @@ module ActionDispatch # end def format=(extension) parameters[:format] = extension.to_s - @format = Mime::Type.lookup_by_extension(parameters[:format]) + @env["action_dispatch.request.format"] = Mime::Type.lookup_by_extension(parameters[:format]) end # Returns a symbolized version of the :format parameter of the request. @@ -328,6 +327,10 @@ EOM port == standard_port ? '' : ":#{port}" end + def server_port + @env['SERVER_PORT'].to_i + end + # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify # a different tld_length, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk". def domain(tld_length = 1) @@ -396,18 +399,19 @@ EOM # Returns both GET and POST \parameters in a single hash. def parameters - @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access + @env["action_dispatch.request.parameters"] ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access end alias_method :params, :parameters def path_parameters=(parameters) #:nodoc: + @env.delete("action_dispatch.request.symbolized_path_parameters") + @env.delete("action_dispatch.request.parameters") @env["action_dispatch.request.path_parameters"] = parameters - @symbolized_path_parameters = @parameters = nil end # The same as path_parameters with explicitly symbolized keys. def symbolized_path_parameters - @symbolized_path_parameters ||= path_parameters.symbolize_keys + @env["action_dispatch.request.symbolized_path_parameters"] ||= path_parameters.symbolize_keys end # Returns a hash with the \parameters used to form the \path of the request. @@ -464,8 +468,8 @@ EOM @env['rack.session.options'] = options end - def server_port - @env['SERVER_PORT'].to_i + def flash + session['flash'] || {} end private diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 1b12308cc9..2b969323ca 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -31,14 +31,6 @@ module ActionDispatch # :nodoc: # end # end class Response < Rack::Response - def self.from_response(response) - new.tap do |resp| - resp.status = response.status - resp.headers = response.headers - resp.body = response.body - end - end - DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request @@ -47,27 +39,6 @@ module ActionDispatch # :nodoc: attr_writer :header alias_method :headers=, :header= - def template - ActiveSupport::Deprecation.warn("response.template has been deprecated. Use controller.template instead", caller) - @template - end - attr_writer :template - - def session - ActiveSupport::Deprecation.warn("response.session has been deprecated. Use request.session instead", caller) - @request.session - end - - def assigns - ActiveSupport::Deprecation.warn("response.assigns has been deprecated. Use controller.assigns instead", caller) - @template.controller.assigns - end - - def layout - ActiveSupport::Deprecation.warn("response.layout has been deprecated. Use template.layout instead", caller) - @template.layout - end - delegate :default_charset, :to => 'ActionController::Base' def initialize @@ -90,33 +61,6 @@ module ActionDispatch # :nodoc: end alias_method :status_message, :message - # Was the response successful? - def success? - (200..299).include?(response_code) - end - - # Was the URL not found? - def missing? - response_code == 404 - end - - # Were we redirected? - def redirect? - (300..399).include?(response_code) - end - - # Was there a server-side error? - def error? - (500..599).include?(response_code) - end - - alias_method :server_error?, :error? - - # Was there a client client? - def client_error? - (400..499).include?(response_code) - end - def body str = '' each { |part| str << part.to_s } diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb new file mode 100644 index 0000000000..3d20b466d3 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -0,0 +1,56 @@ +module ActionDispatch + class TestRequest < Request + def self.new(env = {}) + super + end + + def initialize(env = {}) + super(Rack::MockRequest.env_for('/').merge(env)) + + self.host = 'test.host' + self.remote_addr = '0.0.0.0' + self.user_agent = 'Rails Testing' + end + + def request_method=(method) + @env['REQUEST_METHOD'] = method.to_s.upcase + end + + def host=(host) + @env['HTTP_HOST'] = host + end + + def port=(number) + @env['SERVER_PORT'] = number.to_i + end + + def request_uri=(uri) + @env['REQUEST_URI'] = uri + end + + def path=(path) + @env['PATH_INFO'] = path + end + + def if_modified_since=(last_modified) + @env['HTTP_IF_MODIFIED_SINCE'] = last_modified + end + + def if_none_match=(etag) + @env['HTTP_IF_NONE_MATCH'] = etag + end + + def remote_addr=(addr) + @env['REMOTE_ADDR'] = addr + end + + def user_agent=(user_agent) + @env['HTTP_USER_AGENT'] = user_agent + end + + def accept=(mime_types) + @env.delete("action_dispatch.request.accepts") + @env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb new file mode 100644 index 0000000000..50c6d85828 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -0,0 +1,131 @@ +module ActionDispatch + class TestResponse < Response + def self.from_response(response) + new.tap do |resp| + resp.status = response.status + resp.headers = response.headers + resp.body = response.body + end + end + + module DeprecatedHelpers + def template + ActiveSupport::Deprecation.warn("response.template has been deprecated. Use controller.template instead", caller) + @template + end + attr_writer :template + + def session + ActiveSupport::Deprecation.warn("response.session has been deprecated. Use request.session instead", caller) + @request.session + end + + def assigns + ActiveSupport::Deprecation.warn("response.assigns has been deprecated. Use controller.assigns instead", caller) + @template.controller.assigns + end + + def layout + ActiveSupport::Deprecation.warn("response.layout has been deprecated. Use template.layout instead", caller) + @template.layout + end + + def redirect_url_match?(pattern) + ::ActiveSupport::Deprecation.warn("response.redirect_url_match? is deprecated. Use assert_match(/foo/, response.redirect_url) instead", caller) + return false if redirect_url.nil? + p = Regexp.new(pattern) if pattern.class == String + p = pattern if pattern.class == Regexp + return false if p.nil? + p.match(redirect_url) != nil + end + + # Returns the template of the file which was used to + # render this response (or nil) + def rendered + ActiveSupport::Deprecation.warn("response.rendered has been deprecated. Use tempate.rendered instead", caller) + @template.instance_variable_get(:@_rendered) + end + + # A shortcut to the flash. Returns an empty hash if no session flash exists. + def flash + ActiveSupport::Deprecation.warn("response.flash has been deprecated. Use request.flash instead", caller) + request.session['flash'] || {} + end + + # Do we have a flash? + def has_flash? + ActiveSupport::Deprecation.warn("response.has_flash? has been deprecated. Use flash.any? instead", caller) + !flash.empty? + end + + # Do we have a flash that has contents? + def has_flash_with_contents? + ActiveSupport::Deprecation.warn("response.has_flash_with_contents? has been deprecated. Use flash.any? instead", caller) + !flash.empty? + end + + # Does the specified flash object exist? + def has_flash_object?(name=nil) + ActiveSupport::Deprecation.warn("response.has_flash_object? has been deprecated. Use flash[name] instead", caller) + !flash[name].nil? + end + + # Does the specified object exist in the session? + def has_session_object?(name=nil) + ActiveSupport::Deprecation.warn("response.has_session_object? has been deprecated. Use session[name] instead", caller) + !session[name].nil? + end + + # A shortcut to the template.assigns + def template_objects + ActiveSupport::Deprecation.warn("response.template_objects has been deprecated. Use tempate.assigns instead", caller) + @template.assigns || {} + end + + # Does the specified template object exist? + def has_template_object?(name=nil) + ActiveSupport::Deprecation.warn("response.has_template_object? has been deprecated. Use tempate.assigns[name].nil? instead", caller) + !template_objects[name].nil? + end + end + include DeprecatedHelpers + + # Was the response successful? + def success? + (200..299).include?(response_code) + end + + # Was the URL not found? + def missing? + response_code == 404 + end + + # Were we redirected? + def redirect? + (300..399).include?(response_code) + end + + # Was there a server-side error? + def error? + (500..599).include?(response_code) + end + alias_method :server_error?, :error? + + # Was there a client client? + def client_error? + (400..499).include?(response_code) + end + + # Returns binary content (downloadable file), converted to a String + def binary_content + raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc) + require 'stringio' + + sio = StringIO.new + body_parts.call(self, sio) + + sio.rewind + sio.read + end + end +end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index dd59999a0c..711640f9a9 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -305,24 +305,30 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # check the empty flashing def test_flash_me_naked process :flash_me_naked - assert !@response.has_flash? - assert !@response.has_flash_with_contents? + assert_deprecated do + assert !@response.has_flash? + assert !@response.has_flash_with_contents? + end end # check if we have flash objects def test_flash_haves process :flash_me - assert @response.has_flash? - assert @response.has_flash_with_contents? - assert @response.has_flash_object?('hello') + assert_deprecated do + assert @response.has_flash? + assert @response.has_flash_with_contents? + assert @response.has_flash_object?('hello') + end end # ensure we don't have flash objects def test_flash_have_nots process :nothing - assert !@response.has_flash? - assert !@response.has_flash_with_contents? - assert_nil @response.flash['hello'] + assert_deprecated do + assert !@response.has_flash? + assert !@response.has_flash_with_contents? + assert_nil @response.flash['hello'] + end end # check if we were rendered by a file-based template? diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index b61a58dd09..df1a1b7683 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -345,7 +345,7 @@ class ActionCacheTest < ActionController::TestCase cached_time = content_to_cache reset! - @request.set_REQUEST_URI "/action_caching_test/expire.xml" + @request.request_uri = "/action_caching_test/expire.xml" get :expire, :format => :xml reset! diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index ef56119751..77abb68f32 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1923,7 +1923,7 @@ class RouteSetTest < Test::Unit::TestCase end end - request.path = "/people" + request.request_uri = "/people" request.env["REQUEST_METHOD"] = "GET" assert_nothing_raised { set.recognize(request) } assert_equal("index", request.path_parameters[:action]) @@ -1945,7 +1945,7 @@ class RouteSetTest < Test::Unit::TestCase } request.recycle! - request.path = "/people/5" + request.request_uri = "/people/5" request.env["REQUEST_METHOD"] = "GET" assert_nothing_raised { set.recognize(request) } assert_equal("show", request.path_parameters[:action]) @@ -2047,7 +2047,7 @@ class RouteSetTest < Test::Unit::TestCase end end - request.path = "/people/5" + request.request_uri = "/people/5" request.env["REQUEST_METHOD"] = "GET" assert_nothing_raised { set.recognize(request) } assert_equal("show", request.path_parameters[:action]) @@ -2059,7 +2059,7 @@ class RouteSetTest < Test::Unit::TestCase assert_equal("update", request.path_parameters[:action]) request.recycle! - request.path = "/people/5.png" + request.request_uri = "/people/5.png" request.env["REQUEST_METHOD"] = "GET" assert_nothing_raised { set.recognize(request) } assert_equal("show", request.path_parameters[:action]) diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index b372980242..919f9815ec 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -201,7 +201,7 @@ XML end def test_process_with_request_uri_with_params_with_explicit_uri - @request.set_REQUEST_URI "/explicit/uri" + @request.request_uri = "/explicit/uri" process :test_uri, :id => 7 assert_equal "/explicit/uri", @response.body end @@ -212,7 +212,7 @@ XML end def test_process_with_query_string_with_explicit_uri - @request.set_REQUEST_URI "/explicit/uri?q=test?extra=question" + @request.request_uri = "/explicit/uri?q=test?extra=question" process :test_query_string assert_equal "q=test?extra=question", @response.body end diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb new file mode 100644 index 0000000000..40a7f04079 --- /dev/null +++ b/actionpack/test/dispatch/test_request_test.rb @@ -0,0 +1,30 @@ +require 'abstract_unit' + +class TestRequestTest < ActiveSupport::TestCase + test "sane defaults" do + env = ActionDispatch::TestRequest.new.env + + assert_equal "GET", env.delete("REQUEST_METHOD") + assert_equal "off", env.delete("HTTPS") + assert_equal "http", env.delete("rack.url_scheme") + assert_equal "example.org", env.delete("SERVER_NAME") + assert_equal "80", env.delete("SERVER_PORT") + assert_equal "/", env.delete("PATH_INFO") + assert_equal "", env.delete("SCRIPT_NAME") + assert_equal "", env.delete("QUERY_STRING") + assert_equal "0", env.delete("CONTENT_LENGTH") + + assert_equal "test.host", env.delete("HTTP_HOST") + assert_equal "0.0.0.0", env.delete("REMOTE_ADDR") + assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT") + + assert_equal [0, 1], env.delete("rack.version") + assert_equal "", env.delete("rack.input").string + assert_kind_of StringIO, env.delete("rack.errors") + assert_equal true, env.delete("rack.multithread") + assert_equal true, env.delete("rack.multiprocess") + assert_equal false, env.delete("rack.run_once") + + assert env.empty?, env.inspect + end +end -- cgit v1.2.3 From f0b9e2861943d32ca73a53ab5fb6f86d10c89b04 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 30 Apr 2009 16:34:00 -0700 Subject: Fix render :json => nil [#2589 state:resolved] --- actionpack/lib/action_controller/base/render.rb | 3 ++- actionpack/test/controller/render_test.rb | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb index 4286577ec5..cc0d878e01 100644 --- a/actionpack/lib/action_controller/base/render.rb +++ b/actionpack/lib/action_controller/base/render.rb @@ -253,7 +253,8 @@ module ActionController response.content_type ||= Mime::JS render_for_text(js) - elsif json = options[:json] + elsif options.include?(:json) + json = options[:json] json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? response.content_type ||= Mime::JSON diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index da063710a9..023bf0eeaa 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -194,6 +194,10 @@ class TestController < ActionController::Base render :inline => "<%= controller_name %>" end + def render_json_nil + render :json => nil + end + def render_json_hello_world render :json => ActiveSupport::JSON.encode(:hello => 'world') end @@ -874,6 +878,12 @@ class RenderTest < ActionController::TestCase assert_equal "The secret is in the sauce\n", @response.body end + def test_render_json_nil + get :render_json_nil + assert_equal 'null', @response.body + assert_equal 'application/json', @response.content_type + end + def test_render_json get :render_json_hello_world assert_equal '{"hello":"world"}', @response.body -- cgit v1.2.3 From e59835bd0934a7458b71b13bf65786c8484905bd Mon Sep 17 00:00:00 2001 From: "John F. Douthat" Date: Tue, 21 Apr 2009 13:35:54 -0500 Subject: Fix action-cached exception responses. Methods raising ActiveRecord::RecordNotFound were returning 404 on first request and 200 OK with blank body on subsequent requests. [#2533 state:committed] Signed-off-by: Jeremy Kemper --- .../lib/action_controller/caching/actions.rb | 10 ++++++- actionpack/test/controller/caching_test.rb | 35 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index d95a346862..2b822b52c8 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -61,7 +61,9 @@ module ActionController #:nodoc: 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(cache_filter, filter_options) + around_filter(filter_options) do |controller, action| + cache_filter.filter(controller, action) + end end end @@ -83,6 +85,12 @@ module ActionController #:nodoc: @options = options end + def filter(controller, action) + should_continue = before(controller) + action.call 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]) diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index df1a1b7683..10b904481d 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -1,5 +1,6 @@ require 'fileutils' require 'abstract_unit' +require 'active_record_unit' CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed @@ -153,6 +154,7 @@ class ActionCachingTestController < ActionController::Base caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" } caches_action :with_layout caches_action :layout_false, :layout => false + caches_action :record_not_found, :four_oh_four, :simple_runtime_error layout 'talk_from_action.erb' @@ -175,6 +177,18 @@ class ActionCachingTestController < ActionController::Base render :text => @cache_this, :layout => true end + def record_not_found + raise ActiveRecord::RecordNotFound, "oops!" + end + + def four_oh_four + render :text => "404'd!", :status => 404 + end + + def simple_runtime_error + raise "oops!" + end + alias_method :show, :index alias_method :edit, :index alias_method :destroy, :index @@ -458,6 +472,27 @@ class ActionCacheTest < ActionController::TestCase assert_response :success end + def test_record_not_found_returns_404_for_multiple_requests + get :record_not_found + assert_response 404 + get :record_not_found + assert_response 404 + end + + def test_four_oh_four_returns_404_for_multiple_requests + get :four_oh_four + assert_response 404 + get :four_oh_four + assert_response 404 + end + + def test_simple_runtime_error_returns_500_for_multiple_requests + get :simple_runtime_error + assert_response 500 + get :simple_runtime_error + assert_response 500 + end + private def content_to_cache assigns(:cache_this) -- cgit v1.2.3 From d54604c352ca444c49e54f4dbbfcaff58f8c7d06 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 19:09:47 -0500 Subject: Depend on unreleased rack 1.1 --- actionpack/lib/action_dispatch.rb | 3 +- actionpack/lib/action_dispatch/extensions/rack.rb | 5 - .../lib/action_dispatch/extensions/rack/mock.rb | 65 ----- .../lib/action_dispatch/extensions/rack/utils.rb | 261 --------------------- actionpack/test/dispatch/test_request_test.rb | 2 +- 5 files changed, 2 insertions(+), 334 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/extensions/rack.rb delete mode 100644 actionpack/lib/action_dispatch/extensions/rack/mock.rb delete mode 100644 actionpack/lib/action_dispatch/extensions/rack/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 53368b3d1d..01e894cde6 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -32,9 +32,8 @@ rescue LoadError end require 'active_support/core/all' -gem 'rack', '~> 1.0.0' +gem 'rack', '~> 1.1.0' require 'rack' -require 'action_dispatch/extensions/rack' module ActionDispatch autoload :Request, 'action_dispatch/http/request' diff --git a/actionpack/lib/action_dispatch/extensions/rack.rb b/actionpack/lib/action_dispatch/extensions/rack.rb deleted file mode 100644 index 8a543e2110..0000000000 --- a/actionpack/lib/action_dispatch/extensions/rack.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Monkey patch in new test helper methods -unless Rack::Utils.respond_to?(:build_nested_query) - require 'action_dispatch/extensions/rack/mock' - require 'action_dispatch/extensions/rack/utils' -end diff --git a/actionpack/lib/action_dispatch/extensions/rack/mock.rb b/actionpack/lib/action_dispatch/extensions/rack/mock.rb deleted file mode 100644 index d773a74244..0000000000 --- a/actionpack/lib/action_dispatch/extensions/rack/mock.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'rack/mock' - -module Rack - class MockRequest - # Return the Rack environment used for a request to +uri+. - def self.env_for(uri="", opts={}) - uri = URI(uri) - uri.path = "/#{uri.path}" unless uri.path[0] == ?/ - - env = DEFAULT_ENV.dup - - env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" - env["SERVER_NAME"] = uri.host || "example.org" - env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" - env["QUERY_STRING"] = uri.query.to_s - env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path - env["rack.url_scheme"] = uri.scheme || "http" - env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" - - env["SCRIPT_NAME"] = opts[:script_name] || "" - - if opts[:fatal] - env["rack.errors"] = FatalWarner.new - else - env["rack.errors"] = StringIO.new - end - - if params = opts[:params] - if env["REQUEST_METHOD"] == "GET" - params = Utils.parse_nested_query(params) if params.is_a?(String) - params.update(Utils.parse_nested_query(env["QUERY_STRING"])) - env["QUERY_STRING"] = Utils.build_nested_query(params) - elsif !opts.has_key?(:input) - opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - if params.is_a?(Hash) - if data = Utils::Multipart.build_multipart(params) - opts[:input] = data - opts["CONTENT_LENGTH"] ||= data.length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" - else - opts[:input] = Utils.build_nested_query(params) - end - else - opts[:input] = params - end - end - end - - opts[:input] ||= "" - if String === opts[:input] - env["rack.input"] = StringIO.new(opts[:input]) - else - env["rack.input"] = opts[:input] - end - - env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s - - opts.each { |field, value| - env[field] = value if String === field - } - - env - end - end -end diff --git a/actionpack/lib/action_dispatch/extensions/rack/utils.rb b/actionpack/lib/action_dispatch/extensions/rack/utils.rb deleted file mode 100644 index 8e4b94eda0..0000000000 --- a/actionpack/lib/action_dispatch/extensions/rack/utils.rb +++ /dev/null @@ -1,261 +0,0 @@ -# -*- encoding: binary -*- - -require 'rack/utils' - -module Rack - module Utils - def normalize_params(params, name, v = nil) - name =~ %r(\A[\[\]]*([^\[\]]+)\]*) - k = $1 || '' - after = $' || '' - - return if k.empty? - - if after == "" - params[k] = v - elsif after == "[]" - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - params[k] << v - elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) - child_key = $1 - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) - normalize_params(params[k].last, child_key, v) - else - params[k] << normalize_params({}, child_key, v) - end - else - params[k] ||= {} - raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) - params[k] = normalize_params(params[k], after, v) - end - - return params - end - module_function :normalize_params - - def build_nested_query(value, prefix = nil) - case value - when Array - value.map { |v| - build_nested_query(v, "#{prefix}[]") - }.join("&") - when Hash - value.map { |k, v| - build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) - }.join("&") - when String - raise ArgumentError, "value must be a Hash" if prefix.nil? - "#{prefix}=#{escape(value)}" - else - prefix - end - end - module_function :build_nested_query - - module Multipart - 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 - - MULTIPART_BOUNDARY = "AaB03x" - - def self.parse_multipart(env) - unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n - nil - else - boundary = "--#{$1}" - - params = {} - buf = "" - content_length = env['CONTENT_LENGTH'].to_i - input = env['rack.input'] - input.rewind - - boundary_size = Utils.bytesize(boundary) + EOL.size - bufsize = 16384 - - content_length -= boundary_size - - read_buffer = '' - - status = input.read(boundary_size, read_buffer) - raise EOFError, "bad content body" unless status == boundary + EOL - - rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n - - loop { - head = nil - body = '' - filename = content_type = name = nil - - until head && buf =~ rx - if !head && i = buf.index(EOL+EOL) - head = buf.slice!(0, i+2) # First \r\n - buf.slice!(0, 2) # Second \r\n - - filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] - name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] - - if content_type || filename - body = Tempfile.new("RackMultipart") - body.binmode if body.respond_to?(:binmode) - end - - next - end - - # Save the read body part. - if head && (boundary_size+4 < buf.size) - body << buf.slice!(0, buf.size - (boundary_size+4)) - end - - c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) - raise EOFError, "bad content body" if c.nil? || c.empty? - buf << c - content_length -= c.size - end - - # Save the rest. - if i = buf.index(rx) - body << buf.slice!(0, i) - buf.slice!(0, boundary_size+2) - - content_length = -1 if $1 == "--" - end - - if filename == "" - # filename is blank which means no file has been selected - data = nil - elsif filename - body.rewind - - # Take the basename of the upload's original filename. - # This handles the full Windows paths given by Internet Explorer - # (and perhaps other broken user agents) without affecting - # those which give the lone filename. - filename =~ /^(?:.*[:\\\/])?(.*)/m - filename = $1 - - data = {:filename => filename, :type => content_type, - :name => name, :tempfile => body, :head => head} - elsif !filename && content_type - body.rewind - - # Generic multipart cases, not coming from a form - data = {:type => content_type, - :name => name, :tempfile => body, :head => head} - else - data = body - end - - Utils.normalize_params(params, name, data) unless data.nil? - - break if buf.empty? || content_length == -1 - } - - input.rewind - - params - end - end - - def self.build_multipart(params, first = true) - if first - unless params.is_a?(Hash) - raise ArgumentError, "value must be a Hash" - end - - multipart = false - query = lambda { |value| - case value - when Array - value.each(&query) - when Hash - value.values.each(&query) - when UploadedFile - multipart = true - end - } - params.values.each(&query) - return nil unless multipart - end - - flattened_params = Hash.new - - params.each do |key, value| - k = first ? key.to_s : "[#{key}]" - - case value - when Array - value.map { |v| - build_multipart(v, false).each { |subkey, subvalue| - flattened_params["#{k}[]#{subkey}"] = subvalue - } - } - when Hash - build_multipart(value, false).each { |subkey, subvalue| - flattened_params[k + subkey] = subvalue - } - else - flattened_params[k] = value - end - end - - if first - flattened_params.map { |name, file| - if file.respond_to?(:original_filename) - ::File.open(file.path, "rb") do |f| - f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r -Content-Type: #{file.content_type}\r -Content-Length: #{::File.stat(file.path).size}\r -\r -#{f.read}\r -EOF - end - else -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"\r -\r -#{file}\r -EOF - end - }.join + "--#{MULTIPART_BOUNDARY}--\r" - else - flattened_params - end - end - end - end -end diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index 40a7f04079..f13f67f0ae 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -18,7 +18,7 @@ class TestRequestTest < ActiveSupport::TestCase assert_equal "0.0.0.0", env.delete("REMOTE_ADDR") assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT") - assert_equal [0, 1], env.delete("rack.version") + assert_equal [1, 0], env.delete("rack.version") assert_equal "", env.delete("rack.input").string assert_kind_of StringIO, env.delete("rack.errors") assert_equal true, env.delete("rack.multithread") -- cgit v1.2.3 From a6fff94baf0ca5d436cbc5c0fa81f690c8024ff5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 19:23:50 -0500 Subject: Move TestRequest cookies accessor into AD TestRequest --- .../lib/action_controller/testing/process.rb | 2 -- .../lib/action_dispatch/testing/test_request.rb | 24 +++++++++++++++++++--- actionpack/test/dispatch/test_request_test.rb | 15 ++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index e0f8f026fd..2fbd89ae1c 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -2,7 +2,6 @@ require 'rack/session/abstract/id' module ActionController #:nodoc: class TestRequest < ActionDispatch::TestRequest #:nodoc: - attr_accessor :cookies attr_accessor :query_parameters def initialize(env = {}) @@ -13,7 +12,6 @@ module ActionController #:nodoc: self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) @request_uri = "/" - @cookies = {} end # Wraps raw_post in a StringIO. diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index 3d20b466d3..bd6c26b69b 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -1,17 +1,24 @@ module ActionDispatch class TestRequest < Request + DEFAULT_ENV = Rack::MockRequest.env_for('/') + def self.new(env = {}) super end def initialize(env = {}) - super(Rack::MockRequest.env_for('/').merge(env)) + super(DEFAULT_ENV.merge(env)) self.host = 'test.host' self.remote_addr = '0.0.0.0' self.user_agent = 'Rails Testing' end + def env + write_cookies! + super + end + def request_method=(method) @env['REQUEST_METHOD'] = method.to_s.upcase end @@ -49,8 +56,19 @@ module ActionDispatch end def accept=(mime_types) - @env.delete("action_dispatch.request.accepts") - @env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") + @env.delete('action_dispatch.request.accepts') + @env['HTTP_ACCEPT'] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") end + + def cookies + @cookies ||= super + end + + private + def write_cookies! + unless @cookies.blank? + @env['HTTP_COOKIE'] = @cookies.map { |name, value| "#{name}=#{value};" }.join(' ') + end + end end end diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index f13f67f0ae..19b5e2988b 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -27,4 +27,19 @@ class TestRequestTest < ActiveSupport::TestCase assert env.empty?, env.inspect end + + test "cookie jar" do + req = ActionDispatch::TestRequest.new + + assert_equal({}, req.cookies) + assert_equal nil, req.env["HTTP_COOKIE"] + + req.cookies["user_name"] = "david" + assert_equal({"user_name" => "david"}, req.cookies) + assert_equal "user_name=david;", req.env["HTTP_COOKIE"] + + req.cookies["login"] = "XJ-122" + assert_equal({"user_name" => "david", "login" => "XJ-122"}, req.cookies) + assert_equal "login=XJ-122; user_name=david;", req.env["HTTP_COOKIE"] + end end -- cgit v1.2.3 From 261ec996de6279a58d5b10f6f36ee1cc1fb96fc6 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 19:36:18 -0500 Subject: Missed stray @request_uri --- actionpack/lib/action_controller/testing/process.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 2fbd89ae1c..d059b37f6d 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -10,8 +10,6 @@ module ActionController #:nodoc: @query_parameters = {} self.session = TestSession.new self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) - - @request_uri = "/" end # Wraps raw_post in a StringIO. -- cgit v1.2.3 From 0fa1e75d416f529c61ef1cbfce230a91417d436c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 20:04:55 -0500 Subject: Set rack.input instead of RAW_POST_DATA in TestRequest --- .../lib/action_controller/testing/process.rb | 39 ++++++---------------- 1 file changed, 11 insertions(+), 28 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index d059b37f6d..d397bc0283 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -12,21 +12,6 @@ module ActionController #:nodoc: self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) end - # Wraps raw_post in a StringIO. - def body_stream #:nodoc: - StringIO.new(raw_post) - end - - # Either the RAW_POST_DATA environment variable or the URL-encoded request - # parameters. - def raw_post - @env['RAW_POST_DATA'] ||= begin - data = url_encoded_request_parameters - data.force_encoding(Encoding::BINARY) if data.respond_to?(:force_encoding) - data - end - end - def action=(action_name) query_parameters.update({ "action" => action_name }) end @@ -48,7 +33,17 @@ module ActionController #:nodoc: path_parameters[key.to_s] = value end end - raw_post # populate env['RAW_POST_DATA'] + + params = self.request_parameters.dup + + %w(controller action only_path).each do |k| + params.delete(k) + params.delete(k.to_sym) + end + + data = params.to_query + @env['CONTENT_LENGTH'] = data.length + @env['rack.input'] = StringIO.new(data) end def recycle! @@ -56,18 +51,6 @@ module ActionController #:nodoc: self.query_parameters = {} @headers = nil end - - private - def url_encoded_request_parameters - params = self.request_parameters.dup - - %w(controller action only_path).each do |k| - params.delete(k) - params.delete(k.to_sym) - end - - params.to_query - end end # Integration test methods such as ActionController::Integration::Session#get -- cgit v1.2.3 From 1fcc7dbcc8dcf7f1d42ca8486ad313f0c805033a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 23:31:20 -0500 Subject: Move TestRequest#query_parameters into AD TestRequest --- actionpack/lib/action_controller/testing/process.rb | 14 ++------------ actionpack/lib/action_dispatch/http/request.rb | 2 +- actionpack/lib/action_dispatch/testing/test_request.rb | 4 ++++ 3 files changed, 7 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index d397bc0283..786dc67e2e 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -2,20 +2,13 @@ require 'rack/session/abstract/id' module ActionController #:nodoc: class TestRequest < ActionDispatch::TestRequest #:nodoc: - attr_accessor :query_parameters - def initialize(env = {}) super - @query_parameters = {} self.session = TestSession.new self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16)) end - def action=(action_name) - query_parameters.update({ "action" => action_name }) - end - def assign_parameters(controller_path, action, parameters) parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action) extra_keys = ActionController::Routing::Routes.extra_keys(parameters) @@ -47,9 +40,8 @@ module ActionController #:nodoc: end def recycle! - @env.delete_if { |k, v| k =~ /^action_dispatch\.request/ } - self.query_parameters = {} - @headers = nil + @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ } + @env['action_dispatch.request.query_parameters'] = {} end end @@ -132,8 +124,6 @@ module ActionController #:nodoc: @html_document = nil @request.request_method = http_method - @request.action = action.to_s - parameters ||= {} @request.assign_parameters(@controller.class.controller_path, action.to_s, parameters) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index c28f59dbd6..e4f3a8f125 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -351,7 +351,7 @@ EOM # Returns the query string, accounting for server idiosyncrasies. def query_string - @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '') + @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].to_s.split('?', 2)[1] || '') end # Returns the request URI, accounting for server idiosyncrasies. diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index bd6c26b69b..5d8cd7e619 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -39,6 +39,10 @@ module ActionDispatch @env['PATH_INFO'] = path end + def action=(action_name) + path_parameters["action"] = action_name.to_s + end + def if_modified_since=(last_modified) @env['HTTP_IF_MODIFIED_SINCE'] = last_modified end -- cgit v1.2.3 From 05bd863c022601bb0bbd17c51adbcb420f349323 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 23:36:47 -0500 Subject: alias method chain process with test --- actionpack/lib/action_controller/testing/process.rb | 9 ++++++--- actionpack/test/controller/filters_test.rb | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 786dc67e2e..8315a160ad 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -132,7 +132,7 @@ module ActionController #:nodoc: build_request_uri(action, parameters) Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest - @controller.process_with_test(@request, @response) + @controller.process(@request, @response) end def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @@ -248,11 +248,14 @@ module ActionController #:nodoc: module ProcessWithTest #:nodoc: def self.included(base) - base.class_eval { attr_reader :assigns } + base.class_eval { + attr_reader :assigns + alias_method_chain :process, :test + } end def process_with_test(*args) - process(*args).tap { set_test_assigns } + process_without_test(*args).tap { set_test_assigns } end private diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index aca7a821c8..bdec5d2d4c 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -674,7 +674,7 @@ class FilterTest < Test::Unit::TestCase request.action = action controller = controller.new if controller.is_a?(Class) @controller = controller - @controller.process_with_test(request, ActionController::TestResponse.new) + @controller.process(request, ActionController::TestResponse.new) end end @@ -917,6 +917,6 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase request.action = action controller = controller.new if controller.is_a?(Class) @controller = controller - @controller.process_with_test(request, ActionController::TestResponse.new) + @controller.process(request, ActionController::TestResponse.new) end end -- cgit v1.2.3 From 664ae187a927ba54c8c7ec6eaf9ad89be291fc95 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 30 Apr 2009 23:43:35 -0500 Subject: Update some old tests to use AC TestProcess --- actionpack/test/controller/filters_test.rb | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index bdec5d2d4c..9e74538310 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -2,6 +2,8 @@ require 'abstract_unit' # FIXME: crashes Ruby 1.9 class FilterTest < Test::Unit::TestCase + include ActionController::TestProcess + class TestController < ActionController::Base before_filter :ensure_login after_filter :clean_up @@ -669,12 +671,11 @@ class FilterTest < Test::Unit::TestCase private def test_process(controller, action = "show") - ActionController::Base.class_eval { include ActionController::ProcessWithTest } unless ActionController::Base < ActionController::ProcessWithTest - request = ActionController::TestRequest.new - request.action = action - controller = controller.new if controller.is_a?(Class) - @controller = controller - @controller.process(request, ActionController::TestResponse.new) + @controller = controller.is_a?(Class) ? controller.new : controller + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + process(action) end end @@ -810,6 +811,7 @@ end class YieldingAroundFiltersTest < Test::Unit::TestCase include PostsController::AroundExceptions + include ActionController::TestProcess def test_filters_registering assert_equal 1, ControllerWithFilterMethod.filter_chain.size @@ -912,11 +914,10 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase protected def test_process(controller, action = "show") - ActionController::Base.class_eval { include ActionController::ProcessWithTest } unless ActionController::Base < ActionController::ProcessWithTest - request = ActionController::TestRequest.new - request.action = action - controller = controller.new if controller.is_a?(Class) - @controller = controller - @controller.process(request, ActionController::TestResponse.new) + @controller = controller.is_a?(Class) ? controller.new : controller + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + process(action) end end -- cgit v1.2.3 From 432e631d5c9cc59db3e5c515c348352a4268eb7f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 1 May 2009 20:12:49 +0100 Subject: Vendor Rack edge ( commit : 815342a8e15db564b766f209ffb1e340233f064f ) --- actionpack/lib/action_dispatch.rb | 7 +- actionpack/lib/action_dispatch/vendor/rack/rack.rb | 90 ++++ .../vendor/rack/rack/adapter/camping.rb | 22 + .../vendor/rack/rack/auth/abstract/handler.rb | 37 ++ .../vendor/rack/rack/auth/abstract/request.rb | 37 ++ .../action_dispatch/vendor/rack/rack/auth/basic.rb | 58 +++ .../vendor/rack/rack/auth/digest/md5.rb | 124 +++++ .../vendor/rack/rack/auth/digest/nonce.rb | 51 ++ .../vendor/rack/rack/auth/digest/params.rb | 55 +++ .../vendor/rack/rack/auth/digest/request.rb | 40 ++ .../vendor/rack/rack/auth/openid.rb | 480 ++++++++++++++++++ .../action_dispatch/vendor/rack/rack/builder.rb | 63 +++ .../action_dispatch/vendor/rack/rack/cascade.rb | 36 ++ .../action_dispatch/vendor/rack/rack/chunked.rb | 49 ++ .../vendor/rack/rack/commonlogger.rb | 61 +++ .../vendor/rack/rack/conditionalget.rb | 47 ++ .../vendor/rack/rack/content_length.rb | 29 ++ .../vendor/rack/rack/content_type.rb | 23 + .../action_dispatch/vendor/rack/rack/deflater.rb | 96 ++++ .../action_dispatch/vendor/rack/rack/directory.rb | 153 ++++++ .../lib/action_dispatch/vendor/rack/rack/file.rb | 88 ++++ .../action_dispatch/vendor/rack/rack/handler.rb | 69 +++ .../vendor/rack/rack/handler/cgi.rb | 61 +++ .../vendor/rack/rack/handler/evented_mongrel.rb | 8 + .../vendor/rack/rack/handler/fastcgi.rb | 88 ++++ .../vendor/rack/rack/handler/lsws.rb | 55 +++ .../vendor/rack/rack/handler/mongrel.rb | 84 ++++ .../vendor/rack/rack/handler/scgi.rb | 59 +++ .../rack/rack/handler/swiftiplied_mongrel.rb | 8 + .../vendor/rack/rack/handler/thin.rb | 18 + .../vendor/rack/rack/handler/webrick.rb | 67 +++ .../lib/action_dispatch/vendor/rack/rack/head.rb | 19 + .../lib/action_dispatch/vendor/rack/rack/lint.rb | 537 +++++++++++++++++++++ .../action_dispatch/vendor/rack/rack/lobster.rb | 65 +++ .../lib/action_dispatch/vendor/rack/rack/lock.rb | 16 + .../vendor/rack/rack/methodoverride.rb | 27 ++ .../lib/action_dispatch/vendor/rack/rack/mime.rb | 204 ++++++++ .../lib/action_dispatch/vendor/rack/rack/mock.rb | 184 +++++++ .../action_dispatch/vendor/rack/rack/recursive.rb | 57 +++ .../action_dispatch/vendor/rack/rack/reloader.rb | 106 ++++ .../action_dispatch/vendor/rack/rack/request.rb | 254 ++++++++++ .../action_dispatch/vendor/rack/rack/response.rb | 183 +++++++ .../vendor/rack/rack/rewindable_input.rb | 98 ++++ .../vendor/rack/rack/session/abstract/id.rb | 142 ++++++ .../vendor/rack/rack/session/cookie.rb | 91 ++++ .../vendor/rack/rack/session/memcache.rb | 109 +++++ .../vendor/rack/rack/session/pool.rb | 100 ++++ .../vendor/rack/rack/showexceptions.rb | 349 +++++++++++++ .../action_dispatch/vendor/rack/rack/showstatus.rb | 106 ++++ .../lib/action_dispatch/vendor/rack/rack/static.rb | 38 ++ .../lib/action_dispatch/vendor/rack/rack/urlmap.rb | 55 +++ .../lib/action_dispatch/vendor/rack/rack/utils.rb | 516 ++++++++++++++++++++ 52 files changed, 5418 insertions(+), 1 deletion(-) create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/file.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/head.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/response.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/static.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 01e894cde6..a57fc5abdd 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -32,7 +32,12 @@ rescue LoadError end require 'active_support/core/all' -gem 'rack', '~> 1.1.0' +begin + gem 'rack', '~> 1.1.0' +rescue Gem::LoadError + $:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack" +end + require 'rack' module ActionDispatch diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack.rb b/actionpack/lib/action_dispatch/vendor/rack/rack.rb new file mode 100644 index 0000000000..371d015690 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack.rb @@ -0,0 +1,90 @@ +# Copyright (C) 2007, 2008, 2009 Christian Neukirchen +# +# Rack is freely distributable under the terms of an MIT-style license. +# See COPYING or http://www.opensource.org/licenses/mit-license.php. + +path = File.expand_path(File.dirname(__FILE__)) +$:.unshift(path) unless $:.include?(path) + + +# The Rack main module, serving as a namespace for all core Rack +# modules and classes. +# +# All modules meant for use in your application are autoloaded here, +# so it should be enough just to require rack.rb in your code. + +module Rack + # The Rack protocol version number implemented. + VERSION = [1,0] + + # Return the Rack protocol version as a dotted string. + def self.version + VERSION.join(".") + end + + # Return the Rack release as a dotted string. + def self.release + "1.0" + end + + autoload :Builder, "rack/builder" + autoload :Cascade, "rack/cascade" + autoload :Chunked, "rack/chunked" + autoload :CommonLogger, "rack/commonlogger" + autoload :ConditionalGet, "rack/conditionalget" + autoload :ContentLength, "rack/content_length" + autoload :ContentType, "rack/content_type" + autoload :File, "rack/file" + autoload :Deflater, "rack/deflater" + autoload :Directory, "rack/directory" + autoload :ForwardRequest, "rack/recursive" + autoload :Handler, "rack/handler" + autoload :Head, "rack/head" + autoload :Lint, "rack/lint" + autoload :Lock, "rack/lock" + autoload :MethodOverride, "rack/methodoverride" + autoload :Mime, "rack/mime" + autoload :Recursive, "rack/recursive" + autoload :Reloader, "rack/reloader" + autoload :ShowExceptions, "rack/showexceptions" + autoload :ShowStatus, "rack/showstatus" + autoload :Static, "rack/static" + autoload :URLMap, "rack/urlmap" + autoload :Utils, "rack/utils" + + autoload :MockRequest, "rack/mock" + autoload :MockResponse, "rack/mock" + + autoload :Request, "rack/request" + autoload :Response, "rack/response" + + module Auth + autoload :Basic, "rack/auth/basic" + autoload :AbstractRequest, "rack/auth/abstract/request" + autoload :AbstractHandler, "rack/auth/abstract/handler" + autoload :OpenID, "rack/auth/openid" + module Digest + autoload :MD5, "rack/auth/digest/md5" + autoload :Nonce, "rack/auth/digest/nonce" + autoload :Params, "rack/auth/digest/params" + autoload :Request, "rack/auth/digest/request" + end + end + + module Session + autoload :Cookie, "rack/session/cookie" + autoload :Pool, "rack/session/pool" + autoload :Memcache, "rack/session/memcache" + end + + # *Adapters* connect Rack with third party web frameworks. + # + # Rack includes an adapter for Camping, see README for other + # frameworks supporting Rack in their code bases. + # + # Refer to the submodules for framework-specific calling details. + + module Adapter + autoload :Camping, "rack/adapter/camping" + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb new file mode 100644 index 0000000000..63bc787f54 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb @@ -0,0 +1,22 @@ +module Rack + module Adapter + class Camping + def initialize(app) + @app = app + end + + def call(env) + env["PATH_INFO"] ||= "" + env["SCRIPT_NAME"] ||= "" + controller = @app.run(env['rack.input'], env) + h = controller.headers + h.each_pair do |k,v| + if v.kind_of? URI + h[k] = v.to_s + end + end + [controller.status, controller.headers, [controller.body.to_s]] + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb new file mode 100644 index 0000000000..214df6299e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb @@ -0,0 +1,37 @@ +module Rack + module Auth + # Rack::Auth::AbstractHandler implements common authentication functionality. + # + # +realm+ should be set for all handlers. + + class AbstractHandler + + attr_accessor :realm + + def initialize(app, realm=nil, &authenticator) + @app, @realm, @authenticator = app, realm, authenticator + end + + + private + + def unauthorized(www_authenticate = challenge) + return [ 401, + { 'Content-Type' => 'text/plain', + 'Content-Length' => '0', + 'WWW-Authenticate' => www_authenticate.to_s }, + [] + ] + end + + def bad_request + return [ 400, + { 'Content-Type' => 'text/plain', + 'Content-Length' => '0' }, + [] + ] + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb new file mode 100644 index 0000000000..1d9ccec685 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb @@ -0,0 +1,37 @@ +module Rack + module Auth + class AbstractRequest + + def initialize(env) + @env = env + end + + def provided? + !authorization_key.nil? + end + + def parts + @parts ||= @env[authorization_key].split(' ', 2) + end + + def scheme + @scheme ||= parts.first.downcase.to_sym + end + + def params + @params ||= parts.last + end + + + private + + AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] + + def authorization_key + @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } + end + + end + + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb new file mode 100644 index 0000000000..9557224648 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb @@ -0,0 +1,58 @@ +require 'rack/auth/abstract/handler' +require 'rack/auth/abstract/request' + +module Rack + module Auth + # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. + # + # Initialize with the Rack application that you want protecting, + # and a block that checks if a username and password pair are valid. + # + # See also: example/protectedlobster.rb + + class Basic < AbstractHandler + + def call(env) + auth = Basic::Request.new(env) + + return unauthorized unless auth.provided? + + return bad_request unless auth.basic? + + if valid?(auth) + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + + unauthorized + end + + + private + + def challenge + 'Basic realm="%s"' % realm + end + + def valid?(auth) + @authenticator.call(*auth.credentials) + end + + class Request < Auth::AbstractRequest + def basic? + :basic == scheme + end + + def credentials + @credentials ||= params.unpack("m*").first.split(/:/, 2) + end + + def username + credentials.first + end + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb new file mode 100644 index 0000000000..e579dc9632 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb @@ -0,0 +1,124 @@ +require 'rack/auth/abstract/handler' +require 'rack/auth/digest/request' +require 'rack/auth/digest/params' +require 'rack/auth/digest/nonce' +require 'digest/md5' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of + # HTTP Digest Authentication, as per RFC 2617. + # + # Initialize with the [Rack] application that you want protecting, + # and a block that looks up a plaintext password for a given username. + # + # +opaque+ needs to be set to a constant base64/hexadecimal string. + # + class MD5 < AbstractHandler + + attr_accessor :opaque + + attr_writer :passwords_hashed + + def initialize(*args) + super + @passwords_hashed = nil + end + + def passwords_hashed? + !!@passwords_hashed + end + + def call(env) + auth = Request.new(env) + + unless auth.provided? + return unauthorized + end + + if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) + return bad_request + end + + if valid?(auth) + if auth.nonce.stale? + return unauthorized(challenge(:stale => true)) + else + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + end + + unauthorized + end + + + private + + QOP = 'auth'.freeze + + def params(hash = {}) + Params.new do |params| + params['realm'] = realm + params['nonce'] = Nonce.new.to_s + params['opaque'] = H(opaque) + params['qop'] = QOP + + hash.each { |k, v| params[k] = v } + end + end + + def challenge(hash = {}) + "Digest #{params(hash)}" + end + + def valid?(auth) + valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) + end + + def valid_qop?(auth) + QOP == auth.qop + end + + def valid_opaque?(auth) + H(opaque) == auth.opaque + end + + def valid_nonce?(auth) + auth.nonce.valid? + end + + def valid_digest?(auth) + digest(auth, @authenticator.call(auth.username)) == auth.response + end + + def md5(data) + ::Digest::MD5.hexdigest(data) + end + + alias :H :md5 + + def KD(secret, data) + H([secret, data] * ':') + end + + def A1(auth, password) + [ auth.username, auth.realm, password ] * ':' + end + + def A2(auth) + [ auth.method, auth.uri ] * ':' + end + + def digest(auth, password) + password_hash = passwords_hashed? ? password : H(A1(auth, password)) + + KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb new file mode 100644 index 0000000000..dbe109f29a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb @@ -0,0 +1,51 @@ +require 'digest/md5' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::Nonce is the default nonce generator for the + # Rack::Auth::Digest::MD5 authentication handler. + # + # +private_key+ needs to set to a constant string. + # + # +time_limit+ can be optionally set to an integer (number of seconds), + # to limit the validity of the generated nonces. + + class Nonce + + class << self + attr_accessor :private_key, :time_limit + end + + def self.parse(string) + new(*string.unpack("m*").first.split(' ', 2)) + end + + def initialize(timestamp = Time.now, given_digest = nil) + @timestamp, @given_digest = timestamp.to_i, given_digest + end + + def to_s + [([ @timestamp, digest ] * ' ')].pack("m*").strip + end + + def digest + ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') + end + + def valid? + digest == @given_digest + end + + def stale? + !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit + end + + def fresh? + !stale? + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb new file mode 100644 index 0000000000..730e2efdc8 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb @@ -0,0 +1,55 @@ +module Rack + module Auth + module Digest + class Params < Hash + + def self.parse(str) + split_header_value(str).inject(new) do |header, param| + k, v = param.split('=', 2) + header[k] = dequote(v) + header + end + end + + def self.dequote(str) # From WEBrick::HTTPUtils + ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup + ret.gsub!(/\\(.)/, "\\1") + ret + end + + def self.split_header_value(str) + str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } + end + + def initialize + super + + yield self if block_given? + end + + def [](k) + super k.to_s + end + + def []=(k, v) + super k.to_s, v.to_s + end + + UNQUOTED = ['qop', 'nc', 'stale'] + + def to_s + inject([]) do |parts, (k, v)| + parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) + parts + end.join(', ') + end + + def quote(str) # From WEBrick::HTTPUtils + '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' + end + + end + end + end +end + diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb new file mode 100644 index 0000000000..a8aa3bf996 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb @@ -0,0 +1,40 @@ +require 'rack/auth/abstract/request' +require 'rack/auth/digest/params' +require 'rack/auth/digest/nonce' + +module Rack + module Auth + module Digest + class Request < Auth::AbstractRequest + + def method + @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] + end + + def digest? + :digest == scheme + end + + def correct_uri? + (@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri + end + + def nonce + @nonce ||= Nonce.parse(params['nonce']) + end + + def params + @params ||= Params.parse(parts.last) + end + + def method_missing(sym) + if params.has_key? key = sym.to_s + return params[key] + end + super + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb new file mode 100644 index 0000000000..c5f6a5143e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb @@ -0,0 +1,480 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net + +gem 'ruby-openid', '~> 2' if defined? Gem +require 'rack/request' +require 'rack/utils' +require 'rack/auth/abstract/handler' +require 'uri' +require 'openid' #gem +require 'openid/extension' #gem +require 'openid/store/memory' #gem + +module Rack + class Request + def openid_request + @env['rack.auth.openid.request'] + end + + def openid_response + @env['rack.auth.openid.response'] + end + end + + module Auth + + # Rack::Auth::OpenID provides a simple method for setting up an OpenID + # Consumer. It requires the ruby-openid library from janrain to operate, + # as well as a rack method of session management. + # + # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. + # + # The OpenID specifications can be found at + # http://openid.net/specs/openid-authentication-1_1.html + # and + # http://openid.net/specs/openid-authentication-2_0.html. Documentation + # for published OpenID extensions and related topics can be found at + # http://openid.net/developers/specs/. + # + # It is recommended to read through the OpenID spec, as well as + # ruby-openid's documentation, to understand what exactly goes on. However + # a setup as simple as the presented examples is enough to provide + # Consumer functionality. + # + # This library strongly intends to utilize the OpenID 2.0 features of the + # ruby-openid library, which provides OpenID 1.0 compatiblity. + # + # NOTE: Due to the amount of data that this library stores in the + # session, Rack::Session::Cookie may fault. + + class OpenID + + class NoSession < RuntimeError; end + class BadExtension < RuntimeError; end + # Required for ruby-openid + ValidStatus = [:success, :setup_needed, :cancel, :failure] + + # = Arguments + # + # The first argument is the realm, identifying the site they are trusting + # with their identity. This is required, also treated as the trust_root + # in OpenID 1.x exchanges. + # + # The optional second argument is a hash of options. + # + # == Options + # + # :return_to defines the url to return to after the client + # authenticates with the openid service provider. This url should point + # to where Rack::Auth::OpenID is mounted. If :return_to is not + # provided, return_to will be the current url which allows flexibility + # with caveats. + # + # :session_key defines the key to the session hash in the env. + # It defaults to 'rack.session'. + # + # :openid_param defines at what key in the request parameters to + # find the identifier to resolve. As per the 2.0 spec, the default is + # 'openid_identifier'. + # + # :store defined what OpenID Store to use for persistant + # information. By default a Store::Memory will be used. + # + # :immediate as true will make initial requests to be of an + # immediate type. This is false by default. See OpenID specification + # documentation. + # + # :extensions should be a hash of openid extension + # implementations. The key should be the extension main module, the value + # should be an array of arguments for extension::Request.new. + # The hash is iterated over and passed to #add_extension for processing. + # Please see #add_extension for further documentation. + # + # == Examples + # + # simple_oid = OpenID.new('http://mysite.com/') + # + # return_oid = OpenID.new('http://mysite.com/', { + # :return_to => 'http://mysite.com/openid' + # }) + # + # complex_oid = OpenID.new('http://mysite.com/', + # :immediate => true, + # :extensions => { + # ::OpenID::SReg => [['email'],['nickname']] + # } + # ) + # + # = Advanced + # + # Most of the functionality of this library is encapsulated such that + # expansion and overriding functions isn't difficult nor tricky. + # Alternately, to avoid opening up singleton objects or subclassing, a + # wrapper rack middleware can be composed to act upon Auth::OpenID's + # responses. See #check and #finish for locations of pertinent data. + # + # == Responses + # + # To change the responses that Auth::OpenID returns, override the methods + # #redirect, #bad_request, #unauthorized, #access_denied, and + # #foreign_server_failure. + # + # Additionally #confirm_post_params is used when the URI would exceed + # length limits on a GET request when doing the initial verification + # request. + # + # == Processing + # + # To change methods of processing completed transactions, override the + # methods #success, #setup_needed, #cancel, and #failure. Please ensure + # the returned object is a rack compatible response. + # + # The first argument is an OpenID::Response, the second is a + # Rack::Request of the current request, the last is the hash used in + # ruby-openid handling, which can be found manually at + # env['rack.session'][:openid]. + # + # This is useful if you wanted to expand the processing done, such as + # setting up user accounts. + # + # oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to + # def oid_app.success oid, request, session + # user = Models::User[oid.identity_url] + # user ||= Models::User.create_from_openid oid + # request['rack.session'][:user] = user.id + # redirect MyApp.site_home + # end + # + # site_map['/openid'] = oid_app + # map = Rack::URLMap.new site_map + # ... + + def initialize(realm, options={}) + realm = URI(realm) + raise ArgumentError, "Invalid realm: #{realm}" \ + unless realm.absolute? \ + and realm.fragment.nil? \ + and realm.scheme =~ /^https?$/ \ + and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/ + realm.path = '/' if realm.path.empty? + @realm = realm.to_s + + if ruri = options[:return_to] + ruri = URI(ruri) + raise ArgumentError, "Invalid return_to: #{ruri}" \ + unless ruri.absolute? \ + and ruri.scheme =~ /^https?$/ \ + and ruri.fragment.nil? + raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \ + unless self.within_realm?(ruri) + @return_to = ruri.to_s + end + + @session_key = options[:session_key] || 'rack.session' + @openid_param = options[:openid_param] || 'openid_identifier' + @store = options[:store] || ::OpenID::Store::Memory.new + @immediate = !!options[:immediate] + + @extensions = {} + if extensions = options.delete(:extensions) + extensions.each do |ext, args| + add_extension ext, *args + end + end + + # Undocumented, semi-experimental + @anonymous = !!options[:anonymous] + end + + attr_reader :realm, :return_to, :session_key, :openid_param, :store, + :immediate, :extensions + + # Sets up and uses session data at :openid within the session. + # Errors in this setup will raise a NoSession exception. + # + # If the parameter 'openid.mode' is set, which implies a followup from + # the openid server, processing is passed to #finish and the result is + # returned. However, if there is no appropriate openid information in the + # session, a 400 error is returned. + # + # If the parameter specified by options[:openid_param] is + # present, processing is passed to #check and the result is returned. + # + # If neither of these conditions are met, #unauthorized is called. + + def call(env) + env['rack.auth.openid'] = self + env_session = env[@session_key] + unless env_session and env_session.is_a?(Hash) + raise NoSession, 'No compatible session' + end + # let us work in our own namespace... + session = (env_session[:openid] ||= {}) + unless session and session.is_a?(Hash) + raise NoSession, 'Incompatible openid session' + end + + request = Rack::Request.new(env) + consumer = ::OpenID::Consumer.new(session, @store) + + if mode = request.GET['openid.mode'] + if session.key?(:openid_param) + finish(consumer, session, request) + else + bad_request + end + elsif request.GET[@openid_param] + check(consumer, session, request) + else + unauthorized + end + end + + # As the first part of OpenID consumer action, #check retrieves the data + # required for completion. + # + # If all parameters fit within the max length of a URI, a 303 redirect + # will be returned. Otherwise #confirm_post_params will be called. + # + # Any messages from OpenID's request are logged to env['rack.errors'] + # + # env['rack.auth.openid.request'] is the openid checkid request + # instance. + # + # session[:openid_param] is set to the openid identifier + # provided by the user. + # + # session[:return_to] is set to the return_to uri given to the + # identity provider. + + def check(consumer, session, req) + oid = consumer.begin(req.GET[@openid_param], @anonymous) + req.env['rack.auth.openid.request'] = oid + req.env['rack.errors'].puts(oid.message) + p oid if $DEBUG + + ## Extension support + extensions.each do |ext,args| + oid.add_extension(ext::Request.new(*args)) + end + + session[:openid_param] = req.GET[openid_param] + return_to_uri = return_to ? return_to : req.url + session[:return_to] = return_to_uri + immediate = session.key?(:setup_needed) ? false : immediate + + if oid.send_redirect?(realm, return_to_uri, immediate) + uri = oid.redirect_url(realm, return_to_uri, immediate) + redirect(uri) + else + confirm_post_params(oid, realm, return_to_uri, immediate) + end + rescue ::OpenID::DiscoveryFailure => e + # thrown from inside OpenID::Consumer#begin by yadis stuff + req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n") + return foreign_server_failure + end + + # This is the final portion of authentication. + # If successful, a redirect to the realm is be returned. + # Data gathered from extensions are stored in session[:openid] with the + # extension's namespace uri as the key. + # + # Any messages from OpenID's response are logged to env['rack.errors'] + # + # env['rack.auth.openid.response'] will contain the openid + # response. + + def finish(consumer, session, req) + oid = consumer.complete(req.GET, req.url) + req.env['rack.auth.openid.response'] = oid + req.env['rack.errors'].puts(oid.message) + p oid if $DEBUG + + raise unless ValidStatus.include?(oid.status) + __send__(oid.status, oid, req, session) + end + + # The first argument should be the main extension module. + # The extension module should contain the constants: + # * class Request, should have OpenID::Extension as an ancestor + # * class Response, should have OpenID::Extension as an ancestor + # * string NS_URI, which defining the namespace of the extension + # + # All trailing arguments will be passed to extension::Request.new in + # #check. + # The openid response will be passed to + # extension::Response#from_success_response, #get_extension_args will be + # called on the result to attain the gathered data. + # + # This method returns the key at which the response data will be found in + # the session, which is the namespace uri by default. + + def add_extension(ext, *args) + raise BadExtension unless valid_extension?(ext) + extensions[ext] = args + return ext::NS_URI + end + + # Checks the validitity, in the context of usage, of a submitted + # extension. + + def valid_extension?(ext) + if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) } + raise ArgumentError, 'Extension is missing constants.' + elsif not ext::Response.respond_to?(:from_success_response) + raise ArgumentError, 'Response is missing required method.' + end + return true + rescue + return false + end + + # Checks the provided uri to ensure it'd be considered within the realm. + # is currently not compatible with wildcard realms. + + def within_realm? uri + uri = URI.parse(uri.to_s) + realm = URI.parse(self.realm) + return false unless uri.absolute? + return false unless uri.path[0, realm.path.size] == realm.path + return false unless uri.host == realm.host or realm.host[/^\*\./] + # for wildcard support, is awkward with URI limitations + realm_match = Regexp.escape(realm.host). + sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$' + return false unless uri.host.match(realm_match) + return true + end + alias_method :include?, :within_realm? + + protected + + ### These methods define some of the boilerplate responses. + + # Returns an html form page for posting to an Identity Provider if the + # GET request would exceed the upper URI length limit. + + def confirm_post_params(oid, realm, return_to, immediate) + Rack::Response.new.finish do |r| + r.write 'Confirm...' + r.write oid.form_markup(realm, return_to, immediate) + r.write '' + end + end + + # Returns a 303 redirect with the destination of that provided by the + # argument. + + def redirect(uri) + [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain', + 'Location' => uri}, + [] ] + end + + # Returns an empty 400 response. + + def bad_request + [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'}, + [''] ] + end + + # Returns a basic unauthorized 401 response. + + def unauthorized + [ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'}, + ['Unauthorized.'] ] + end + + # Returns a basic access denied 403 response. + + def access_denied + [ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'}, + ['Access denied.'] ] + end + + # Returns a 503 response to be used if communication with the remote + # OpenID server fails. + + def foreign_server_failure + [ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'}, + ['Foreign server failure.'] ] + end + + private + + ### These methods are called after a transaction is completed, depending + # on its outcome. These should all return a rack compatible response. + # You'd want to override these to provide additional functionality. + + # Called to complete processing on a successful transaction. + # Within the openid session, :openid_identity and :openid_identifier are + # set to the user friendly and the standard representation of the + # validated identity. All other data in the openid session is cleared. + + def success(oid, request, session) + session.clear + session[:openid_identity] = oid.display_identifier + session[:openid_identifier] = oid.identity_url + extensions.keys.each do |ext| + label = ext.name[/[^:]+$/].downcase + response = ext::Response.from_success_response(oid) + session[label] = response.data + end + redirect(realm) + end + + # Called if the Identity Provider indicates further setup by the user is + # required. + # The identifier is retrived from the openid session at :openid_param. + # And :setup_needed is set to true to prevent looping. + + def setup_needed(oid, request, session) + identifier = session[:openid_param] + session[:setup_needed] = true + redirect req.script_name + '?' + openid_param + '=' + identifier + end + + # Called if the user indicates they wish to cancel identification. + # Data within openid session is cleared. + + def cancel(oid, request, session) + session.clear + access_denied + end + + # Called if the Identity Provider indicates the user is unable to confirm + # their identity. Data within the openid session is left alone, in case + # of swarm auth attacks. + + def failure(oid, request, session) + unauthorized + end + end + + # A class developed out of the request to use OpenID as an authentication + # middleware. The request will be sent to the OpenID instance unless the + # block evaluates to true. For example in rackup, you can use it as such: + # + # use Rack::Session::Pool + # use Rack::Auth::OpenIDAuth, realm, openid_options do |env| + # env['rack.session'][:authkey] == a_string + # end + # run RackApp + # + # Or simply: + # + # app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth + + class OpenIDAuth < Rack::Auth::AbstractHandler + attr_reader :oid + def initialize(app, realm, options={}, &auth) + @oid = OpenID.new(realm, options) + super(app, &auth) + end + + def call(env) + to = auth.call(env) ? @app : @oid + to.call env + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb new file mode 100644 index 0000000000..295235e56a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb @@ -0,0 +1,63 @@ +module Rack + # Rack::Builder implements a small DSL to iteratively construct Rack + # applications. + # + # Example: + # + # app = Rack::Builder.new { + # use Rack::CommonLogger + # use Rack::ShowExceptions + # map "/lobster" do + # use Rack::Lint + # run Rack::Lobster.new + # end + # } + # + # Or + # + # app = Rack::Builder.app do + # use Rack::CommonLogger + # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } + # end + # + # +use+ adds a middleware to the stack, +run+ dispatches to an application. + # You can use +map+ to construct a Rack::URLMap in a convenient way. + + class Builder + def initialize(&block) + @ins = [] + instance_eval(&block) if block_given? + end + + def self.app(&block) + self.new(&block).to_app + end + + def use(middleware, *args, &block) + @ins << lambda { |app| middleware.new(app, *args, &block) } + end + + def run(app) + @ins << app #lambda { |nothing| app } + end + + def map(path, &block) + if @ins.last.kind_of? Hash + @ins.last[path] = self.class.new(&block).to_app + else + @ins << {} + map(path, &block) + end + end + + def to_app + @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last + inner_app = @ins.last + @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } + end + + def call(env) + to_app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb new file mode 100644 index 0000000000..a038aa1105 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb @@ -0,0 +1,36 @@ +module Rack + # Rack::Cascade tries an request on several apps, and returns the + # first response that is not 404 (or in a list of configurable + # status codes). + + class Cascade + attr_reader :apps + + def initialize(apps, catch=404) + @apps = apps + @catch = [*catch] + end + + def call(env) + status = headers = body = nil + raise ArgumentError, "empty cascade" if @apps.empty? + @apps.each { |app| + begin + status, headers, body = app.call(env) + break unless @catch.include?(status.to_i) + end + } + [status, headers, body] + end + + def add app + @apps << app + end + + def include? app + @apps.include? app + end + + alias_method :<<, :add + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb new file mode 100644 index 0000000000..280d89dd65 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb @@ -0,0 +1,49 @@ +require 'rack/utils' + +module Rack + + # Middleware that applies chunked transfer encoding to response bodies + # when the response does not include a Content-Length header. + class Chunked + include Rack::Utils + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash.new(headers) + + if env['HTTP_VERSION'] == 'HTTP/1.0' || + STATUS_WITH_NO_ENTITY_BODY.include?(status) || + headers['Content-Length'] || + headers['Transfer-Encoding'] + [status, headers.to_hash, body] + else + dup.chunk(status, headers, body) + end + end + + def chunk(status, headers, body) + @body = body + headers.delete('Content-Length') + headers['Transfer-Encoding'] = 'chunked' + [status, headers.to_hash, self] + end + + def each + term = "\r\n" + @body.each do |chunk| + size = bytesize(chunk) + next if size == 0 + yield [size.to_s(16), term, chunk, term].join + end + yield ["0", term, "", term].join + end + + def close + @body.close if @body.respond_to?(:close) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb new file mode 100644 index 0000000000..5e68ac626d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb @@ -0,0 +1,61 @@ +module Rack + # Rack::CommonLogger forwards every request to an +app+ given, and + # logs a line in the Apache common log format to the +logger+, or + # rack.errors by default. + + class CommonLogger + def initialize(app, logger=nil) + @app = app + @logger = logger + end + + def call(env) + dup._call(env) + end + + def _call(env) + @env = env + @logger ||= self + @time = Time.now + @status, @header, @body = @app.call(env) + [@status, @header, self] + end + + def close + @body.close if @body.respond_to? :close + end + + # By default, log to rack.errors. + def <<(str) + @env["rack.errors"].write(str) + @env["rack.errors"].flush + end + + def each + length = 0 + @body.each { |part| + length += part.size + yield part + } + + @now = Time.now + + # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common + # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - + # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % + @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % + [ + @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", + @env["REMOTE_USER"] || "-", + @now.strftime("%d/%b/%Y %H:%M:%S"), + @env["REQUEST_METHOD"], + @env["PATH_INFO"], + @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], + @env["HTTP_VERSION"], + @status.to_s[0..3], + (length.zero? ? "-" : length.to_s), + @now - @time + ] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb new file mode 100644 index 0000000000..046ebdb00a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb @@ -0,0 +1,47 @@ +require 'rack/utils' + +module Rack + + # Middleware that enables conditional GET using If-None-Match and + # If-Modified-Since. The application should set either or both of the + # Last-Modified or Etag response headers according to RFC 2616. When + # either of the conditions is met, the response body is set to be zero + # length and the response status is set to 304 Not Modified. + # + # Applications that defer response body generation until the body's each + # message is received will avoid response body generation completely when + # a conditional GET matches. + # + # Adapted from Michael Klishin's Merb implementation: + # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb + class ConditionalGet + def initialize(app) + @app = app + end + + def call(env) + return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD']) + + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + if etag_matches?(env, headers) || modified_since?(env, headers) + status = 304 + headers.delete('Content-Type') + headers.delete('Content-Length') + body = [] + end + [status, headers, body] + end + + private + def etag_matches?(env, headers) + etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH'] + end + + def modified_since?(env, headers) + last_modified = headers['Last-Modified'] and + last_modified == env['HTTP_IF_MODIFIED_SINCE'] + end + end + +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb new file mode 100644 index 0000000000..1e56d43853 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb @@ -0,0 +1,29 @@ +require 'rack/utils' + +module Rack + # Sets the Content-Length header on responses with fixed-length bodies. + class ContentLength + include Rack::Utils + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash.new(headers) + + if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && + !headers['Content-Length'] && + !headers['Transfer-Encoding'] && + (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) + + body = [body] if body.respond_to?(:to_str) # rack 0.4 compat + length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } + headers['Content-Length'] = length.to_s + end + + [status, headers, body] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb new file mode 100644 index 0000000000..0c1e1ca3e1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb @@ -0,0 +1,23 @@ +require 'rack/utils' + +module Rack + + # Sets the Content-Type header on responses which don't have one. + # + # Builder Usage: + # use Rack::ContentType, "text/plain" + # + # When no content type argument is provided, "text/html" is assumed. + class ContentType + def initialize(app, content_type = "text/html") + @app, @content_type = app, content_type + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + headers['Content-Type'] ||= @content_type + [status, headers.to_hash, body] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb new file mode 100644 index 0000000000..14137a944d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb @@ -0,0 +1,96 @@ +require "zlib" +require "stringio" +require "time" # for Time.httpdate +require 'rack/utils' + +module Rack + class Deflater + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + + # Skip compressing empty entity body responses and responses with + # no-transform set. + if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || + headers['Cache-Control'].to_s =~ /\bno-transform\b/ + return [status, headers, body] + end + + request = Request.new(env) + + encoding = Utils.select_best_encoding(%w(gzip deflate identity), + request.accept_encoding) + + # Set the Vary HTTP header. + vary = headers["Vary"].to_s.split(",").map { |v| v.strip } + unless vary.include?("*") || vary.include?("Accept-Encoding") + headers["Vary"] = vary.push("Accept-Encoding").join(",") + end + + case encoding + when "gzip" + headers['Content-Encoding'] = "gzip" + headers.delete('Content-Length') + mtime = headers.key?("Last-Modified") ? + Time.httpdate(headers["Last-Modified"]) : Time.now + [status, headers, GzipStream.new(body, mtime)] + when "deflate" + headers['Content-Encoding'] = "deflate" + headers.delete('Content-Length') + [status, headers, DeflateStream.new(body)] + when "identity" + [status, headers, body] + when nil + message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." + [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]] + end + end + + class GzipStream + def initialize(body, mtime) + @body = body + @mtime = mtime + end + + def each(&block) + @writer = block + gzip =::Zlib::GzipWriter.new(self) + gzip.mtime = @mtime + @body.each { |part| gzip << part } + @body.close if @body.respond_to?(:close) + gzip.close + @writer = nil + end + + def write(data) + @writer.call(data) + end + end + + class DeflateStream + DEFLATE_ARGS = [ + Zlib::DEFAULT_COMPRESSION, + # drop the zlib header which causes both Safari and IE to choke + -Zlib::MAX_WBITS, + Zlib::DEF_MEM_LEVEL, + Zlib::DEFAULT_STRATEGY + ] + + def initialize(body) + @body = body + end + + def each + deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS) + @body.each { |part| yield deflater.deflate(part) } + @body.close if @body.respond_to?(:close) + yield deflater.finish + nil + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb new file mode 100644 index 0000000000..acdd3029d3 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb @@ -0,0 +1,153 @@ +require 'time' +require 'rack/utils' +require 'rack/mime' + +module Rack + # Rack::Directory serves entries below the +root+ given, according to the + # path info of the Rack request. If a directory is found, the file's contents + # will be presented in an html based index. If a file is found, the env will + # be passed to the specified +app+. + # + # If +app+ is not specified, a Rack::File of the same +root+ will be used. + + class Directory + DIR_FILE = "%s%s%s%s" + DIR_PAGE = <<-PAGE + + %s + + + +

%s

+
+ + + + + + + +%s +
NameSizeTypeLast Modified
+
+ + PAGE + + attr_reader :files + attr_accessor :root, :path + + def initialize(root, app=nil) + @root = F.expand_path(root) + @app = app || Rack::File.new(@root) + end + + def call(env) + dup._call(env) + end + + F = ::File + + def _call(env) + @env = env + @script_name = env['SCRIPT_NAME'] + @path_info = Utils.unescape(env['PATH_INFO']) + + if forbidden = check_forbidden + forbidden + else + @path = F.join(@root, @path_info) + list_path + end + end + + def check_forbidden + return unless @path_info.include? ".." + + body = "Forbidden\n" + size = Rack::Utils.bytesize(body) + return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] + end + + def list_directory + @files = [['../','Parent Directory','','','']] + glob = F.join(@path, '*') + + Dir[glob].sort.each do |node| + stat = stat(node) + next unless stat + basename = F.basename(node) + ext = F.extname(node) + + url = F.join(@script_name, @path_info, basename) + size = stat.size + type = stat.directory? ? 'directory' : Mime.mime_type(ext) + size = stat.directory? ? '-' : filesize_format(size) + mtime = stat.mtime.httpdate + url << '/' if stat.directory? + basename << '/' if stat.directory? + + @files << [ url, basename, size, type, mtime ] + end + + return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] + end + + def stat(node, max = 10) + F.stat(node) + rescue Errno::ENOENT, Errno::ELOOP + return nil + end + + # TODO: add correct response if not readable, not sure if 404 is the best + # option + def list_path + @stat = F.stat(@path) + + if @stat.readable? + return @app.call(@env) if @stat.file? + return list_directory if @stat.directory? + else + raise Errno::ENOENT, 'No such file or directory' + end + + rescue Errno::ENOENT, Errno::ELOOP + return entity_not_found + end + + def entity_not_found + body = "Entity not found: #{@path_info}\n" + size = Rack::Utils.bytesize(body) + return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] + end + + def each + show_path = @path.sub(/^#{@root}/,'') + files = @files.map{|f| DIR_FILE % f }*"\n" + page = DIR_PAGE % [ show_path, show_path , files ] + page.each_line{|l| yield l } + end + + # Stolen from Ramaze + + FILESIZE_FORMAT = [ + ['%.1fT', 1 << 40], + ['%.1fG', 1 << 30], + ['%.1fM', 1 << 20], + ['%.1fK', 1 << 10], + ] + + def filesize_format(int) + FILESIZE_FORMAT.each do |format, size| + return format % (int.to_f / size) if int >= size + end + + int.to_s + 'B' + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb new file mode 100644 index 0000000000..fe62bd6b86 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb @@ -0,0 +1,88 @@ +require 'time' +require 'rack/utils' +require 'rack/mime' + +module Rack + # Rack::File serves files below the +root+ given, according to the + # path info of the Rack request. + # + # Handlers can detect if bodies are a Rack::File, and use mechanisms + # like sendfile on the +path+. + + class File + attr_accessor :root + attr_accessor :path + + alias :to_path :path + + def initialize(root) + @root = root + end + + def call(env) + dup._call(env) + end + + F = ::File + + def _call(env) + @path_info = Utils.unescape(env["PATH_INFO"]) + return forbidden if @path_info.include? ".." + + @path = F.join(@root, @path_info) + + begin + if F.file?(@path) && F.readable?(@path) + serving + else + raise Errno::EPERM + end + rescue SystemCallError + not_found + end + end + + def forbidden + body = "Forbidden\n" + [403, {"Content-Type" => "text/plain", + "Content-Length" => body.size.to_s}, + [body]] + end + + # NOTE: + # We check via File::size? whether this file provides size info + # via stat (e.g. /proc files often don't), otherwise we have to + # figure it out by reading the whole file into memory. And while + # we're at it we also use this as body then. + + def serving + if size = F.size?(@path) + body = self + else + body = [F.read(@path)] + size = Utils.bytesize(body.first) + end + + [200, { + "Last-Modified" => F.mtime(@path).httpdate, + "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), + "Content-Length" => size.to_s + }, body] + end + + def not_found + body = "File not found: #{@path_info}\n" + [404, {"Content-Type" => "text/plain", + "Content-Length" => body.size.to_s}, + [body]] + end + + def each + F.open(@path, "rb") { |file| + while part = file.read(8192) + yield part + end + } + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb new file mode 100644 index 0000000000..5624a1e79d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb @@ -0,0 +1,69 @@ +module Rack + # *Handlers* connect web servers with Rack. + # + # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI + # and LiteSpeed. + # + # Handlers usually are activated by calling MyHandler.run(myapp). + # A second optional hash can be passed to include server-specific + # configuration. + module Handler + def self.get(server) + return unless server + server = server.to_s + + if klass = @handlers[server] + obj = Object + klass.split("::").each { |x| obj = obj.const_get(x) } + obj + else + try_require('rack/handler', server) + const_get(server) + end + end + + # Transforms server-name constants to their canonical form as filenames, + # then tries to require them but silences the LoadError if not found + # + # Naming convention: + # + # Foo # => 'foo' + # FooBar # => 'foo_bar.rb' + # FooBAR # => 'foobar.rb' + # FOObar # => 'foobar.rb' + # FOOBAR # => 'foobar.rb' + # FooBarBaz # => 'foo_bar_baz.rb' + def self.try_require(prefix, const_name) + file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. + gsub(/[A-Z]+[^A-Z]/, '_\&').downcase + + require(::File.join(prefix, file)) + rescue LoadError + end + + def self.register(server, klass) + @handlers ||= {} + @handlers[server] = klass + end + + autoload :CGI, "rack/handler/cgi" + autoload :FastCGI, "rack/handler/fastcgi" + autoload :Mongrel, "rack/handler/mongrel" + autoload :EventedMongrel, "rack/handler/evented_mongrel" + autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel" + autoload :WEBrick, "rack/handler/webrick" + autoload :LSWS, "rack/handler/lsws" + autoload :SCGI, "rack/handler/scgi" + autoload :Thin, "rack/handler/thin" + + register 'cgi', 'Rack::Handler::CGI' + register 'fastcgi', 'Rack::Handler::FastCGI' + register 'mongrel', 'Rack::Handler::Mongrel' + register 'emongrel', 'Rack::Handler::EventedMongrel' + register 'smongrel', 'Rack::Handler::SwiftipliedMongrel' + register 'webrick', 'Rack::Handler::WEBrick' + register 'lsws', 'Rack::Handler::LSWS' + register 'scgi', 'Rack::Handler::SCGI' + register 'thin', 'Rack::Handler::Thin' + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb new file mode 100644 index 0000000000..f45f3d735a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb @@ -0,0 +1,61 @@ +require 'rack/content_length' + +module Rack + module Handler + class CGI + def self.run(app, options=nil) + serve app + end + + def self.serve(app) + app = ContentLength.new(app) + + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + env.update({"rack.version" => [1,0], + "rack.input" => $stdin, + "rack.errors" => $stderr, + + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => true, + + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + end + + def self.send_headers(status, headers) + STDOUT.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + STDOUT.print "#{k}: #{v}\r\n" + } + } + STDOUT.print "\r\n" + STDOUT.flush + end + + def self.send_body(body) + body.each { |part| + STDOUT.print part + STDOUT.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb new file mode 100644 index 0000000000..0f5cbf7293 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb @@ -0,0 +1,8 @@ +require 'swiftcore/evented_mongrel' + +module Rack + module Handler + class EventedMongrel < Handler::Mongrel + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb new file mode 100644 index 0000000000..11e1fcaa74 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb @@ -0,0 +1,88 @@ +require 'fcgi' +require 'socket' +require 'rack/content_length' +require 'rack/rewindable_input' + +class FCGI::Stream + alias _rack_read_without_buffer read + + def read(n, buffer=nil) + buf = _rack_read_without_buffer n + buffer.replace(buf.to_s) if buffer + buf + end +end + +module Rack + module Handler + class FastCGI + def self.run(app, options={}) + file = options[:File] and STDIN.reopen(UNIXServer.new(file)) + port = options[:Port] and STDIN.reopen(TCPServer.new(port)) + FCGI.each { |request| + serve request, app + } + end + + def self.serve(request, app) + app = Rack::ContentLength.new(app) + + env = request.env + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + rack_input = RewindableInput.new(request.in) + + env.update({"rack.version" => [1,0], + "rack.input" => rack_input, + "rack.errors" => request.err, + + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" + }) + + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + env.delete "PATH_INFO" if env["PATH_INFO"] == "" + env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" + env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" + + begin + status, headers, body = app.call(env) + begin + send_headers request.out, status, headers + send_body request.out, body + ensure + body.close if body.respond_to? :close + end + ensure + rack_input.close + request.finish + end + end + + def self.send_headers(out, status, headers) + out.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + out.print "#{k}: #{v}\r\n" + } + } + out.print "\r\n" + out.flush + end + + def self.send_body(out, body) + body.each { |part| + out.print part + out.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb new file mode 100644 index 0000000000..7231336d7b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb @@ -0,0 +1,55 @@ +require 'lsapi' +require 'rack/content_length' + +module Rack + module Handler + class LSWS + def self.run(app, options=nil) + while LSAPI.accept != nil + serve app + end + end + def self.serve(app) + app = Rack::ContentLength.new(app) + + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new($stdin.read.to_s), + "rack.errors" => $stderr, + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + end + def self.send_headers(status, headers) + print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + print "#{k}: #{v}\r\n" + } + } + print "\r\n" + STDOUT.flush + end + def self.send_body(body) + body.each { |part| + print part + STDOUT.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb new file mode 100644 index 0000000000..3a5ef32d4b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb @@ -0,0 +1,84 @@ +require 'mongrel' +require 'stringio' +require 'rack/content_length' +require 'rack/chunked' + +module Rack + module Handler + class Mongrel < ::Mongrel::HttpHandler + def self.run(app, options={}) + server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', + options[:Port] || 8080) + # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. + # Use is similar to #run, replacing the app argument with a hash of + # { path=>app, ... } or an instance of Rack::URLMap. + if options[:map] + if app.is_a? Hash + app.each do |path, appl| + path = '/'+path unless path[0] == ?/ + server.register(path, Rack::Handler::Mongrel.new(appl)) + end + elsif app.is_a? URLMap + app.instance_variable_get(:@mapping).each do |(host, path, appl)| + next if !host.nil? && !options[:Host].nil? && options[:Host] != host + path = '/'+path unless path[0] == ?/ + server.register(path, Rack::Handler::Mongrel.new(appl)) + end + else + raise ArgumentError, "first argument should be a Hash or URLMap" + end + else + server.register('/', Rack::Handler::Mongrel.new(app)) + end + yield server if block_given? + server.run.join + end + + def initialize(app) + @app = Rack::Chunked.new(Rack::ContentLength.new(app)) + end + + def process(request, response) + env = {}.replace(request.params) + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + env.update({"rack.version" => [1,0], + "rack.input" => request.body || StringIO.new(""), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => false, # ??? + "rack.run_once" => false, + + "rack.url_scheme" => "http", + }) + env["QUERY_STRING"] ||= "" + env.delete "PATH_INFO" if env["PATH_INFO"] == "" + + status, headers, body = @app.call(env) + + begin + response.status = status.to_i + response.send_status(nil) + + headers.each { |k, vs| + vs.split("\n").each { |v| + response.header[k] = v + } + } + response.send_header + + body.each { |part| + response.write part + response.socket.flush + } + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb new file mode 100644 index 0000000000..6c4932df95 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb @@ -0,0 +1,59 @@ +require 'scgi' +require 'stringio' +require 'rack/content_length' +require 'rack/chunked' + +module Rack + module Handler + class SCGI < ::SCGI::Processor + attr_accessor :app + + def self.run(app, options=nil) + new(options.merge(:app=>app, + :host=>options[:Host], + :port=>options[:Port], + :socket=>options[:Socket])).listen + end + + def initialize(settings = {}) + @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) + @log = Object.new + def @log.info(*args); end + def @log.error(*args); end + super(settings) + end + + def process_request(request, input_body, socket) + env = {}.replace(request) + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["PATH_INFO"] = env["REQUEST_PATH"] + env["QUERY_STRING"] ||= "" + env["SCRIPT_NAME"] = "" + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new(input_body), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" + }) + status, headers, body = app.call(env) + begin + socket.write("Status: #{status}\r\n") + headers.each do |k, vs| + vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} + end + socket.write("\r\n") + body.each {|s| socket.write(s)} + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb new file mode 100644 index 0000000000..4bafd0b953 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb @@ -0,0 +1,8 @@ +require 'swiftcore/swiftiplied_mongrel' + +module Rack + module Handler + class SwiftipliedMongrel < Handler::Mongrel + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb new file mode 100644 index 0000000000..3d4fedff75 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb @@ -0,0 +1,18 @@ +require "thin" +require "rack/content_length" +require "rack/chunked" + +module Rack + module Handler + class Thin + def self.run(app, options={}) + app = Rack::Chunked.new(Rack::ContentLength.new(app)) + server = ::Thin::Server.new(options[:Host] || '0.0.0.0', + options[:Port] || 8080, + app) + yield server if block_given? + server.start + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb new file mode 100644 index 0000000000..2bdc83a9ff --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb @@ -0,0 +1,67 @@ +require 'webrick' +require 'stringio' +require 'rack/content_length' + +module Rack + module Handler + class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet + def self.run(app, options={}) + server = ::WEBrick::HTTPServer.new(options) + server.mount "/", Rack::Handler::WEBrick, app + trap(:INT) { server.shutdown } + yield server if block_given? + server.start + end + + def initialize(server, app) + super server + @app = Rack::ContentLength.new(app) + end + + def service(req, res) + env = req.meta_vars + env.delete_if { |k, v| v.nil? } + + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new(req.body.to_s), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => false, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["QUERY_STRING"] ||= "" + env["REQUEST_PATH"] ||= "/" + if env["PATH_INFO"] == "" + env.delete "PATH_INFO" + else + path, n = req.request_uri.path, env["SCRIPT_NAME"].length + env["PATH_INFO"] = path[n, path.length-n] + end + + status, headers, body = @app.call(env) + begin + res.status = status.to_i + headers.each { |k, vs| + if k.downcase == "set-cookie" + res.cookies.concat vs.split("\n") + else + vs.split("\n").each { |v| + res[k] = v + } + end + } + body.each { |part| + res.body << part + } + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb new file mode 100644 index 0000000000..deab822a99 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb @@ -0,0 +1,19 @@ +module Rack + +class Head + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + if env["REQUEST_METHOD"] == "HEAD" + [status, headers, []] + else + [status, headers, body] + end + end +end + +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb new file mode 100644 index 0000000000..bf2e9787a1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb @@ -0,0 +1,537 @@ +require 'rack/utils' + +module Rack + # Rack::Lint validates your application and the requests and + # responses according to the Rack spec. + + class Lint + def initialize(app) + @app = app + end + + # :stopdoc: + + class LintError < RuntimeError; end + module Assertion + def assert(message, &block) + unless block.call + raise LintError, message + end + end + end + include Assertion + + ## This specification aims to formalize the Rack protocol. You + ## can (and should) use Rack::Lint to enforce it. + ## + ## When you develop middleware, be sure to add a Lint before and + ## after to catch all mistakes. + + ## = Rack applications + + ## A Rack application is an Ruby object (not a class) that + ## responds to +call+. + def call(env=nil) + dup._call(env) + end + + def _call(env) + ## It takes exactly one argument, the *environment* + assert("No env given") { env } + check_env env + + env['rack.input'] = InputWrapper.new(env['rack.input']) + env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) + + ## and returns an Array of exactly three values: + status, headers, @body = @app.call(env) + ## The *status*, + check_status status + ## the *headers*, + check_headers headers + ## and the *body*. + check_content_type status, headers + check_content_length status, headers, env + [status, headers, self] + end + + ## == The Environment + def check_env(env) + ## The environment must be an true instance of Hash (no + ## subclassing allowed) that includes CGI-like headers. + ## The application is free to modify the environment. + assert("env #{env.inspect} is not a Hash, but #{env.class}") { + env.instance_of? Hash + } + + ## + ## The environment is required to include these variables + ## (adopted from PEP333), except when they'd be empty, but see + ## below. + + ## REQUEST_METHOD:: The HTTP request method, such as + ## "GET" or "POST". This cannot ever + ## be an empty string, and so is + ## always required. + + ## SCRIPT_NAME:: The initial portion of the request + ## URL's "path" that corresponds to the + ## application object, so that the + ## application knows its virtual + ## "location". This may be an empty + ## string, if the application corresponds + ## to the "root" of the server. + + ## PATH_INFO:: The remainder of the request URL's + ## "path", designating the virtual + ## "location" of the request's target + ## within the application. This may be an + ## empty string, if the request URL targets + ## the application root and does not have a + ## trailing slash. This value may be + ## percent-encoded when I originating from + ## a URL. + + ## QUERY_STRING:: The portion of the request URL that + ## follows the ?, if any. May be + ## empty, but is always required! + + ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. + + ## HTTP_ Variables:: Variables corresponding to the + ## client-supplied HTTP request + ## headers (i.e., variables whose + ## names begin with HTTP_). The + ## presence or absence of these + ## variables should correspond with + ## the presence or absence of the + ## appropriate HTTP header in the + ## request. + + ## In addition to this, the Rack environment must include these + ## Rack-specific variables: + + ## rack.version:: The Array [1,0], representing this version of Rack. + ## rack.url_scheme:: +http+ or +https+, depending on the request URL. + ## rack.input:: See below, the input stream. + ## rack.errors:: See below, the error stream. + ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. + ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. + ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). + ## + + ## Additional environment specifications have approved to + ## standardized middleware APIs. None of these are required to + ## be implemented by the server. + + ## rack.session:: A hash like interface for storing request session data. + ## The store must implement: + if session = env['rack.session'] + ## store(key, value) (aliased as []=); + assert("session #{session.inspect} must respond to store and []=") { + session.respond_to?(:store) && session.respond_to?(:[]=) + } + + ## fetch(key, default = nil) (aliased as []); + assert("session #{session.inspect} must respond to fetch and []") { + session.respond_to?(:fetch) && session.respond_to?(:[]) + } + + ## delete(key); + assert("session #{session.inspect} must respond to delete") { + session.respond_to?(:delete) + } + + ## clear; + assert("session #{session.inspect} must respond to clear") { + session.respond_to?(:clear) + } + end + + ## The server or the application can store their own data in the + ## environment, too. The keys must contain at least one dot, + ## and should be prefixed uniquely. The prefix rack. + ## is reserved for use with the Rack core distribution and other + ## accepted specifications and must not be used otherwise. + ## + + %w[REQUEST_METHOD SERVER_NAME SERVER_PORT + QUERY_STRING + rack.version rack.input rack.errors + rack.multithread rack.multiprocess rack.run_once].each { |header| + assert("env missing required key #{header}") { env.include? header } + } + + ## The environment must not contain the keys + ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH + ## (use the versions without HTTP_). + %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| + assert("env contains #{header}, must use #{header[5,-1]}") { + not env.include? header + } + } + + ## The CGI keys (named without a period) must have String values. + env.each { |key, value| + next if key.include? "." # Skip extensions + assert("env variable #{key} has non-string value #{value.inspect}") { + value.instance_of? String + } + } + + ## + ## There are the following restrictions: + + ## * rack.version must be an array of Integers. + assert("rack.version must be an Array, was #{env["rack.version"].class}") { + env["rack.version"].instance_of? Array + } + ## * rack.url_scheme must either be +http+ or +https+. + assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { + %w[http https].include? env["rack.url_scheme"] + } + + ## * There must be a valid input stream in rack.input. + check_input env["rack.input"] + ## * There must be a valid error stream in rack.errors. + check_error env["rack.errors"] + + ## * The REQUEST_METHOD must be a valid token. + assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { + env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ + } + + ## * The SCRIPT_NAME, if non-empty, must start with / + assert("SCRIPT_NAME must start with /") { + !env.include?("SCRIPT_NAME") || + env["SCRIPT_NAME"] == "" || + env["SCRIPT_NAME"] =~ /\A\// + } + ## * The PATH_INFO, if non-empty, must start with / + assert("PATH_INFO must start with /") { + !env.include?("PATH_INFO") || + env["PATH_INFO"] == "" || + env["PATH_INFO"] =~ /\A\// + } + ## * The CONTENT_LENGTH, if given, must consist of digits only. + assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { + !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ + } + + ## * One of SCRIPT_NAME or PATH_INFO must be + ## set. PATH_INFO should be / if + ## SCRIPT_NAME is empty. + assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { + env["SCRIPT_NAME"] || env["PATH_INFO"] + } + ## SCRIPT_NAME never should be /, but instead be empty. + assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { + env["SCRIPT_NAME"] != "/" + } + end + + ## === The Input Stream + ## + ## The input stream is an IO-like object which contains the raw HTTP + ## POST data. If it is a file then it must be opened in binary mode. + def check_input(input) + ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. + [:gets, :each, :read, :rewind].each { |method| + assert("rack.input #{input} does not respond to ##{method}") { + input.respond_to? method + } + } + end + + class InputWrapper + include Assertion + + def initialize(input) + @input = input + end + + def size + @input.size + end + + ## * +gets+ must be called without arguments and return a string, + ## or +nil+ on EOF. + def gets(*args) + assert("rack.input#gets called with arguments") { args.size == 0 } + v = @input.gets + assert("rack.input#gets didn't return a String") { + v.nil? or v.instance_of? String + } + v + end + + ## * +read+ behaves like IO#read. Its signature is read([length, [buffer]]). + ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must + ## be a String and may not be nil. If +length+ is given and not nil, then this method + ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil, + ## then this method reads all data until EOF. + ## When EOF is reached, this method returns nil if +length+ is given and not nil, or "" + ## if +length+ is not given or is nil. + ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a + ## newly created String object. + def read(*args) + assert("rack.input#read called with too many arguments") { + args.size <= 2 + } + if args.size >= 1 + assert("rack.input#read called with non-integer and non-nil length") { + args.first.kind_of?(Integer) || args.first.nil? + } + assert("rack.input#read called with a negative length") { + args.first.nil? || args.first >= 0 + } + end + if args.size >= 2 + assert("rack.input#read called with non-String buffer") { + args[1].kind_of?(String) + } + end + + v = @input.read(*args) + + assert("rack.input#read didn't return nil or a String") { + v.nil? or v.instance_of? String + } + if args[0].nil? + assert("rack.input#read(nil) returned nil on EOF") { + !v.nil? + } + end + + v + end + + ## * +each+ must be called without arguments and only yield Strings. + def each(*args) + assert("rack.input#each called with arguments") { args.size == 0 } + @input.each { |line| + assert("rack.input#each didn't yield a String") { + line.instance_of? String + } + yield line + } + end + + ## * +rewind+ must be called without arguments. It rewinds the input + ## stream back to the beginning. It must not raise Errno::ESPIPE: + ## that is, it may not be a pipe or a socket. Therefore, handler + ## developers must buffer the input data into some rewindable object + ## if the underlying input stream is not rewindable. + def rewind(*args) + assert("rack.input#rewind called with arguments") { args.size == 0 } + assert("rack.input#rewind raised Errno::ESPIPE") { + begin + @input.rewind + true + rescue Errno::ESPIPE + false + end + } + end + + ## * +close+ must never be called on the input stream. + def close(*args) + assert("rack.input#close must not be called") { false } + end + end + + ## === The Error Stream + def check_error(error) + ## The error stream must respond to +puts+, +write+ and +flush+. + [:puts, :write, :flush].each { |method| + assert("rack.error #{error} does not respond to ##{method}") { + error.respond_to? method + } + } + end + + class ErrorWrapper + include Assertion + + def initialize(error) + @error = error + end + + ## * +puts+ must be called with a single argument that responds to +to_s+. + def puts(str) + @error.puts str + end + + ## * +write+ must be called with a single argument that is a String. + def write(str) + assert("rack.errors#write not called with a String") { str.instance_of? String } + @error.write str + end + + ## * +flush+ must be called without arguments and must be called + ## in order to make the error appear for sure. + def flush + @error.flush + end + + ## * +close+ must never be called on the error stream. + def close(*args) + assert("rack.errors#close must not be called") { false } + end + end + + ## == The Response + + ## === The Status + def check_status(status) + ## This is an HTTP status. When parsed as integer (+to_i+), it must be + ## greater than or equal to 100. + assert("Status must be >=100 seen as integer") { status.to_i >= 100 } + end + + ## === The Headers + def check_headers(header) + ## The header must respond to +each+, and yield values of key and value. + assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { + header.respond_to? :each + } + header.each { |key, value| + ## The header keys must be Strings. + assert("header key must be a string, was #{key.class}") { + key.instance_of? String + } + ## The header must not contain a +Status+ key, + assert("header must not contain Status") { key.downcase != "status" } + ## contain keys with : or newlines in their name, + assert("header names must not contain : or \\n") { key !~ /[:\n]/ } + ## contain keys names that end in - or _, + assert("header names must not end in - or _") { key !~ /[-_]\z/ } + ## but only contain keys that consist of + ## letters, digits, _ or - and start with a letter. + assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } + + ## The values of the header must be Strings, + assert("a header value must be a String, but the value of " + + "'#{key}' is a #{value.class}") { value.kind_of? String } + ## consisting of lines (for multiple header values, e.g. multiple + ## Set-Cookie values) seperated by "\n". + value.split("\n").each { |item| + ## The lines must not contain characters below 037. + assert("invalid header value #{key}: #{item.inspect}") { + item !~ /[\000-\037]/ + } + } + } + end + + ## === The Content-Type + def check_content_type(status, headers) + headers.each { |key, value| + ## There must be a Content-Type, except when the + ## +Status+ is 1xx, 204 or 304, in which case there must be none + ## given. + if key.downcase == "content-type" + assert("Content-Type header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + return + end + } + assert("No Content-Type header found") { + Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + end + + ## === The Content-Length + def check_content_length(status, headers, env) + headers.each { |key, value| + if key.downcase == 'content-length' + ## There must not be a Content-Length header when the + ## +Status+ is 1xx, 204 or 304. + assert("Content-Length header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + + bytes = 0 + string_body = true + + if @body.respond_to?(:to_ary) + @body.each { |part| + unless part.kind_of?(String) + string_body = false + break + end + + bytes += Rack::Utils.bytesize(part) + } + + if env["REQUEST_METHOD"] == "HEAD" + assert("Response body was given for HEAD request, but should be empty") { + bytes == 0 + } + else + if string_body + assert("Content-Length header was #{value}, but should be #{bytes}") { + value == bytes.to_s + } + end + end + end + + return + end + } + end + + ## === The Body + def each + @closed = false + ## The Body must respond to +each+ + @body.each { |part| + ## and must only yield String values. + assert("Body yielded non-string value #{part.inspect}") { + part.instance_of? String + } + yield part + } + ## + ## The Body itself should not be an instance of String, as this will + ## break in Ruby 1.9. + ## + ## If the Body responds to +close+, it will be called after iteration. + # XXX howto: assert("Body has not been closed") { @closed } + + + ## + ## If the Body responds to +to_path+, it must return a String + ## identifying the location of a file whose contents are identical + ## to that produced by calling +each+; this may be used by the + ## server as an alternative, possibly more efficient way to + ## transport the response. + + if @body.respond_to?(:to_path) + assert("The file identified by body.to_path does not exist") { + ::File.exist? @body.to_path + } + end + + ## + ## The Body commonly is an Array of Strings, the application + ## instance itself, or a File-like object. + end + + def close + @closed = true + @body.close if @body.respond_to?(:close) + end + + # :startdoc: + + end +end + +## == Thanks +## Some parts of this specification are adopted from PEP333: Python +## Web Server Gateway Interface +## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank +## everyone involved in that effort. diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb new file mode 100644 index 0000000000..f63f419a49 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb @@ -0,0 +1,65 @@ +require 'zlib' + +require 'rack/request' +require 'rack/response' + +module Rack + # Paste has a Pony, Rack has a Lobster! + class Lobster + LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 + P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 + t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ + I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) + + LambdaLobster = lambda { |env| + if env["QUERY_STRING"].include?("flip") + lobster = LobsterString.split("\n"). + map { |line| line.ljust(42).reverse }. + join("\n") + href = "?" + else + lobster = LobsterString + href = "?flip" + end + + content = ["Lobstericious!", + "
", lobster, "
", + "flip!"] + length = content.inject(0) { |a,e| a+e.size }.to_s + [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] + } + + def call(env) + req = Request.new(env) + if req.GET["flip"] == "left" + lobster = LobsterString.split("\n"). + map { |line| line.ljust(42).reverse }. + join("\n") + href = "?flip=right" + elsif req.GET["flip"] == "crash" + raise "Lobster crashed" + else + lobster = LobsterString + href = "?flip=left" + end + + res = Response.new + res.write "Lobstericious!" + res.write "
"
+      res.write lobster
+      res.write "
" + res.write "

flip!

" + res.write "

crash!

" + res.finish + end + + end +end + +if $0 == __FILE__ + require 'rack' + require 'rack/showexceptions' + Rack::Handler::WEBrick.run \ + Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), + :Port => 9292 +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb new file mode 100644 index 0000000000..93238528c4 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb @@ -0,0 +1,16 @@ +module Rack + class Lock + FLAG = 'rack.multithread'.freeze + + def initialize(app, lock = Mutex.new) + @app, @lock = app, lock + end + + def call(env) + old, env[FLAG] = env[FLAG], false + @lock.synchronize { @app.call(env) } + ensure + env[FLAG] = old + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb new file mode 100644 index 0000000000..0eed29f471 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb @@ -0,0 +1,27 @@ +module Rack + class MethodOverride + HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS) + + METHOD_OVERRIDE_PARAM_KEY = "_method".freeze + HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze + + def initialize(app) + @app = app + end + + def call(env) + if env["REQUEST_METHOD"] == "POST" + req = Request.new(env) + method = req.POST[METHOD_OVERRIDE_PARAM_KEY] || + env[HTTP_METHOD_OVERRIDE_HEADER] + method = method.to_s.upcase + if HTTP_METHODS.include?(method) + env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] + env["REQUEST_METHOD"] = method + end + end + + @app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb new file mode 100644 index 0000000000..5a6a73a97b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb @@ -0,0 +1,204 @@ +module Rack + module Mime + # Returns String with mime type if found, otherwise use +fallback+. + # +ext+ should be filename extension in the '.ext' format that + # File.extname(file) returns. + # +fallback+ may be any object + # + # Also see the documentation for MIME_TYPES + # + # Usage: + # Rack::Mime.mime_type('.foo') + # + # This is a shortcut for: + # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') + + def mime_type(ext, fallback='application/octet-stream') + MIME_TYPES.fetch(ext, fallback) + end + module_function :mime_type + + # List of most common mime-types, selected various sources + # according to their usefulness in a webserving scope for Ruby + # users. + # + # To amend this list with your local mime.types list you can use: + # + # require 'webrick/httputils' + # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') + # Rack::Mime::MIME_TYPES.merge!(list) + # + # To add the list mongrel provides, use: + # + # require 'mongrel/handlers' + # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES) + + MIME_TYPES = { + ".3gp" => "video/3gpp", + ".a" => "application/octet-stream", + ".ai" => "application/postscript", + ".aif" => "audio/x-aiff", + ".aiff" => "audio/x-aiff", + ".asc" => "application/pgp-signature", + ".asf" => "video/x-ms-asf", + ".asm" => "text/x-asm", + ".asx" => "video/x-ms-asf", + ".atom" => "application/atom+xml", + ".au" => "audio/basic", + ".avi" => "video/x-msvideo", + ".bat" => "application/x-msdownload", + ".bin" => "application/octet-stream", + ".bmp" => "image/bmp", + ".bz2" => "application/x-bzip2", + ".c" => "text/x-c", + ".cab" => "application/vnd.ms-cab-compressed", + ".cc" => "text/x-c", + ".chm" => "application/vnd.ms-htmlhelp", + ".class" => "application/octet-stream", + ".com" => "application/x-msdownload", + ".conf" => "text/plain", + ".cpp" => "text/x-c", + ".crt" => "application/x-x509-ca-cert", + ".css" => "text/css", + ".csv" => "text/csv", + ".cxx" => "text/x-c", + ".deb" => "application/x-debian-package", + ".der" => "application/x-x509-ca-cert", + ".diff" => "text/x-diff", + ".djv" => "image/vnd.djvu", + ".djvu" => "image/vnd.djvu", + ".dll" => "application/x-msdownload", + ".dmg" => "application/octet-stream", + ".doc" => "application/msword", + ".dot" => "application/msword", + ".dtd" => "application/xml-dtd", + ".dvi" => "application/x-dvi", + ".ear" => "application/java-archive", + ".eml" => "message/rfc822", + ".eps" => "application/postscript", + ".exe" => "application/x-msdownload", + ".f" => "text/x-fortran", + ".f77" => "text/x-fortran", + ".f90" => "text/x-fortran", + ".flv" => "video/x-flv", + ".for" => "text/x-fortran", + ".gem" => "application/octet-stream", + ".gemspec" => "text/x-script.ruby", + ".gif" => "image/gif", + ".gz" => "application/x-gzip", + ".h" => "text/x-c", + ".hh" => "text/x-c", + ".htm" => "text/html", + ".html" => "text/html", + ".ico" => "image/vnd.microsoft.icon", + ".ics" => "text/calendar", + ".ifb" => "text/calendar", + ".iso" => "application/octet-stream", + ".jar" => "application/java-archive", + ".java" => "text/x-java-source", + ".jnlp" => "application/x-java-jnlp-file", + ".jpeg" => "image/jpeg", + ".jpg" => "image/jpeg", + ".js" => "application/javascript", + ".json" => "application/json", + ".log" => "text/plain", + ".m3u" => "audio/x-mpegurl", + ".m4v" => "video/mp4", + ".man" => "text/troff", + ".mathml" => "application/mathml+xml", + ".mbox" => "application/mbox", + ".mdoc" => "text/troff", + ".me" => "text/troff", + ".mid" => "audio/midi", + ".midi" => "audio/midi", + ".mime" => "message/rfc822", + ".mml" => "application/mathml+xml", + ".mng" => "video/x-mng", + ".mov" => "video/quicktime", + ".mp3" => "audio/mpeg", + ".mp4" => "video/mp4", + ".mp4v" => "video/mp4", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".ms" => "text/troff", + ".msi" => "application/x-msdownload", + ".odp" => "application/vnd.oasis.opendocument.presentation", + ".ods" => "application/vnd.oasis.opendocument.spreadsheet", + ".odt" => "application/vnd.oasis.opendocument.text", + ".ogg" => "application/ogg", + ".p" => "text/x-pascal", + ".pas" => "text/x-pascal", + ".pbm" => "image/x-portable-bitmap", + ".pdf" => "application/pdf", + ".pem" => "application/x-x509-ca-cert", + ".pgm" => "image/x-portable-graymap", + ".pgp" => "application/pgp-encrypted", + ".pkg" => "application/octet-stream", + ".pl" => "text/x-script.perl", + ".pm" => "text/x-script.perl-module", + ".png" => "image/png", + ".pnm" => "image/x-portable-anymap", + ".ppm" => "image/x-portable-pixmap", + ".pps" => "application/vnd.ms-powerpoint", + ".ppt" => "application/vnd.ms-powerpoint", + ".ps" => "application/postscript", + ".psd" => "image/vnd.adobe.photoshop", + ".py" => "text/x-script.python", + ".qt" => "video/quicktime", + ".ra" => "audio/x-pn-realaudio", + ".rake" => "text/x-script.ruby", + ".ram" => "audio/x-pn-realaudio", + ".rar" => "application/x-rar-compressed", + ".rb" => "text/x-script.ruby", + ".rdf" => "application/rdf+xml", + ".roff" => "text/troff", + ".rpm" => "application/x-redhat-package-manager", + ".rss" => "application/rss+xml", + ".rtf" => "application/rtf", + ".ru" => "text/x-script.ruby", + ".s" => "text/x-asm", + ".sgm" => "text/sgml", + ".sgml" => "text/sgml", + ".sh" => "application/x-sh", + ".sig" => "application/pgp-signature", + ".snd" => "audio/basic", + ".so" => "application/octet-stream", + ".svg" => "image/svg+xml", + ".svgz" => "image/svg+xml", + ".swf" => "application/x-shockwave-flash", + ".t" => "text/troff", + ".tar" => "application/x-tar", + ".tbz" => "application/x-bzip-compressed-tar", + ".tcl" => "application/x-tcl", + ".tex" => "application/x-tex", + ".texi" => "application/x-texinfo", + ".texinfo" => "application/x-texinfo", + ".text" => "text/plain", + ".tif" => "image/tiff", + ".tiff" => "image/tiff", + ".torrent" => "application/x-bittorrent", + ".tr" => "text/troff", + ".txt" => "text/plain", + ".vcf" => "text/x-vcard", + ".vcs" => "text/x-vcalendar", + ".vrml" => "model/vrml", + ".war" => "application/java-archive", + ".wav" => "audio/x-wav", + ".wma" => "audio/x-ms-wma", + ".wmv" => "video/x-ms-wmv", + ".wmx" => "video/x-ms-wmx", + ".wrl" => "model/vrml", + ".wsdl" => "application/wsdl+xml", + ".xbm" => "image/x-xbitmap", + ".xhtml" => "application/xhtml+xml", + ".xls" => "application/vnd.ms-excel", + ".xml" => "application/xml", + ".xpm" => "image/x-xpixmap", + ".xsl" => "application/xml", + ".xslt" => "application/xslt+xml", + ".yaml" => "text/yaml", + ".yml" => "text/yaml", + ".zip" => "application/zip", + } + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb new file mode 100644 index 0000000000..fdefb0340a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb @@ -0,0 +1,184 @@ +require 'uri' +require 'stringio' +require 'rack/lint' +require 'rack/utils' +require 'rack/response' + +module Rack + # Rack::MockRequest helps testing your Rack application without + # actually using HTTP. + # + # After performing a request on a URL with get/post/put/delete, it + # returns a MockResponse with useful helper methods for effective + # testing. + # + # You can pass a hash with additional configuration to the + # get/post/put/delete. + # :input:: A String or IO-like to be used as rack.input. + # :fatal:: Raise a FatalWarning if the app writes to rack.errors. + # :lint:: If true, wrap the application in a Rack::Lint. + + class MockRequest + class FatalWarning < RuntimeError + end + + class FatalWarner + def puts(warning) + raise FatalWarning, warning + end + + def write(warning) + raise FatalWarning, warning + end + + def flush + end + + def string + "" + end + end + + DEFAULT_ENV = { + "rack.version" => [1,0], + "rack.input" => StringIO.new, + "rack.errors" => StringIO.new, + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + } + + def initialize(app) + @app = app + end + + def get(uri, opts={}) request("GET", uri, opts) end + def post(uri, opts={}) request("POST", uri, opts) end + def put(uri, opts={}) request("PUT", uri, opts) end + def delete(uri, opts={}) request("DELETE", uri, opts) end + + def request(method="GET", uri="", opts={}) + env = self.class.env_for(uri, opts.merge(:method => method)) + + if opts[:lint] + app = Rack::Lint.new(@app) + else + app = @app + end + + errors = env["rack.errors"] + MockResponse.new(*(app.call(env) + [errors])) + end + + # Return the Rack environment used for a request to +uri+. + def self.env_for(uri="", opts={}) + uri = URI(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + + env = DEFAULT_ENV.dup + + env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" + env["SERVER_NAME"] = uri.host || "example.org" + env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" + env["QUERY_STRING"] = uri.query.to_s + env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path + env["rack.url_scheme"] = uri.scheme || "http" + env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" + + env["SCRIPT_NAME"] = opts[:script_name] || "" + + if opts[:fatal] + env["rack.errors"] = FatalWarner.new + else + env["rack.errors"] = StringIO.new + end + + if params = opts[:params] + if env["REQUEST_METHOD"] == "GET" + params = Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Utils.parse_nested_query(env["QUERY_STRING"])) + env["QUERY_STRING"] = Utils.build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Utils::Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = Utils.build_nested_query(params) + end + else + opts[:input] = params + end + end + end + + opts[:input] ||= "" + if String === opts[:input] + env["rack.input"] = StringIO.new(opts[:input]) + else + env["rack.input"] = opts[:input] + end + + env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s + + opts.each { |field, value| + env[field] = value if String === field + } + + env + end + end + + # Rack::MockResponse provides useful helpers for testing your apps. + # Usually, you don't create the MockResponse on your own, but use + # MockRequest. + + class MockResponse + def initialize(status, headers, body, errors=StringIO.new("")) + @status = status.to_i + + @original_headers = headers + @headers = Rack::Utils::HeaderHash.new + headers.each { |field, values| + @headers[field] = values + @headers[field] = "" if values.empty? + } + + @body = "" + body.each { |part| @body << part } + + @errors = errors.string if errors.respond_to?(:string) + end + + # Status + attr_reader :status + + # Headers + attr_reader :headers, :original_headers + + def [](field) + headers[field] + end + + + # Body + attr_reader :body + + def =~(other) + @body =~ other + end + + def match(other) + @body.match other + end + + + # Errors + attr_accessor :errors + + + include Response::Helpers + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb new file mode 100644 index 0000000000..bf8b965925 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb @@ -0,0 +1,57 @@ +require 'uri' + +module Rack + # Rack::ForwardRequest gets caught by Rack::Recursive and redirects + # the current request to the app at +url+. + # + # raise ForwardRequest.new("/not-found") + # + + class ForwardRequest < Exception + attr_reader :url, :env + + def initialize(url, env={}) + @url = URI(url) + @env = env + + @env["PATH_INFO"] = @url.path + @env["QUERY_STRING"] = @url.query if @url.query + @env["HTTP_HOST"] = @url.host if @url.host + @env["HTTP_PORT"] = @url.port if @url.port + @env["rack.url_scheme"] = @url.scheme if @url.scheme + + super "forwarding to #{url}" + end + end + + # Rack::Recursive allows applications called down the chain to + # include data from other applications (by using + # rack['rack.recursive.include'][...] or raise a + # ForwardRequest to redirect internally. + + class Recursive + def initialize(app) + @app = app + end + + def call(env) + @script_name = env["SCRIPT_NAME"] + @app.call(env.merge('rack.recursive.include' => method(:include))) + rescue ForwardRequest => req + call(env.merge(req.env)) + end + + def include(env, path) + unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || + path[@script_name.size].nil?) + raise ArgumentError, "can only include below #{@script_name}, not #{path}" + end + + env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, + "REQUEST_METHOD" => "GET", + "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", + "rack.input" => StringIO.new("")) + @app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb new file mode 100644 index 0000000000..aa2f060be5 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb @@ -0,0 +1,106 @@ +# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com +# All files in this distribution are subject to the terms of the Ruby license. + +require 'pathname' + +module Rack + + # High performant source reloader + # + # This class acts as Rack middleware. + # + # What makes it especially suited for use in a production environment is that + # any file will only be checked once and there will only be made one system + # call stat(2). + # + # Please note that this will not reload files in the background, it does so + # only when actively called. + # + # It is performing a check/reload cycle at the start of every request, but + # also respects a cool down time, during which nothing will be done. + class Reloader + def initialize(app, cooldown = 10, backend = Stat) + @app = app + @cooldown = cooldown + @last = (Time.now - cooldown) + @cache = {} + @mtimes = {} + + extend backend + end + + def call(env) + if @cooldown and Time.now > @last + @cooldown + if Thread.list.size > 1 + Thread.exclusive{ reload! } + else + reload! + end + + @last = Time.now + end + + @app.call(env) + end + + def reload!(stderr = $stderr) + rotation do |file, mtime| + previous_mtime = @mtimes[file] ||= mtime + safe_load(file, mtime, stderr) if mtime > previous_mtime + end + end + + # A safe Kernel::load, issuing the hooks depending on the results + def safe_load(file, mtime, stderr = $stderr) + load(file) + stderr.puts "#{self.class}: reloaded `#{file}'" + file + rescue LoadError, SyntaxError => ex + stderr.puts ex + ensure + @mtimes[file] = mtime + end + + module Stat + def rotation + files = [$0, *$LOADED_FEATURES].uniq + paths = ['./', *$LOAD_PATH].uniq + + files.map{|file| + next if file =~ /\.(so|bundle)$/ # cannot reload compiled files + + found, stat = figure_path(file, paths) + next unless found and stat and mtime = stat.mtime + + @cache[file] = found + + yield(found, mtime) + }.compact + end + + # Takes a relative or absolute +file+ name, a couple possible +paths+ that + # the +file+ might reside in. Returns the full path and File::Stat for the + # path. + def figure_path(file, paths) + found = @cache[file] + found = file if !found and Pathname.new(file).absolute? + found, stat = safe_stat(found) + return found, stat if found + + paths.each do |possible_path| + path = ::File.join(possible_path, file) + found, stat = safe_stat(path) + return ::File.expand_path(found), stat if found + end + end + + def safe_stat(file) + return unless file + stat = ::File.stat(file) + return file, stat if stat.file? + rescue Errno::ENOENT, Errno::ENOTDIR + @cache.delete(file) and false + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb new file mode 100644 index 0000000000..0bff7af038 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb @@ -0,0 +1,254 @@ +require 'rack/utils' + +module Rack + # Rack::Request provides a convenient interface to a Rack + # environment. It is stateless, the environment +env+ passed to the + # constructor will be directly modified. + # + # req = Rack::Request.new(env) + # req.post? + # req.params["data"] + # + # The environment hash passed will store a reference to the Request object + # instantiated so that it will only instantiate if an instance of the Request + # object doesn't already exist. + + class Request + # The environment of the request. + attr_reader :env + + def self.new(env, *args) + if self == Rack::Request + env["rack.request"] ||= super + else + super + end + end + + def initialize(env) + @env = env + end + + def body; @env["rack.input"] end + def scheme; @env["rack.url_scheme"] end + def script_name; @env["SCRIPT_NAME"].to_s end + def path_info; @env["PATH_INFO"].to_s end + def port; @env["SERVER_PORT"].to_i end + def request_method; @env["REQUEST_METHOD"] end + def query_string; @env["QUERY_STRING"].to_s end + def content_length; @env['CONTENT_LENGTH'] end + def content_type; @env['CONTENT_TYPE'] end + def session; @env['rack.session'] ||= {} end + def session_options; @env['rack.session.options'] ||= {} end + + # The media type (type/subtype) portion of the CONTENT_TYPE header + # without any media type parameters. e.g., when CONTENT_TYPE is + # "text/plain;charset=utf-8", the media-type is "text/plain". + # + # For more information on the use of media types in HTTP, see: + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 + def media_type + content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase + end + + # The media type parameters provided in CONTENT_TYPE as a Hash, or + # an empty Hash if no CONTENT_TYPE or media-type parameters were + # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", + # this method responds with the following Hash: + # { 'charset' => 'utf-8' } + def media_type_params + return {} if content_type.nil? + content_type.split(/\s*[;,]\s*/)[1..-1]. + collect { |s| s.split('=', 2) }. + inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } + end + + # The character set of the request body if a "charset" media type + # parameter was given, or nil if no "charset" was specified. Note + # that, per RFC2616, text/* media types that specify no explicit + # charset are to be considered ISO-8859-1. + def content_charset + media_type_params['charset'] + end + + def host + # Remove port number. + (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') + end + + def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end + def path_info=(s); @env["PATH_INFO"] = s.to_s end + + def get?; request_method == "GET" end + def post?; request_method == "POST" end + def put?; request_method == "PUT" end + def delete?; request_method == "DELETE" end + def head?; request_method == "HEAD" end + + # The set of form-data media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for form-data / param parsing. + FORM_DATA_MEDIA_TYPES = [ + nil, + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ] + + # The set of media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + + # Determine whether the request body contains form-data by checking + # the request media_type against registered form-data media-types: + # "application/x-www-form-urlencoded" and "multipart/form-data". The + # list of form-data media types can be modified through the + # +FORM_DATA_MEDIA_TYPES+ array. + def form_data? + FORM_DATA_MEDIA_TYPES.include?(media_type) + end + + # Determine whether the request body contains data by checking + # the request media_type against registered parse-data media-types + def parseable_data? + PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) + end + + # Returns the data recieved in the query string. + def GET + if @env["rack.request.query_string"] == query_string + @env["rack.request.query_hash"] + else + @env["rack.request.query_string"] = query_string + @env["rack.request.query_hash"] = + Utils.parse_nested_query(query_string) + end + end + + # Returns the data recieved in the request body. + # + # This method support both application/x-www-form-urlencoded and + # multipart/form-data. + def POST + if @env["rack.request.form_input"].eql? @env["rack.input"] + @env["rack.request.form_hash"] + elsif form_data? || parseable_data? + @env["rack.request.form_input"] = @env["rack.input"] + unless @env["rack.request.form_hash"] = + Utils::Multipart.parse_multipart(env) + form_vars = @env["rack.input"].read + + # Fix for Safari Ajax postings that always append \0 + form_vars.sub!(/\0\z/, '') + + @env["rack.request.form_vars"] = form_vars + @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) + + @env["rack.input"].rewind + end + @env["rack.request.form_hash"] + else + {} + end + end + + # The union of GET and POST data. + def params + self.put? ? self.GET : self.GET.update(self.POST) + rescue EOFError => e + self.GET + end + + # shortcut for request.params[key] + def [](key) + params[key.to_s] + end + + # shortcut for request.params[key] = value + def []=(key, value) + params[key.to_s] = value + end + + # like Hash#values_at + def values_at(*keys) + keys.map{|key| params[key] } + end + + # the referer of the client or '/' + def referer + @env['HTTP_REFERER'] || '/' + end + alias referrer referer + + + def cookies + return {} unless @env["HTTP_COOKIE"] + + if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] + @env["rack.request.cookie_hash"] + else + @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] + # According to RFC 2109: + # If multiple cookies satisfy the criteria above, they are ordered in + # the Cookie header such that those with more specific Path attributes + # precede those with less specific. Ordering with respect to other + # attributes (e.g., Domain) is unspecified. + @env["rack.request.cookie_hash"] = + Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| + h[k] = Array === v ? v.first : v + h + } + end + end + + def xhr? + @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" + end + + # Tries to return a remake of the original request URL as a string. + def url + url = scheme + "://" + url << host + + if scheme == "https" && port != 443 || + scheme == "http" && port != 80 + url << ":#{port}" + end + + url << fullpath + + url + end + + def path + script_name + path_info + end + + def fullpath + query_string.empty? ? path : "#{path}?#{query_string}" + end + + def accept_encoding + @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| + m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick + + if m + [m[1], (m[2] || 1.0).to_f] + else + raise "Invalid value for Accept-Encoding: #{part.inspect}" + end + end + end + + def ip + if addr = @env['HTTP_X_FORWARDED_FOR'] + addr.split(',').last.strip + else + @env['REMOTE_ADDR'] + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb new file mode 100644 index 0000000000..28b4d8302f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb @@ -0,0 +1,183 @@ +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::Response provides a convenient interface to create a Rack + # response. + # + # It allows setting of headers and cookies, and provides useful + # defaults (a OK response containing HTML). + # + # You can use Response#write to iteratively generate your response, + # but note that this is buffered by Rack::Response until you call + # +finish+. +finish+ however can take a block inside which calls to + # +write+ are syncronous with the Rack response. + # + # Your application's +call+ should end returning Response#finish. + + class Response + attr_accessor :length + + def initialize(body=[], status=200, header={}, &block) + @status = status + @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. + merge(header)) + + @writer = lambda { |x| @body << x } + @block = nil + @length = 0 + + @body = [] + + if body.respond_to? :to_str + write body.to_str + elsif body.respond_to?(:each) + body.each { |part| + write part.to_s + } + else + raise TypeError, "stringable or iterable required" + end + + yield self if block_given? + end + + attr_reader :header + attr_accessor :status, :body + + def [](key) + header[key] + end + + def []=(key, value) + header[key] = value + end + + def set_cookie(key, value) + case value + when Hash + domain = "; domain=" + value[:domain] if value[:domain] + path = "; path=" + value[:path] if value[:path] + # According to RFC 2109, we need dashes here. + # N.B.: cgi.rb uses spaces... + expires = "; expires=" + value[:expires].clone.gmtime. + strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] + secure = "; secure" if value[:secure] + httponly = "; HttpOnly" if value[:httponly] + value = value[:value] + end + value = [value] unless Array === value + cookie = Utils.escape(key) + "=" + + value.map { |v| Utils.escape v }.join("&") + + "#{domain}#{path}#{expires}#{secure}#{httponly}" + + case self["Set-Cookie"] + when Array + self["Set-Cookie"] << cookie + when String + self["Set-Cookie"] = [self["Set-Cookie"], cookie] + when nil + self["Set-Cookie"] = cookie + end + end + + def delete_cookie(key, value={}) + unless Array === self["Set-Cookie"] + self["Set-Cookie"] = [self["Set-Cookie"]].compact + end + + self["Set-Cookie"].reject! { |cookie| + cookie =~ /\A#{Utils.escape(key)}=/ + } + + set_cookie(key, + {:value => '', :path => nil, :domain => nil, + :expires => Time.at(0) }.merge(value)) + end + + def redirect(target, status=302) + self.status = status + self["Location"] = target + end + + def finish(&block) + @block = block + + if [204, 304].include?(status.to_i) + header.delete "Content-Type" + [status.to_i, header.to_hash, []] + else + [status.to_i, header.to_hash, self] + end + end + alias to_a finish # For *response + + def each(&callback) + @body.each(&callback) + @writer = callback + @block.call(self) if @block + end + + # Append to body and update Content-Length. + # + # NOTE: Do not mix #write and direct #body access! + # + def write(str) + s = str.to_s + @length += Rack::Utils.bytesize(s) + @writer.call s + + header["Content-Length"] = @length.to_s + str + end + + def close + body.close if body.respond_to?(:close) + end + + def empty? + @block == nil && @body.empty? + end + + alias headers header + + module Helpers + def invalid?; @status < 100 || @status >= 600; end + + def informational?; @status >= 100 && @status < 200; end + def successful?; @status >= 200 && @status < 300; end + def redirection?; @status >= 300 && @status < 400; end + def client_error?; @status >= 400 && @status < 500; end + def server_error?; @status >= 500 && @status < 600; end + + def ok?; @status == 200; end + def forbidden?; @status == 403; end + def not_found?; @status == 404; end + + def redirect?; [301, 302, 303, 307].include? @status; end + def empty?; [201, 204, 304].include? @status; end + + # Headers + attr_reader :headers, :original_headers + + def include?(header) + !!headers[header] + end + + def content_type + headers["Content-Type"] + end + + def content_length + cl = headers["Content-Length"] + cl ? cl.to_i : cl + end + + def location + headers["Location"] + end + end + + include Helpers + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb new file mode 100644 index 0000000000..9e9b21ff99 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb @@ -0,0 +1,98 @@ +require 'tempfile' + +module Rack + # Class which can make any IO object rewindable, including non-rewindable ones. It does + # this by buffering the data into a tempfile, which is rewindable. + # + # rack.input is required to be rewindable, so if your input stream IO is non-rewindable + # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class + # to easily make it rewindable. + # + # Don't forget to call #close when you're done. This frees up temporary resources that + # RewindableInput uses, though it does *not* close the original IO object. + class RewindableInput + def initialize(io) + @io = io + @rewindable_io = nil + @unlinked = false + end + + def gets + make_rewindable unless @rewindable_io + @rewindable_io.gets + end + + def read(*args) + make_rewindable unless @rewindable_io + @rewindable_io.read(*args) + end + + def each(&block) + make_rewindable unless @rewindable_io + @rewindable_io.each(&block) + end + + def rewind + make_rewindable unless @rewindable_io + @rewindable_io.rewind + end + + # Closes this RewindableInput object without closing the originally + # wrapped IO oject. Cleans up any temporary resources that this RewindableInput + # has created. + # + # This method may be called multiple times. It does nothing on subsequent calls. + def close + if @rewindable_io + if @unlinked + @rewindable_io.close + else + @rewindable_io.close! + end + @rewindable_io = nil + end + end + + private + + # Ruby's Tempfile class has a bug. Subclass it and fix it. + class Tempfile < ::Tempfile + def _close + @tmpfile.close if @tmpfile + @data[1] = nil if @data + @tmpfile = nil + end + end + + def make_rewindable + # Buffer all data into a tempfile. Since this tempfile is private to this + # RewindableInput object, we chmod it so that nobody else can read or write + # it. On POSIX filesystems we also unlink the file so that it doesn't + # even have a file entry on the filesystem anymore, though we can still + # access it because we have the file handle open. + @rewindable_io = Tempfile.new('RackRewindableInput') + @rewindable_io.chmod(0000) + if filesystem_has_posix_semantics? + @rewindable_io.unlink + @unlinked = true + end + + buffer = "" + while @io.read(1024 * 4, buffer) + entire_buffer_written_out = false + while !entire_buffer_written_out + written = @rewindable_io.write(buffer) + entire_buffer_written_out = written == buffer.size + if !entire_buffer_written_out + buffer.slice!(0 .. written - 1) + end + end + end + @rewindable_io.rewind + end + + def filesystem_has_posix_semantics? + RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb new file mode 100644 index 0000000000..218144c17f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb @@ -0,0 +1,142 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# bugrep: Andreas Zehnder + +require 'time' +require 'rack/request' +require 'rack/response' + +module Rack + + module Session + + module Abstract + + # ID sets up a basic framework for implementing an id based sessioning + # service. Cookies sent to the client for maintaining sessions will only + # contain an id reference. Only #get_session and #set_session are + # required to be overwritten. + # + # All parameters are optional. + # * :key determines the name of the cookie, by default it is + # 'rack.session' + # * :path, :domain, :expire_after, :secure, and :httponly set the related + # cookie options as by Rack::Response#add_cookie + # * :defer will not set a cookie in the response. + # * :renew (implementation dependent) will prompt the generation of a new + # session id, and migration of data to be referenced at the new id. If + # :defer is set, it will be overridden and the cookie will be set. + # * :sidbits sets the number of bits in length that a generated session + # id will be. + # + # These options can be set on a per request basis, at the location of + # env['rack.session.options']. Additionally the id of the session can be + # found within the options hash at the key :id. It is highly not + # recommended to change its value. + # + # Is Rack::Utils::Context compatible. + + class ID + DEFAULT_OPTIONS = { + :path => '/', + :domain => nil, + :expire_after => nil, + :secure => false, + :httponly => true, + :defer => false, + :renew => false, + :sidbits => 128 + } + + attr_reader :key, :default_options + def initialize(app, options={}) + @app = app + @key = options[:key] || "rack.session" + @default_options = self.class::DEFAULT_OPTIONS.merge(options) + end + + def call(env) + context(env) + end + + def context(env, app=@app) + load_session(env) + status, headers, body = app.call(env) + commit_session(env, status, headers, body) + end + + private + + # Generate a new session id using Ruby #rand. The size of the + # session id is controlled by the :sidbits option. + # Monkey patch this to use custom methods for session id generation. + + def generate_sid + "%0#{@default_options[:sidbits] / 4}x" % + rand(2**@default_options[:sidbits] - 1) + end + + # Extracts the session id from provided cookies and passes it and the + # environment to #get_session. It then sets the resulting session into + # 'rack.session', and places options and session metadata into + # 'rack.session.options'. + + def load_session(env) + request = Rack::Request.new(env) + session_id = request.cookies[@key] + + begin + session_id, session = get_session(env, session_id) + env['rack.session'] = session + rescue + env['rack.session'] = Hash.new + end + + env['rack.session.options'] = @default_options. + merge(:id => session_id) + end + + # Acquires the session from the environment and the session id from + # the session options and passes them to #set_session. If successful + # and the :defer option is not true, a cookie will be added to the + # response with the session's id. + + def commit_session(env, status, headers, body) + session = env['rack.session'] + options = env['rack.session.options'] + session_id = options[:id] + + if not session_id = set_session(env, session_id, session, options) + env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") + [status, headers, body] + elsif options[:defer] and not options[:renew] + env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE + [status, headers, body] + else + cookie = Hash.new + cookie[:value] = session_id + cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? + response = Rack::Response.new(body, status, headers) + response.set_cookie(@key, cookie.merge(options)) + response.to_a + end + end + + # All thread safety and session retrival proceedures should occur here. + # Should return [session_id, session]. + # If nil is provided as the session id, generation of a new valid id + # should occur within. + + def get_session(env, sid) + raise '#get_session not implemented.' + end + + # All thread safety and session storage proceedures should occur here. + # Should return true or false dependant on whether or not the session + # was saved or not. + def set_session(env, sid, session, options) + raise '#set_session not implemented.' + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb new file mode 100644 index 0000000000..eace9bd0c6 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb @@ -0,0 +1,91 @@ +require 'openssl' +require 'rack/request' +require 'rack/response' + +module Rack + + module Session + + # Rack::Session::Cookie provides simple cookie based session management. + # The session is a Ruby Hash stored as base64 encoded marshalled data + # set to :key (default: rack.session). + # When the secret key is set, cookie data is checked for data integrity. + # + # Example: + # + # use Rack::Session::Cookie, :key => 'rack.session', + # :domain => 'foo.com', + # :path => '/', + # :expire_after => 2592000, + # :secret => 'change_me' + # + # All parameters are optional. + + class Cookie + + def initialize(app, options={}) + @app = app + @key = options[:key] || "rack.session" + @secret = options[:secret] + @default_options = {:domain => nil, + :path => "/", + :expire_after => nil}.merge(options) + end + + def call(env) + load_session(env) + status, headers, body = @app.call(env) + commit_session(env, status, headers, body) + end + + private + + def load_session(env) + request = Rack::Request.new(env) + session_data = request.cookies[@key] + + if @secret && session_data + session_data, digest = session_data.split("--") + session_data = nil unless digest == generate_hmac(session_data) + end + + begin + session_data = session_data.unpack("m*").first + session_data = Marshal.load(session_data) + env["rack.session"] = session_data + rescue + env["rack.session"] = Hash.new + end + + env["rack.session.options"] = @default_options.dup + end + + def commit_session(env, status, headers, body) + session_data = Marshal.dump(env["rack.session"]) + session_data = [session_data].pack("m*") + + if @secret + session_data = "#{session_data}--#{generate_hmac(session_data)}" + end + + if session_data.size > (4096 - @key.size) + env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") + [status, headers, body] + else + options = env["rack.session.options"] + cookie = Hash.new + cookie[:value] = session_data + cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? + response = Rack::Response.new(body, status, headers) + response.set_cookie(@key, cookie.merge(options)) + response.to_a + end + end + + def generate_hmac(data) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb new file mode 100644 index 0000000000..4a65cbf35d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb @@ -0,0 +1,109 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net + +require 'rack/session/abstract/id' +require 'memcache' + +module Rack + module Session + # Rack::Session::Memcache provides simple cookie based session management. + # Session data is stored in memcached. The corresponding session key is + # maintained in the cookie. + # You may treat Session::Memcache as you would Session::Pool with the + # following caveats. + # + # * Setting :expire_after to 0 would note to the Memcache server to hang + # onto the session data until it would drop it according to it's own + # specifications. However, the cookie sent to the client would expire + # immediately. + # + # Note that memcache does drop data before it may be listed to expire. For + # a full description of behaviour, please see memcache's documentation. + + class Memcache < Abstract::ID + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \ + :namespace => 'rack:session', + :memcache_server => 'localhost:11211' + + def initialize(app, options={}) + super + + @mutex = Mutex.new + @pool = MemCache. + new @default_options[:memcache_server], @default_options + raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} + end + + def generate_sid + loop do + sid = super + break sid unless @pool.get(sid, true) + end + end + + def get_session(env, sid) + session = @pool.get(sid) if sid + @mutex.lock if env['rack.multithread'] + unless sid and session + env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? + session = {} + sid = generate_sid + ret = @pool.add sid, session + raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret + end + session.instance_variable_set('@old', {}.merge(session)) + return [sid, session] + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return [ nil, {} ] + ensure + @mutex.unlock if env['rack.multithread'] + end + + def set_session(env, session_id, new_session, options) + expiry = options[:expire_after] + expiry = expiry.nil? ? 0 : expiry + 1 + + @mutex.lock if env['rack.multithread'] + session = @pool.get(session_id) || {} + if options[:renew] or options[:drop] + @pool.delete session_id + return false if options[:drop] + session_id = generate_sid + @pool.add session_id, 0 # so we don't worry about cache miss on #set + end + old_session = new_session.instance_variable_get('@old') || {} + session = merge_sessions session_id, old_session, new_session, session + @pool.set session_id, session, expiry + return session_id + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return false + ensure + @mutex.unlock if env['rack.multithread'] + end + + private + + def merge_sessions sid, old, new, cur=nil + cur ||= {} + unless Hash === old and Hash === new + warn 'Bad old or new sessions provided.' + return cur + end + + delete = old.keys - new.keys + warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? + delete.each{|k| cur.delete k } + + update = new.keys.select{|k| new[k] != old[k] } + warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? + update.each{|k| cur[k] = new[k] } + + cur + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb new file mode 100644 index 0000000000..f6f87408bb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb @@ -0,0 +1,100 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# THANKS: +# apeiros, for session id generation, expiry setup, and threadiness +# sergio, threadiness and bugreps + +require 'rack/session/abstract/id' +require 'thread' + +module Rack + module Session + # Rack::Session::Pool provides simple cookie based session management. + # Session data is stored in a hash held by @pool. + # In the context of a multithreaded environment, sessions being + # committed to the pool is done in a merging manner. + # + # The :drop option is available in rack.session.options if you with to + # explicitly remove the session from the session cache. + # + # Example: + # myapp = MyRackApp.new + # sessioned = Rack::Session::Pool.new(myapp, + # :domain => 'foo.com', + # :expire_after => 2592000 + # ) + # Rack::Handler::WEBrick.run sessioned + + class Pool < Abstract::ID + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false + + def initialize(app, options={}) + super + @pool = Hash.new + @mutex = Mutex.new + end + + def generate_sid + loop do + sid = super + break sid unless @pool.key? sid + end + end + + def get_session(env, sid) + session = @pool[sid] if sid + @mutex.lock if env['rack.multithread'] + unless sid and session + env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? + session = {} + sid = generate_sid + @pool.store sid, session + end + session.instance_variable_set('@old', {}.merge(session)) + return [sid, session] + ensure + @mutex.unlock if env['rack.multithread'] + end + + def set_session(env, session_id, new_session, options) + @mutex.lock if env['rack.multithread'] + session = @pool[session_id] + if options[:renew] or options[:drop] + @pool.delete session_id + return false if options[:drop] + session_id = generate_sid + @pool.store session_id, 0 + end + old_session = new_session.instance_variable_get('@old') || {} + session = merge_sessions session_id, old_session, new_session, session + @pool.store session_id, session + return session_id + rescue + warn "#{new_session.inspect} has been lost." + warn $!.inspect + ensure + @mutex.unlock if env['rack.multithread'] + end + + private + + def merge_sessions sid, old, new, cur=nil + cur ||= {} + unless Hash === old and Hash === new + warn 'Bad old or new sessions provided.' + return cur + end + + delete = old.keys - new.keys + warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty? + delete.each{|k| cur.delete k } + + update = new.keys.select{|k| new[k] != old[k] } + warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty? + update.each{|k| cur[k] = new[k] } + + cur + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb new file mode 100644 index 0000000000..697bc41fdb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb @@ -0,0 +1,349 @@ +require 'ostruct' +require 'erb' +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::ShowExceptions catches all exceptions raised from the app it + # wraps. It shows a useful backtrace with the sourcefile and + # clickable context, the whole Rack environment and the request + # data. + # + # Be careful when you use this on public-facing sites as it could + # reveal information helpful to attackers. + + class ShowExceptions + CONTEXT = 7 + + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + @app.call(env) + rescue StandardError, LoadError, SyntaxError => e + backtrace = pretty(env, e) + [500, + {"Content-Type" => "text/html", + "Content-Length" => backtrace.join.size.to_s}, + backtrace] + end + + def pretty(env, exception) + req = Rack::Request.new(env) + path = (req.script_name + req.path_info).squeeze("/") + + frames = exception.backtrace.map { |line| + frame = OpenStruct.new + if line =~ /(.*?):(\d+)(:in `(.*)')?/ + frame.filename = $1 + frame.lineno = $2.to_i + frame.function = $4 + + begin + lineno = frame.lineno-1 + lines = ::File.readlines(frame.filename) + frame.pre_context_lineno = [lineno-CONTEXT, 0].max + frame.pre_context = lines[frame.pre_context_lineno...lineno] + frame.context_line = lines[lineno].chomp + frame.post_context_lineno = [lineno+CONTEXT, lines.size].min + frame.post_context = lines[lineno+1..frame.post_context_lineno] + rescue + end + + frame + else + nil + end + }.compact + + env["rack.errors"].puts "#{exception.class}: #{exception.message}" + env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } + env["rack.errors"].flush + + [@template.result(binding)] + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django +# Copyright (c) 2005, the Lawrence Journal-World +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' + + + + + + <%=h exception.class %> at <%=h path %> + + + + + +
+

<%=h exception.class %> at <%=h path %>

+

<%=h exception.message %>

+ + + + + + +
Ruby<%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web<%=h req.request_method %> <%=h(req.host + path)%>
+ +

Jump to:

+ +
+ +
+

Traceback (innermost first)

+
    +<% frames.each { |frame| %> +
  • + <%=h frame.filename %>: in <%=h frame.function %> + + <% if frame.context_line %> +
    + <% if frame.pre_context %> +
      + <% frame.pre_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> + +
      +
    1. <%=h frame.context_line %>...
    + + <% if frame.post_context %> +
      + <% frame.post_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> +
    + <% end %> +
  • +<% } %> +
+
+ +
+

Request information

+ +

GET

+ <% unless req.GET.empty? %> + + + + + + + + + <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No GET data.

+ <% end %> + +

POST

+ <% unless req.POST.empty? %> + + + + + + + + + <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No POST data.

+ <% end %> + + + + <% unless req.cookies.empty? %> + + + + + + + + + <% req.cookies.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No cookie data.

+ <% end %> + +

Rack ENV

+ + + + + + + + + <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val %>
+ +
+ +
+

+ You're seeing this error because you use Rack::ShowExceptions. +

+
+ + + +HTML + + # :startdoc: + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb new file mode 100644 index 0000000000..28258c7c89 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb @@ -0,0 +1,106 @@ +require 'erb' +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::ShowStatus catches all empty responses the app it wraps and + # replaces them with a site explaining the error. + # + # Additional details can be put into rack.showstatus.detail + # and will be shown as HTML. If such details exist, the error page + # is always rendered, even if the reply was not empty. + + class ShowStatus + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + empty = headers['Content-Length'].to_i <= 0 + + # client or server error, or explicit message + if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] + req = Rack::Request.new(env) + message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s + detail = env["rack.showstatus.detail"] || message + body = @template.result(binding) + size = Rack::Utils.bytesize(body) + [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] + else + [status, headers, body] + end + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django +# Copyright (c) 2005, the Lawrence Journal-World +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' + + + + + <%=h message %> at <%=h req.script_name + req.path_info %> + + + + +
+

<%=h message %> (<%= status.to_i %>)

+ + + + + + + + + +
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
+
+
+

<%= detail %>

+
+ +
+

+ You're seeing this error because you use Rack::ShowStatus. +

+
+ + +HTML + + # :startdoc: + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb new file mode 100644 index 0000000000..168e8f83b2 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb @@ -0,0 +1,38 @@ +module Rack + + # The Rack::Static middleware intercepts requests for static files + # (javascript files, images, stylesheets, etc) based on the url prefixes + # passed in the options, and serves them using a Rack::File object. This + # allows a Rack stack to serve both static and dynamic content. + # + # Examples: + # use Rack::Static, :urls => ["/media"] + # will serve all requests beginning with /media from the "media" folder + # located in the current directory (ie media/*). + # + # use Rack::Static, :urls => ["/css", "/images"], :root => "public" + # will serve all requests beginning with /css or /images from the folder + # "public" in the current directory (ie public/css/* and public/images/*) + + class Static + + def initialize(app, options={}) + @app = app + @urls = options[:urls] || ["/favicon.ico"] + root = options[:root] || Dir.pwd + @file_server = Rack::File.new(root) + end + + def call(env) + path = env["PATH_INFO"] + can_serve = @urls.any? { |url| path.index(url) == 0 } + + if can_serve + @file_server.call(env) + else + @app.call(env) + end + end + + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb new file mode 100644 index 0000000000..fcf6616c58 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb @@ -0,0 +1,55 @@ +module Rack + # Rack::URLMap takes a hash mapping urls or paths to apps, and + # dispatches accordingly. Support for HTTP/1.1 host names exists if + # the URLs start with http:// or https://. + # + # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part + # relevant for dispatch is in the SCRIPT_NAME, and the rest in the + # PATH_INFO. This should be taken care of when you need to + # reconstruct the URL in order to create links. + # + # URLMap dispatches in such a way that the longest paths are tried + # first, since they are most specific. + + class URLMap + def initialize(map = {}) + remap(map) + end + + def remap(map) + @mapping = map.map { |location, app| + if location =~ %r{\Ahttps?://(.*?)(/.*)} + host, location = $1, $2 + else + host = nil + end + + unless location[0] == ?/ + raise ArgumentError, "paths need to start with /" + end + location = location.chomp('/') + + [host, location, app] + }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first + end + + def call(env) + path = env["PATH_INFO"].to_s.squeeze("/") + script_name = env['SCRIPT_NAME'] + hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') + @mapping.each { |host, location, app| + next unless (hHost == host || sName == host \ + || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) + next unless location == path[0, location.size] + next unless path[location.size] == nil || path[location.size] == ?/ + + return app.call( + env.merge( + 'SCRIPT_NAME' => (script_name + location), + 'PATH_INFO' => path[location.size..-1])) + } + [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] + end + end +end + diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb new file mode 100644 index 0000000000..42e2e698f4 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb @@ -0,0 +1,516 @@ +# -*- encoding: binary -*- + +require 'set' +require 'tempfile' + +module Rack + # Rack::Utils contains a grab-bag of useful methods for writing web + # applications adopted from all kinds of Ruby libraries. + + module Utils + # Performs URI escaping so that you can construct proper + # query strings faster. Use this rather than the cgi.rb + # version since it's faster. (Stolen from Camping). + def escape(s) + s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { + '%'+$1.unpack('H2'*$1.size).join('%').upcase + }.tr(' ', '+') + end + module_function :escape + + # Unescapes a URI escaped string. (Stolen from Camping). + def unescape(s) + s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ + [$1.delete('%')].pack('H*') + } + end + module_function :unescape + + # Stolen from Mongrel, with some small modifications: + # Parses a query string by breaking it up at the '&' + # and ';' characters. You can also use this to parse + # cookies by changing the characters used in the second + # parameter (which defaults to '&;'). + def parse_query(qs, d = '&;') + params = {} + + (qs || '').split(/[#{d}] */n).each do |p| + k, v = unescape(p).split('=', 2) + + if cur = params[k] + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + end + + return params + end + module_function :parse_query + + def parse_nested_query(qs, d = '&;') + params = {} + + (qs || '').split(/[#{d}] */n).each do |p| + k, v = unescape(p).split('=', 2) + normalize_params(params, k, v) + end + + return params + end + module_function :parse_nested_query + + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + params[k] = v + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + module_function :normalize_params + + def build_query(params) + params.map { |k, v| + if v.class == Array + build_query(v.map { |x| [k, x] }) + else + escape(k) + "=" + escape(v) + end + }.join("&") + end + module_function :build_query + + def build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{escape(value)}" + else + prefix + end + end + module_function :build_nested_query + + # Escape ampersands, brackets and quotes to their HTML/XML entities. + def escape_html(string) + string.to_s.gsub("&", "&"). + gsub("<", "<"). + gsub(">", ">"). + gsub("'", "'"). + gsub('"', """) + end + module_function :escape_html + + def select_best_encoding(available_encodings, accept_encoding) + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + + expanded_accept_encoding = + accept_encoding.map { |m, q| + if m == "*" + (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } + else + [[m, q]] + end + }.inject([]) { |mem, list| + mem + list + } + + encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } + + unless encoding_candidates.include?("identity") + encoding_candidates.push("identity") + end + + expanded_accept_encoding.find_all { |m, q| + q == 0.0 + }.each { |m, _| + encoding_candidates.delete(m) + } + + return (encoding_candidates & available_encodings)[0] + end + module_function :select_best_encoding + + # Return the bytesize of String; uses String#length under Ruby 1.8 and + # String#bytesize under 1.9. + if ''.respond_to?(:bytesize) + def bytesize(string) + string.bytesize + end + else + def bytesize(string) + string.size + end + end + module_function :bytesize + + # Context allows the use of a compatible middleware at different points + # in a request handling stack. A compatible middleware must define + # #context which should take the arguments env and app. The first of which + # would be the request environment. The second of which would be the rack + # application that the request would be forwarded to. + class Context + attr_reader :for, :app + + def initialize(app_f, app_r) + raise 'running context does not respond to #context' unless app_f.respond_to? :context + @for, @app = app_f, app_r + end + + def call(env) + @for.context(env, @app) + end + + def recontext(app) + self.class.new(@for, app) + end + + def context(env, app=@app) + recontext(app).call(env) + end + end + + # A case-insensitive Hash that preserves the original case of a + # header when set. + class HeaderHash < Hash + def initialize(hash={}) + @names = {} + hash.each { |k, v| self[k] = v } + end + + def to_hash + inject({}) do |hash, (k,v)| + if v.respond_to? :to_ary + hash[k] = v.to_ary.join("\n") + else + hash[k] = v + end + hash + end + end + + def [](k) + super @names[k.downcase] + end + + def []=(k, v) + delete k + @names[k.downcase] = k + super k, v + end + + def delete(k) + super @names.delete(k.downcase) + end + + def include?(k) + @names.has_key? k.downcase + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + + def merge(other) + hash = dup + hash.merge! other + end + end + + # Every standard HTTP code mapped to the appropriate message. + # Stolen from Mongrel. + HTTP_STATUS_CODES = { + 100 => 'Continue', + 101 => 'Switching Protocols', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Large', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + } + + # Responses with HTTP status codes that should not have an entity body + STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) + + # A multipart form data parser, adapted from IOWA. + # + # Usually, Rack::Request#POST takes care of calling this. + + module Multipart + 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 + + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" + + def self.parse_multipart(env) + unless env['CONTENT_TYPE'] =~ + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n + nil + else + boundary = "--#{$1}" + + params = {} + buf = "" + content_length = env['CONTENT_LENGTH'].to_i + input = env['rack.input'] + input.rewind + + boundary_size = Utils.bytesize(boundary) + EOL.size + bufsize = 16384 + + content_length -= boundary_size + + read_buffer = '' + + status = input.read(boundary_size, read_buffer) + raise EOFError, "bad content body" unless status == boundary + EOL + + rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n + + loop { + head = nil + body = '' + filename = content_type = name = nil + + until head && buf =~ rx + if !head && i = buf.index(EOL+EOL) + head = buf.slice!(0, i+2) # First \r\n + buf.slice!(0, 2) # Second \r\n + + filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] + + if content_type || filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end + + next + end + + # Save the read body part. + if head && (boundary_size+4 < buf.size) + body << buf.slice!(0, buf.size - (boundary_size+4)) + end + + c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) + raise EOFError, "bad content body" if c.nil? || c.empty? + buf << c + content_length -= c.size + end + + # Save the rest. + if i = buf.index(rx) + body << buf.slice!(0, i) + buf.slice!(0, boundary_size+2) + + content_length = -1 if $1 == "--" + end + + if filename == "" + # filename is blank which means no file has been selected + data = nil + elsif filename + body.rewind + + # Take the basename of the upload's original filename. + # This handles the full Windows paths given by Internet Explorer + # (and perhaps other broken user agents) without affecting + # those which give the lone filename. + filename =~ /^(?:.*[:\\\/])?(.*)/m + filename = $1 + + data = {:filename => filename, :type => content_type, + :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} + else + data = body + end + + Utils.normalize_params(params, name, data) unless data.nil? + + break if buf.empty? || content_length == -1 + } + + input.rewind + + params + end + end + + def self.build_multipart(params, first = true) + if first + unless params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + + multipart = false + query = lambda { |value| + case value + when Array + value.each(&query) + when Hash + value.values.each(&query) + when UploadedFile + multipart = true + end + } + params.values.each(&query) + return nil unless multipart + end + + flattened_params = Hash.new + + params.each do |key, value| + k = first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + build_multipart(v, false).each { |subkey, subvalue| + flattened_params["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + build_multipart(value, false).each { |subkey, subvalue| + flattened_params[k + subkey] = subvalue + } + else + flattened_params[k] = value + end + end + + if first + flattened_params.map { |name, file| + if file.respond_to?(:original_filename) + ::File.open(file.path, "rb") do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r +Content-Type: #{file.content_type}\r +Content-Length: #{::File.stat(file.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + }.join + "--#{MULTIPART_BOUNDARY}--\r" + else + flattened_params + end + end + end + end +end -- cgit v1.2.3 From 853c229bbdb32c27231df8ad0d446bb35e588586 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 1 May 2009 20:24:14 +0100 Subject: Rename vendor/rack to vendor/rack-1.1.pre --- actionpack/lib/action_dispatch.rb | 4 +- .../action_dispatch/vendor/rack-1.1.pre/rack.rb | 90 ++++ .../vendor/rack-1.1.pre/rack/adapter/camping.rb | 22 + .../rack-1.1.pre/rack/auth/abstract/handler.rb | 37 ++ .../rack-1.1.pre/rack/auth/abstract/request.rb | 37 ++ .../vendor/rack-1.1.pre/rack/auth/basic.rb | 58 +++ .../vendor/rack-1.1.pre/rack/auth/digest/md5.rb | 124 +++++ .../vendor/rack-1.1.pre/rack/auth/digest/nonce.rb | 51 ++ .../vendor/rack-1.1.pre/rack/auth/digest/params.rb | 55 +++ .../rack-1.1.pre/rack/auth/digest/request.rb | 40 ++ .../vendor/rack-1.1.pre/rack/auth/openid.rb | 480 ++++++++++++++++++ .../vendor/rack-1.1.pre/rack/builder.rb | 63 +++ .../vendor/rack-1.1.pre/rack/cascade.rb | 36 ++ .../vendor/rack-1.1.pre/rack/chunked.rb | 49 ++ .../vendor/rack-1.1.pre/rack/commonlogger.rb | 61 +++ .../vendor/rack-1.1.pre/rack/conditionalget.rb | 47 ++ .../vendor/rack-1.1.pre/rack/content_length.rb | 29 ++ .../vendor/rack-1.1.pre/rack/content_type.rb | 23 + .../vendor/rack-1.1.pre/rack/deflater.rb | 96 ++++ .../vendor/rack-1.1.pre/rack/directory.rb | 153 ++++++ .../vendor/rack-1.1.pre/rack/file.rb | 88 ++++ .../vendor/rack-1.1.pre/rack/handler.rb | 69 +++ .../vendor/rack-1.1.pre/rack/handler/cgi.rb | 61 +++ .../rack-1.1.pre/rack/handler/evented_mongrel.rb | 8 + .../vendor/rack-1.1.pre/rack/handler/fastcgi.rb | 88 ++++ .../vendor/rack-1.1.pre/rack/handler/lsws.rb | 55 +++ .../vendor/rack-1.1.pre/rack/handler/mongrel.rb | 84 ++++ .../vendor/rack-1.1.pre/rack/handler/scgi.rb | 59 +++ .../rack/handler/swiftiplied_mongrel.rb | 8 + .../vendor/rack-1.1.pre/rack/handler/thin.rb | 18 + .../vendor/rack-1.1.pre/rack/handler/webrick.rb | 67 +++ .../vendor/rack-1.1.pre/rack/head.rb | 19 + .../vendor/rack-1.1.pre/rack/lint.rb | 537 +++++++++++++++++++++ .../vendor/rack-1.1.pre/rack/lobster.rb | 65 +++ .../vendor/rack-1.1.pre/rack/lock.rb | 16 + .../vendor/rack-1.1.pre/rack/methodoverride.rb | 27 ++ .../vendor/rack-1.1.pre/rack/mime.rb | 204 ++++++++ .../vendor/rack-1.1.pre/rack/mock.rb | 184 +++++++ .../vendor/rack-1.1.pre/rack/recursive.rb | 57 +++ .../vendor/rack-1.1.pre/rack/reloader.rb | 106 ++++ .../vendor/rack-1.1.pre/rack/request.rb | 254 ++++++++++ .../vendor/rack-1.1.pre/rack/response.rb | 183 +++++++ .../vendor/rack-1.1.pre/rack/rewindable_input.rb | 98 ++++ .../rack-1.1.pre/rack/session/abstract/id.rb | 142 ++++++ .../vendor/rack-1.1.pre/rack/session/cookie.rb | 91 ++++ .../vendor/rack-1.1.pre/rack/session/memcache.rb | 109 +++++ .../vendor/rack-1.1.pre/rack/session/pool.rb | 100 ++++ .../vendor/rack-1.1.pre/rack/showexceptions.rb | 349 +++++++++++++ .../vendor/rack-1.1.pre/rack/showstatus.rb | 106 ++++ .../vendor/rack-1.1.pre/rack/static.rb | 38 ++ .../vendor/rack-1.1.pre/rack/urlmap.rb | 55 +++ .../vendor/rack-1.1.pre/rack/utils.rb | 516 ++++++++++++++++++++ actionpack/lib/action_dispatch/vendor/rack/rack.rb | 90 ---- .../vendor/rack/rack/adapter/camping.rb | 22 - .../vendor/rack/rack/auth/abstract/handler.rb | 37 -- .../vendor/rack/rack/auth/abstract/request.rb | 37 -- .../action_dispatch/vendor/rack/rack/auth/basic.rb | 58 --- .../vendor/rack/rack/auth/digest/md5.rb | 124 ----- .../vendor/rack/rack/auth/digest/nonce.rb | 51 -- .../vendor/rack/rack/auth/digest/params.rb | 55 --- .../vendor/rack/rack/auth/digest/request.rb | 40 -- .../vendor/rack/rack/auth/openid.rb | 480 ------------------ .../action_dispatch/vendor/rack/rack/builder.rb | 63 --- .../action_dispatch/vendor/rack/rack/cascade.rb | 36 -- .../action_dispatch/vendor/rack/rack/chunked.rb | 49 -- .../vendor/rack/rack/commonlogger.rb | 61 --- .../vendor/rack/rack/conditionalget.rb | 47 -- .../vendor/rack/rack/content_length.rb | 29 -- .../vendor/rack/rack/content_type.rb | 23 - .../action_dispatch/vendor/rack/rack/deflater.rb | 96 ---- .../action_dispatch/vendor/rack/rack/directory.rb | 153 ------ .../lib/action_dispatch/vendor/rack/rack/file.rb | 88 ---- .../action_dispatch/vendor/rack/rack/handler.rb | 69 --- .../vendor/rack/rack/handler/cgi.rb | 61 --- .../vendor/rack/rack/handler/evented_mongrel.rb | 8 - .../vendor/rack/rack/handler/fastcgi.rb | 88 ---- .../vendor/rack/rack/handler/lsws.rb | 55 --- .../vendor/rack/rack/handler/mongrel.rb | 84 ---- .../vendor/rack/rack/handler/scgi.rb | 59 --- .../rack/rack/handler/swiftiplied_mongrel.rb | 8 - .../vendor/rack/rack/handler/thin.rb | 18 - .../vendor/rack/rack/handler/webrick.rb | 67 --- .../lib/action_dispatch/vendor/rack/rack/head.rb | 19 - .../lib/action_dispatch/vendor/rack/rack/lint.rb | 537 --------------------- .../action_dispatch/vendor/rack/rack/lobster.rb | 65 --- .../lib/action_dispatch/vendor/rack/rack/lock.rb | 16 - .../vendor/rack/rack/methodoverride.rb | 27 -- .../lib/action_dispatch/vendor/rack/rack/mime.rb | 204 -------- .../lib/action_dispatch/vendor/rack/rack/mock.rb | 184 ------- .../action_dispatch/vendor/rack/rack/recursive.rb | 57 --- .../action_dispatch/vendor/rack/rack/reloader.rb | 106 ---- .../action_dispatch/vendor/rack/rack/request.rb | 254 ---------- .../action_dispatch/vendor/rack/rack/response.rb | 183 ------- .../vendor/rack/rack/rewindable_input.rb | 98 ---- .../vendor/rack/rack/session/abstract/id.rb | 142 ------ .../vendor/rack/rack/session/cookie.rb | 91 ---- .../vendor/rack/rack/session/memcache.rb | 109 ----- .../vendor/rack/rack/session/pool.rb | 100 ---- .../vendor/rack/rack/showexceptions.rb | 349 ------------- .../action_dispatch/vendor/rack/rack/showstatus.rb | 106 ---- .../lib/action_dispatch/vendor/rack/rack/static.rb | 38 -- .../lib/action_dispatch/vendor/rack/rack/urlmap.rb | 55 --- .../lib/action_dispatch/vendor/rack/rack/utils.rb | 516 -------------------- 103 files changed, 5414 insertions(+), 5414 deletions(-) create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/file.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/head.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/request.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/response.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/static.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb delete mode 100644 actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index a57fc5abdd..5f6202d153 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -33,9 +33,9 @@ end require 'active_support/core/all' begin - gem 'rack', '~> 1.1.0' + gem 'rack', '~> 1.1.pre' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack" + $:.unshift "#{File.dirname(__FILE__)}/action_dispatch/vendor/rack-1.1.pre" end require 'rack' diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb new file mode 100644 index 0000000000..371d015690 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb @@ -0,0 +1,90 @@ +# Copyright (C) 2007, 2008, 2009 Christian Neukirchen +# +# Rack is freely distributable under the terms of an MIT-style license. +# See COPYING or http://www.opensource.org/licenses/mit-license.php. + +path = File.expand_path(File.dirname(__FILE__)) +$:.unshift(path) unless $:.include?(path) + + +# The Rack main module, serving as a namespace for all core Rack +# modules and classes. +# +# All modules meant for use in your application are autoloaded here, +# so it should be enough just to require rack.rb in your code. + +module Rack + # The Rack protocol version number implemented. + VERSION = [1,0] + + # Return the Rack protocol version as a dotted string. + def self.version + VERSION.join(".") + end + + # Return the Rack release as a dotted string. + def self.release + "1.0" + end + + autoload :Builder, "rack/builder" + autoload :Cascade, "rack/cascade" + autoload :Chunked, "rack/chunked" + autoload :CommonLogger, "rack/commonlogger" + autoload :ConditionalGet, "rack/conditionalget" + autoload :ContentLength, "rack/content_length" + autoload :ContentType, "rack/content_type" + autoload :File, "rack/file" + autoload :Deflater, "rack/deflater" + autoload :Directory, "rack/directory" + autoload :ForwardRequest, "rack/recursive" + autoload :Handler, "rack/handler" + autoload :Head, "rack/head" + autoload :Lint, "rack/lint" + autoload :Lock, "rack/lock" + autoload :MethodOverride, "rack/methodoverride" + autoload :Mime, "rack/mime" + autoload :Recursive, "rack/recursive" + autoload :Reloader, "rack/reloader" + autoload :ShowExceptions, "rack/showexceptions" + autoload :ShowStatus, "rack/showstatus" + autoload :Static, "rack/static" + autoload :URLMap, "rack/urlmap" + autoload :Utils, "rack/utils" + + autoload :MockRequest, "rack/mock" + autoload :MockResponse, "rack/mock" + + autoload :Request, "rack/request" + autoload :Response, "rack/response" + + module Auth + autoload :Basic, "rack/auth/basic" + autoload :AbstractRequest, "rack/auth/abstract/request" + autoload :AbstractHandler, "rack/auth/abstract/handler" + autoload :OpenID, "rack/auth/openid" + module Digest + autoload :MD5, "rack/auth/digest/md5" + autoload :Nonce, "rack/auth/digest/nonce" + autoload :Params, "rack/auth/digest/params" + autoload :Request, "rack/auth/digest/request" + end + end + + module Session + autoload :Cookie, "rack/session/cookie" + autoload :Pool, "rack/session/pool" + autoload :Memcache, "rack/session/memcache" + end + + # *Adapters* connect Rack with third party web frameworks. + # + # Rack includes an adapter for Camping, see README for other + # frameworks supporting Rack in their code bases. + # + # Refer to the submodules for framework-specific calling details. + + module Adapter + autoload :Camping, "rack/adapter/camping" + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb new file mode 100644 index 0000000000..63bc787f54 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb @@ -0,0 +1,22 @@ +module Rack + module Adapter + class Camping + def initialize(app) + @app = app + end + + def call(env) + env["PATH_INFO"] ||= "" + env["SCRIPT_NAME"] ||= "" + controller = @app.run(env['rack.input'], env) + h = controller.headers + h.each_pair do |k,v| + if v.kind_of? URI + h[k] = v.to_s + end + end + [controller.status, controller.headers, [controller.body.to_s]] + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb new file mode 100644 index 0000000000..214df6299e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb @@ -0,0 +1,37 @@ +module Rack + module Auth + # Rack::Auth::AbstractHandler implements common authentication functionality. + # + # +realm+ should be set for all handlers. + + class AbstractHandler + + attr_accessor :realm + + def initialize(app, realm=nil, &authenticator) + @app, @realm, @authenticator = app, realm, authenticator + end + + + private + + def unauthorized(www_authenticate = challenge) + return [ 401, + { 'Content-Type' => 'text/plain', + 'Content-Length' => '0', + 'WWW-Authenticate' => www_authenticate.to_s }, + [] + ] + end + + def bad_request + return [ 400, + { 'Content-Type' => 'text/plain', + 'Content-Length' => '0' }, + [] + ] + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb new file mode 100644 index 0000000000..1d9ccec685 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb @@ -0,0 +1,37 @@ +module Rack + module Auth + class AbstractRequest + + def initialize(env) + @env = env + end + + def provided? + !authorization_key.nil? + end + + def parts + @parts ||= @env[authorization_key].split(' ', 2) + end + + def scheme + @scheme ||= parts.first.downcase.to_sym + end + + def params + @params ||= parts.last + end + + + private + + AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] + + def authorization_key + @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } + end + + end + + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb new file mode 100644 index 0000000000..9557224648 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb @@ -0,0 +1,58 @@ +require 'rack/auth/abstract/handler' +require 'rack/auth/abstract/request' + +module Rack + module Auth + # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. + # + # Initialize with the Rack application that you want protecting, + # and a block that checks if a username and password pair are valid. + # + # See also: example/protectedlobster.rb + + class Basic < AbstractHandler + + def call(env) + auth = Basic::Request.new(env) + + return unauthorized unless auth.provided? + + return bad_request unless auth.basic? + + if valid?(auth) + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + + unauthorized + end + + + private + + def challenge + 'Basic realm="%s"' % realm + end + + def valid?(auth) + @authenticator.call(*auth.credentials) + end + + class Request < Auth::AbstractRequest + def basic? + :basic == scheme + end + + def credentials + @credentials ||= params.unpack("m*").first.split(/:/, 2) + end + + def username + credentials.first + end + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb new file mode 100644 index 0000000000..e579dc9632 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb @@ -0,0 +1,124 @@ +require 'rack/auth/abstract/handler' +require 'rack/auth/digest/request' +require 'rack/auth/digest/params' +require 'rack/auth/digest/nonce' +require 'digest/md5' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of + # HTTP Digest Authentication, as per RFC 2617. + # + # Initialize with the [Rack] application that you want protecting, + # and a block that looks up a plaintext password for a given username. + # + # +opaque+ needs to be set to a constant base64/hexadecimal string. + # + class MD5 < AbstractHandler + + attr_accessor :opaque + + attr_writer :passwords_hashed + + def initialize(*args) + super + @passwords_hashed = nil + end + + def passwords_hashed? + !!@passwords_hashed + end + + def call(env) + auth = Request.new(env) + + unless auth.provided? + return unauthorized + end + + if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) + return bad_request + end + + if valid?(auth) + if auth.nonce.stale? + return unauthorized(challenge(:stale => true)) + else + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + end + + unauthorized + end + + + private + + QOP = 'auth'.freeze + + def params(hash = {}) + Params.new do |params| + params['realm'] = realm + params['nonce'] = Nonce.new.to_s + params['opaque'] = H(opaque) + params['qop'] = QOP + + hash.each { |k, v| params[k] = v } + end + end + + def challenge(hash = {}) + "Digest #{params(hash)}" + end + + def valid?(auth) + valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) + end + + def valid_qop?(auth) + QOP == auth.qop + end + + def valid_opaque?(auth) + H(opaque) == auth.opaque + end + + def valid_nonce?(auth) + auth.nonce.valid? + end + + def valid_digest?(auth) + digest(auth, @authenticator.call(auth.username)) == auth.response + end + + def md5(data) + ::Digest::MD5.hexdigest(data) + end + + alias :H :md5 + + def KD(secret, data) + H([secret, data] * ':') + end + + def A1(auth, password) + [ auth.username, auth.realm, password ] * ':' + end + + def A2(auth) + [ auth.method, auth.uri ] * ':' + end + + def digest(auth, password) + password_hash = passwords_hashed? ? password : H(A1(auth, password)) + + KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb new file mode 100644 index 0000000000..dbe109f29a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb @@ -0,0 +1,51 @@ +require 'digest/md5' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::Nonce is the default nonce generator for the + # Rack::Auth::Digest::MD5 authentication handler. + # + # +private_key+ needs to set to a constant string. + # + # +time_limit+ can be optionally set to an integer (number of seconds), + # to limit the validity of the generated nonces. + + class Nonce + + class << self + attr_accessor :private_key, :time_limit + end + + def self.parse(string) + new(*string.unpack("m*").first.split(' ', 2)) + end + + def initialize(timestamp = Time.now, given_digest = nil) + @timestamp, @given_digest = timestamp.to_i, given_digest + end + + def to_s + [([ @timestamp, digest ] * ' ')].pack("m*").strip + end + + def digest + ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') + end + + def valid? + digest == @given_digest + end + + def stale? + !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit + end + + def fresh? + !stale? + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb new file mode 100644 index 0000000000..730e2efdc8 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb @@ -0,0 +1,55 @@ +module Rack + module Auth + module Digest + class Params < Hash + + def self.parse(str) + split_header_value(str).inject(new) do |header, param| + k, v = param.split('=', 2) + header[k] = dequote(v) + header + end + end + + def self.dequote(str) # From WEBrick::HTTPUtils + ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup + ret.gsub!(/\\(.)/, "\\1") + ret + end + + def self.split_header_value(str) + str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } + end + + def initialize + super + + yield self if block_given? + end + + def [](k) + super k.to_s + end + + def []=(k, v) + super k.to_s, v.to_s + end + + UNQUOTED = ['qop', 'nc', 'stale'] + + def to_s + inject([]) do |parts, (k, v)| + parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) + parts + end.join(', ') + end + + def quote(str) # From WEBrick::HTTPUtils + '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' + end + + end + end + end +end + diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb new file mode 100644 index 0000000000..a8aa3bf996 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb @@ -0,0 +1,40 @@ +require 'rack/auth/abstract/request' +require 'rack/auth/digest/params' +require 'rack/auth/digest/nonce' + +module Rack + module Auth + module Digest + class Request < Auth::AbstractRequest + + def method + @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] + end + + def digest? + :digest == scheme + end + + def correct_uri? + (@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri + end + + def nonce + @nonce ||= Nonce.parse(params['nonce']) + end + + def params + @params ||= Params.parse(parts.last) + end + + def method_missing(sym) + if params.has_key? key = sym.to_s + return params[key] + end + super + end + + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb new file mode 100644 index 0000000000..c5f6a5143e --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb @@ -0,0 +1,480 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net + +gem 'ruby-openid', '~> 2' if defined? Gem +require 'rack/request' +require 'rack/utils' +require 'rack/auth/abstract/handler' +require 'uri' +require 'openid' #gem +require 'openid/extension' #gem +require 'openid/store/memory' #gem + +module Rack + class Request + def openid_request + @env['rack.auth.openid.request'] + end + + def openid_response + @env['rack.auth.openid.response'] + end + end + + module Auth + + # Rack::Auth::OpenID provides a simple method for setting up an OpenID + # Consumer. It requires the ruby-openid library from janrain to operate, + # as well as a rack method of session management. + # + # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. + # + # The OpenID specifications can be found at + # http://openid.net/specs/openid-authentication-1_1.html + # and + # http://openid.net/specs/openid-authentication-2_0.html. Documentation + # for published OpenID extensions and related topics can be found at + # http://openid.net/developers/specs/. + # + # It is recommended to read through the OpenID spec, as well as + # ruby-openid's documentation, to understand what exactly goes on. However + # a setup as simple as the presented examples is enough to provide + # Consumer functionality. + # + # This library strongly intends to utilize the OpenID 2.0 features of the + # ruby-openid library, which provides OpenID 1.0 compatiblity. + # + # NOTE: Due to the amount of data that this library stores in the + # session, Rack::Session::Cookie may fault. + + class OpenID + + class NoSession < RuntimeError; end + class BadExtension < RuntimeError; end + # Required for ruby-openid + ValidStatus = [:success, :setup_needed, :cancel, :failure] + + # = Arguments + # + # The first argument is the realm, identifying the site they are trusting + # with their identity. This is required, also treated as the trust_root + # in OpenID 1.x exchanges. + # + # The optional second argument is a hash of options. + # + # == Options + # + # :return_to defines the url to return to after the client + # authenticates with the openid service provider. This url should point + # to where Rack::Auth::OpenID is mounted. If :return_to is not + # provided, return_to will be the current url which allows flexibility + # with caveats. + # + # :session_key defines the key to the session hash in the env. + # It defaults to 'rack.session'. + # + # :openid_param defines at what key in the request parameters to + # find the identifier to resolve. As per the 2.0 spec, the default is + # 'openid_identifier'. + # + # :store defined what OpenID Store to use for persistant + # information. By default a Store::Memory will be used. + # + # :immediate as true will make initial requests to be of an + # immediate type. This is false by default. See OpenID specification + # documentation. + # + # :extensions should be a hash of openid extension + # implementations. The key should be the extension main module, the value + # should be an array of arguments for extension::Request.new. + # The hash is iterated over and passed to #add_extension for processing. + # Please see #add_extension for further documentation. + # + # == Examples + # + # simple_oid = OpenID.new('http://mysite.com/') + # + # return_oid = OpenID.new('http://mysite.com/', { + # :return_to => 'http://mysite.com/openid' + # }) + # + # complex_oid = OpenID.new('http://mysite.com/', + # :immediate => true, + # :extensions => { + # ::OpenID::SReg => [['email'],['nickname']] + # } + # ) + # + # = Advanced + # + # Most of the functionality of this library is encapsulated such that + # expansion and overriding functions isn't difficult nor tricky. + # Alternately, to avoid opening up singleton objects or subclassing, a + # wrapper rack middleware can be composed to act upon Auth::OpenID's + # responses. See #check and #finish for locations of pertinent data. + # + # == Responses + # + # To change the responses that Auth::OpenID returns, override the methods + # #redirect, #bad_request, #unauthorized, #access_denied, and + # #foreign_server_failure. + # + # Additionally #confirm_post_params is used when the URI would exceed + # length limits on a GET request when doing the initial verification + # request. + # + # == Processing + # + # To change methods of processing completed transactions, override the + # methods #success, #setup_needed, #cancel, and #failure. Please ensure + # the returned object is a rack compatible response. + # + # The first argument is an OpenID::Response, the second is a + # Rack::Request of the current request, the last is the hash used in + # ruby-openid handling, which can be found manually at + # env['rack.session'][:openid]. + # + # This is useful if you wanted to expand the processing done, such as + # setting up user accounts. + # + # oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to + # def oid_app.success oid, request, session + # user = Models::User[oid.identity_url] + # user ||= Models::User.create_from_openid oid + # request['rack.session'][:user] = user.id + # redirect MyApp.site_home + # end + # + # site_map['/openid'] = oid_app + # map = Rack::URLMap.new site_map + # ... + + def initialize(realm, options={}) + realm = URI(realm) + raise ArgumentError, "Invalid realm: #{realm}" \ + unless realm.absolute? \ + and realm.fragment.nil? \ + and realm.scheme =~ /^https?$/ \ + and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/ + realm.path = '/' if realm.path.empty? + @realm = realm.to_s + + if ruri = options[:return_to] + ruri = URI(ruri) + raise ArgumentError, "Invalid return_to: #{ruri}" \ + unless ruri.absolute? \ + and ruri.scheme =~ /^https?$/ \ + and ruri.fragment.nil? + raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \ + unless self.within_realm?(ruri) + @return_to = ruri.to_s + end + + @session_key = options[:session_key] || 'rack.session' + @openid_param = options[:openid_param] || 'openid_identifier' + @store = options[:store] || ::OpenID::Store::Memory.new + @immediate = !!options[:immediate] + + @extensions = {} + if extensions = options.delete(:extensions) + extensions.each do |ext, args| + add_extension ext, *args + end + end + + # Undocumented, semi-experimental + @anonymous = !!options[:anonymous] + end + + attr_reader :realm, :return_to, :session_key, :openid_param, :store, + :immediate, :extensions + + # Sets up and uses session data at :openid within the session. + # Errors in this setup will raise a NoSession exception. + # + # If the parameter 'openid.mode' is set, which implies a followup from + # the openid server, processing is passed to #finish and the result is + # returned. However, if there is no appropriate openid information in the + # session, a 400 error is returned. + # + # If the parameter specified by options[:openid_param] is + # present, processing is passed to #check and the result is returned. + # + # If neither of these conditions are met, #unauthorized is called. + + def call(env) + env['rack.auth.openid'] = self + env_session = env[@session_key] + unless env_session and env_session.is_a?(Hash) + raise NoSession, 'No compatible session' + end + # let us work in our own namespace... + session = (env_session[:openid] ||= {}) + unless session and session.is_a?(Hash) + raise NoSession, 'Incompatible openid session' + end + + request = Rack::Request.new(env) + consumer = ::OpenID::Consumer.new(session, @store) + + if mode = request.GET['openid.mode'] + if session.key?(:openid_param) + finish(consumer, session, request) + else + bad_request + end + elsif request.GET[@openid_param] + check(consumer, session, request) + else + unauthorized + end + end + + # As the first part of OpenID consumer action, #check retrieves the data + # required for completion. + # + # If all parameters fit within the max length of a URI, a 303 redirect + # will be returned. Otherwise #confirm_post_params will be called. + # + # Any messages from OpenID's request are logged to env['rack.errors'] + # + # env['rack.auth.openid.request'] is the openid checkid request + # instance. + # + # session[:openid_param] is set to the openid identifier + # provided by the user. + # + # session[:return_to] is set to the return_to uri given to the + # identity provider. + + def check(consumer, session, req) + oid = consumer.begin(req.GET[@openid_param], @anonymous) + req.env['rack.auth.openid.request'] = oid + req.env['rack.errors'].puts(oid.message) + p oid if $DEBUG + + ## Extension support + extensions.each do |ext,args| + oid.add_extension(ext::Request.new(*args)) + end + + session[:openid_param] = req.GET[openid_param] + return_to_uri = return_to ? return_to : req.url + session[:return_to] = return_to_uri + immediate = session.key?(:setup_needed) ? false : immediate + + if oid.send_redirect?(realm, return_to_uri, immediate) + uri = oid.redirect_url(realm, return_to_uri, immediate) + redirect(uri) + else + confirm_post_params(oid, realm, return_to_uri, immediate) + end + rescue ::OpenID::DiscoveryFailure => e + # thrown from inside OpenID::Consumer#begin by yadis stuff + req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n") + return foreign_server_failure + end + + # This is the final portion of authentication. + # If successful, a redirect to the realm is be returned. + # Data gathered from extensions are stored in session[:openid] with the + # extension's namespace uri as the key. + # + # Any messages from OpenID's response are logged to env['rack.errors'] + # + # env['rack.auth.openid.response'] will contain the openid + # response. + + def finish(consumer, session, req) + oid = consumer.complete(req.GET, req.url) + req.env['rack.auth.openid.response'] = oid + req.env['rack.errors'].puts(oid.message) + p oid if $DEBUG + + raise unless ValidStatus.include?(oid.status) + __send__(oid.status, oid, req, session) + end + + # The first argument should be the main extension module. + # The extension module should contain the constants: + # * class Request, should have OpenID::Extension as an ancestor + # * class Response, should have OpenID::Extension as an ancestor + # * string NS_URI, which defining the namespace of the extension + # + # All trailing arguments will be passed to extension::Request.new in + # #check. + # The openid response will be passed to + # extension::Response#from_success_response, #get_extension_args will be + # called on the result to attain the gathered data. + # + # This method returns the key at which the response data will be found in + # the session, which is the namespace uri by default. + + def add_extension(ext, *args) + raise BadExtension unless valid_extension?(ext) + extensions[ext] = args + return ext::NS_URI + end + + # Checks the validitity, in the context of usage, of a submitted + # extension. + + def valid_extension?(ext) + if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) } + raise ArgumentError, 'Extension is missing constants.' + elsif not ext::Response.respond_to?(:from_success_response) + raise ArgumentError, 'Response is missing required method.' + end + return true + rescue + return false + end + + # Checks the provided uri to ensure it'd be considered within the realm. + # is currently not compatible with wildcard realms. + + def within_realm? uri + uri = URI.parse(uri.to_s) + realm = URI.parse(self.realm) + return false unless uri.absolute? + return false unless uri.path[0, realm.path.size] == realm.path + return false unless uri.host == realm.host or realm.host[/^\*\./] + # for wildcard support, is awkward with URI limitations + realm_match = Regexp.escape(realm.host). + sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$' + return false unless uri.host.match(realm_match) + return true + end + alias_method :include?, :within_realm? + + protected + + ### These methods define some of the boilerplate responses. + + # Returns an html form page for posting to an Identity Provider if the + # GET request would exceed the upper URI length limit. + + def confirm_post_params(oid, realm, return_to, immediate) + Rack::Response.new.finish do |r| + r.write 'Confirm...' + r.write oid.form_markup(realm, return_to, immediate) + r.write '' + end + end + + # Returns a 303 redirect with the destination of that provided by the + # argument. + + def redirect(uri) + [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain', + 'Location' => uri}, + [] ] + end + + # Returns an empty 400 response. + + def bad_request + [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'}, + [''] ] + end + + # Returns a basic unauthorized 401 response. + + def unauthorized + [ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'}, + ['Unauthorized.'] ] + end + + # Returns a basic access denied 403 response. + + def access_denied + [ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'}, + ['Access denied.'] ] + end + + # Returns a 503 response to be used if communication with the remote + # OpenID server fails. + + def foreign_server_failure + [ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'}, + ['Foreign server failure.'] ] + end + + private + + ### These methods are called after a transaction is completed, depending + # on its outcome. These should all return a rack compatible response. + # You'd want to override these to provide additional functionality. + + # Called to complete processing on a successful transaction. + # Within the openid session, :openid_identity and :openid_identifier are + # set to the user friendly and the standard representation of the + # validated identity. All other data in the openid session is cleared. + + def success(oid, request, session) + session.clear + session[:openid_identity] = oid.display_identifier + session[:openid_identifier] = oid.identity_url + extensions.keys.each do |ext| + label = ext.name[/[^:]+$/].downcase + response = ext::Response.from_success_response(oid) + session[label] = response.data + end + redirect(realm) + end + + # Called if the Identity Provider indicates further setup by the user is + # required. + # The identifier is retrived from the openid session at :openid_param. + # And :setup_needed is set to true to prevent looping. + + def setup_needed(oid, request, session) + identifier = session[:openid_param] + session[:setup_needed] = true + redirect req.script_name + '?' + openid_param + '=' + identifier + end + + # Called if the user indicates they wish to cancel identification. + # Data within openid session is cleared. + + def cancel(oid, request, session) + session.clear + access_denied + end + + # Called if the Identity Provider indicates the user is unable to confirm + # their identity. Data within the openid session is left alone, in case + # of swarm auth attacks. + + def failure(oid, request, session) + unauthorized + end + end + + # A class developed out of the request to use OpenID as an authentication + # middleware. The request will be sent to the OpenID instance unless the + # block evaluates to true. For example in rackup, you can use it as such: + # + # use Rack::Session::Pool + # use Rack::Auth::OpenIDAuth, realm, openid_options do |env| + # env['rack.session'][:authkey] == a_string + # end + # run RackApp + # + # Or simply: + # + # app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth + + class OpenIDAuth < Rack::Auth::AbstractHandler + attr_reader :oid + def initialize(app, realm, options={}, &auth) + @oid = OpenID.new(realm, options) + super(app, &auth) + end + + def call(env) + to = auth.call(env) ? @app : @oid + to.call env + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb new file mode 100644 index 0000000000..295235e56a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb @@ -0,0 +1,63 @@ +module Rack + # Rack::Builder implements a small DSL to iteratively construct Rack + # applications. + # + # Example: + # + # app = Rack::Builder.new { + # use Rack::CommonLogger + # use Rack::ShowExceptions + # map "/lobster" do + # use Rack::Lint + # run Rack::Lobster.new + # end + # } + # + # Or + # + # app = Rack::Builder.app do + # use Rack::CommonLogger + # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } + # end + # + # +use+ adds a middleware to the stack, +run+ dispatches to an application. + # You can use +map+ to construct a Rack::URLMap in a convenient way. + + class Builder + def initialize(&block) + @ins = [] + instance_eval(&block) if block_given? + end + + def self.app(&block) + self.new(&block).to_app + end + + def use(middleware, *args, &block) + @ins << lambda { |app| middleware.new(app, *args, &block) } + end + + def run(app) + @ins << app #lambda { |nothing| app } + end + + def map(path, &block) + if @ins.last.kind_of? Hash + @ins.last[path] = self.class.new(&block).to_app + else + @ins << {} + map(path, &block) + end + end + + def to_app + @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last + inner_app = @ins.last + @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } + end + + def call(env) + to_app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb new file mode 100644 index 0000000000..a038aa1105 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb @@ -0,0 +1,36 @@ +module Rack + # Rack::Cascade tries an request on several apps, and returns the + # first response that is not 404 (or in a list of configurable + # status codes). + + class Cascade + attr_reader :apps + + def initialize(apps, catch=404) + @apps = apps + @catch = [*catch] + end + + def call(env) + status = headers = body = nil + raise ArgumentError, "empty cascade" if @apps.empty? + @apps.each { |app| + begin + status, headers, body = app.call(env) + break unless @catch.include?(status.to_i) + end + } + [status, headers, body] + end + + def add app + @apps << app + end + + def include? app + @apps.include? app + end + + alias_method :<<, :add + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb new file mode 100644 index 0000000000..280d89dd65 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb @@ -0,0 +1,49 @@ +require 'rack/utils' + +module Rack + + # Middleware that applies chunked transfer encoding to response bodies + # when the response does not include a Content-Length header. + class Chunked + include Rack::Utils + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash.new(headers) + + if env['HTTP_VERSION'] == 'HTTP/1.0' || + STATUS_WITH_NO_ENTITY_BODY.include?(status) || + headers['Content-Length'] || + headers['Transfer-Encoding'] + [status, headers.to_hash, body] + else + dup.chunk(status, headers, body) + end + end + + def chunk(status, headers, body) + @body = body + headers.delete('Content-Length') + headers['Transfer-Encoding'] = 'chunked' + [status, headers.to_hash, self] + end + + def each + term = "\r\n" + @body.each do |chunk| + size = bytesize(chunk) + next if size == 0 + yield [size.to_s(16), term, chunk, term].join + end + yield ["0", term, "", term].join + end + + def close + @body.close if @body.respond_to?(:close) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb new file mode 100644 index 0000000000..5e68ac626d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb @@ -0,0 +1,61 @@ +module Rack + # Rack::CommonLogger forwards every request to an +app+ given, and + # logs a line in the Apache common log format to the +logger+, or + # rack.errors by default. + + class CommonLogger + def initialize(app, logger=nil) + @app = app + @logger = logger + end + + def call(env) + dup._call(env) + end + + def _call(env) + @env = env + @logger ||= self + @time = Time.now + @status, @header, @body = @app.call(env) + [@status, @header, self] + end + + def close + @body.close if @body.respond_to? :close + end + + # By default, log to rack.errors. + def <<(str) + @env["rack.errors"].write(str) + @env["rack.errors"].flush + end + + def each + length = 0 + @body.each { |part| + length += part.size + yield part + } + + @now = Time.now + + # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common + # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - + # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % + @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % + [ + @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", + @env["REMOTE_USER"] || "-", + @now.strftime("%d/%b/%Y %H:%M:%S"), + @env["REQUEST_METHOD"], + @env["PATH_INFO"], + @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], + @env["HTTP_VERSION"], + @status.to_s[0..3], + (length.zero? ? "-" : length.to_s), + @now - @time + ] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb new file mode 100644 index 0000000000..046ebdb00a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb @@ -0,0 +1,47 @@ +require 'rack/utils' + +module Rack + + # Middleware that enables conditional GET using If-None-Match and + # If-Modified-Since. The application should set either or both of the + # Last-Modified or Etag response headers according to RFC 2616. When + # either of the conditions is met, the response body is set to be zero + # length and the response status is set to 304 Not Modified. + # + # Applications that defer response body generation until the body's each + # message is received will avoid response body generation completely when + # a conditional GET matches. + # + # Adapted from Michael Klishin's Merb implementation: + # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb + class ConditionalGet + def initialize(app) + @app = app + end + + def call(env) + return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD']) + + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + if etag_matches?(env, headers) || modified_since?(env, headers) + status = 304 + headers.delete('Content-Type') + headers.delete('Content-Length') + body = [] + end + [status, headers, body] + end + + private + def etag_matches?(env, headers) + etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH'] + end + + def modified_since?(env, headers) + last_modified = headers['Last-Modified'] and + last_modified == env['HTTP_IF_MODIFIED_SINCE'] + end + end + +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb new file mode 100644 index 0000000000..1e56d43853 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb @@ -0,0 +1,29 @@ +require 'rack/utils' + +module Rack + # Sets the Content-Length header on responses with fixed-length bodies. + class ContentLength + include Rack::Utils + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash.new(headers) + + if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && + !headers['Content-Length'] && + !headers['Transfer-Encoding'] && + (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) + + body = [body] if body.respond_to?(:to_str) # rack 0.4 compat + length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } + headers['Content-Length'] = length.to_s + end + + [status, headers, body] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb new file mode 100644 index 0000000000..0c1e1ca3e1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb @@ -0,0 +1,23 @@ +require 'rack/utils' + +module Rack + + # Sets the Content-Type header on responses which don't have one. + # + # Builder Usage: + # use Rack::ContentType, "text/plain" + # + # When no content type argument is provided, "text/html" is assumed. + class ContentType + def initialize(app, content_type = "text/html") + @app, @content_type = app, content_type + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + headers['Content-Type'] ||= @content_type + [status, headers.to_hash, body] + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb new file mode 100644 index 0000000000..14137a944d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb @@ -0,0 +1,96 @@ +require "zlib" +require "stringio" +require "time" # for Time.httpdate +require 'rack/utils' + +module Rack + class Deflater + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + + # Skip compressing empty entity body responses and responses with + # no-transform set. + if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || + headers['Cache-Control'].to_s =~ /\bno-transform\b/ + return [status, headers, body] + end + + request = Request.new(env) + + encoding = Utils.select_best_encoding(%w(gzip deflate identity), + request.accept_encoding) + + # Set the Vary HTTP header. + vary = headers["Vary"].to_s.split(",").map { |v| v.strip } + unless vary.include?("*") || vary.include?("Accept-Encoding") + headers["Vary"] = vary.push("Accept-Encoding").join(",") + end + + case encoding + when "gzip" + headers['Content-Encoding'] = "gzip" + headers.delete('Content-Length') + mtime = headers.key?("Last-Modified") ? + Time.httpdate(headers["Last-Modified"]) : Time.now + [status, headers, GzipStream.new(body, mtime)] + when "deflate" + headers['Content-Encoding'] = "deflate" + headers.delete('Content-Length') + [status, headers, DeflateStream.new(body)] + when "identity" + [status, headers, body] + when nil + message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." + [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]] + end + end + + class GzipStream + def initialize(body, mtime) + @body = body + @mtime = mtime + end + + def each(&block) + @writer = block + gzip =::Zlib::GzipWriter.new(self) + gzip.mtime = @mtime + @body.each { |part| gzip << part } + @body.close if @body.respond_to?(:close) + gzip.close + @writer = nil + end + + def write(data) + @writer.call(data) + end + end + + class DeflateStream + DEFLATE_ARGS = [ + Zlib::DEFAULT_COMPRESSION, + # drop the zlib header which causes both Safari and IE to choke + -Zlib::MAX_WBITS, + Zlib::DEF_MEM_LEVEL, + Zlib::DEFAULT_STRATEGY + ] + + def initialize(body) + @body = body + end + + def each + deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS) + @body.each { |part| yield deflater.deflate(part) } + @body.close if @body.respond_to?(:close) + yield deflater.finish + nil + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb new file mode 100644 index 0000000000..acdd3029d3 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb @@ -0,0 +1,153 @@ +require 'time' +require 'rack/utils' +require 'rack/mime' + +module Rack + # Rack::Directory serves entries below the +root+ given, according to the + # path info of the Rack request. If a directory is found, the file's contents + # will be presented in an html based index. If a file is found, the env will + # be passed to the specified +app+. + # + # If +app+ is not specified, a Rack::File of the same +root+ will be used. + + class Directory + DIR_FILE = "%s%s%s%s" + DIR_PAGE = <<-PAGE + + %s + + + +

%s

+
+ + + + + + + +%s +
NameSizeTypeLast Modified
+
+ + PAGE + + attr_reader :files + attr_accessor :root, :path + + def initialize(root, app=nil) + @root = F.expand_path(root) + @app = app || Rack::File.new(@root) + end + + def call(env) + dup._call(env) + end + + F = ::File + + def _call(env) + @env = env + @script_name = env['SCRIPT_NAME'] + @path_info = Utils.unescape(env['PATH_INFO']) + + if forbidden = check_forbidden + forbidden + else + @path = F.join(@root, @path_info) + list_path + end + end + + def check_forbidden + return unless @path_info.include? ".." + + body = "Forbidden\n" + size = Rack::Utils.bytesize(body) + return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] + end + + def list_directory + @files = [['../','Parent Directory','','','']] + glob = F.join(@path, '*') + + Dir[glob].sort.each do |node| + stat = stat(node) + next unless stat + basename = F.basename(node) + ext = F.extname(node) + + url = F.join(@script_name, @path_info, basename) + size = stat.size + type = stat.directory? ? 'directory' : Mime.mime_type(ext) + size = stat.directory? ? '-' : filesize_format(size) + mtime = stat.mtime.httpdate + url << '/' if stat.directory? + basename << '/' if stat.directory? + + @files << [ url, basename, size, type, mtime ] + end + + return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] + end + + def stat(node, max = 10) + F.stat(node) + rescue Errno::ENOENT, Errno::ELOOP + return nil + end + + # TODO: add correct response if not readable, not sure if 404 is the best + # option + def list_path + @stat = F.stat(@path) + + if @stat.readable? + return @app.call(@env) if @stat.file? + return list_directory if @stat.directory? + else + raise Errno::ENOENT, 'No such file or directory' + end + + rescue Errno::ENOENT, Errno::ELOOP + return entity_not_found + end + + def entity_not_found + body = "Entity not found: #{@path_info}\n" + size = Rack::Utils.bytesize(body) + return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] + end + + def each + show_path = @path.sub(/^#{@root}/,'') + files = @files.map{|f| DIR_FILE % f }*"\n" + page = DIR_PAGE % [ show_path, show_path , files ] + page.each_line{|l| yield l } + end + + # Stolen from Ramaze + + FILESIZE_FORMAT = [ + ['%.1fT', 1 << 40], + ['%.1fG', 1 << 30], + ['%.1fM', 1 << 20], + ['%.1fK', 1 << 10], + ] + + def filesize_format(int) + FILESIZE_FORMAT.each do |format, size| + return format % (int.to_f / size) if int >= size + end + + int.to_s + 'B' + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb new file mode 100644 index 0000000000..fe62bd6b86 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb @@ -0,0 +1,88 @@ +require 'time' +require 'rack/utils' +require 'rack/mime' + +module Rack + # Rack::File serves files below the +root+ given, according to the + # path info of the Rack request. + # + # Handlers can detect if bodies are a Rack::File, and use mechanisms + # like sendfile on the +path+. + + class File + attr_accessor :root + attr_accessor :path + + alias :to_path :path + + def initialize(root) + @root = root + end + + def call(env) + dup._call(env) + end + + F = ::File + + def _call(env) + @path_info = Utils.unescape(env["PATH_INFO"]) + return forbidden if @path_info.include? ".." + + @path = F.join(@root, @path_info) + + begin + if F.file?(@path) && F.readable?(@path) + serving + else + raise Errno::EPERM + end + rescue SystemCallError + not_found + end + end + + def forbidden + body = "Forbidden\n" + [403, {"Content-Type" => "text/plain", + "Content-Length" => body.size.to_s}, + [body]] + end + + # NOTE: + # We check via File::size? whether this file provides size info + # via stat (e.g. /proc files often don't), otherwise we have to + # figure it out by reading the whole file into memory. And while + # we're at it we also use this as body then. + + def serving + if size = F.size?(@path) + body = self + else + body = [F.read(@path)] + size = Utils.bytesize(body.first) + end + + [200, { + "Last-Modified" => F.mtime(@path).httpdate, + "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), + "Content-Length" => size.to_s + }, body] + end + + def not_found + body = "File not found: #{@path_info}\n" + [404, {"Content-Type" => "text/plain", + "Content-Length" => body.size.to_s}, + [body]] + end + + def each + F.open(@path, "rb") { |file| + while part = file.read(8192) + yield part + end + } + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb new file mode 100644 index 0000000000..5624a1e79d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb @@ -0,0 +1,69 @@ +module Rack + # *Handlers* connect web servers with Rack. + # + # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI + # and LiteSpeed. + # + # Handlers usually are activated by calling MyHandler.run(myapp). + # A second optional hash can be passed to include server-specific + # configuration. + module Handler + def self.get(server) + return unless server + server = server.to_s + + if klass = @handlers[server] + obj = Object + klass.split("::").each { |x| obj = obj.const_get(x) } + obj + else + try_require('rack/handler', server) + const_get(server) + end + end + + # Transforms server-name constants to their canonical form as filenames, + # then tries to require them but silences the LoadError if not found + # + # Naming convention: + # + # Foo # => 'foo' + # FooBar # => 'foo_bar.rb' + # FooBAR # => 'foobar.rb' + # FOObar # => 'foobar.rb' + # FOOBAR # => 'foobar.rb' + # FooBarBaz # => 'foo_bar_baz.rb' + def self.try_require(prefix, const_name) + file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. + gsub(/[A-Z]+[^A-Z]/, '_\&').downcase + + require(::File.join(prefix, file)) + rescue LoadError + end + + def self.register(server, klass) + @handlers ||= {} + @handlers[server] = klass + end + + autoload :CGI, "rack/handler/cgi" + autoload :FastCGI, "rack/handler/fastcgi" + autoload :Mongrel, "rack/handler/mongrel" + autoload :EventedMongrel, "rack/handler/evented_mongrel" + autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel" + autoload :WEBrick, "rack/handler/webrick" + autoload :LSWS, "rack/handler/lsws" + autoload :SCGI, "rack/handler/scgi" + autoload :Thin, "rack/handler/thin" + + register 'cgi', 'Rack::Handler::CGI' + register 'fastcgi', 'Rack::Handler::FastCGI' + register 'mongrel', 'Rack::Handler::Mongrel' + register 'emongrel', 'Rack::Handler::EventedMongrel' + register 'smongrel', 'Rack::Handler::SwiftipliedMongrel' + register 'webrick', 'Rack::Handler::WEBrick' + register 'lsws', 'Rack::Handler::LSWS' + register 'scgi', 'Rack::Handler::SCGI' + register 'thin', 'Rack::Handler::Thin' + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb new file mode 100644 index 0000000000..f45f3d735a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb @@ -0,0 +1,61 @@ +require 'rack/content_length' + +module Rack + module Handler + class CGI + def self.run(app, options=nil) + serve app + end + + def self.serve(app) + app = ContentLength.new(app) + + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + env.update({"rack.version" => [1,0], + "rack.input" => $stdin, + "rack.errors" => $stderr, + + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => true, + + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + end + + def self.send_headers(status, headers) + STDOUT.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + STDOUT.print "#{k}: #{v}\r\n" + } + } + STDOUT.print "\r\n" + STDOUT.flush + end + + def self.send_body(body) + body.each { |part| + STDOUT.print part + STDOUT.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb new file mode 100644 index 0000000000..0f5cbf7293 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb @@ -0,0 +1,8 @@ +require 'swiftcore/evented_mongrel' + +module Rack + module Handler + class EventedMongrel < Handler::Mongrel + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb new file mode 100644 index 0000000000..11e1fcaa74 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb @@ -0,0 +1,88 @@ +require 'fcgi' +require 'socket' +require 'rack/content_length' +require 'rack/rewindable_input' + +class FCGI::Stream + alias _rack_read_without_buffer read + + def read(n, buffer=nil) + buf = _rack_read_without_buffer n + buffer.replace(buf.to_s) if buffer + buf + end +end + +module Rack + module Handler + class FastCGI + def self.run(app, options={}) + file = options[:File] and STDIN.reopen(UNIXServer.new(file)) + port = options[:Port] and STDIN.reopen(TCPServer.new(port)) + FCGI.each { |request| + serve request, app + } + end + + def self.serve(request, app) + app = Rack::ContentLength.new(app) + + env = request.env + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + rack_input = RewindableInput.new(request.in) + + env.update({"rack.version" => [1,0], + "rack.input" => rack_input, + "rack.errors" => request.err, + + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" + }) + + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + env.delete "PATH_INFO" if env["PATH_INFO"] == "" + env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" + env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" + + begin + status, headers, body = app.call(env) + begin + send_headers request.out, status, headers + send_body request.out, body + ensure + body.close if body.respond_to? :close + end + ensure + rack_input.close + request.finish + end + end + + def self.send_headers(out, status, headers) + out.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + out.print "#{k}: #{v}\r\n" + } + } + out.print "\r\n" + out.flush + end + + def self.send_body(out, body) + body.each { |part| + out.print part + out.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb new file mode 100644 index 0000000000..7231336d7b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb @@ -0,0 +1,55 @@ +require 'lsapi' +require 'rack/content_length' + +module Rack + module Handler + class LSWS + def self.run(app, options=nil) + while LSAPI.accept != nil + serve app + end + end + def self.serve(app) + app = Rack::ContentLength.new(app) + + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new($stdin.read.to_s), + "rack.errors" => $stderr, + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + end + def self.send_headers(status, headers) + print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + print "#{k}: #{v}\r\n" + } + } + print "\r\n" + STDOUT.flush + end + def self.send_body(body) + body.each { |part| + print part + STDOUT.flush + } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb new file mode 100644 index 0000000000..3a5ef32d4b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb @@ -0,0 +1,84 @@ +require 'mongrel' +require 'stringio' +require 'rack/content_length' +require 'rack/chunked' + +module Rack + module Handler + class Mongrel < ::Mongrel::HttpHandler + def self.run(app, options={}) + server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', + options[:Port] || 8080) + # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. + # Use is similar to #run, replacing the app argument with a hash of + # { path=>app, ... } or an instance of Rack::URLMap. + if options[:map] + if app.is_a? Hash + app.each do |path, appl| + path = '/'+path unless path[0] == ?/ + server.register(path, Rack::Handler::Mongrel.new(appl)) + end + elsif app.is_a? URLMap + app.instance_variable_get(:@mapping).each do |(host, path, appl)| + next if !host.nil? && !options[:Host].nil? && options[:Host] != host + path = '/'+path unless path[0] == ?/ + server.register(path, Rack::Handler::Mongrel.new(appl)) + end + else + raise ArgumentError, "first argument should be a Hash or URLMap" + end + else + server.register('/', Rack::Handler::Mongrel.new(app)) + end + yield server if block_given? + server.run.join + end + + def initialize(app) + @app = Rack::Chunked.new(Rack::ContentLength.new(app)) + end + + def process(request, response) + env = {}.replace(request.params) + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + env.update({"rack.version" => [1,0], + "rack.input" => request.body || StringIO.new(""), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => false, # ??? + "rack.run_once" => false, + + "rack.url_scheme" => "http", + }) + env["QUERY_STRING"] ||= "" + env.delete "PATH_INFO" if env["PATH_INFO"] == "" + + status, headers, body = @app.call(env) + + begin + response.status = status.to_i + response.send_status(nil) + + headers.each { |k, vs| + vs.split("\n").each { |v| + response.header[k] = v + } + } + response.send_header + + body.each { |part| + response.write part + response.socket.flush + } + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb new file mode 100644 index 0000000000..6c4932df95 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb @@ -0,0 +1,59 @@ +require 'scgi' +require 'stringio' +require 'rack/content_length' +require 'rack/chunked' + +module Rack + module Handler + class SCGI < ::SCGI::Processor + attr_accessor :app + + def self.run(app, options=nil) + new(options.merge(:app=>app, + :host=>options[:Host], + :port=>options[:Port], + :socket=>options[:Socket])).listen + end + + def initialize(settings = {}) + @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) + @log = Object.new + def @log.info(*args); end + def @log.error(*args); end + super(settings) + end + + def process_request(request, input_body, socket) + env = {}.replace(request) + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["PATH_INFO"] = env["REQUEST_PATH"] + env["QUERY_STRING"] ||= "" + env["SCRIPT_NAME"] = "" + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new(input_body), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" + }) + status, headers, body = app.call(env) + begin + socket.write("Status: #{status}\r\n") + headers.each do |k, vs| + vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} + end + socket.write("\r\n") + body.each {|s| socket.write(s)} + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb new file mode 100644 index 0000000000..4bafd0b953 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb @@ -0,0 +1,8 @@ +require 'swiftcore/swiftiplied_mongrel' + +module Rack + module Handler + class SwiftipliedMongrel < Handler::Mongrel + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb new file mode 100644 index 0000000000..3d4fedff75 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb @@ -0,0 +1,18 @@ +require "thin" +require "rack/content_length" +require "rack/chunked" + +module Rack + module Handler + class Thin + def self.run(app, options={}) + app = Rack::Chunked.new(Rack::ContentLength.new(app)) + server = ::Thin::Server.new(options[:Host] || '0.0.0.0', + options[:Port] || 8080, + app) + yield server if block_given? + server.start + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb new file mode 100644 index 0000000000..2bdc83a9ff --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb @@ -0,0 +1,67 @@ +require 'webrick' +require 'stringio' +require 'rack/content_length' + +module Rack + module Handler + class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet + def self.run(app, options={}) + server = ::WEBrick::HTTPServer.new(options) + server.mount "/", Rack::Handler::WEBrick, app + trap(:INT) { server.shutdown } + yield server if block_given? + server.start + end + + def initialize(server, app) + super server + @app = Rack::ContentLength.new(app) + end + + def service(req, res) + env = req.meta_vars + env.delete_if { |k, v| v.nil? } + + env.update({"rack.version" => [1,0], + "rack.input" => StringIO.new(req.body.to_s), + "rack.errors" => $stderr, + + "rack.multithread" => true, + "rack.multiprocess" => false, + "rack.run_once" => false, + + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + }) + + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["QUERY_STRING"] ||= "" + env["REQUEST_PATH"] ||= "/" + if env["PATH_INFO"] == "" + env.delete "PATH_INFO" + else + path, n = req.request_uri.path, env["SCRIPT_NAME"].length + env["PATH_INFO"] = path[n, path.length-n] + end + + status, headers, body = @app.call(env) + begin + res.status = status.to_i + headers.each { |k, vs| + if k.downcase == "set-cookie" + res.cookies.concat vs.split("\n") + else + vs.split("\n").each { |v| + res[k] = v + } + end + } + body.each { |part| + res.body << part + } + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb new file mode 100644 index 0000000000..deab822a99 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb @@ -0,0 +1,19 @@ +module Rack + +class Head + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + if env["REQUEST_METHOD"] == "HEAD" + [status, headers, []] + else + [status, headers, body] + end + end +end + +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb new file mode 100644 index 0000000000..bf2e9787a1 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb @@ -0,0 +1,537 @@ +require 'rack/utils' + +module Rack + # Rack::Lint validates your application and the requests and + # responses according to the Rack spec. + + class Lint + def initialize(app) + @app = app + end + + # :stopdoc: + + class LintError < RuntimeError; end + module Assertion + def assert(message, &block) + unless block.call + raise LintError, message + end + end + end + include Assertion + + ## This specification aims to formalize the Rack protocol. You + ## can (and should) use Rack::Lint to enforce it. + ## + ## When you develop middleware, be sure to add a Lint before and + ## after to catch all mistakes. + + ## = Rack applications + + ## A Rack application is an Ruby object (not a class) that + ## responds to +call+. + def call(env=nil) + dup._call(env) + end + + def _call(env) + ## It takes exactly one argument, the *environment* + assert("No env given") { env } + check_env env + + env['rack.input'] = InputWrapper.new(env['rack.input']) + env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) + + ## and returns an Array of exactly three values: + status, headers, @body = @app.call(env) + ## The *status*, + check_status status + ## the *headers*, + check_headers headers + ## and the *body*. + check_content_type status, headers + check_content_length status, headers, env + [status, headers, self] + end + + ## == The Environment + def check_env(env) + ## The environment must be an true instance of Hash (no + ## subclassing allowed) that includes CGI-like headers. + ## The application is free to modify the environment. + assert("env #{env.inspect} is not a Hash, but #{env.class}") { + env.instance_of? Hash + } + + ## + ## The environment is required to include these variables + ## (adopted from PEP333), except when they'd be empty, but see + ## below. + + ## REQUEST_METHOD:: The HTTP request method, such as + ## "GET" or "POST". This cannot ever + ## be an empty string, and so is + ## always required. + + ## SCRIPT_NAME:: The initial portion of the request + ## URL's "path" that corresponds to the + ## application object, so that the + ## application knows its virtual + ## "location". This may be an empty + ## string, if the application corresponds + ## to the "root" of the server. + + ## PATH_INFO:: The remainder of the request URL's + ## "path", designating the virtual + ## "location" of the request's target + ## within the application. This may be an + ## empty string, if the request URL targets + ## the application root and does not have a + ## trailing slash. This value may be + ## percent-encoded when I originating from + ## a URL. + + ## QUERY_STRING:: The portion of the request URL that + ## follows the ?, if any. May be + ## empty, but is always required! + + ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. + + ## HTTP_ Variables:: Variables corresponding to the + ## client-supplied HTTP request + ## headers (i.e., variables whose + ## names begin with HTTP_). The + ## presence or absence of these + ## variables should correspond with + ## the presence or absence of the + ## appropriate HTTP header in the + ## request. + + ## In addition to this, the Rack environment must include these + ## Rack-specific variables: + + ## rack.version:: The Array [1,0], representing this version of Rack. + ## rack.url_scheme:: +http+ or +https+, depending on the request URL. + ## rack.input:: See below, the input stream. + ## rack.errors:: See below, the error stream. + ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. + ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. + ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). + ## + + ## Additional environment specifications have approved to + ## standardized middleware APIs. None of these are required to + ## be implemented by the server. + + ## rack.session:: A hash like interface for storing request session data. + ## The store must implement: + if session = env['rack.session'] + ## store(key, value) (aliased as []=); + assert("session #{session.inspect} must respond to store and []=") { + session.respond_to?(:store) && session.respond_to?(:[]=) + } + + ## fetch(key, default = nil) (aliased as []); + assert("session #{session.inspect} must respond to fetch and []") { + session.respond_to?(:fetch) && session.respond_to?(:[]) + } + + ## delete(key); + assert("session #{session.inspect} must respond to delete") { + session.respond_to?(:delete) + } + + ## clear; + assert("session #{session.inspect} must respond to clear") { + session.respond_to?(:clear) + } + end + + ## The server or the application can store their own data in the + ## environment, too. The keys must contain at least one dot, + ## and should be prefixed uniquely. The prefix rack. + ## is reserved for use with the Rack core distribution and other + ## accepted specifications and must not be used otherwise. + ## + + %w[REQUEST_METHOD SERVER_NAME SERVER_PORT + QUERY_STRING + rack.version rack.input rack.errors + rack.multithread rack.multiprocess rack.run_once].each { |header| + assert("env missing required key #{header}") { env.include? header } + } + + ## The environment must not contain the keys + ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH + ## (use the versions without HTTP_). + %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| + assert("env contains #{header}, must use #{header[5,-1]}") { + not env.include? header + } + } + + ## The CGI keys (named without a period) must have String values. + env.each { |key, value| + next if key.include? "." # Skip extensions + assert("env variable #{key} has non-string value #{value.inspect}") { + value.instance_of? String + } + } + + ## + ## There are the following restrictions: + + ## * rack.version must be an array of Integers. + assert("rack.version must be an Array, was #{env["rack.version"].class}") { + env["rack.version"].instance_of? Array + } + ## * rack.url_scheme must either be +http+ or +https+. + assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { + %w[http https].include? env["rack.url_scheme"] + } + + ## * There must be a valid input stream in rack.input. + check_input env["rack.input"] + ## * There must be a valid error stream in rack.errors. + check_error env["rack.errors"] + + ## * The REQUEST_METHOD must be a valid token. + assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { + env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ + } + + ## * The SCRIPT_NAME, if non-empty, must start with / + assert("SCRIPT_NAME must start with /") { + !env.include?("SCRIPT_NAME") || + env["SCRIPT_NAME"] == "" || + env["SCRIPT_NAME"] =~ /\A\// + } + ## * The PATH_INFO, if non-empty, must start with / + assert("PATH_INFO must start with /") { + !env.include?("PATH_INFO") || + env["PATH_INFO"] == "" || + env["PATH_INFO"] =~ /\A\// + } + ## * The CONTENT_LENGTH, if given, must consist of digits only. + assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { + !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ + } + + ## * One of SCRIPT_NAME or PATH_INFO must be + ## set. PATH_INFO should be / if + ## SCRIPT_NAME is empty. + assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { + env["SCRIPT_NAME"] || env["PATH_INFO"] + } + ## SCRIPT_NAME never should be /, but instead be empty. + assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { + env["SCRIPT_NAME"] != "/" + } + end + + ## === The Input Stream + ## + ## The input stream is an IO-like object which contains the raw HTTP + ## POST data. If it is a file then it must be opened in binary mode. + def check_input(input) + ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. + [:gets, :each, :read, :rewind].each { |method| + assert("rack.input #{input} does not respond to ##{method}") { + input.respond_to? method + } + } + end + + class InputWrapper + include Assertion + + def initialize(input) + @input = input + end + + def size + @input.size + end + + ## * +gets+ must be called without arguments and return a string, + ## or +nil+ on EOF. + def gets(*args) + assert("rack.input#gets called with arguments") { args.size == 0 } + v = @input.gets + assert("rack.input#gets didn't return a String") { + v.nil? or v.instance_of? String + } + v + end + + ## * +read+ behaves like IO#read. Its signature is read([length, [buffer]]). + ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must + ## be a String and may not be nil. If +length+ is given and not nil, then this method + ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil, + ## then this method reads all data until EOF. + ## When EOF is reached, this method returns nil if +length+ is given and not nil, or "" + ## if +length+ is not given or is nil. + ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a + ## newly created String object. + def read(*args) + assert("rack.input#read called with too many arguments") { + args.size <= 2 + } + if args.size >= 1 + assert("rack.input#read called with non-integer and non-nil length") { + args.first.kind_of?(Integer) || args.first.nil? + } + assert("rack.input#read called with a negative length") { + args.first.nil? || args.first >= 0 + } + end + if args.size >= 2 + assert("rack.input#read called with non-String buffer") { + args[1].kind_of?(String) + } + end + + v = @input.read(*args) + + assert("rack.input#read didn't return nil or a String") { + v.nil? or v.instance_of? String + } + if args[0].nil? + assert("rack.input#read(nil) returned nil on EOF") { + !v.nil? + } + end + + v + end + + ## * +each+ must be called without arguments and only yield Strings. + def each(*args) + assert("rack.input#each called with arguments") { args.size == 0 } + @input.each { |line| + assert("rack.input#each didn't yield a String") { + line.instance_of? String + } + yield line + } + end + + ## * +rewind+ must be called without arguments. It rewinds the input + ## stream back to the beginning. It must not raise Errno::ESPIPE: + ## that is, it may not be a pipe or a socket. Therefore, handler + ## developers must buffer the input data into some rewindable object + ## if the underlying input stream is not rewindable. + def rewind(*args) + assert("rack.input#rewind called with arguments") { args.size == 0 } + assert("rack.input#rewind raised Errno::ESPIPE") { + begin + @input.rewind + true + rescue Errno::ESPIPE + false + end + } + end + + ## * +close+ must never be called on the input stream. + def close(*args) + assert("rack.input#close must not be called") { false } + end + end + + ## === The Error Stream + def check_error(error) + ## The error stream must respond to +puts+, +write+ and +flush+. + [:puts, :write, :flush].each { |method| + assert("rack.error #{error} does not respond to ##{method}") { + error.respond_to? method + } + } + end + + class ErrorWrapper + include Assertion + + def initialize(error) + @error = error + end + + ## * +puts+ must be called with a single argument that responds to +to_s+. + def puts(str) + @error.puts str + end + + ## * +write+ must be called with a single argument that is a String. + def write(str) + assert("rack.errors#write not called with a String") { str.instance_of? String } + @error.write str + end + + ## * +flush+ must be called without arguments and must be called + ## in order to make the error appear for sure. + def flush + @error.flush + end + + ## * +close+ must never be called on the error stream. + def close(*args) + assert("rack.errors#close must not be called") { false } + end + end + + ## == The Response + + ## === The Status + def check_status(status) + ## This is an HTTP status. When parsed as integer (+to_i+), it must be + ## greater than or equal to 100. + assert("Status must be >=100 seen as integer") { status.to_i >= 100 } + end + + ## === The Headers + def check_headers(header) + ## The header must respond to +each+, and yield values of key and value. + assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { + header.respond_to? :each + } + header.each { |key, value| + ## The header keys must be Strings. + assert("header key must be a string, was #{key.class}") { + key.instance_of? String + } + ## The header must not contain a +Status+ key, + assert("header must not contain Status") { key.downcase != "status" } + ## contain keys with : or newlines in their name, + assert("header names must not contain : or \\n") { key !~ /[:\n]/ } + ## contain keys names that end in - or _, + assert("header names must not end in - or _") { key !~ /[-_]\z/ } + ## but only contain keys that consist of + ## letters, digits, _ or - and start with a letter. + assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } + + ## The values of the header must be Strings, + assert("a header value must be a String, but the value of " + + "'#{key}' is a #{value.class}") { value.kind_of? String } + ## consisting of lines (for multiple header values, e.g. multiple + ## Set-Cookie values) seperated by "\n". + value.split("\n").each { |item| + ## The lines must not contain characters below 037. + assert("invalid header value #{key}: #{item.inspect}") { + item !~ /[\000-\037]/ + } + } + } + end + + ## === The Content-Type + def check_content_type(status, headers) + headers.each { |key, value| + ## There must be a Content-Type, except when the + ## +Status+ is 1xx, 204 or 304, in which case there must be none + ## given. + if key.downcase == "content-type" + assert("Content-Type header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + return + end + } + assert("No Content-Type header found") { + Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + end + + ## === The Content-Length + def check_content_length(status, headers, env) + headers.each { |key, value| + if key.downcase == 'content-length' + ## There must not be a Content-Length header when the + ## +Status+ is 1xx, 204 or 304. + assert("Content-Length header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i + } + + bytes = 0 + string_body = true + + if @body.respond_to?(:to_ary) + @body.each { |part| + unless part.kind_of?(String) + string_body = false + break + end + + bytes += Rack::Utils.bytesize(part) + } + + if env["REQUEST_METHOD"] == "HEAD" + assert("Response body was given for HEAD request, but should be empty") { + bytes == 0 + } + else + if string_body + assert("Content-Length header was #{value}, but should be #{bytes}") { + value == bytes.to_s + } + end + end + end + + return + end + } + end + + ## === The Body + def each + @closed = false + ## The Body must respond to +each+ + @body.each { |part| + ## and must only yield String values. + assert("Body yielded non-string value #{part.inspect}") { + part.instance_of? String + } + yield part + } + ## + ## The Body itself should not be an instance of String, as this will + ## break in Ruby 1.9. + ## + ## If the Body responds to +close+, it will be called after iteration. + # XXX howto: assert("Body has not been closed") { @closed } + + + ## + ## If the Body responds to +to_path+, it must return a String + ## identifying the location of a file whose contents are identical + ## to that produced by calling +each+; this may be used by the + ## server as an alternative, possibly more efficient way to + ## transport the response. + + if @body.respond_to?(:to_path) + assert("The file identified by body.to_path does not exist") { + ::File.exist? @body.to_path + } + end + + ## + ## The Body commonly is an Array of Strings, the application + ## instance itself, or a File-like object. + end + + def close + @closed = true + @body.close if @body.respond_to?(:close) + end + + # :startdoc: + + end +end + +## == Thanks +## Some parts of this specification are adopted from PEP333: Python +## Web Server Gateway Interface +## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank +## everyone involved in that effort. diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb new file mode 100644 index 0000000000..f63f419a49 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb @@ -0,0 +1,65 @@ +require 'zlib' + +require 'rack/request' +require 'rack/response' + +module Rack + # Paste has a Pony, Rack has a Lobster! + class Lobster + LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 + P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 + t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ + I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) + + LambdaLobster = lambda { |env| + if env["QUERY_STRING"].include?("flip") + lobster = LobsterString.split("\n"). + map { |line| line.ljust(42).reverse }. + join("\n") + href = "?" + else + lobster = LobsterString + href = "?flip" + end + + content = ["Lobstericious!", + "
", lobster, "
", + "flip!"] + length = content.inject(0) { |a,e| a+e.size }.to_s + [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] + } + + def call(env) + req = Request.new(env) + if req.GET["flip"] == "left" + lobster = LobsterString.split("\n"). + map { |line| line.ljust(42).reverse }. + join("\n") + href = "?flip=right" + elsif req.GET["flip"] == "crash" + raise "Lobster crashed" + else + lobster = LobsterString + href = "?flip=left" + end + + res = Response.new + res.write "Lobstericious!" + res.write "
"
+      res.write lobster
+      res.write "
" + res.write "

flip!

" + res.write "

crash!

" + res.finish + end + + end +end + +if $0 == __FILE__ + require 'rack' + require 'rack/showexceptions' + Rack::Handler::WEBrick.run \ + Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), + :Port => 9292 +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb new file mode 100644 index 0000000000..93238528c4 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb @@ -0,0 +1,16 @@ +module Rack + class Lock + FLAG = 'rack.multithread'.freeze + + def initialize(app, lock = Mutex.new) + @app, @lock = app, lock + end + + def call(env) + old, env[FLAG] = env[FLAG], false + @lock.synchronize { @app.call(env) } + ensure + env[FLAG] = old + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb new file mode 100644 index 0000000000..0eed29f471 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb @@ -0,0 +1,27 @@ +module Rack + class MethodOverride + HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS) + + METHOD_OVERRIDE_PARAM_KEY = "_method".freeze + HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze + + def initialize(app) + @app = app + end + + def call(env) + if env["REQUEST_METHOD"] == "POST" + req = Request.new(env) + method = req.POST[METHOD_OVERRIDE_PARAM_KEY] || + env[HTTP_METHOD_OVERRIDE_HEADER] + method = method.to_s.upcase + if HTTP_METHODS.include?(method) + env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] + env["REQUEST_METHOD"] = method + end + end + + @app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb new file mode 100644 index 0000000000..5a6a73a97b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb @@ -0,0 +1,204 @@ +module Rack + module Mime + # Returns String with mime type if found, otherwise use +fallback+. + # +ext+ should be filename extension in the '.ext' format that + # File.extname(file) returns. + # +fallback+ may be any object + # + # Also see the documentation for MIME_TYPES + # + # Usage: + # Rack::Mime.mime_type('.foo') + # + # This is a shortcut for: + # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') + + def mime_type(ext, fallback='application/octet-stream') + MIME_TYPES.fetch(ext, fallback) + end + module_function :mime_type + + # List of most common mime-types, selected various sources + # according to their usefulness in a webserving scope for Ruby + # users. + # + # To amend this list with your local mime.types list you can use: + # + # require 'webrick/httputils' + # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') + # Rack::Mime::MIME_TYPES.merge!(list) + # + # To add the list mongrel provides, use: + # + # require 'mongrel/handlers' + # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES) + + MIME_TYPES = { + ".3gp" => "video/3gpp", + ".a" => "application/octet-stream", + ".ai" => "application/postscript", + ".aif" => "audio/x-aiff", + ".aiff" => "audio/x-aiff", + ".asc" => "application/pgp-signature", + ".asf" => "video/x-ms-asf", + ".asm" => "text/x-asm", + ".asx" => "video/x-ms-asf", + ".atom" => "application/atom+xml", + ".au" => "audio/basic", + ".avi" => "video/x-msvideo", + ".bat" => "application/x-msdownload", + ".bin" => "application/octet-stream", + ".bmp" => "image/bmp", + ".bz2" => "application/x-bzip2", + ".c" => "text/x-c", + ".cab" => "application/vnd.ms-cab-compressed", + ".cc" => "text/x-c", + ".chm" => "application/vnd.ms-htmlhelp", + ".class" => "application/octet-stream", + ".com" => "application/x-msdownload", + ".conf" => "text/plain", + ".cpp" => "text/x-c", + ".crt" => "application/x-x509-ca-cert", + ".css" => "text/css", + ".csv" => "text/csv", + ".cxx" => "text/x-c", + ".deb" => "application/x-debian-package", + ".der" => "application/x-x509-ca-cert", + ".diff" => "text/x-diff", + ".djv" => "image/vnd.djvu", + ".djvu" => "image/vnd.djvu", + ".dll" => "application/x-msdownload", + ".dmg" => "application/octet-stream", + ".doc" => "application/msword", + ".dot" => "application/msword", + ".dtd" => "application/xml-dtd", + ".dvi" => "application/x-dvi", + ".ear" => "application/java-archive", + ".eml" => "message/rfc822", + ".eps" => "application/postscript", + ".exe" => "application/x-msdownload", + ".f" => "text/x-fortran", + ".f77" => "text/x-fortran", + ".f90" => "text/x-fortran", + ".flv" => "video/x-flv", + ".for" => "text/x-fortran", + ".gem" => "application/octet-stream", + ".gemspec" => "text/x-script.ruby", + ".gif" => "image/gif", + ".gz" => "application/x-gzip", + ".h" => "text/x-c", + ".hh" => "text/x-c", + ".htm" => "text/html", + ".html" => "text/html", + ".ico" => "image/vnd.microsoft.icon", + ".ics" => "text/calendar", + ".ifb" => "text/calendar", + ".iso" => "application/octet-stream", + ".jar" => "application/java-archive", + ".java" => "text/x-java-source", + ".jnlp" => "application/x-java-jnlp-file", + ".jpeg" => "image/jpeg", + ".jpg" => "image/jpeg", + ".js" => "application/javascript", + ".json" => "application/json", + ".log" => "text/plain", + ".m3u" => "audio/x-mpegurl", + ".m4v" => "video/mp4", + ".man" => "text/troff", + ".mathml" => "application/mathml+xml", + ".mbox" => "application/mbox", + ".mdoc" => "text/troff", + ".me" => "text/troff", + ".mid" => "audio/midi", + ".midi" => "audio/midi", + ".mime" => "message/rfc822", + ".mml" => "application/mathml+xml", + ".mng" => "video/x-mng", + ".mov" => "video/quicktime", + ".mp3" => "audio/mpeg", + ".mp4" => "video/mp4", + ".mp4v" => "video/mp4", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".ms" => "text/troff", + ".msi" => "application/x-msdownload", + ".odp" => "application/vnd.oasis.opendocument.presentation", + ".ods" => "application/vnd.oasis.opendocument.spreadsheet", + ".odt" => "application/vnd.oasis.opendocument.text", + ".ogg" => "application/ogg", + ".p" => "text/x-pascal", + ".pas" => "text/x-pascal", + ".pbm" => "image/x-portable-bitmap", + ".pdf" => "application/pdf", + ".pem" => "application/x-x509-ca-cert", + ".pgm" => "image/x-portable-graymap", + ".pgp" => "application/pgp-encrypted", + ".pkg" => "application/octet-stream", + ".pl" => "text/x-script.perl", + ".pm" => "text/x-script.perl-module", + ".png" => "image/png", + ".pnm" => "image/x-portable-anymap", + ".ppm" => "image/x-portable-pixmap", + ".pps" => "application/vnd.ms-powerpoint", + ".ppt" => "application/vnd.ms-powerpoint", + ".ps" => "application/postscript", + ".psd" => "image/vnd.adobe.photoshop", + ".py" => "text/x-script.python", + ".qt" => "video/quicktime", + ".ra" => "audio/x-pn-realaudio", + ".rake" => "text/x-script.ruby", + ".ram" => "audio/x-pn-realaudio", + ".rar" => "application/x-rar-compressed", + ".rb" => "text/x-script.ruby", + ".rdf" => "application/rdf+xml", + ".roff" => "text/troff", + ".rpm" => "application/x-redhat-package-manager", + ".rss" => "application/rss+xml", + ".rtf" => "application/rtf", + ".ru" => "text/x-script.ruby", + ".s" => "text/x-asm", + ".sgm" => "text/sgml", + ".sgml" => "text/sgml", + ".sh" => "application/x-sh", + ".sig" => "application/pgp-signature", + ".snd" => "audio/basic", + ".so" => "application/octet-stream", + ".svg" => "image/svg+xml", + ".svgz" => "image/svg+xml", + ".swf" => "application/x-shockwave-flash", + ".t" => "text/troff", + ".tar" => "application/x-tar", + ".tbz" => "application/x-bzip-compressed-tar", + ".tcl" => "application/x-tcl", + ".tex" => "application/x-tex", + ".texi" => "application/x-texinfo", + ".texinfo" => "application/x-texinfo", + ".text" => "text/plain", + ".tif" => "image/tiff", + ".tiff" => "image/tiff", + ".torrent" => "application/x-bittorrent", + ".tr" => "text/troff", + ".txt" => "text/plain", + ".vcf" => "text/x-vcard", + ".vcs" => "text/x-vcalendar", + ".vrml" => "model/vrml", + ".war" => "application/java-archive", + ".wav" => "audio/x-wav", + ".wma" => "audio/x-ms-wma", + ".wmv" => "video/x-ms-wmv", + ".wmx" => "video/x-ms-wmx", + ".wrl" => "model/vrml", + ".wsdl" => "application/wsdl+xml", + ".xbm" => "image/x-xbitmap", + ".xhtml" => "application/xhtml+xml", + ".xls" => "application/vnd.ms-excel", + ".xml" => "application/xml", + ".xpm" => "image/x-xpixmap", + ".xsl" => "application/xml", + ".xslt" => "application/xslt+xml", + ".yaml" => "text/yaml", + ".yml" => "text/yaml", + ".zip" => "application/zip", + } + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb new file mode 100644 index 0000000000..fdefb0340a --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb @@ -0,0 +1,184 @@ +require 'uri' +require 'stringio' +require 'rack/lint' +require 'rack/utils' +require 'rack/response' + +module Rack + # Rack::MockRequest helps testing your Rack application without + # actually using HTTP. + # + # After performing a request on a URL with get/post/put/delete, it + # returns a MockResponse with useful helper methods for effective + # testing. + # + # You can pass a hash with additional configuration to the + # get/post/put/delete. + # :input:: A String or IO-like to be used as rack.input. + # :fatal:: Raise a FatalWarning if the app writes to rack.errors. + # :lint:: If true, wrap the application in a Rack::Lint. + + class MockRequest + class FatalWarning < RuntimeError + end + + class FatalWarner + def puts(warning) + raise FatalWarning, warning + end + + def write(warning) + raise FatalWarning, warning + end + + def flush + end + + def string + "" + end + end + + DEFAULT_ENV = { + "rack.version" => [1,0], + "rack.input" => StringIO.new, + "rack.errors" => StringIO.new, + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + } + + def initialize(app) + @app = app + end + + def get(uri, opts={}) request("GET", uri, opts) end + def post(uri, opts={}) request("POST", uri, opts) end + def put(uri, opts={}) request("PUT", uri, opts) end + def delete(uri, opts={}) request("DELETE", uri, opts) end + + def request(method="GET", uri="", opts={}) + env = self.class.env_for(uri, opts.merge(:method => method)) + + if opts[:lint] + app = Rack::Lint.new(@app) + else + app = @app + end + + errors = env["rack.errors"] + MockResponse.new(*(app.call(env) + [errors])) + end + + # Return the Rack environment used for a request to +uri+. + def self.env_for(uri="", opts={}) + uri = URI(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + + env = DEFAULT_ENV.dup + + env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" + env["SERVER_NAME"] = uri.host || "example.org" + env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" + env["QUERY_STRING"] = uri.query.to_s + env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path + env["rack.url_scheme"] = uri.scheme || "http" + env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" + + env["SCRIPT_NAME"] = opts[:script_name] || "" + + if opts[:fatal] + env["rack.errors"] = FatalWarner.new + else + env["rack.errors"] = StringIO.new + end + + if params = opts[:params] + if env["REQUEST_METHOD"] == "GET" + params = Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Utils.parse_nested_query(env["QUERY_STRING"])) + env["QUERY_STRING"] = Utils.build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Utils::Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = Utils.build_nested_query(params) + end + else + opts[:input] = params + end + end + end + + opts[:input] ||= "" + if String === opts[:input] + env["rack.input"] = StringIO.new(opts[:input]) + else + env["rack.input"] = opts[:input] + end + + env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s + + opts.each { |field, value| + env[field] = value if String === field + } + + env + end + end + + # Rack::MockResponse provides useful helpers for testing your apps. + # Usually, you don't create the MockResponse on your own, but use + # MockRequest. + + class MockResponse + def initialize(status, headers, body, errors=StringIO.new("")) + @status = status.to_i + + @original_headers = headers + @headers = Rack::Utils::HeaderHash.new + headers.each { |field, values| + @headers[field] = values + @headers[field] = "" if values.empty? + } + + @body = "" + body.each { |part| @body << part } + + @errors = errors.string if errors.respond_to?(:string) + end + + # Status + attr_reader :status + + # Headers + attr_reader :headers, :original_headers + + def [](field) + headers[field] + end + + + # Body + attr_reader :body + + def =~(other) + @body =~ other + end + + def match(other) + @body.match other + end + + + # Errors + attr_accessor :errors + + + include Response::Helpers + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb new file mode 100644 index 0000000000..bf8b965925 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb @@ -0,0 +1,57 @@ +require 'uri' + +module Rack + # Rack::ForwardRequest gets caught by Rack::Recursive and redirects + # the current request to the app at +url+. + # + # raise ForwardRequest.new("/not-found") + # + + class ForwardRequest < Exception + attr_reader :url, :env + + def initialize(url, env={}) + @url = URI(url) + @env = env + + @env["PATH_INFO"] = @url.path + @env["QUERY_STRING"] = @url.query if @url.query + @env["HTTP_HOST"] = @url.host if @url.host + @env["HTTP_PORT"] = @url.port if @url.port + @env["rack.url_scheme"] = @url.scheme if @url.scheme + + super "forwarding to #{url}" + end + end + + # Rack::Recursive allows applications called down the chain to + # include data from other applications (by using + # rack['rack.recursive.include'][...] or raise a + # ForwardRequest to redirect internally. + + class Recursive + def initialize(app) + @app = app + end + + def call(env) + @script_name = env["SCRIPT_NAME"] + @app.call(env.merge('rack.recursive.include' => method(:include))) + rescue ForwardRequest => req + call(env.merge(req.env)) + end + + def include(env, path) + unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || + path[@script_name.size].nil?) + raise ArgumentError, "can only include below #{@script_name}, not #{path}" + end + + env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, + "REQUEST_METHOD" => "GET", + "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", + "rack.input" => StringIO.new("")) + @app.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb new file mode 100644 index 0000000000..aa2f060be5 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb @@ -0,0 +1,106 @@ +# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com +# All files in this distribution are subject to the terms of the Ruby license. + +require 'pathname' + +module Rack + + # High performant source reloader + # + # This class acts as Rack middleware. + # + # What makes it especially suited for use in a production environment is that + # any file will only be checked once and there will only be made one system + # call stat(2). + # + # Please note that this will not reload files in the background, it does so + # only when actively called. + # + # It is performing a check/reload cycle at the start of every request, but + # also respects a cool down time, during which nothing will be done. + class Reloader + def initialize(app, cooldown = 10, backend = Stat) + @app = app + @cooldown = cooldown + @last = (Time.now - cooldown) + @cache = {} + @mtimes = {} + + extend backend + end + + def call(env) + if @cooldown and Time.now > @last + @cooldown + if Thread.list.size > 1 + Thread.exclusive{ reload! } + else + reload! + end + + @last = Time.now + end + + @app.call(env) + end + + def reload!(stderr = $stderr) + rotation do |file, mtime| + previous_mtime = @mtimes[file] ||= mtime + safe_load(file, mtime, stderr) if mtime > previous_mtime + end + end + + # A safe Kernel::load, issuing the hooks depending on the results + def safe_load(file, mtime, stderr = $stderr) + load(file) + stderr.puts "#{self.class}: reloaded `#{file}'" + file + rescue LoadError, SyntaxError => ex + stderr.puts ex + ensure + @mtimes[file] = mtime + end + + module Stat + def rotation + files = [$0, *$LOADED_FEATURES].uniq + paths = ['./', *$LOAD_PATH].uniq + + files.map{|file| + next if file =~ /\.(so|bundle)$/ # cannot reload compiled files + + found, stat = figure_path(file, paths) + next unless found and stat and mtime = stat.mtime + + @cache[file] = found + + yield(found, mtime) + }.compact + end + + # Takes a relative or absolute +file+ name, a couple possible +paths+ that + # the +file+ might reside in. Returns the full path and File::Stat for the + # path. + def figure_path(file, paths) + found = @cache[file] + found = file if !found and Pathname.new(file).absolute? + found, stat = safe_stat(found) + return found, stat if found + + paths.each do |possible_path| + path = ::File.join(possible_path, file) + found, stat = safe_stat(path) + return ::File.expand_path(found), stat if found + end + end + + def safe_stat(file) + return unless file + stat = ::File.stat(file) + return file, stat if stat.file? + rescue Errno::ENOENT, Errno::ENOTDIR + @cache.delete(file) and false + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb new file mode 100644 index 0000000000..0bff7af038 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb @@ -0,0 +1,254 @@ +require 'rack/utils' + +module Rack + # Rack::Request provides a convenient interface to a Rack + # environment. It is stateless, the environment +env+ passed to the + # constructor will be directly modified. + # + # req = Rack::Request.new(env) + # req.post? + # req.params["data"] + # + # The environment hash passed will store a reference to the Request object + # instantiated so that it will only instantiate if an instance of the Request + # object doesn't already exist. + + class Request + # The environment of the request. + attr_reader :env + + def self.new(env, *args) + if self == Rack::Request + env["rack.request"] ||= super + else + super + end + end + + def initialize(env) + @env = env + end + + def body; @env["rack.input"] end + def scheme; @env["rack.url_scheme"] end + def script_name; @env["SCRIPT_NAME"].to_s end + def path_info; @env["PATH_INFO"].to_s end + def port; @env["SERVER_PORT"].to_i end + def request_method; @env["REQUEST_METHOD"] end + def query_string; @env["QUERY_STRING"].to_s end + def content_length; @env['CONTENT_LENGTH'] end + def content_type; @env['CONTENT_TYPE'] end + def session; @env['rack.session'] ||= {} end + def session_options; @env['rack.session.options'] ||= {} end + + # The media type (type/subtype) portion of the CONTENT_TYPE header + # without any media type parameters. e.g., when CONTENT_TYPE is + # "text/plain;charset=utf-8", the media-type is "text/plain". + # + # For more information on the use of media types in HTTP, see: + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 + def media_type + content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase + end + + # The media type parameters provided in CONTENT_TYPE as a Hash, or + # an empty Hash if no CONTENT_TYPE or media-type parameters were + # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", + # this method responds with the following Hash: + # { 'charset' => 'utf-8' } + def media_type_params + return {} if content_type.nil? + content_type.split(/\s*[;,]\s*/)[1..-1]. + collect { |s| s.split('=', 2) }. + inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } + end + + # The character set of the request body if a "charset" media type + # parameter was given, or nil if no "charset" was specified. Note + # that, per RFC2616, text/* media types that specify no explicit + # charset are to be considered ISO-8859-1. + def content_charset + media_type_params['charset'] + end + + def host + # Remove port number. + (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') + end + + def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end + def path_info=(s); @env["PATH_INFO"] = s.to_s end + + def get?; request_method == "GET" end + def post?; request_method == "POST" end + def put?; request_method == "PUT" end + def delete?; request_method == "DELETE" end + def head?; request_method == "HEAD" end + + # The set of form-data media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for form-data / param parsing. + FORM_DATA_MEDIA_TYPES = [ + nil, + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ] + + # The set of media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + + # Determine whether the request body contains form-data by checking + # the request media_type against registered form-data media-types: + # "application/x-www-form-urlencoded" and "multipart/form-data". The + # list of form-data media types can be modified through the + # +FORM_DATA_MEDIA_TYPES+ array. + def form_data? + FORM_DATA_MEDIA_TYPES.include?(media_type) + end + + # Determine whether the request body contains data by checking + # the request media_type against registered parse-data media-types + def parseable_data? + PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) + end + + # Returns the data recieved in the query string. + def GET + if @env["rack.request.query_string"] == query_string + @env["rack.request.query_hash"] + else + @env["rack.request.query_string"] = query_string + @env["rack.request.query_hash"] = + Utils.parse_nested_query(query_string) + end + end + + # Returns the data recieved in the request body. + # + # This method support both application/x-www-form-urlencoded and + # multipart/form-data. + def POST + if @env["rack.request.form_input"].eql? @env["rack.input"] + @env["rack.request.form_hash"] + elsif form_data? || parseable_data? + @env["rack.request.form_input"] = @env["rack.input"] + unless @env["rack.request.form_hash"] = + Utils::Multipart.parse_multipart(env) + form_vars = @env["rack.input"].read + + # Fix for Safari Ajax postings that always append \0 + form_vars.sub!(/\0\z/, '') + + @env["rack.request.form_vars"] = form_vars + @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) + + @env["rack.input"].rewind + end + @env["rack.request.form_hash"] + else + {} + end + end + + # The union of GET and POST data. + def params + self.put? ? self.GET : self.GET.update(self.POST) + rescue EOFError => e + self.GET + end + + # shortcut for request.params[key] + def [](key) + params[key.to_s] + end + + # shortcut for request.params[key] = value + def []=(key, value) + params[key.to_s] = value + end + + # like Hash#values_at + def values_at(*keys) + keys.map{|key| params[key] } + end + + # the referer of the client or '/' + def referer + @env['HTTP_REFERER'] || '/' + end + alias referrer referer + + + def cookies + return {} unless @env["HTTP_COOKIE"] + + if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] + @env["rack.request.cookie_hash"] + else + @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] + # According to RFC 2109: + # If multiple cookies satisfy the criteria above, they are ordered in + # the Cookie header such that those with more specific Path attributes + # precede those with less specific. Ordering with respect to other + # attributes (e.g., Domain) is unspecified. + @env["rack.request.cookie_hash"] = + Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| + h[k] = Array === v ? v.first : v + h + } + end + end + + def xhr? + @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" + end + + # Tries to return a remake of the original request URL as a string. + def url + url = scheme + "://" + url << host + + if scheme == "https" && port != 443 || + scheme == "http" && port != 80 + url << ":#{port}" + end + + url << fullpath + + url + end + + def path + script_name + path_info + end + + def fullpath + query_string.empty? ? path : "#{path}?#{query_string}" + end + + def accept_encoding + @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| + m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick + + if m + [m[1], (m[2] || 1.0).to_f] + else + raise "Invalid value for Accept-Encoding: #{part.inspect}" + end + end + end + + def ip + if addr = @env['HTTP_X_FORWARDED_FOR'] + addr.split(',').last.strip + else + @env['REMOTE_ADDR'] + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb new file mode 100644 index 0000000000..28b4d8302f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb @@ -0,0 +1,183 @@ +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::Response provides a convenient interface to create a Rack + # response. + # + # It allows setting of headers and cookies, and provides useful + # defaults (a OK response containing HTML). + # + # You can use Response#write to iteratively generate your response, + # but note that this is buffered by Rack::Response until you call + # +finish+. +finish+ however can take a block inside which calls to + # +write+ are syncronous with the Rack response. + # + # Your application's +call+ should end returning Response#finish. + + class Response + attr_accessor :length + + def initialize(body=[], status=200, header={}, &block) + @status = status + @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. + merge(header)) + + @writer = lambda { |x| @body << x } + @block = nil + @length = 0 + + @body = [] + + if body.respond_to? :to_str + write body.to_str + elsif body.respond_to?(:each) + body.each { |part| + write part.to_s + } + else + raise TypeError, "stringable or iterable required" + end + + yield self if block_given? + end + + attr_reader :header + attr_accessor :status, :body + + def [](key) + header[key] + end + + def []=(key, value) + header[key] = value + end + + def set_cookie(key, value) + case value + when Hash + domain = "; domain=" + value[:domain] if value[:domain] + path = "; path=" + value[:path] if value[:path] + # According to RFC 2109, we need dashes here. + # N.B.: cgi.rb uses spaces... + expires = "; expires=" + value[:expires].clone.gmtime. + strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] + secure = "; secure" if value[:secure] + httponly = "; HttpOnly" if value[:httponly] + value = value[:value] + end + value = [value] unless Array === value + cookie = Utils.escape(key) + "=" + + value.map { |v| Utils.escape v }.join("&") + + "#{domain}#{path}#{expires}#{secure}#{httponly}" + + case self["Set-Cookie"] + when Array + self["Set-Cookie"] << cookie + when String + self["Set-Cookie"] = [self["Set-Cookie"], cookie] + when nil + self["Set-Cookie"] = cookie + end + end + + def delete_cookie(key, value={}) + unless Array === self["Set-Cookie"] + self["Set-Cookie"] = [self["Set-Cookie"]].compact + end + + self["Set-Cookie"].reject! { |cookie| + cookie =~ /\A#{Utils.escape(key)}=/ + } + + set_cookie(key, + {:value => '', :path => nil, :domain => nil, + :expires => Time.at(0) }.merge(value)) + end + + def redirect(target, status=302) + self.status = status + self["Location"] = target + end + + def finish(&block) + @block = block + + if [204, 304].include?(status.to_i) + header.delete "Content-Type" + [status.to_i, header.to_hash, []] + else + [status.to_i, header.to_hash, self] + end + end + alias to_a finish # For *response + + def each(&callback) + @body.each(&callback) + @writer = callback + @block.call(self) if @block + end + + # Append to body and update Content-Length. + # + # NOTE: Do not mix #write and direct #body access! + # + def write(str) + s = str.to_s + @length += Rack::Utils.bytesize(s) + @writer.call s + + header["Content-Length"] = @length.to_s + str + end + + def close + body.close if body.respond_to?(:close) + end + + def empty? + @block == nil && @body.empty? + end + + alias headers header + + module Helpers + def invalid?; @status < 100 || @status >= 600; end + + def informational?; @status >= 100 && @status < 200; end + def successful?; @status >= 200 && @status < 300; end + def redirection?; @status >= 300 && @status < 400; end + def client_error?; @status >= 400 && @status < 500; end + def server_error?; @status >= 500 && @status < 600; end + + def ok?; @status == 200; end + def forbidden?; @status == 403; end + def not_found?; @status == 404; end + + def redirect?; [301, 302, 303, 307].include? @status; end + def empty?; [201, 204, 304].include? @status; end + + # Headers + attr_reader :headers, :original_headers + + def include?(header) + !!headers[header] + end + + def content_type + headers["Content-Type"] + end + + def content_length + cl = headers["Content-Length"] + cl ? cl.to_i : cl + end + + def location + headers["Location"] + end + end + + include Helpers + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb new file mode 100644 index 0000000000..9e9b21ff99 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb @@ -0,0 +1,98 @@ +require 'tempfile' + +module Rack + # Class which can make any IO object rewindable, including non-rewindable ones. It does + # this by buffering the data into a tempfile, which is rewindable. + # + # rack.input is required to be rewindable, so if your input stream IO is non-rewindable + # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class + # to easily make it rewindable. + # + # Don't forget to call #close when you're done. This frees up temporary resources that + # RewindableInput uses, though it does *not* close the original IO object. + class RewindableInput + def initialize(io) + @io = io + @rewindable_io = nil + @unlinked = false + end + + def gets + make_rewindable unless @rewindable_io + @rewindable_io.gets + end + + def read(*args) + make_rewindable unless @rewindable_io + @rewindable_io.read(*args) + end + + def each(&block) + make_rewindable unless @rewindable_io + @rewindable_io.each(&block) + end + + def rewind + make_rewindable unless @rewindable_io + @rewindable_io.rewind + end + + # Closes this RewindableInput object without closing the originally + # wrapped IO oject. Cleans up any temporary resources that this RewindableInput + # has created. + # + # This method may be called multiple times. It does nothing on subsequent calls. + def close + if @rewindable_io + if @unlinked + @rewindable_io.close + else + @rewindable_io.close! + end + @rewindable_io = nil + end + end + + private + + # Ruby's Tempfile class has a bug. Subclass it and fix it. + class Tempfile < ::Tempfile + def _close + @tmpfile.close if @tmpfile + @data[1] = nil if @data + @tmpfile = nil + end + end + + def make_rewindable + # Buffer all data into a tempfile. Since this tempfile is private to this + # RewindableInput object, we chmod it so that nobody else can read or write + # it. On POSIX filesystems we also unlink the file so that it doesn't + # even have a file entry on the filesystem anymore, though we can still + # access it because we have the file handle open. + @rewindable_io = Tempfile.new('RackRewindableInput') + @rewindable_io.chmod(0000) + if filesystem_has_posix_semantics? + @rewindable_io.unlink + @unlinked = true + end + + buffer = "" + while @io.read(1024 * 4, buffer) + entire_buffer_written_out = false + while !entire_buffer_written_out + written = @rewindable_io.write(buffer) + entire_buffer_written_out = written == buffer.size + if !entire_buffer_written_out + buffer.slice!(0 .. written - 1) + end + end + end + @rewindable_io.rewind + end + + def filesystem_has_posix_semantics? + RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb new file mode 100644 index 0000000000..218144c17f --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb @@ -0,0 +1,142 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# bugrep: Andreas Zehnder + +require 'time' +require 'rack/request' +require 'rack/response' + +module Rack + + module Session + + module Abstract + + # ID sets up a basic framework for implementing an id based sessioning + # service. Cookies sent to the client for maintaining sessions will only + # contain an id reference. Only #get_session and #set_session are + # required to be overwritten. + # + # All parameters are optional. + # * :key determines the name of the cookie, by default it is + # 'rack.session' + # * :path, :domain, :expire_after, :secure, and :httponly set the related + # cookie options as by Rack::Response#add_cookie + # * :defer will not set a cookie in the response. + # * :renew (implementation dependent) will prompt the generation of a new + # session id, and migration of data to be referenced at the new id. If + # :defer is set, it will be overridden and the cookie will be set. + # * :sidbits sets the number of bits in length that a generated session + # id will be. + # + # These options can be set on a per request basis, at the location of + # env['rack.session.options']. Additionally the id of the session can be + # found within the options hash at the key :id. It is highly not + # recommended to change its value. + # + # Is Rack::Utils::Context compatible. + + class ID + DEFAULT_OPTIONS = { + :path => '/', + :domain => nil, + :expire_after => nil, + :secure => false, + :httponly => true, + :defer => false, + :renew => false, + :sidbits => 128 + } + + attr_reader :key, :default_options + def initialize(app, options={}) + @app = app + @key = options[:key] || "rack.session" + @default_options = self.class::DEFAULT_OPTIONS.merge(options) + end + + def call(env) + context(env) + end + + def context(env, app=@app) + load_session(env) + status, headers, body = app.call(env) + commit_session(env, status, headers, body) + end + + private + + # Generate a new session id using Ruby #rand. The size of the + # session id is controlled by the :sidbits option. + # Monkey patch this to use custom methods for session id generation. + + def generate_sid + "%0#{@default_options[:sidbits] / 4}x" % + rand(2**@default_options[:sidbits] - 1) + end + + # Extracts the session id from provided cookies and passes it and the + # environment to #get_session. It then sets the resulting session into + # 'rack.session', and places options and session metadata into + # 'rack.session.options'. + + def load_session(env) + request = Rack::Request.new(env) + session_id = request.cookies[@key] + + begin + session_id, session = get_session(env, session_id) + env['rack.session'] = session + rescue + env['rack.session'] = Hash.new + end + + env['rack.session.options'] = @default_options. + merge(:id => session_id) + end + + # Acquires the session from the environment and the session id from + # the session options and passes them to #set_session. If successful + # and the :defer option is not true, a cookie will be added to the + # response with the session's id. + + def commit_session(env, status, headers, body) + session = env['rack.session'] + options = env['rack.session.options'] + session_id = options[:id] + + if not session_id = set_session(env, session_id, session, options) + env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") + [status, headers, body] + elsif options[:defer] and not options[:renew] + env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE + [status, headers, body] + else + cookie = Hash.new + cookie[:value] = session_id + cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? + response = Rack::Response.new(body, status, headers) + response.set_cookie(@key, cookie.merge(options)) + response.to_a + end + end + + # All thread safety and session retrival proceedures should occur here. + # Should return [session_id, session]. + # If nil is provided as the session id, generation of a new valid id + # should occur within. + + def get_session(env, sid) + raise '#get_session not implemented.' + end + + # All thread safety and session storage proceedures should occur here. + # Should return true or false dependant on whether or not the session + # was saved or not. + def set_session(env, sid, session, options) + raise '#set_session not implemented.' + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb new file mode 100644 index 0000000000..eace9bd0c6 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb @@ -0,0 +1,91 @@ +require 'openssl' +require 'rack/request' +require 'rack/response' + +module Rack + + module Session + + # Rack::Session::Cookie provides simple cookie based session management. + # The session is a Ruby Hash stored as base64 encoded marshalled data + # set to :key (default: rack.session). + # When the secret key is set, cookie data is checked for data integrity. + # + # Example: + # + # use Rack::Session::Cookie, :key => 'rack.session', + # :domain => 'foo.com', + # :path => '/', + # :expire_after => 2592000, + # :secret => 'change_me' + # + # All parameters are optional. + + class Cookie + + def initialize(app, options={}) + @app = app + @key = options[:key] || "rack.session" + @secret = options[:secret] + @default_options = {:domain => nil, + :path => "/", + :expire_after => nil}.merge(options) + end + + def call(env) + load_session(env) + status, headers, body = @app.call(env) + commit_session(env, status, headers, body) + end + + private + + def load_session(env) + request = Rack::Request.new(env) + session_data = request.cookies[@key] + + if @secret && session_data + session_data, digest = session_data.split("--") + session_data = nil unless digest == generate_hmac(session_data) + end + + begin + session_data = session_data.unpack("m*").first + session_data = Marshal.load(session_data) + env["rack.session"] = session_data + rescue + env["rack.session"] = Hash.new + end + + env["rack.session.options"] = @default_options.dup + end + + def commit_session(env, status, headers, body) + session_data = Marshal.dump(env["rack.session"]) + session_data = [session_data].pack("m*") + + if @secret + session_data = "#{session_data}--#{generate_hmac(session_data)}" + end + + if session_data.size > (4096 - @key.size) + env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") + [status, headers, body] + else + options = env["rack.session.options"] + cookie = Hash.new + cookie[:value] = session_data + cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? + response = Rack::Response.new(body, status, headers) + response.set_cookie(@key, cookie.merge(options)) + response.to_a + end + end + + def generate_hmac(data) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) + end + + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb new file mode 100644 index 0000000000..4a65cbf35d --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb @@ -0,0 +1,109 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net + +require 'rack/session/abstract/id' +require 'memcache' + +module Rack + module Session + # Rack::Session::Memcache provides simple cookie based session management. + # Session data is stored in memcached. The corresponding session key is + # maintained in the cookie. + # You may treat Session::Memcache as you would Session::Pool with the + # following caveats. + # + # * Setting :expire_after to 0 would note to the Memcache server to hang + # onto the session data until it would drop it according to it's own + # specifications. However, the cookie sent to the client would expire + # immediately. + # + # Note that memcache does drop data before it may be listed to expire. For + # a full description of behaviour, please see memcache's documentation. + + class Memcache < Abstract::ID + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \ + :namespace => 'rack:session', + :memcache_server => 'localhost:11211' + + def initialize(app, options={}) + super + + @mutex = Mutex.new + @pool = MemCache. + new @default_options[:memcache_server], @default_options + raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} + end + + def generate_sid + loop do + sid = super + break sid unless @pool.get(sid, true) + end + end + + def get_session(env, sid) + session = @pool.get(sid) if sid + @mutex.lock if env['rack.multithread'] + unless sid and session + env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? + session = {} + sid = generate_sid + ret = @pool.add sid, session + raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret + end + session.instance_variable_set('@old', {}.merge(session)) + return [sid, session] + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return [ nil, {} ] + ensure + @mutex.unlock if env['rack.multithread'] + end + + def set_session(env, session_id, new_session, options) + expiry = options[:expire_after] + expiry = expiry.nil? ? 0 : expiry + 1 + + @mutex.lock if env['rack.multithread'] + session = @pool.get(session_id) || {} + if options[:renew] or options[:drop] + @pool.delete session_id + return false if options[:drop] + session_id = generate_sid + @pool.add session_id, 0 # so we don't worry about cache miss on #set + end + old_session = new_session.instance_variable_get('@old') || {} + session = merge_sessions session_id, old_session, new_session, session + @pool.set session_id, session, expiry + return session_id + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return false + ensure + @mutex.unlock if env['rack.multithread'] + end + + private + + def merge_sessions sid, old, new, cur=nil + cur ||= {} + unless Hash === old and Hash === new + warn 'Bad old or new sessions provided.' + return cur + end + + delete = old.keys - new.keys + warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? + delete.each{|k| cur.delete k } + + update = new.keys.select{|k| new[k] != old[k] } + warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? + update.each{|k| cur[k] = new[k] } + + cur + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb new file mode 100644 index 0000000000..f6f87408bb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb @@ -0,0 +1,100 @@ +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# THANKS: +# apeiros, for session id generation, expiry setup, and threadiness +# sergio, threadiness and bugreps + +require 'rack/session/abstract/id' +require 'thread' + +module Rack + module Session + # Rack::Session::Pool provides simple cookie based session management. + # Session data is stored in a hash held by @pool. + # In the context of a multithreaded environment, sessions being + # committed to the pool is done in a merging manner. + # + # The :drop option is available in rack.session.options if you with to + # explicitly remove the session from the session cache. + # + # Example: + # myapp = MyRackApp.new + # sessioned = Rack::Session::Pool.new(myapp, + # :domain => 'foo.com', + # :expire_after => 2592000 + # ) + # Rack::Handler::WEBrick.run sessioned + + class Pool < Abstract::ID + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false + + def initialize(app, options={}) + super + @pool = Hash.new + @mutex = Mutex.new + end + + def generate_sid + loop do + sid = super + break sid unless @pool.key? sid + end + end + + def get_session(env, sid) + session = @pool[sid] if sid + @mutex.lock if env['rack.multithread'] + unless sid and session + env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? + session = {} + sid = generate_sid + @pool.store sid, session + end + session.instance_variable_set('@old', {}.merge(session)) + return [sid, session] + ensure + @mutex.unlock if env['rack.multithread'] + end + + def set_session(env, session_id, new_session, options) + @mutex.lock if env['rack.multithread'] + session = @pool[session_id] + if options[:renew] or options[:drop] + @pool.delete session_id + return false if options[:drop] + session_id = generate_sid + @pool.store session_id, 0 + end + old_session = new_session.instance_variable_get('@old') || {} + session = merge_sessions session_id, old_session, new_session, session + @pool.store session_id, session + return session_id + rescue + warn "#{new_session.inspect} has been lost." + warn $!.inspect + ensure + @mutex.unlock if env['rack.multithread'] + end + + private + + def merge_sessions sid, old, new, cur=nil + cur ||= {} + unless Hash === old and Hash === new + warn 'Bad old or new sessions provided.' + return cur + end + + delete = old.keys - new.keys + warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty? + delete.each{|k| cur.delete k } + + update = new.keys.select{|k| new[k] != old[k] } + warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty? + update.each{|k| cur[k] = new[k] } + + cur + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb new file mode 100644 index 0000000000..697bc41fdb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb @@ -0,0 +1,349 @@ +require 'ostruct' +require 'erb' +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::ShowExceptions catches all exceptions raised from the app it + # wraps. It shows a useful backtrace with the sourcefile and + # clickable context, the whole Rack environment and the request + # data. + # + # Be careful when you use this on public-facing sites as it could + # reveal information helpful to attackers. + + class ShowExceptions + CONTEXT = 7 + + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + @app.call(env) + rescue StandardError, LoadError, SyntaxError => e + backtrace = pretty(env, e) + [500, + {"Content-Type" => "text/html", + "Content-Length" => backtrace.join.size.to_s}, + backtrace] + end + + def pretty(env, exception) + req = Rack::Request.new(env) + path = (req.script_name + req.path_info).squeeze("/") + + frames = exception.backtrace.map { |line| + frame = OpenStruct.new + if line =~ /(.*?):(\d+)(:in `(.*)')?/ + frame.filename = $1 + frame.lineno = $2.to_i + frame.function = $4 + + begin + lineno = frame.lineno-1 + lines = ::File.readlines(frame.filename) + frame.pre_context_lineno = [lineno-CONTEXT, 0].max + frame.pre_context = lines[frame.pre_context_lineno...lineno] + frame.context_line = lines[lineno].chomp + frame.post_context_lineno = [lineno+CONTEXT, lines.size].min + frame.post_context = lines[lineno+1..frame.post_context_lineno] + rescue + end + + frame + else + nil + end + }.compact + + env["rack.errors"].puts "#{exception.class}: #{exception.message}" + env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } + env["rack.errors"].flush + + [@template.result(binding)] + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django +# Copyright (c) 2005, the Lawrence Journal-World +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' + + + + + + <%=h exception.class %> at <%=h path %> + + + + + +
+

<%=h exception.class %> at <%=h path %>

+

<%=h exception.message %>

+ + + + + + +
Ruby<%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web<%=h req.request_method %> <%=h(req.host + path)%>
+ +

Jump to:

+ +
+ +
+

Traceback (innermost first)

+
    +<% frames.each { |frame| %> +
  • + <%=h frame.filename %>: in <%=h frame.function %> + + <% if frame.context_line %> +
    + <% if frame.pre_context %> +
      + <% frame.pre_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> + +
      +
    1. <%=h frame.context_line %>...
    + + <% if frame.post_context %> +
      + <% frame.post_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> +
    + <% end %> +
  • +<% } %> +
+
+ +
+

Request information

+ +

GET

+ <% unless req.GET.empty? %> + + + + + + + + + <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No GET data.

+ <% end %> + +

POST

+ <% unless req.POST.empty? %> + + + + + + + + + <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No POST data.

+ <% end %> + + + + <% unless req.cookies.empty? %> + + + + + + + + + <% req.cookies.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No cookie data.

+ <% end %> + +

Rack ENV

+ + + + + + + + + <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val %>
+ +
+ +
+

+ You're seeing this error because you use Rack::ShowExceptions. +

+
+ + + +HTML + + # :startdoc: + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb new file mode 100644 index 0000000000..28258c7c89 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb @@ -0,0 +1,106 @@ +require 'erb' +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::ShowStatus catches all empty responses the app it wraps and + # replaces them with a site explaining the error. + # + # Additional details can be put into rack.showstatus.detail + # and will be shown as HTML. If such details exist, the error page + # is always rendered, even if the reply was not empty. + + class ShowStatus + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash.new(headers) + empty = headers['Content-Length'].to_i <= 0 + + # client or server error, or explicit message + if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] + req = Rack::Request.new(env) + message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s + detail = env["rack.showstatus.detail"] || message + body = @template.result(binding) + size = Rack::Utils.bytesize(body) + [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] + else + [status, headers, body] + end + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django +# Copyright (c) 2005, the Lawrence Journal-World +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' + + + + + <%=h message %> at <%=h req.script_name + req.path_info %> + + + + +
+

<%=h message %> (<%= status.to_i %>)

+ + + + + + + + + +
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
+
+
+

<%= detail %>

+
+ +
+

+ You're seeing this error because you use Rack::ShowStatus. +

+
+ + +HTML + + # :startdoc: + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb new file mode 100644 index 0000000000..168e8f83b2 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb @@ -0,0 +1,38 @@ +module Rack + + # The Rack::Static middleware intercepts requests for static files + # (javascript files, images, stylesheets, etc) based on the url prefixes + # passed in the options, and serves them using a Rack::File object. This + # allows a Rack stack to serve both static and dynamic content. + # + # Examples: + # use Rack::Static, :urls => ["/media"] + # will serve all requests beginning with /media from the "media" folder + # located in the current directory (ie media/*). + # + # use Rack::Static, :urls => ["/css", "/images"], :root => "public" + # will serve all requests beginning with /css or /images from the folder + # "public" in the current directory (ie public/css/* and public/images/*) + + class Static + + def initialize(app, options={}) + @app = app + @urls = options[:urls] || ["/favicon.ico"] + root = options[:root] || Dir.pwd + @file_server = Rack::File.new(root) + end + + def call(env) + path = env["PATH_INFO"] + can_serve = @urls.any? { |url| path.index(url) == 0 } + + if can_serve + @file_server.call(env) + else + @app.call(env) + end + end + + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb new file mode 100644 index 0000000000..fcf6616c58 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb @@ -0,0 +1,55 @@ +module Rack + # Rack::URLMap takes a hash mapping urls or paths to apps, and + # dispatches accordingly. Support for HTTP/1.1 host names exists if + # the URLs start with http:// or https://. + # + # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part + # relevant for dispatch is in the SCRIPT_NAME, and the rest in the + # PATH_INFO. This should be taken care of when you need to + # reconstruct the URL in order to create links. + # + # URLMap dispatches in such a way that the longest paths are tried + # first, since they are most specific. + + class URLMap + def initialize(map = {}) + remap(map) + end + + def remap(map) + @mapping = map.map { |location, app| + if location =~ %r{\Ahttps?://(.*?)(/.*)} + host, location = $1, $2 + else + host = nil + end + + unless location[0] == ?/ + raise ArgumentError, "paths need to start with /" + end + location = location.chomp('/') + + [host, location, app] + }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first + end + + def call(env) + path = env["PATH_INFO"].to_s.squeeze("/") + script_name = env['SCRIPT_NAME'] + hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') + @mapping.each { |host, location, app| + next unless (hHost == host || sName == host \ + || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) + next unless location == path[0, location.size] + next unless path[location.size] == nil || path[location.size] == ?/ + + return app.call( + env.merge( + 'SCRIPT_NAME' => (script_name + location), + 'PATH_INFO' => path[location.size..-1])) + } + [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] + end + end +end + diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb new file mode 100644 index 0000000000..42e2e698f4 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb @@ -0,0 +1,516 @@ +# -*- encoding: binary -*- + +require 'set' +require 'tempfile' + +module Rack + # Rack::Utils contains a grab-bag of useful methods for writing web + # applications adopted from all kinds of Ruby libraries. + + module Utils + # Performs URI escaping so that you can construct proper + # query strings faster. Use this rather than the cgi.rb + # version since it's faster. (Stolen from Camping). + def escape(s) + s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { + '%'+$1.unpack('H2'*$1.size).join('%').upcase + }.tr(' ', '+') + end + module_function :escape + + # Unescapes a URI escaped string. (Stolen from Camping). + def unescape(s) + s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ + [$1.delete('%')].pack('H*') + } + end + module_function :unescape + + # Stolen from Mongrel, with some small modifications: + # Parses a query string by breaking it up at the '&' + # and ';' characters. You can also use this to parse + # cookies by changing the characters used in the second + # parameter (which defaults to '&;'). + def parse_query(qs, d = '&;') + params = {} + + (qs || '').split(/[#{d}] */n).each do |p| + k, v = unescape(p).split('=', 2) + + if cur = params[k] + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + end + + return params + end + module_function :parse_query + + def parse_nested_query(qs, d = '&;') + params = {} + + (qs || '').split(/[#{d}] */n).each do |p| + k, v = unescape(p).split('=', 2) + normalize_params(params, k, v) + end + + return params + end + module_function :parse_nested_query + + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + params[k] = v + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + module_function :normalize_params + + def build_query(params) + params.map { |k, v| + if v.class == Array + build_query(v.map { |x| [k, x] }) + else + escape(k) + "=" + escape(v) + end + }.join("&") + end + module_function :build_query + + def build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) + }.join("&") + when String + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{escape(value)}" + else + prefix + end + end + module_function :build_nested_query + + # Escape ampersands, brackets and quotes to their HTML/XML entities. + def escape_html(string) + string.to_s.gsub("&", "&"). + gsub("<", "<"). + gsub(">", ">"). + gsub("'", "'"). + gsub('"', """) + end + module_function :escape_html + + def select_best_encoding(available_encodings, accept_encoding) + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + + expanded_accept_encoding = + accept_encoding.map { |m, q| + if m == "*" + (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } + else + [[m, q]] + end + }.inject([]) { |mem, list| + mem + list + } + + encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } + + unless encoding_candidates.include?("identity") + encoding_candidates.push("identity") + end + + expanded_accept_encoding.find_all { |m, q| + q == 0.0 + }.each { |m, _| + encoding_candidates.delete(m) + } + + return (encoding_candidates & available_encodings)[0] + end + module_function :select_best_encoding + + # Return the bytesize of String; uses String#length under Ruby 1.8 and + # String#bytesize under 1.9. + if ''.respond_to?(:bytesize) + def bytesize(string) + string.bytesize + end + else + def bytesize(string) + string.size + end + end + module_function :bytesize + + # Context allows the use of a compatible middleware at different points + # in a request handling stack. A compatible middleware must define + # #context which should take the arguments env and app. The first of which + # would be the request environment. The second of which would be the rack + # application that the request would be forwarded to. + class Context + attr_reader :for, :app + + def initialize(app_f, app_r) + raise 'running context does not respond to #context' unless app_f.respond_to? :context + @for, @app = app_f, app_r + end + + def call(env) + @for.context(env, @app) + end + + def recontext(app) + self.class.new(@for, app) + end + + def context(env, app=@app) + recontext(app).call(env) + end + end + + # A case-insensitive Hash that preserves the original case of a + # header when set. + class HeaderHash < Hash + def initialize(hash={}) + @names = {} + hash.each { |k, v| self[k] = v } + end + + def to_hash + inject({}) do |hash, (k,v)| + if v.respond_to? :to_ary + hash[k] = v.to_ary.join("\n") + else + hash[k] = v + end + hash + end + end + + def [](k) + super @names[k.downcase] + end + + def []=(k, v) + delete k + @names[k.downcase] = k + super k, v + end + + def delete(k) + super @names.delete(k.downcase) + end + + def include?(k) + @names.has_key? k.downcase + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + + def merge(other) + hash = dup + hash.merge! other + end + end + + # Every standard HTTP code mapped to the appropriate message. + # Stolen from Mongrel. + HTTP_STATUS_CODES = { + 100 => 'Continue', + 101 => 'Switching Protocols', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Large', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + } + + # Responses with HTTP status codes that should not have an entity body + STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) + + # A multipart form data parser, adapted from IOWA. + # + # Usually, Rack::Request#POST takes care of calling this. + + module Multipart + 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 + + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" + + def self.parse_multipart(env) + unless env['CONTENT_TYPE'] =~ + %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n + nil + else + boundary = "--#{$1}" + + params = {} + buf = "" + content_length = env['CONTENT_LENGTH'].to_i + input = env['rack.input'] + input.rewind + + boundary_size = Utils.bytesize(boundary) + EOL.size + bufsize = 16384 + + content_length -= boundary_size + + read_buffer = '' + + status = input.read(boundary_size, read_buffer) + raise EOFError, "bad content body" unless status == boundary + EOL + + rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n + + loop { + head = nil + body = '' + filename = content_type = name = nil + + until head && buf =~ rx + if !head && i = buf.index(EOL+EOL) + head = buf.slice!(0, i+2) # First \r\n + buf.slice!(0, 2) # Second \r\n + + filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] + name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] + + if content_type || filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end + + next + end + + # Save the read body part. + if head && (boundary_size+4 < buf.size) + body << buf.slice!(0, buf.size - (boundary_size+4)) + end + + c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) + raise EOFError, "bad content body" if c.nil? || c.empty? + buf << c + content_length -= c.size + end + + # Save the rest. + if i = buf.index(rx) + body << buf.slice!(0, i) + buf.slice!(0, boundary_size+2) + + content_length = -1 if $1 == "--" + end + + if filename == "" + # filename is blank which means no file has been selected + data = nil + elsif filename + body.rewind + + # Take the basename of the upload's original filename. + # This handles the full Windows paths given by Internet Explorer + # (and perhaps other broken user agents) without affecting + # those which give the lone filename. + filename =~ /^(?:.*[:\\\/])?(.*)/m + filename = $1 + + data = {:filename => filename, :type => content_type, + :name => name, :tempfile => body, :head => head} + elsif !filename && content_type + body.rewind + + # Generic multipart cases, not coming from a form + data = {:type => content_type, + :name => name, :tempfile => body, :head => head} + else + data = body + end + + Utils.normalize_params(params, name, data) unless data.nil? + + break if buf.empty? || content_length == -1 + } + + input.rewind + + params + end + end + + def self.build_multipart(params, first = true) + if first + unless params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + + multipart = false + query = lambda { |value| + case value + when Array + value.each(&query) + when Hash + value.values.each(&query) + when UploadedFile + multipart = true + end + } + params.values.each(&query) + return nil unless multipart + end + + flattened_params = Hash.new + + params.each do |key, value| + k = first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + build_multipart(v, false).each { |subkey, subvalue| + flattened_params["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + build_multipart(value, false).each { |subkey, subvalue| + flattened_params[k + subkey] = subvalue + } + else + flattened_params[k] = value + end + end + + if first + flattened_params.map { |name, file| + if file.respond_to?(:original_filename) + ::File.open(file.path, "rb") do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r +Content-Type: #{file.content_type}\r +Content-Length: #{::File.stat(file.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + }.join + "--#{MULTIPART_BOUNDARY}--\r" + else + flattened_params + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack.rb b/actionpack/lib/action_dispatch/vendor/rack/rack.rb deleted file mode 100644 index 371d015690..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack.rb +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2007, 2008, 2009 Christian Neukirchen -# -# Rack is freely distributable under the terms of an MIT-style license. -# See COPYING or http://www.opensource.org/licenses/mit-license.php. - -path = File.expand_path(File.dirname(__FILE__)) -$:.unshift(path) unless $:.include?(path) - - -# The Rack main module, serving as a namespace for all core Rack -# modules and classes. -# -# All modules meant for use in your application are autoloaded here, -# so it should be enough just to require rack.rb in your code. - -module Rack - # The Rack protocol version number implemented. - VERSION = [1,0] - - # Return the Rack protocol version as a dotted string. - def self.version - VERSION.join(".") - end - - # Return the Rack release as a dotted string. - def self.release - "1.0" - end - - autoload :Builder, "rack/builder" - autoload :Cascade, "rack/cascade" - autoload :Chunked, "rack/chunked" - autoload :CommonLogger, "rack/commonlogger" - autoload :ConditionalGet, "rack/conditionalget" - autoload :ContentLength, "rack/content_length" - autoload :ContentType, "rack/content_type" - autoload :File, "rack/file" - autoload :Deflater, "rack/deflater" - autoload :Directory, "rack/directory" - autoload :ForwardRequest, "rack/recursive" - autoload :Handler, "rack/handler" - autoload :Head, "rack/head" - autoload :Lint, "rack/lint" - autoload :Lock, "rack/lock" - autoload :MethodOverride, "rack/methodoverride" - autoload :Mime, "rack/mime" - autoload :Recursive, "rack/recursive" - autoload :Reloader, "rack/reloader" - autoload :ShowExceptions, "rack/showexceptions" - autoload :ShowStatus, "rack/showstatus" - autoload :Static, "rack/static" - autoload :URLMap, "rack/urlmap" - autoload :Utils, "rack/utils" - - autoload :MockRequest, "rack/mock" - autoload :MockResponse, "rack/mock" - - autoload :Request, "rack/request" - autoload :Response, "rack/response" - - module Auth - autoload :Basic, "rack/auth/basic" - autoload :AbstractRequest, "rack/auth/abstract/request" - autoload :AbstractHandler, "rack/auth/abstract/handler" - autoload :OpenID, "rack/auth/openid" - module Digest - autoload :MD5, "rack/auth/digest/md5" - autoload :Nonce, "rack/auth/digest/nonce" - autoload :Params, "rack/auth/digest/params" - autoload :Request, "rack/auth/digest/request" - end - end - - module Session - autoload :Cookie, "rack/session/cookie" - autoload :Pool, "rack/session/pool" - autoload :Memcache, "rack/session/memcache" - end - - # *Adapters* connect Rack with third party web frameworks. - # - # Rack includes an adapter for Camping, see README for other - # frameworks supporting Rack in their code bases. - # - # Refer to the submodules for framework-specific calling details. - - module Adapter - autoload :Camping, "rack/adapter/camping" - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb deleted file mode 100644 index 63bc787f54..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/adapter/camping.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Rack - module Adapter - class Camping - def initialize(app) - @app = app - end - - def call(env) - env["PATH_INFO"] ||= "" - env["SCRIPT_NAME"] ||= "" - controller = @app.run(env['rack.input'], env) - h = controller.headers - h.each_pair do |k,v| - if v.kind_of? URI - h[k] = v.to_s - end - end - [controller.status, controller.headers, [controller.body.to_s]] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb deleted file mode 100644 index 214df6299e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/handler.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - # Rack::Auth::AbstractHandler implements common authentication functionality. - # - # +realm+ should be set for all handlers. - - class AbstractHandler - - attr_accessor :realm - - def initialize(app, realm=nil, &authenticator) - @app, @realm, @authenticator = app, realm, authenticator - end - - - private - - def unauthorized(www_authenticate = challenge) - return [ 401, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0', - 'WWW-Authenticate' => www_authenticate.to_s }, - [] - ] - end - - def bad_request - return [ 400, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0' }, - [] - ] - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb deleted file mode 100644 index 1d9ccec685..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/abstract/request.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Rack - module Auth - class AbstractRequest - - def initialize(env) - @env = env - end - - def provided? - !authorization_key.nil? - end - - def parts - @parts ||= @env[authorization_key].split(' ', 2) - end - - def scheme - @scheme ||= parts.first.downcase.to_sym - end - - def params - @params ||= parts.last - end - - - private - - AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] - - def authorization_key - @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } - end - - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb deleted file mode 100644 index 9557224648..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/basic.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/abstract/request' - -module Rack - module Auth - # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. - # - # Initialize with the Rack application that you want protecting, - # and a block that checks if a username and password pair are valid. - # - # See also: example/protectedlobster.rb - - class Basic < AbstractHandler - - def call(env) - auth = Basic::Request.new(env) - - return unauthorized unless auth.provided? - - return bad_request unless auth.basic? - - if valid?(auth) - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - - unauthorized - end - - - private - - def challenge - 'Basic realm="%s"' % realm - end - - def valid?(auth) - @authenticator.call(*auth.credentials) - end - - class Request < Auth::AbstractRequest - def basic? - :basic == scheme - end - - def credentials - @credentials ||= params.unpack("m*").first.split(/:/, 2) - end - - def username - credentials.first - end - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb deleted file mode 100644 index e579dc9632..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/md5.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'rack/auth/abstract/handler' -require 'rack/auth/digest/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of - # HTTP Digest Authentication, as per RFC 2617. - # - # Initialize with the [Rack] application that you want protecting, - # and a block that looks up a plaintext password for a given username. - # - # +opaque+ needs to be set to a constant base64/hexadecimal string. - # - class MD5 < AbstractHandler - - attr_accessor :opaque - - attr_writer :passwords_hashed - - def initialize(*args) - super - @passwords_hashed = nil - end - - def passwords_hashed? - !!@passwords_hashed - end - - def call(env) - auth = Request.new(env) - - unless auth.provided? - return unauthorized - end - - if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) - return bad_request - end - - if valid?(auth) - if auth.nonce.stale? - return unauthorized(challenge(:stale => true)) - else - env['REMOTE_USER'] = auth.username - - return @app.call(env) - end - end - - unauthorized - end - - - private - - QOP = 'auth'.freeze - - def params(hash = {}) - Params.new do |params| - params['realm'] = realm - params['nonce'] = Nonce.new.to_s - params['opaque'] = H(opaque) - params['qop'] = QOP - - hash.each { |k, v| params[k] = v } - end - end - - def challenge(hash = {}) - "Digest #{params(hash)}" - end - - def valid?(auth) - valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) - end - - def valid_qop?(auth) - QOP == auth.qop - end - - def valid_opaque?(auth) - H(opaque) == auth.opaque - end - - def valid_nonce?(auth) - auth.nonce.valid? - end - - def valid_digest?(auth) - digest(auth, @authenticator.call(auth.username)) == auth.response - end - - def md5(data) - ::Digest::MD5.hexdigest(data) - end - - alias :H :md5 - - def KD(secret, data) - H([secret, data] * ':') - end - - def A1(auth, password) - [ auth.username, auth.realm, password ] * ':' - end - - def A2(auth) - [ auth.method, auth.uri ] * ':' - end - - def digest(auth, password) - password_hash = passwords_hashed? ? password : H(A1(auth, password)) - - KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb deleted file mode 100644 index dbe109f29a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/nonce.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'digest/md5' - -module Rack - module Auth - module Digest - # Rack::Auth::Digest::Nonce is the default nonce generator for the - # Rack::Auth::Digest::MD5 authentication handler. - # - # +private_key+ needs to set to a constant string. - # - # +time_limit+ can be optionally set to an integer (number of seconds), - # to limit the validity of the generated nonces. - - class Nonce - - class << self - attr_accessor :private_key, :time_limit - end - - def self.parse(string) - new(*string.unpack("m*").first.split(' ', 2)) - end - - def initialize(timestamp = Time.now, given_digest = nil) - @timestamp, @given_digest = timestamp.to_i, given_digest - end - - def to_s - [([ @timestamp, digest ] * ' ')].pack("m*").strip - end - - def digest - ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') - end - - def valid? - digest == @given_digest - end - - def stale? - !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit - end - - def fresh? - !stale? - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb deleted file mode 100644 index 730e2efdc8..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/params.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - module Auth - module Digest - class Params < Hash - - def self.parse(str) - split_header_value(str).inject(new) do |header, param| - k, v = param.split('=', 2) - header[k] = dequote(v) - header - end - end - - def self.dequote(str) # From WEBrick::HTTPUtils - ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup - ret.gsub!(/\\(.)/, "\\1") - ret - end - - def self.split_header_value(str) - str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } - end - - def initialize - super - - yield self if block_given? - end - - def [](k) - super k.to_s - end - - def []=(k, v) - super k.to_s, v.to_s - end - - UNQUOTED = ['qop', 'nc', 'stale'] - - def to_s - inject([]) do |parts, (k, v)| - parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) - parts - end.join(', ') - end - - def quote(str) # From WEBrick::HTTPUtils - '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' - end - - end - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb deleted file mode 100644 index a8aa3bf996..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/digest/request.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'rack/auth/abstract/request' -require 'rack/auth/digest/params' -require 'rack/auth/digest/nonce' - -module Rack - module Auth - module Digest - class Request < Auth::AbstractRequest - - def method - @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] - end - - def digest? - :digest == scheme - end - - def correct_uri? - (@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri - end - - def nonce - @nonce ||= Nonce.parse(params['nonce']) - end - - def params - @params ||= Params.parse(parts.last) - end - - def method_missing(sym) - if params.has_key? key = sym.to_s - return params[key] - end - super - end - - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb deleted file mode 100644 index c5f6a5143e..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/auth/openid.rb +++ /dev/null @@ -1,480 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -gem 'ruby-openid', '~> 2' if defined? Gem -require 'rack/request' -require 'rack/utils' -require 'rack/auth/abstract/handler' -require 'uri' -require 'openid' #gem -require 'openid/extension' #gem -require 'openid/store/memory' #gem - -module Rack - class Request - def openid_request - @env['rack.auth.openid.request'] - end - - def openid_response - @env['rack.auth.openid.response'] - end - end - - module Auth - - # Rack::Auth::OpenID provides a simple method for setting up an OpenID - # Consumer. It requires the ruby-openid library from janrain to operate, - # as well as a rack method of session management. - # - # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. - # - # The OpenID specifications can be found at - # http://openid.net/specs/openid-authentication-1_1.html - # and - # http://openid.net/specs/openid-authentication-2_0.html. Documentation - # for published OpenID extensions and related topics can be found at - # http://openid.net/developers/specs/. - # - # It is recommended to read through the OpenID spec, as well as - # ruby-openid's documentation, to understand what exactly goes on. However - # a setup as simple as the presented examples is enough to provide - # Consumer functionality. - # - # This library strongly intends to utilize the OpenID 2.0 features of the - # ruby-openid library, which provides OpenID 1.0 compatiblity. - # - # NOTE: Due to the amount of data that this library stores in the - # session, Rack::Session::Cookie may fault. - - class OpenID - - class NoSession < RuntimeError; end - class BadExtension < RuntimeError; end - # Required for ruby-openid - ValidStatus = [:success, :setup_needed, :cancel, :failure] - - # = Arguments - # - # The first argument is the realm, identifying the site they are trusting - # with their identity. This is required, also treated as the trust_root - # in OpenID 1.x exchanges. - # - # The optional second argument is a hash of options. - # - # == Options - # - # :return_to defines the url to return to after the client - # authenticates with the openid service provider. This url should point - # to where Rack::Auth::OpenID is mounted. If :return_to is not - # provided, return_to will be the current url which allows flexibility - # with caveats. - # - # :session_key defines the key to the session hash in the env. - # It defaults to 'rack.session'. - # - # :openid_param defines at what key in the request parameters to - # find the identifier to resolve. As per the 2.0 spec, the default is - # 'openid_identifier'. - # - # :store defined what OpenID Store to use for persistant - # information. By default a Store::Memory will be used. - # - # :immediate as true will make initial requests to be of an - # immediate type. This is false by default. See OpenID specification - # documentation. - # - # :extensions should be a hash of openid extension - # implementations. The key should be the extension main module, the value - # should be an array of arguments for extension::Request.new. - # The hash is iterated over and passed to #add_extension for processing. - # Please see #add_extension for further documentation. - # - # == Examples - # - # simple_oid = OpenID.new('http://mysite.com/') - # - # return_oid = OpenID.new('http://mysite.com/', { - # :return_to => 'http://mysite.com/openid' - # }) - # - # complex_oid = OpenID.new('http://mysite.com/', - # :immediate => true, - # :extensions => { - # ::OpenID::SReg => [['email'],['nickname']] - # } - # ) - # - # = Advanced - # - # Most of the functionality of this library is encapsulated such that - # expansion and overriding functions isn't difficult nor tricky. - # Alternately, to avoid opening up singleton objects or subclassing, a - # wrapper rack middleware can be composed to act upon Auth::OpenID's - # responses. See #check and #finish for locations of pertinent data. - # - # == Responses - # - # To change the responses that Auth::OpenID returns, override the methods - # #redirect, #bad_request, #unauthorized, #access_denied, and - # #foreign_server_failure. - # - # Additionally #confirm_post_params is used when the URI would exceed - # length limits on a GET request when doing the initial verification - # request. - # - # == Processing - # - # To change methods of processing completed transactions, override the - # methods #success, #setup_needed, #cancel, and #failure. Please ensure - # the returned object is a rack compatible response. - # - # The first argument is an OpenID::Response, the second is a - # Rack::Request of the current request, the last is the hash used in - # ruby-openid handling, which can be found manually at - # env['rack.session'][:openid]. - # - # This is useful if you wanted to expand the processing done, such as - # setting up user accounts. - # - # oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to - # def oid_app.success oid, request, session - # user = Models::User[oid.identity_url] - # user ||= Models::User.create_from_openid oid - # request['rack.session'][:user] = user.id - # redirect MyApp.site_home - # end - # - # site_map['/openid'] = oid_app - # map = Rack::URLMap.new site_map - # ... - - def initialize(realm, options={}) - realm = URI(realm) - raise ArgumentError, "Invalid realm: #{realm}" \ - unless realm.absolute? \ - and realm.fragment.nil? \ - and realm.scheme =~ /^https?$/ \ - and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/ - realm.path = '/' if realm.path.empty? - @realm = realm.to_s - - if ruri = options[:return_to] - ruri = URI(ruri) - raise ArgumentError, "Invalid return_to: #{ruri}" \ - unless ruri.absolute? \ - and ruri.scheme =~ /^https?$/ \ - and ruri.fragment.nil? - raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \ - unless self.within_realm?(ruri) - @return_to = ruri.to_s - end - - @session_key = options[:session_key] || 'rack.session' - @openid_param = options[:openid_param] || 'openid_identifier' - @store = options[:store] || ::OpenID::Store::Memory.new - @immediate = !!options[:immediate] - - @extensions = {} - if extensions = options.delete(:extensions) - extensions.each do |ext, args| - add_extension ext, *args - end - end - - # Undocumented, semi-experimental - @anonymous = !!options[:anonymous] - end - - attr_reader :realm, :return_to, :session_key, :openid_param, :store, - :immediate, :extensions - - # Sets up and uses session data at :openid within the session. - # Errors in this setup will raise a NoSession exception. - # - # If the parameter 'openid.mode' is set, which implies a followup from - # the openid server, processing is passed to #finish and the result is - # returned. However, if there is no appropriate openid information in the - # session, a 400 error is returned. - # - # If the parameter specified by options[:openid_param] is - # present, processing is passed to #check and the result is returned. - # - # If neither of these conditions are met, #unauthorized is called. - - def call(env) - env['rack.auth.openid'] = self - env_session = env[@session_key] - unless env_session and env_session.is_a?(Hash) - raise NoSession, 'No compatible session' - end - # let us work in our own namespace... - session = (env_session[:openid] ||= {}) - unless session and session.is_a?(Hash) - raise NoSession, 'Incompatible openid session' - end - - request = Rack::Request.new(env) - consumer = ::OpenID::Consumer.new(session, @store) - - if mode = request.GET['openid.mode'] - if session.key?(:openid_param) - finish(consumer, session, request) - else - bad_request - end - elsif request.GET[@openid_param] - check(consumer, session, request) - else - unauthorized - end - end - - # As the first part of OpenID consumer action, #check retrieves the data - # required for completion. - # - # If all parameters fit within the max length of a URI, a 303 redirect - # will be returned. Otherwise #confirm_post_params will be called. - # - # Any messages from OpenID's request are logged to env['rack.errors'] - # - # env['rack.auth.openid.request'] is the openid checkid request - # instance. - # - # session[:openid_param] is set to the openid identifier - # provided by the user. - # - # session[:return_to] is set to the return_to uri given to the - # identity provider. - - def check(consumer, session, req) - oid = consumer.begin(req.GET[@openid_param], @anonymous) - req.env['rack.auth.openid.request'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - ## Extension support - extensions.each do |ext,args| - oid.add_extension(ext::Request.new(*args)) - end - - session[:openid_param] = req.GET[openid_param] - return_to_uri = return_to ? return_to : req.url - session[:return_to] = return_to_uri - immediate = session.key?(:setup_needed) ? false : immediate - - if oid.send_redirect?(realm, return_to_uri, immediate) - uri = oid.redirect_url(realm, return_to_uri, immediate) - redirect(uri) - else - confirm_post_params(oid, realm, return_to_uri, immediate) - end - rescue ::OpenID::DiscoveryFailure => e - # thrown from inside OpenID::Consumer#begin by yadis stuff - req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n") - return foreign_server_failure - end - - # This is the final portion of authentication. - # If successful, a redirect to the realm is be returned. - # Data gathered from extensions are stored in session[:openid] with the - # extension's namespace uri as the key. - # - # Any messages from OpenID's response are logged to env['rack.errors'] - # - # env['rack.auth.openid.response'] will contain the openid - # response. - - def finish(consumer, session, req) - oid = consumer.complete(req.GET, req.url) - req.env['rack.auth.openid.response'] = oid - req.env['rack.errors'].puts(oid.message) - p oid if $DEBUG - - raise unless ValidStatus.include?(oid.status) - __send__(oid.status, oid, req, session) - end - - # The first argument should be the main extension module. - # The extension module should contain the constants: - # * class Request, should have OpenID::Extension as an ancestor - # * class Response, should have OpenID::Extension as an ancestor - # * string NS_URI, which defining the namespace of the extension - # - # All trailing arguments will be passed to extension::Request.new in - # #check. - # The openid response will be passed to - # extension::Response#from_success_response, #get_extension_args will be - # called on the result to attain the gathered data. - # - # This method returns the key at which the response data will be found in - # the session, which is the namespace uri by default. - - def add_extension(ext, *args) - raise BadExtension unless valid_extension?(ext) - extensions[ext] = args - return ext::NS_URI - end - - # Checks the validitity, in the context of usage, of a submitted - # extension. - - def valid_extension?(ext) - if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) } - raise ArgumentError, 'Extension is missing constants.' - elsif not ext::Response.respond_to?(:from_success_response) - raise ArgumentError, 'Response is missing required method.' - end - return true - rescue - return false - end - - # Checks the provided uri to ensure it'd be considered within the realm. - # is currently not compatible with wildcard realms. - - def within_realm? uri - uri = URI.parse(uri.to_s) - realm = URI.parse(self.realm) - return false unless uri.absolute? - return false unless uri.path[0, realm.path.size] == realm.path - return false unless uri.host == realm.host or realm.host[/^\*\./] - # for wildcard support, is awkward with URI limitations - realm_match = Regexp.escape(realm.host). - sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$' - return false unless uri.host.match(realm_match) - return true - end - alias_method :include?, :within_realm? - - protected - - ### These methods define some of the boilerplate responses. - - # Returns an html form page for posting to an Identity Provider if the - # GET request would exceed the upper URI length limit. - - def confirm_post_params(oid, realm, return_to, immediate) - Rack::Response.new.finish do |r| - r.write 'Confirm...' - r.write oid.form_markup(realm, return_to, immediate) - r.write '' - end - end - - # Returns a 303 redirect with the destination of that provided by the - # argument. - - def redirect(uri) - [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain', - 'Location' => uri}, - [] ] - end - - # Returns an empty 400 response. - - def bad_request - [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'}, - [''] ] - end - - # Returns a basic unauthorized 401 response. - - def unauthorized - [ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'}, - ['Unauthorized.'] ] - end - - # Returns a basic access denied 403 response. - - def access_denied - [ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'}, - ['Access denied.'] ] - end - - # Returns a 503 response to be used if communication with the remote - # OpenID server fails. - - def foreign_server_failure - [ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'}, - ['Foreign server failure.'] ] - end - - private - - ### These methods are called after a transaction is completed, depending - # on its outcome. These should all return a rack compatible response. - # You'd want to override these to provide additional functionality. - - # Called to complete processing on a successful transaction. - # Within the openid session, :openid_identity and :openid_identifier are - # set to the user friendly and the standard representation of the - # validated identity. All other data in the openid session is cleared. - - def success(oid, request, session) - session.clear - session[:openid_identity] = oid.display_identifier - session[:openid_identifier] = oid.identity_url - extensions.keys.each do |ext| - label = ext.name[/[^:]+$/].downcase - response = ext::Response.from_success_response(oid) - session[label] = response.data - end - redirect(realm) - end - - # Called if the Identity Provider indicates further setup by the user is - # required. - # The identifier is retrived from the openid session at :openid_param. - # And :setup_needed is set to true to prevent looping. - - def setup_needed(oid, request, session) - identifier = session[:openid_param] - session[:setup_needed] = true - redirect req.script_name + '?' + openid_param + '=' + identifier - end - - # Called if the user indicates they wish to cancel identification. - # Data within openid session is cleared. - - def cancel(oid, request, session) - session.clear - access_denied - end - - # Called if the Identity Provider indicates the user is unable to confirm - # their identity. Data within the openid session is left alone, in case - # of swarm auth attacks. - - def failure(oid, request, session) - unauthorized - end - end - - # A class developed out of the request to use OpenID as an authentication - # middleware. The request will be sent to the OpenID instance unless the - # block evaluates to true. For example in rackup, you can use it as such: - # - # use Rack::Session::Pool - # use Rack::Auth::OpenIDAuth, realm, openid_options do |env| - # env['rack.session'][:authkey] == a_string - # end - # run RackApp - # - # Or simply: - # - # app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth - - class OpenIDAuth < Rack::Auth::AbstractHandler - attr_reader :oid - def initialize(app, realm, options={}, &auth) - @oid = OpenID.new(realm, options) - super(app, &auth) - end - - def call(env) - to = auth.call(env) ? @app : @oid - to.call env - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb deleted file mode 100644 index 295235e56a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/builder.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Rack - # Rack::Builder implements a small DSL to iteratively construct Rack - # applications. - # - # Example: - # - # app = Rack::Builder.new { - # use Rack::CommonLogger - # use Rack::ShowExceptions - # map "/lobster" do - # use Rack::Lint - # run Rack::Lobster.new - # end - # } - # - # Or - # - # app = Rack::Builder.app do - # use Rack::CommonLogger - # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } - # end - # - # +use+ adds a middleware to the stack, +run+ dispatches to an application. - # You can use +map+ to construct a Rack::URLMap in a convenient way. - - class Builder - def initialize(&block) - @ins = [] - instance_eval(&block) if block_given? - end - - def self.app(&block) - self.new(&block).to_app - end - - def use(middleware, *args, &block) - @ins << lambda { |app| middleware.new(app, *args, &block) } - end - - def run(app) - @ins << app #lambda { |nothing| app } - end - - def map(path, &block) - if @ins.last.kind_of? Hash - @ins.last[path] = self.class.new(&block).to_app - else - @ins << {} - map(path, &block) - end - end - - def to_app - @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last - inner_app = @ins.last - @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } - end - - def call(env) - to_app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb deleted file mode 100644 index a038aa1105..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/cascade.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Rack - # Rack::Cascade tries an request on several apps, and returns the - # first response that is not 404 (or in a list of configurable - # status codes). - - class Cascade - attr_reader :apps - - def initialize(apps, catch=404) - @apps = apps - @catch = [*catch] - end - - def call(env) - status = headers = body = nil - raise ArgumentError, "empty cascade" if @apps.empty? - @apps.each { |app| - begin - status, headers, body = app.call(env) - break unless @catch.include?(status.to_i) - end - } - [status, headers, body] - end - - def add app - @apps << app - end - - def include? app - @apps.include? app - end - - alias_method :<<, :add - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb deleted file mode 100644 index 280d89dd65..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/chunked.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that applies chunked transfer encoding to response bodies - # when the response does not include a Content-Length header. - class Chunked - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if env['HTTP_VERSION'] == 'HTTP/1.0' || - STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Content-Length'] || - headers['Transfer-Encoding'] - [status, headers.to_hash, body] - else - dup.chunk(status, headers, body) - end - end - - def chunk(status, headers, body) - @body = body - headers.delete('Content-Length') - headers['Transfer-Encoding'] = 'chunked' - [status, headers.to_hash, self] - end - - def each - term = "\r\n" - @body.each do |chunk| - size = bytesize(chunk) - next if size == 0 - yield [size.to_s(16), term, chunk, term].join - end - yield ["0", term, "", term].join - end - - def close - @body.close if @body.respond_to?(:close) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb deleted file mode 100644 index 5e68ac626d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/commonlogger.rb +++ /dev/null @@ -1,61 +0,0 @@ -module Rack - # Rack::CommonLogger forwards every request to an +app+ given, and - # logs a line in the Apache common log format to the +logger+, or - # rack.errors by default. - - class CommonLogger - def initialize(app, logger=nil) - @app = app - @logger = logger - end - - def call(env) - dup._call(env) - end - - def _call(env) - @env = env - @logger ||= self - @time = Time.now - @status, @header, @body = @app.call(env) - [@status, @header, self] - end - - def close - @body.close if @body.respond_to? :close - end - - # By default, log to rack.errors. - def <<(str) - @env["rack.errors"].write(str) - @env["rack.errors"].flush - end - - def each - length = 0 - @body.each { |part| - length += part.size - yield part - } - - @now = Time.now - - # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common - # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - - # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % - @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % - [ - @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", - @env["REMOTE_USER"] || "-", - @now.strftime("%d/%b/%Y %H:%M:%S"), - @env["REQUEST_METHOD"], - @env["PATH_INFO"], - @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], - @env["HTTP_VERSION"], - @status.to_s[0..3], - (length.zero? ? "-" : length.to_s), - @now - @time - ] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb deleted file mode 100644 index 046ebdb00a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/conditionalget.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'rack/utils' - -module Rack - - # Middleware that enables conditional GET using If-None-Match and - # If-Modified-Since. The application should set either or both of the - # Last-Modified or Etag response headers according to RFC 2616. When - # either of the conditions is met, the response body is set to be zero - # length and the response status is set to 304 Not Modified. - # - # Applications that defer response body generation until the body's each - # message is received will avoid response body generation completely when - # a conditional GET matches. - # - # Adapted from Michael Klishin's Merb implementation: - # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb - class ConditionalGet - def initialize(app) - @app = app - end - - def call(env) - return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD']) - - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - if etag_matches?(env, headers) || modified_since?(env, headers) - status = 304 - headers.delete('Content-Type') - headers.delete('Content-Length') - body = [] - end - [status, headers, body] - end - - private - def etag_matches?(env, headers) - etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH'] - end - - def modified_since?(env, headers) - last_modified = headers['Last-Modified'] and - last_modified == env['HTTP_IF_MODIFIED_SINCE'] - end - end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb deleted file mode 100644 index 1e56d43853..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/content_length.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'rack/utils' - -module Rack - # Sets the Content-Length header on responses with fixed-length bodies. - class ContentLength - include Rack::Utils - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && - !headers['Content-Length'] && - !headers['Transfer-Encoding'] && - (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) - - body = [body] if body.respond_to?(:to_str) # rack 0.4 compat - length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } - headers['Content-Length'] = length.to_s - end - - [status, headers, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb deleted file mode 100644 index 0c1e1ca3e1..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/content_type.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'rack/utils' - -module Rack - - # Sets the Content-Type header on responses which don't have one. - # - # Builder Usage: - # use Rack::ContentType, "text/plain" - # - # When no content type argument is provided, "text/html" is assumed. - class ContentType - def initialize(app, content_type = "text/html") - @app, @content_type = app, content_type - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - headers['Content-Type'] ||= @content_type - [status, headers.to_hash, body] - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb deleted file mode 100644 index 14137a944d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/deflater.rb +++ /dev/null @@ -1,96 +0,0 @@ -require "zlib" -require "stringio" -require "time" # for Time.httpdate -require 'rack/utils' - -module Rack - class Deflater - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - - # Skip compressing empty entity body responses and responses with - # no-transform set. - if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Cache-Control'].to_s =~ /\bno-transform\b/ - return [status, headers, body] - end - - request = Request.new(env) - - encoding = Utils.select_best_encoding(%w(gzip deflate identity), - request.accept_encoding) - - # Set the Vary HTTP header. - vary = headers["Vary"].to_s.split(",").map { |v| v.strip } - unless vary.include?("*") || vary.include?("Accept-Encoding") - headers["Vary"] = vary.push("Accept-Encoding").join(",") - end - - case encoding - when "gzip" - headers['Content-Encoding'] = "gzip" - headers.delete('Content-Length') - mtime = headers.key?("Last-Modified") ? - Time.httpdate(headers["Last-Modified"]) : Time.now - [status, headers, GzipStream.new(body, mtime)] - when "deflate" - headers['Content-Encoding'] = "deflate" - headers.delete('Content-Length') - [status, headers, DeflateStream.new(body)] - when "identity" - [status, headers, body] - when nil - message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." - [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]] - end - end - - class GzipStream - def initialize(body, mtime) - @body = body - @mtime = mtime - end - - def each(&block) - @writer = block - gzip =::Zlib::GzipWriter.new(self) - gzip.mtime = @mtime - @body.each { |part| gzip << part } - @body.close if @body.respond_to?(:close) - gzip.close - @writer = nil - end - - def write(data) - @writer.call(data) - end - end - - class DeflateStream - DEFLATE_ARGS = [ - Zlib::DEFAULT_COMPRESSION, - # drop the zlib header which causes both Safari and IE to choke - -Zlib::MAX_WBITS, - Zlib::DEF_MEM_LEVEL, - Zlib::DEFAULT_STRATEGY - ] - - def initialize(body) - @body = body - end - - def each - deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS) - @body.each { |part| yield deflater.deflate(part) } - @body.close if @body.respond_to?(:close) - yield deflater.finish - nil - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb deleted file mode 100644 index acdd3029d3..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/directory.rb +++ /dev/null @@ -1,153 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::Directory serves entries below the +root+ given, according to the - # path info of the Rack request. If a directory is found, the file's contents - # will be presented in an html based index. If a file is found, the env will - # be passed to the specified +app+. - # - # If +app+ is not specified, a Rack::File of the same +root+ will be used. - - class Directory - DIR_FILE = "%s%s%s%s" - DIR_PAGE = <<-PAGE - - %s - - - -

%s

-
- - - - - - - -%s -
NameSizeTypeLast Modified
-
- - PAGE - - attr_reader :files - attr_accessor :root, :path - - def initialize(root, app=nil) - @root = F.expand_path(root) - @app = app || Rack::File.new(@root) - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @env = env - @script_name = env['SCRIPT_NAME'] - @path_info = Utils.unescape(env['PATH_INFO']) - - if forbidden = check_forbidden - forbidden - else - @path = F.join(@root, @path_info) - list_path - end - end - - def check_forbidden - return unless @path_info.include? ".." - - body = "Forbidden\n" - size = Rack::Utils.bytesize(body) - return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] - end - - def list_directory - @files = [['../','Parent Directory','','','']] - glob = F.join(@path, '*') - - Dir[glob].sort.each do |node| - stat = stat(node) - next unless stat - basename = F.basename(node) - ext = F.extname(node) - - url = F.join(@script_name, @path_info, basename) - size = stat.size - type = stat.directory? ? 'directory' : Mime.mime_type(ext) - size = stat.directory? ? '-' : filesize_format(size) - mtime = stat.mtime.httpdate - url << '/' if stat.directory? - basename << '/' if stat.directory? - - @files << [ url, basename, size, type, mtime ] - end - - return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] - end - - def stat(node, max = 10) - F.stat(node) - rescue Errno::ENOENT, Errno::ELOOP - return nil - end - - # TODO: add correct response if not readable, not sure if 404 is the best - # option - def list_path - @stat = F.stat(@path) - - if @stat.readable? - return @app.call(@env) if @stat.file? - return list_directory if @stat.directory? - else - raise Errno::ENOENT, 'No such file or directory' - end - - rescue Errno::ENOENT, Errno::ELOOP - return entity_not_found - end - - def entity_not_found - body = "Entity not found: #{@path_info}\n" - size = Rack::Utils.bytesize(body) - return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] - end - - def each - show_path = @path.sub(/^#{@root}/,'') - files = @files.map{|f| DIR_FILE % f }*"\n" - page = DIR_PAGE % [ show_path, show_path , files ] - page.each_line{|l| yield l } - end - - # Stolen from Ramaze - - FILESIZE_FORMAT = [ - ['%.1fT', 1 << 40], - ['%.1fG', 1 << 30], - ['%.1fM', 1 << 20], - ['%.1fK', 1 << 10], - ] - - def filesize_format(int) - FILESIZE_FORMAT.each do |format, size| - return format % (int.to_f / size) if int >= size - end - - int.to_s + 'B' - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb deleted file mode 100644 index fe62bd6b86..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/file.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'time' -require 'rack/utils' -require 'rack/mime' - -module Rack - # Rack::File serves files below the +root+ given, according to the - # path info of the Rack request. - # - # Handlers can detect if bodies are a Rack::File, and use mechanisms - # like sendfile on the +path+. - - class File - attr_accessor :root - attr_accessor :path - - alias :to_path :path - - def initialize(root) - @root = root - end - - def call(env) - dup._call(env) - end - - F = ::File - - def _call(env) - @path_info = Utils.unescape(env["PATH_INFO"]) - return forbidden if @path_info.include? ".." - - @path = F.join(@root, @path_info) - - begin - if F.file?(@path) && F.readable?(@path) - serving - else - raise Errno::EPERM - end - rescue SystemCallError - not_found - end - end - - def forbidden - body = "Forbidden\n" - [403, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - # NOTE: - # We check via File::size? whether this file provides size info - # via stat (e.g. /proc files often don't), otherwise we have to - # figure it out by reading the whole file into memory. And while - # we're at it we also use this as body then. - - def serving - if size = F.size?(@path) - body = self - else - body = [F.read(@path)] - size = Utils.bytesize(body.first) - end - - [200, { - "Last-Modified" => F.mtime(@path).httpdate, - "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), - "Content-Length" => size.to_s - }, body] - end - - def not_found - body = "File not found: #{@path_info}\n" - [404, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, - [body]] - end - - def each - F.open(@path, "rb") { |file| - while part = file.read(8192) - yield part - end - } - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb deleted file mode 100644 index 5624a1e79d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler.rb +++ /dev/null @@ -1,69 +0,0 @@ -module Rack - # *Handlers* connect web servers with Rack. - # - # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI - # and LiteSpeed. - # - # Handlers usually are activated by calling MyHandler.run(myapp). - # A second optional hash can be passed to include server-specific - # configuration. - module Handler - def self.get(server) - return unless server - server = server.to_s - - if klass = @handlers[server] - obj = Object - klass.split("::").each { |x| obj = obj.const_get(x) } - obj - else - try_require('rack/handler', server) - const_get(server) - end - end - - # Transforms server-name constants to their canonical form as filenames, - # then tries to require them but silences the LoadError if not found - # - # Naming convention: - # - # Foo # => 'foo' - # FooBar # => 'foo_bar.rb' - # FooBAR # => 'foobar.rb' - # FOObar # => 'foobar.rb' - # FOOBAR # => 'foobar.rb' - # FooBarBaz # => 'foo_bar_baz.rb' - def self.try_require(prefix, const_name) - file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. - gsub(/[A-Z]+[^A-Z]/, '_\&').downcase - - require(::File.join(prefix, file)) - rescue LoadError - end - - def self.register(server, klass) - @handlers ||= {} - @handlers[server] = klass - end - - autoload :CGI, "rack/handler/cgi" - autoload :FastCGI, "rack/handler/fastcgi" - autoload :Mongrel, "rack/handler/mongrel" - autoload :EventedMongrel, "rack/handler/evented_mongrel" - autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel" - autoload :WEBrick, "rack/handler/webrick" - autoload :LSWS, "rack/handler/lsws" - autoload :SCGI, "rack/handler/scgi" - autoload :Thin, "rack/handler/thin" - - register 'cgi', 'Rack::Handler::CGI' - register 'fastcgi', 'Rack::Handler::FastCGI' - register 'mongrel', 'Rack::Handler::Mongrel' - register 'emongrel', 'Rack::Handler::EventedMongrel' - register 'smongrel', 'Rack::Handler::SwiftipliedMongrel' - register 'webrick', 'Rack::Handler::WEBrick' - register 'lsws', 'Rack::Handler::LSWS' - register 'scgi', 'Rack::Handler::SCGI' - register 'thin', 'Rack::Handler::Thin' - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb deleted file mode 100644 index f45f3d735a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/cgi.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'rack/content_length' - -module Rack - module Handler - class CGI - def self.run(app, options=nil) - serve app - end - - def self.serve(app) - app = ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [1,0], - "rack.input" => $stdin, - "rack.errors" => $stderr, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => true, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - - def self.send_headers(status, headers) - STDOUT.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - STDOUT.print "#{k}: #{v}\r\n" - } - } - STDOUT.print "\r\n" - STDOUT.flush - end - - def self.send_body(body) - body.each { |part| - STDOUT.print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb deleted file mode 100644 index 0f5cbf7293..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/evented_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/evented_mongrel' - -module Rack - module Handler - class EventedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb deleted file mode 100644 index 11e1fcaa74..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/fastcgi.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'fcgi' -require 'socket' -require 'rack/content_length' -require 'rack/rewindable_input' - -class FCGI::Stream - alias _rack_read_without_buffer read - - def read(n, buffer=nil) - buf = _rack_read_without_buffer n - buffer.replace(buf.to_s) if buffer - buf - end -end - -module Rack - module Handler - class FastCGI - def self.run(app, options={}) - file = options[:File] and STDIN.reopen(UNIXServer.new(file)) - port = options[:Port] and STDIN.reopen(TCPServer.new(port)) - FCGI.each { |request| - serve request, app - } - end - - def self.serve(request, app) - app = Rack::ContentLength.new(app) - - env = request.env - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - rack_input = RewindableInput.new(request.in) - - env.update({"rack.version" => [1,0], - "rack.input" => rack_input, - "rack.errors" => request.err, - - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" - env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" - - begin - status, headers, body = app.call(env) - begin - send_headers request.out, status, headers - send_body request.out, body - ensure - body.close if body.respond_to? :close - end - ensure - rack_input.close - request.finish - end - end - - def self.send_headers(out, status, headers) - out.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - out.print "#{k}: #{v}\r\n" - } - } - out.print "\r\n" - out.flush - end - - def self.send_body(out, body) - body.each { |part| - out.print part - out.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb deleted file mode 100644 index 7231336d7b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/lsws.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'lsapi' -require 'rack/content_length' - -module Rack - module Handler - class LSWS - def self.run(app, options=nil) - while LSAPI.accept != nil - serve app - end - end - def self.serve(app) - app = Rack::ContentLength.new(app) - - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new($stdin.read.to_s), - "rack.errors" => $stderr, - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - end - def self.send_headers(status, headers) - print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - print "#{k}: #{v}\r\n" - } - } - print "\r\n" - STDOUT.flush - end - def self.send_body(body) - body.each { |part| - print part - STDOUT.flush - } - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb deleted file mode 100644 index 3a5ef32d4b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/mongrel.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'mongrel' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class Mongrel < ::Mongrel::HttpHandler - def self.run(app, options={}) - server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080) - # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of - # { path=>app, ... } or an instance of Rack::URLMap. - if options[:map] - if app.is_a? Hash - app.each do |path, appl| - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - elsif app.is_a? URLMap - app.instance_variable_get(:@mapping).each do |(host, path, appl)| - next if !host.nil? && !options[:Host].nil? && options[:Host] != host - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - else - raise ArgumentError, "first argument should be a Hash or URLMap" - end - else - server.register('/', Rack::Handler::Mongrel.new(app)) - end - yield server if block_given? - server.run.join - end - - def initialize(app) - @app = Rack::Chunked.new(Rack::ContentLength.new(app)) - end - - def process(request, response) - env = {}.replace(request.params) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({"rack.version" => [1,0], - "rack.input" => request.body || StringIO.new(""), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, # ??? - "rack.run_once" => false, - - "rack.url_scheme" => "http", - }) - env["QUERY_STRING"] ||= "" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - - status, headers, body = @app.call(env) - - begin - response.status = status.to_i - response.send_status(nil) - - headers.each { |k, vs| - vs.split("\n").each { |v| - response.header[k] = v - } - } - response.send_header - - body.each { |part| - response.write part - response.socket.flush - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb deleted file mode 100644 index 6c4932df95..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/scgi.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'scgi' -require 'stringio' -require 'rack/content_length' -require 'rack/chunked' - -module Rack - module Handler - class SCGI < ::SCGI::Processor - attr_accessor :app - - def self.run(app, options=nil) - new(options.merge(:app=>app, - :host=>options[:Host], - :port=>options[:Port], - :socket=>options[:Socket])).listen - end - - def initialize(settings = {}) - @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) - @log = Object.new - def @log.info(*args); end - def @log.error(*args); end - super(settings) - end - - def process_request(request, input_body, socket) - env = {}.replace(request) - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["PATH_INFO"] = env["REQUEST_PATH"] - env["QUERY_STRING"] ||= "" - env["SCRIPT_NAME"] = "" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new(input_body), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - status, headers, body = app.call(env) - begin - socket.write("Status: #{status}\r\n") - headers.each do |k, vs| - vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} - end - socket.write("\r\n") - body.each {|s| socket.write(s)} - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb deleted file mode 100644 index 4bafd0b953..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/swiftiplied_mongrel.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'swiftcore/swiftiplied_mongrel' - -module Rack - module Handler - class SwiftipliedMongrel < Handler::Mongrel - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb deleted file mode 100644 index 3d4fedff75..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/thin.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "thin" -require "rack/content_length" -require "rack/chunked" - -module Rack - module Handler - class Thin - def self.run(app, options={}) - app = Rack::Chunked.new(Rack::ContentLength.new(app)) - server = ::Thin::Server.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080, - app) - yield server if block_given? - server.start - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb deleted file mode 100644 index 2bdc83a9ff..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/handler/webrick.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'webrick' -require 'stringio' -require 'rack/content_length' - -module Rack - module Handler - class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet - def self.run(app, options={}) - server = ::WEBrick::HTTPServer.new(options) - server.mount "/", Rack::Handler::WEBrick, app - trap(:INT) { server.shutdown } - yield server if block_given? - server.start - end - - def initialize(server, app) - super server - @app = Rack::ContentLength.new(app) - end - - def service(req, res) - env = req.meta_vars - env.delete_if { |k, v| v.nil? } - - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new(req.body.to_s), - "rack.errors" => $stderr, - - "rack.multithread" => true, - "rack.multiprocess" => false, - "rack.run_once" => false, - - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) - - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["QUERY_STRING"] ||= "" - env["REQUEST_PATH"] ||= "/" - if env["PATH_INFO"] == "" - env.delete "PATH_INFO" - else - path, n = req.request_uri.path, env["SCRIPT_NAME"].length - env["PATH_INFO"] = path[n, path.length-n] - end - - status, headers, body = @app.call(env) - begin - res.status = status.to_i - headers.each { |k, vs| - if k.downcase == "set-cookie" - res.cookies.concat vs.split("\n") - else - vs.split("\n").each { |v| - res[k] = v - } - end - } - body.each { |part| - res.body << part - } - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb deleted file mode 100644 index deab822a99..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/head.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Rack - -class Head - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - - if env["REQUEST_METHOD"] == "HEAD" - [status, headers, []] - else - [status, headers, body] - end - end -end - -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb deleted file mode 100644 index bf2e9787a1..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/lint.rb +++ /dev/null @@ -1,537 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Lint validates your application and the requests and - # responses according to the Rack spec. - - class Lint - def initialize(app) - @app = app - end - - # :stopdoc: - - class LintError < RuntimeError; end - module Assertion - def assert(message, &block) - unless block.call - raise LintError, message - end - end - end - include Assertion - - ## This specification aims to formalize the Rack protocol. You - ## can (and should) use Rack::Lint to enforce it. - ## - ## When you develop middleware, be sure to add a Lint before and - ## after to catch all mistakes. - - ## = Rack applications - - ## A Rack application is an Ruby object (not a class) that - ## responds to +call+. - def call(env=nil) - dup._call(env) - end - - def _call(env) - ## It takes exactly one argument, the *environment* - assert("No env given") { env } - check_env env - - env['rack.input'] = InputWrapper.new(env['rack.input']) - env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) - - ## and returns an Array of exactly three values: - status, headers, @body = @app.call(env) - ## The *status*, - check_status status - ## the *headers*, - check_headers headers - ## and the *body*. - check_content_type status, headers - check_content_length status, headers, env - [status, headers, self] - end - - ## == The Environment - def check_env(env) - ## The environment must be an true instance of Hash (no - ## subclassing allowed) that includes CGI-like headers. - ## The application is free to modify the environment. - assert("env #{env.inspect} is not a Hash, but #{env.class}") { - env.instance_of? Hash - } - - ## - ## The environment is required to include these variables - ## (adopted from PEP333), except when they'd be empty, but see - ## below. - - ## REQUEST_METHOD:: The HTTP request method, such as - ## "GET" or "POST". This cannot ever - ## be an empty string, and so is - ## always required. - - ## SCRIPT_NAME:: The initial portion of the request - ## URL's "path" that corresponds to the - ## application object, so that the - ## application knows its virtual - ## "location". This may be an empty - ## string, if the application corresponds - ## to the "root" of the server. - - ## PATH_INFO:: The remainder of the request URL's - ## "path", designating the virtual - ## "location" of the request's target - ## within the application. This may be an - ## empty string, if the request URL targets - ## the application root and does not have a - ## trailing slash. This value may be - ## percent-encoded when I originating from - ## a URL. - - ## QUERY_STRING:: The portion of the request URL that - ## follows the ?, if any. May be - ## empty, but is always required! - - ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. - - ## HTTP_ Variables:: Variables corresponding to the - ## client-supplied HTTP request - ## headers (i.e., variables whose - ## names begin with HTTP_). The - ## presence or absence of these - ## variables should correspond with - ## the presence or absence of the - ## appropriate HTTP header in the - ## request. - - ## In addition to this, the Rack environment must include these - ## Rack-specific variables: - - ## rack.version:: The Array [1,0], representing this version of Rack. - ## rack.url_scheme:: +http+ or +https+, depending on the request URL. - ## rack.input:: See below, the input stream. - ## rack.errors:: See below, the error stream. - ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. - ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. - ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). - ## - - ## Additional environment specifications have approved to - ## standardized middleware APIs. None of these are required to - ## be implemented by the server. - - ## rack.session:: A hash like interface for storing request session data. - ## The store must implement: - if session = env['rack.session'] - ## store(key, value) (aliased as []=); - assert("session #{session.inspect} must respond to store and []=") { - session.respond_to?(:store) && session.respond_to?(:[]=) - } - - ## fetch(key, default = nil) (aliased as []); - assert("session #{session.inspect} must respond to fetch and []") { - session.respond_to?(:fetch) && session.respond_to?(:[]) - } - - ## delete(key); - assert("session #{session.inspect} must respond to delete") { - session.respond_to?(:delete) - } - - ## clear; - assert("session #{session.inspect} must respond to clear") { - session.respond_to?(:clear) - } - end - - ## The server or the application can store their own data in the - ## environment, too. The keys must contain at least one dot, - ## and should be prefixed uniquely. The prefix rack. - ## is reserved for use with the Rack core distribution and other - ## accepted specifications and must not be used otherwise. - ## - - %w[REQUEST_METHOD SERVER_NAME SERVER_PORT - QUERY_STRING - rack.version rack.input rack.errors - rack.multithread rack.multiprocess rack.run_once].each { |header| - assert("env missing required key #{header}") { env.include? header } - } - - ## The environment must not contain the keys - ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH - ## (use the versions without HTTP_). - %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| - assert("env contains #{header}, must use #{header[5,-1]}") { - not env.include? header - } - } - - ## The CGI keys (named without a period) must have String values. - env.each { |key, value| - next if key.include? "." # Skip extensions - assert("env variable #{key} has non-string value #{value.inspect}") { - value.instance_of? String - } - } - - ## - ## There are the following restrictions: - - ## * rack.version must be an array of Integers. - assert("rack.version must be an Array, was #{env["rack.version"].class}") { - env["rack.version"].instance_of? Array - } - ## * rack.url_scheme must either be +http+ or +https+. - assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { - %w[http https].include? env["rack.url_scheme"] - } - - ## * There must be a valid input stream in rack.input. - check_input env["rack.input"] - ## * There must be a valid error stream in rack.errors. - check_error env["rack.errors"] - - ## * The REQUEST_METHOD must be a valid token. - assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { - env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ - } - - ## * The SCRIPT_NAME, if non-empty, must start with / - assert("SCRIPT_NAME must start with /") { - !env.include?("SCRIPT_NAME") || - env["SCRIPT_NAME"] == "" || - env["SCRIPT_NAME"] =~ /\A\// - } - ## * The PATH_INFO, if non-empty, must start with / - assert("PATH_INFO must start with /") { - !env.include?("PATH_INFO") || - env["PATH_INFO"] == "" || - env["PATH_INFO"] =~ /\A\// - } - ## * The CONTENT_LENGTH, if given, must consist of digits only. - assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { - !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ - } - - ## * One of SCRIPT_NAME or PATH_INFO must be - ## set. PATH_INFO should be / if - ## SCRIPT_NAME is empty. - assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { - env["SCRIPT_NAME"] || env["PATH_INFO"] - } - ## SCRIPT_NAME never should be /, but instead be empty. - assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { - env["SCRIPT_NAME"] != "/" - } - end - - ## === The Input Stream - ## - ## The input stream is an IO-like object which contains the raw HTTP - ## POST data. If it is a file then it must be opened in binary mode. - def check_input(input) - ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. - [:gets, :each, :read, :rewind].each { |method| - assert("rack.input #{input} does not respond to ##{method}") { - input.respond_to? method - } - } - end - - class InputWrapper - include Assertion - - def initialize(input) - @input = input - end - - def size - @input.size - end - - ## * +gets+ must be called without arguments and return a string, - ## or +nil+ on EOF. - def gets(*args) - assert("rack.input#gets called with arguments") { args.size == 0 } - v = @input.gets - assert("rack.input#gets didn't return a String") { - v.nil? or v.instance_of? String - } - v - end - - ## * +read+ behaves like IO#read. Its signature is read([length, [buffer]]). - ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must - ## be a String and may not be nil. If +length+ is given and not nil, then this method - ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil, - ## then this method reads all data until EOF. - ## When EOF is reached, this method returns nil if +length+ is given and not nil, or "" - ## if +length+ is not given or is nil. - ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a - ## newly created String object. - def read(*args) - assert("rack.input#read called with too many arguments") { - args.size <= 2 - } - if args.size >= 1 - assert("rack.input#read called with non-integer and non-nil length") { - args.first.kind_of?(Integer) || args.first.nil? - } - assert("rack.input#read called with a negative length") { - args.first.nil? || args.first >= 0 - } - end - if args.size >= 2 - assert("rack.input#read called with non-String buffer") { - args[1].kind_of?(String) - } - end - - v = @input.read(*args) - - assert("rack.input#read didn't return nil or a String") { - v.nil? or v.instance_of? String - } - if args[0].nil? - assert("rack.input#read(nil) returned nil on EOF") { - !v.nil? - } - end - - v - end - - ## * +each+ must be called without arguments and only yield Strings. - def each(*args) - assert("rack.input#each called with arguments") { args.size == 0 } - @input.each { |line| - assert("rack.input#each didn't yield a String") { - line.instance_of? String - } - yield line - } - end - - ## * +rewind+ must be called without arguments. It rewinds the input - ## stream back to the beginning. It must not raise Errno::ESPIPE: - ## that is, it may not be a pipe or a socket. Therefore, handler - ## developers must buffer the input data into some rewindable object - ## if the underlying input stream is not rewindable. - def rewind(*args) - assert("rack.input#rewind called with arguments") { args.size == 0 } - assert("rack.input#rewind raised Errno::ESPIPE") { - begin - @input.rewind - true - rescue Errno::ESPIPE - false - end - } - end - - ## * +close+ must never be called on the input stream. - def close(*args) - assert("rack.input#close must not be called") { false } - end - end - - ## === The Error Stream - def check_error(error) - ## The error stream must respond to +puts+, +write+ and +flush+. - [:puts, :write, :flush].each { |method| - assert("rack.error #{error} does not respond to ##{method}") { - error.respond_to? method - } - } - end - - class ErrorWrapper - include Assertion - - def initialize(error) - @error = error - end - - ## * +puts+ must be called with a single argument that responds to +to_s+. - def puts(str) - @error.puts str - end - - ## * +write+ must be called with a single argument that is a String. - def write(str) - assert("rack.errors#write not called with a String") { str.instance_of? String } - @error.write str - end - - ## * +flush+ must be called without arguments and must be called - ## in order to make the error appear for sure. - def flush - @error.flush - end - - ## * +close+ must never be called on the error stream. - def close(*args) - assert("rack.errors#close must not be called") { false } - end - end - - ## == The Response - - ## === The Status - def check_status(status) - ## This is an HTTP status. When parsed as integer (+to_i+), it must be - ## greater than or equal to 100. - assert("Status must be >=100 seen as integer") { status.to_i >= 100 } - end - - ## === The Headers - def check_headers(header) - ## The header must respond to +each+, and yield values of key and value. - assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { - header.respond_to? :each - } - header.each { |key, value| - ## The header keys must be Strings. - assert("header key must be a string, was #{key.class}") { - key.instance_of? String - } - ## The header must not contain a +Status+ key, - assert("header must not contain Status") { key.downcase != "status" } - ## contain keys with : or newlines in their name, - assert("header names must not contain : or \\n") { key !~ /[:\n]/ } - ## contain keys names that end in - or _, - assert("header names must not end in - or _") { key !~ /[-_]\z/ } - ## but only contain keys that consist of - ## letters, digits, _ or - and start with a letter. - assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } - - ## The values of the header must be Strings, - assert("a header value must be a String, but the value of " + - "'#{key}' is a #{value.class}") { value.kind_of? String } - ## consisting of lines (for multiple header values, e.g. multiple - ## Set-Cookie values) seperated by "\n". - value.split("\n").each { |item| - ## The lines must not contain characters below 037. - assert("invalid header value #{key}: #{item.inspect}") { - item !~ /[\000-\037]/ - } - } - } - end - - ## === The Content-Type - def check_content_type(status, headers) - headers.each { |key, value| - ## There must be a Content-Type, except when the - ## +Status+ is 1xx, 204 or 304, in which case there must be none - ## given. - if key.downcase == "content-type" - assert("Content-Type header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - return - end - } - assert("No Content-Type header found") { - Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - end - - ## === The Content-Length - def check_content_length(status, headers, env) - headers.each { |key, value| - if key.downcase == 'content-length' - ## There must not be a Content-Length header when the - ## +Status+ is 1xx, 204 or 304. - assert("Content-Length header found in #{status} response, not allowed") { - not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i - } - - bytes = 0 - string_body = true - - if @body.respond_to?(:to_ary) - @body.each { |part| - unless part.kind_of?(String) - string_body = false - break - end - - bytes += Rack::Utils.bytesize(part) - } - - if env["REQUEST_METHOD"] == "HEAD" - assert("Response body was given for HEAD request, but should be empty") { - bytes == 0 - } - else - if string_body - assert("Content-Length header was #{value}, but should be #{bytes}") { - value == bytes.to_s - } - end - end - end - - return - end - } - end - - ## === The Body - def each - @closed = false - ## The Body must respond to +each+ - @body.each { |part| - ## and must only yield String values. - assert("Body yielded non-string value #{part.inspect}") { - part.instance_of? String - } - yield part - } - ## - ## The Body itself should not be an instance of String, as this will - ## break in Ruby 1.9. - ## - ## If the Body responds to +close+, it will be called after iteration. - # XXX howto: assert("Body has not been closed") { @closed } - - - ## - ## If the Body responds to +to_path+, it must return a String - ## identifying the location of a file whose contents are identical - ## to that produced by calling +each+; this may be used by the - ## server as an alternative, possibly more efficient way to - ## transport the response. - - if @body.respond_to?(:to_path) - assert("The file identified by body.to_path does not exist") { - ::File.exist? @body.to_path - } - end - - ## - ## The Body commonly is an Array of Strings, the application - ## instance itself, or a File-like object. - end - - def close - @closed = true - @body.close if @body.respond_to?(:close) - end - - # :startdoc: - - end -end - -## == Thanks -## Some parts of this specification are adopted from PEP333: Python -## Web Server Gateway Interface -## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank -## everyone involved in that effort. diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb deleted file mode 100644 index f63f419a49..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/lobster.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'zlib' - -require 'rack/request' -require 'rack/response' - -module Rack - # Paste has a Pony, Rack has a Lobster! - class Lobster - LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 - P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 - t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ - I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) - - LambdaLobster = lambda { |env| - if env["QUERY_STRING"].include?("flip") - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?" - else - lobster = LobsterString - href = "?flip" - end - - content = ["Lobstericious!", - "
", lobster, "
", - "flip!"] - length = content.inject(0) { |a,e| a+e.size }.to_s - [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] - } - - def call(env) - req = Request.new(env) - if req.GET["flip"] == "left" - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?flip=right" - elsif req.GET["flip"] == "crash" - raise "Lobster crashed" - else - lobster = LobsterString - href = "?flip=left" - end - - res = Response.new - res.write "Lobstericious!" - res.write "
"
-      res.write lobster
-      res.write "
" - res.write "

flip!

" - res.write "

crash!

" - res.finish - end - - end -end - -if $0 == __FILE__ - require 'rack' - require 'rack/showexceptions' - Rack::Handler::WEBrick.run \ - Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), - :Port => 9292 -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb deleted file mode 100644 index 93238528c4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/lock.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Rack - class Lock - FLAG = 'rack.multithread'.freeze - - def initialize(app, lock = Mutex.new) - @app, @lock = app, lock - end - - def call(env) - old, env[FLAG] = env[FLAG], false - @lock.synchronize { @app.call(env) } - ensure - env[FLAG] = old - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb deleted file mode 100644 index 0eed29f471..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/methodoverride.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Rack - class MethodOverride - HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS) - - METHOD_OVERRIDE_PARAM_KEY = "_method".freeze - HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze - - def initialize(app) - @app = app - end - - def call(env) - if env["REQUEST_METHOD"] == "POST" - req = Request.new(env) - method = req.POST[METHOD_OVERRIDE_PARAM_KEY] || - env[HTTP_METHOD_OVERRIDE_HEADER] - method = method.to_s.upcase - if HTTP_METHODS.include?(method) - env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] - env["REQUEST_METHOD"] = method - end - end - - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb deleted file mode 100644 index 5a6a73a97b..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/mime.rb +++ /dev/null @@ -1,204 +0,0 @@ -module Rack - module Mime - # Returns String with mime type if found, otherwise use +fallback+. - # +ext+ should be filename extension in the '.ext' format that - # File.extname(file) returns. - # +fallback+ may be any object - # - # Also see the documentation for MIME_TYPES - # - # Usage: - # Rack::Mime.mime_type('.foo') - # - # This is a shortcut for: - # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') - - def mime_type(ext, fallback='application/octet-stream') - MIME_TYPES.fetch(ext, fallback) - end - module_function :mime_type - - # List of most common mime-types, selected various sources - # according to their usefulness in a webserving scope for Ruby - # users. - # - # To amend this list with your local mime.types list you can use: - # - # require 'webrick/httputils' - # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') - # Rack::Mime::MIME_TYPES.merge!(list) - # - # To add the list mongrel provides, use: - # - # require 'mongrel/handlers' - # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES) - - MIME_TYPES = { - ".3gp" => "video/3gpp", - ".a" => "application/octet-stream", - ".ai" => "application/postscript", - ".aif" => "audio/x-aiff", - ".aiff" => "audio/x-aiff", - ".asc" => "application/pgp-signature", - ".asf" => "video/x-ms-asf", - ".asm" => "text/x-asm", - ".asx" => "video/x-ms-asf", - ".atom" => "application/atom+xml", - ".au" => "audio/basic", - ".avi" => "video/x-msvideo", - ".bat" => "application/x-msdownload", - ".bin" => "application/octet-stream", - ".bmp" => "image/bmp", - ".bz2" => "application/x-bzip2", - ".c" => "text/x-c", - ".cab" => "application/vnd.ms-cab-compressed", - ".cc" => "text/x-c", - ".chm" => "application/vnd.ms-htmlhelp", - ".class" => "application/octet-stream", - ".com" => "application/x-msdownload", - ".conf" => "text/plain", - ".cpp" => "text/x-c", - ".crt" => "application/x-x509-ca-cert", - ".css" => "text/css", - ".csv" => "text/csv", - ".cxx" => "text/x-c", - ".deb" => "application/x-debian-package", - ".der" => "application/x-x509-ca-cert", - ".diff" => "text/x-diff", - ".djv" => "image/vnd.djvu", - ".djvu" => "image/vnd.djvu", - ".dll" => "application/x-msdownload", - ".dmg" => "application/octet-stream", - ".doc" => "application/msword", - ".dot" => "application/msword", - ".dtd" => "application/xml-dtd", - ".dvi" => "application/x-dvi", - ".ear" => "application/java-archive", - ".eml" => "message/rfc822", - ".eps" => "application/postscript", - ".exe" => "application/x-msdownload", - ".f" => "text/x-fortran", - ".f77" => "text/x-fortran", - ".f90" => "text/x-fortran", - ".flv" => "video/x-flv", - ".for" => "text/x-fortran", - ".gem" => "application/octet-stream", - ".gemspec" => "text/x-script.ruby", - ".gif" => "image/gif", - ".gz" => "application/x-gzip", - ".h" => "text/x-c", - ".hh" => "text/x-c", - ".htm" => "text/html", - ".html" => "text/html", - ".ico" => "image/vnd.microsoft.icon", - ".ics" => "text/calendar", - ".ifb" => "text/calendar", - ".iso" => "application/octet-stream", - ".jar" => "application/java-archive", - ".java" => "text/x-java-source", - ".jnlp" => "application/x-java-jnlp-file", - ".jpeg" => "image/jpeg", - ".jpg" => "image/jpeg", - ".js" => "application/javascript", - ".json" => "application/json", - ".log" => "text/plain", - ".m3u" => "audio/x-mpegurl", - ".m4v" => "video/mp4", - ".man" => "text/troff", - ".mathml" => "application/mathml+xml", - ".mbox" => "application/mbox", - ".mdoc" => "text/troff", - ".me" => "text/troff", - ".mid" => "audio/midi", - ".midi" => "audio/midi", - ".mime" => "message/rfc822", - ".mml" => "application/mathml+xml", - ".mng" => "video/x-mng", - ".mov" => "video/quicktime", - ".mp3" => "audio/mpeg", - ".mp4" => "video/mp4", - ".mp4v" => "video/mp4", - ".mpeg" => "video/mpeg", - ".mpg" => "video/mpeg", - ".ms" => "text/troff", - ".msi" => "application/x-msdownload", - ".odp" => "application/vnd.oasis.opendocument.presentation", - ".ods" => "application/vnd.oasis.opendocument.spreadsheet", - ".odt" => "application/vnd.oasis.opendocument.text", - ".ogg" => "application/ogg", - ".p" => "text/x-pascal", - ".pas" => "text/x-pascal", - ".pbm" => "image/x-portable-bitmap", - ".pdf" => "application/pdf", - ".pem" => "application/x-x509-ca-cert", - ".pgm" => "image/x-portable-graymap", - ".pgp" => "application/pgp-encrypted", - ".pkg" => "application/octet-stream", - ".pl" => "text/x-script.perl", - ".pm" => "text/x-script.perl-module", - ".png" => "image/png", - ".pnm" => "image/x-portable-anymap", - ".ppm" => "image/x-portable-pixmap", - ".pps" => "application/vnd.ms-powerpoint", - ".ppt" => "application/vnd.ms-powerpoint", - ".ps" => "application/postscript", - ".psd" => "image/vnd.adobe.photoshop", - ".py" => "text/x-script.python", - ".qt" => "video/quicktime", - ".ra" => "audio/x-pn-realaudio", - ".rake" => "text/x-script.ruby", - ".ram" => "audio/x-pn-realaudio", - ".rar" => "application/x-rar-compressed", - ".rb" => "text/x-script.ruby", - ".rdf" => "application/rdf+xml", - ".roff" => "text/troff", - ".rpm" => "application/x-redhat-package-manager", - ".rss" => "application/rss+xml", - ".rtf" => "application/rtf", - ".ru" => "text/x-script.ruby", - ".s" => "text/x-asm", - ".sgm" => "text/sgml", - ".sgml" => "text/sgml", - ".sh" => "application/x-sh", - ".sig" => "application/pgp-signature", - ".snd" => "audio/basic", - ".so" => "application/octet-stream", - ".svg" => "image/svg+xml", - ".svgz" => "image/svg+xml", - ".swf" => "application/x-shockwave-flash", - ".t" => "text/troff", - ".tar" => "application/x-tar", - ".tbz" => "application/x-bzip-compressed-tar", - ".tcl" => "application/x-tcl", - ".tex" => "application/x-tex", - ".texi" => "application/x-texinfo", - ".texinfo" => "application/x-texinfo", - ".text" => "text/plain", - ".tif" => "image/tiff", - ".tiff" => "image/tiff", - ".torrent" => "application/x-bittorrent", - ".tr" => "text/troff", - ".txt" => "text/plain", - ".vcf" => "text/x-vcard", - ".vcs" => "text/x-vcalendar", - ".vrml" => "model/vrml", - ".war" => "application/java-archive", - ".wav" => "audio/x-wav", - ".wma" => "audio/x-ms-wma", - ".wmv" => "video/x-ms-wmv", - ".wmx" => "video/x-ms-wmx", - ".wrl" => "model/vrml", - ".wsdl" => "application/wsdl+xml", - ".xbm" => "image/x-xbitmap", - ".xhtml" => "application/xhtml+xml", - ".xls" => "application/vnd.ms-excel", - ".xml" => "application/xml", - ".xpm" => "image/x-xpixmap", - ".xsl" => "application/xml", - ".xslt" => "application/xslt+xml", - ".yaml" => "text/yaml", - ".yml" => "text/yaml", - ".zip" => "application/zip", - } - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb deleted file mode 100644 index fdefb0340a..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/mock.rb +++ /dev/null @@ -1,184 +0,0 @@ -require 'uri' -require 'stringio' -require 'rack/lint' -require 'rack/utils' -require 'rack/response' - -module Rack - # Rack::MockRequest helps testing your Rack application without - # actually using HTTP. - # - # After performing a request on a URL with get/post/put/delete, it - # returns a MockResponse with useful helper methods for effective - # testing. - # - # You can pass a hash with additional configuration to the - # get/post/put/delete. - # :input:: A String or IO-like to be used as rack.input. - # :fatal:: Raise a FatalWarning if the app writes to rack.errors. - # :lint:: If true, wrap the application in a Rack::Lint. - - class MockRequest - class FatalWarning < RuntimeError - end - - class FatalWarner - def puts(warning) - raise FatalWarning, warning - end - - def write(warning) - raise FatalWarning, warning - end - - def flush - end - - def string - "" - end - end - - DEFAULT_ENV = { - "rack.version" => [1,0], - "rack.input" => StringIO.new, - "rack.errors" => StringIO.new, - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - } - - def initialize(app) - @app = app - end - - def get(uri, opts={}) request("GET", uri, opts) end - def post(uri, opts={}) request("POST", uri, opts) end - def put(uri, opts={}) request("PUT", uri, opts) end - def delete(uri, opts={}) request("DELETE", uri, opts) end - - def request(method="GET", uri="", opts={}) - env = self.class.env_for(uri, opts.merge(:method => method)) - - if opts[:lint] - app = Rack::Lint.new(@app) - else - app = @app - end - - errors = env["rack.errors"] - MockResponse.new(*(app.call(env) + [errors])) - end - - # Return the Rack environment used for a request to +uri+. - def self.env_for(uri="", opts={}) - uri = URI(uri) - uri.path = "/#{uri.path}" unless uri.path[0] == ?/ - - env = DEFAULT_ENV.dup - - env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" - env["SERVER_NAME"] = uri.host || "example.org" - env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" - env["QUERY_STRING"] = uri.query.to_s - env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path - env["rack.url_scheme"] = uri.scheme || "http" - env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" - - env["SCRIPT_NAME"] = opts[:script_name] || "" - - if opts[:fatal] - env["rack.errors"] = FatalWarner.new - else - env["rack.errors"] = StringIO.new - end - - if params = opts[:params] - if env["REQUEST_METHOD"] == "GET" - params = Utils.parse_nested_query(params) if params.is_a?(String) - params.update(Utils.parse_nested_query(env["QUERY_STRING"])) - env["QUERY_STRING"] = Utils.build_nested_query(params) - elsif !opts.has_key?(:input) - opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - if params.is_a?(Hash) - if data = Utils::Multipart.build_multipart(params) - opts[:input] = data - opts["CONTENT_LENGTH"] ||= data.length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" - else - opts[:input] = Utils.build_nested_query(params) - end - else - opts[:input] = params - end - end - end - - opts[:input] ||= "" - if String === opts[:input] - env["rack.input"] = StringIO.new(opts[:input]) - else - env["rack.input"] = opts[:input] - end - - env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s - - opts.each { |field, value| - env[field] = value if String === field - } - - env - end - end - - # Rack::MockResponse provides useful helpers for testing your apps. - # Usually, you don't create the MockResponse on your own, but use - # MockRequest. - - class MockResponse - def initialize(status, headers, body, errors=StringIO.new("")) - @status = status.to_i - - @original_headers = headers - @headers = Rack::Utils::HeaderHash.new - headers.each { |field, values| - @headers[field] = values - @headers[field] = "" if values.empty? - } - - @body = "" - body.each { |part| @body << part } - - @errors = errors.string if errors.respond_to?(:string) - end - - # Status - attr_reader :status - - # Headers - attr_reader :headers, :original_headers - - def [](field) - headers[field] - end - - - # Body - attr_reader :body - - def =~(other) - @body =~ other - end - - def match(other) - @body.match other - end - - - # Errors - attr_accessor :errors - - - include Response::Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb deleted file mode 100644 index bf8b965925..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/recursive.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'uri' - -module Rack - # Rack::ForwardRequest gets caught by Rack::Recursive and redirects - # the current request to the app at +url+. - # - # raise ForwardRequest.new("/not-found") - # - - class ForwardRequest < Exception - attr_reader :url, :env - - def initialize(url, env={}) - @url = URI(url) - @env = env - - @env["PATH_INFO"] = @url.path - @env["QUERY_STRING"] = @url.query if @url.query - @env["HTTP_HOST"] = @url.host if @url.host - @env["HTTP_PORT"] = @url.port if @url.port - @env["rack.url_scheme"] = @url.scheme if @url.scheme - - super "forwarding to #{url}" - end - end - - # Rack::Recursive allows applications called down the chain to - # include data from other applications (by using - # rack['rack.recursive.include'][...] or raise a - # ForwardRequest to redirect internally. - - class Recursive - def initialize(app) - @app = app - end - - def call(env) - @script_name = env["SCRIPT_NAME"] - @app.call(env.merge('rack.recursive.include' => method(:include))) - rescue ForwardRequest => req - call(env.merge(req.env)) - end - - def include(env, path) - unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || - path[@script_name.size].nil?) - raise ArgumentError, "can only include below #{@script_name}, not #{path}" - end - - env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, - "REQUEST_METHOD" => "GET", - "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", - "rack.input" => StringIO.new("")) - @app.call(env) - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb deleted file mode 100644 index aa2f060be5..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/reloader.rb +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com -# All files in this distribution are subject to the terms of the Ruby license. - -require 'pathname' - -module Rack - - # High performant source reloader - # - # This class acts as Rack middleware. - # - # What makes it especially suited for use in a production environment is that - # any file will only be checked once and there will only be made one system - # call stat(2). - # - # Please note that this will not reload files in the background, it does so - # only when actively called. - # - # It is performing a check/reload cycle at the start of every request, but - # also respects a cool down time, during which nothing will be done. - class Reloader - def initialize(app, cooldown = 10, backend = Stat) - @app = app - @cooldown = cooldown - @last = (Time.now - cooldown) - @cache = {} - @mtimes = {} - - extend backend - end - - def call(env) - if @cooldown and Time.now > @last + @cooldown - if Thread.list.size > 1 - Thread.exclusive{ reload! } - else - reload! - end - - @last = Time.now - end - - @app.call(env) - end - - def reload!(stderr = $stderr) - rotation do |file, mtime| - previous_mtime = @mtimes[file] ||= mtime - safe_load(file, mtime, stderr) if mtime > previous_mtime - end - end - - # A safe Kernel::load, issuing the hooks depending on the results - def safe_load(file, mtime, stderr = $stderr) - load(file) - stderr.puts "#{self.class}: reloaded `#{file}'" - file - rescue LoadError, SyntaxError => ex - stderr.puts ex - ensure - @mtimes[file] = mtime - end - - module Stat - def rotation - files = [$0, *$LOADED_FEATURES].uniq - paths = ['./', *$LOAD_PATH].uniq - - files.map{|file| - next if file =~ /\.(so|bundle)$/ # cannot reload compiled files - - found, stat = figure_path(file, paths) - next unless found and stat and mtime = stat.mtime - - @cache[file] = found - - yield(found, mtime) - }.compact - end - - # Takes a relative or absolute +file+ name, a couple possible +paths+ that - # the +file+ might reside in. Returns the full path and File::Stat for the - # path. - def figure_path(file, paths) - found = @cache[file] - found = file if !found and Pathname.new(file).absolute? - found, stat = safe_stat(found) - return found, stat if found - - paths.each do |possible_path| - path = ::File.join(possible_path, file) - found, stat = safe_stat(path) - return ::File.expand_path(found), stat if found - end - end - - def safe_stat(file) - return unless file - stat = ::File.stat(file) - return file, stat if stat.file? - rescue Errno::ENOENT, Errno::ENOTDIR - @cache.delete(file) and false - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb deleted file mode 100644 index 0bff7af038..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/request.rb +++ /dev/null @@ -1,254 +0,0 @@ -require 'rack/utils' - -module Rack - # Rack::Request provides a convenient interface to a Rack - # environment. It is stateless, the environment +env+ passed to the - # constructor will be directly modified. - # - # req = Rack::Request.new(env) - # req.post? - # req.params["data"] - # - # The environment hash passed will store a reference to the Request object - # instantiated so that it will only instantiate if an instance of the Request - # object doesn't already exist. - - class Request - # The environment of the request. - attr_reader :env - - def self.new(env, *args) - if self == Rack::Request - env["rack.request"] ||= super - else - super - end - end - - def initialize(env) - @env = env - end - - def body; @env["rack.input"] end - def scheme; @env["rack.url_scheme"] end - def script_name; @env["SCRIPT_NAME"].to_s end - def path_info; @env["PATH_INFO"].to_s end - def port; @env["SERVER_PORT"].to_i end - def request_method; @env["REQUEST_METHOD"] end - def query_string; @env["QUERY_STRING"].to_s end - def content_length; @env['CONTENT_LENGTH'] end - def content_type; @env['CONTENT_TYPE'] end - def session; @env['rack.session'] ||= {} end - def session_options; @env['rack.session.options'] ||= {} end - - # The media type (type/subtype) portion of the CONTENT_TYPE header - # without any media type parameters. e.g., when CONTENT_TYPE is - # "text/plain;charset=utf-8", the media-type is "text/plain". - # - # For more information on the use of media types in HTTP, see: - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 - def media_type - content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase - end - - # The media type parameters provided in CONTENT_TYPE as a Hash, or - # an empty Hash if no CONTENT_TYPE or media-type parameters were - # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", - # this method responds with the following Hash: - # { 'charset' => 'utf-8' } - def media_type_params - return {} if content_type.nil? - content_type.split(/\s*[;,]\s*/)[1..-1]. - collect { |s| s.split('=', 2) }. - inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } - end - - # The character set of the request body if a "charset" media type - # parameter was given, or nil if no "charset" was specified. Note - # that, per RFC2616, text/* media types that specify no explicit - # charset are to be considered ISO-8859-1. - def content_charset - media_type_params['charset'] - end - - def host - # Remove port number. - (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') - end - - def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end - def path_info=(s); @env["PATH_INFO"] = s.to_s end - - def get?; request_method == "GET" end - def post?; request_method == "POST" end - def put?; request_method == "PUT" end - def delete?; request_method == "DELETE" end - def head?; request_method == "HEAD" end - - # The set of form-data media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for form-data / param parsing. - FORM_DATA_MEDIA_TYPES = [ - nil, - 'application/x-www-form-urlencoded', - 'multipart/form-data' - ] - - # The set of media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for param parsing like soap attachments or generic multiparts - PARSEABLE_DATA_MEDIA_TYPES = [ - 'multipart/related', - 'multipart/mixed' - ] - - # Determine whether the request body contains form-data by checking - # the request media_type against registered form-data media-types: - # "application/x-www-form-urlencoded" and "multipart/form-data". The - # list of form-data media types can be modified through the - # +FORM_DATA_MEDIA_TYPES+ array. - def form_data? - FORM_DATA_MEDIA_TYPES.include?(media_type) - end - - # Determine whether the request body contains data by checking - # the request media_type against registered parse-data media-types - def parseable_data? - PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) - end - - # Returns the data recieved in the query string. - def GET - if @env["rack.request.query_string"] == query_string - @env["rack.request.query_hash"] - else - @env["rack.request.query_string"] = query_string - @env["rack.request.query_hash"] = - Utils.parse_nested_query(query_string) - end - end - - # Returns the data recieved in the request body. - # - # This method support both application/x-www-form-urlencoded and - # multipart/form-data. - def POST - if @env["rack.request.form_input"].eql? @env["rack.input"] - @env["rack.request.form_hash"] - elsif form_data? || parseable_data? - @env["rack.request.form_input"] = @env["rack.input"] - unless @env["rack.request.form_hash"] = - Utils::Multipart.parse_multipart(env) - form_vars = @env["rack.input"].read - - # Fix for Safari Ajax postings that always append \0 - form_vars.sub!(/\0\z/, '') - - @env["rack.request.form_vars"] = form_vars - @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) - - @env["rack.input"].rewind - end - @env["rack.request.form_hash"] - else - {} - end - end - - # The union of GET and POST data. - def params - self.put? ? self.GET : self.GET.update(self.POST) - rescue EOFError => e - self.GET - end - - # shortcut for request.params[key] - def [](key) - params[key.to_s] - end - - # shortcut for request.params[key] = value - def []=(key, value) - params[key.to_s] = value - end - - # like Hash#values_at - def values_at(*keys) - keys.map{|key| params[key] } - end - - # the referer of the client or '/' - def referer - @env['HTTP_REFERER'] || '/' - end - alias referrer referer - - - def cookies - return {} unless @env["HTTP_COOKIE"] - - if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] - @env["rack.request.cookie_hash"] - else - @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] - # According to RFC 2109: - # If multiple cookies satisfy the criteria above, they are ordered in - # the Cookie header such that those with more specific Path attributes - # precede those with less specific. Ordering with respect to other - # attributes (e.g., Domain) is unspecified. - @env["rack.request.cookie_hash"] = - Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| - h[k] = Array === v ? v.first : v - h - } - end - end - - def xhr? - @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" - end - - # Tries to return a remake of the original request URL as a string. - def url - url = scheme + "://" - url << host - - if scheme == "https" && port != 443 || - scheme == "http" && port != 80 - url << ":#{port}" - end - - url << fullpath - - url - end - - def path - script_name + path_info - end - - def fullpath - query_string.empty? ? path : "#{path}?#{query_string}" - end - - def accept_encoding - @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| - m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick - - if m - [m[1], (m[2] || 1.0).to_f] - else - raise "Invalid value for Accept-Encoding: #{part.inspect}" - end - end - end - - def ip - if addr = @env['HTTP_X_FORWARDED_FOR'] - addr.split(',').last.strip - else - @env['REMOTE_ADDR'] - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb deleted file mode 100644 index 28b4d8302f..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/response.rb +++ /dev/null @@ -1,183 +0,0 @@ -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::Response provides a convenient interface to create a Rack - # response. - # - # It allows setting of headers and cookies, and provides useful - # defaults (a OK response containing HTML). - # - # You can use Response#write to iteratively generate your response, - # but note that this is buffered by Rack::Response until you call - # +finish+. +finish+ however can take a block inside which calls to - # +write+ are syncronous with the Rack response. - # - # Your application's +call+ should end returning Response#finish. - - class Response - attr_accessor :length - - def initialize(body=[], status=200, header={}, &block) - @status = status - @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. - merge(header)) - - @writer = lambda { |x| @body << x } - @block = nil - @length = 0 - - @body = [] - - if body.respond_to? :to_str - write body.to_str - elsif body.respond_to?(:each) - body.each { |part| - write part.to_s - } - else - raise TypeError, "stringable or iterable required" - end - - yield self if block_given? - end - - attr_reader :header - attr_accessor :status, :body - - def [](key) - header[key] - end - - def []=(key, value) - header[key] = value - end - - def set_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Utils.escape(key) + "=" + - value.map { |v| Utils.escape v }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - - case self["Set-Cookie"] - when Array - self["Set-Cookie"] << cookie - when String - self["Set-Cookie"] = [self["Set-Cookie"], cookie] - when nil - self["Set-Cookie"] = cookie - end - end - - def delete_cookie(key, value={}) - unless Array === self["Set-Cookie"] - self["Set-Cookie"] = [self["Set-Cookie"]].compact - end - - self["Set-Cookie"].reject! { |cookie| - cookie =~ /\A#{Utils.escape(key)}=/ - } - - set_cookie(key, - {:value => '', :path => nil, :domain => nil, - :expires => Time.at(0) }.merge(value)) - end - - def redirect(target, status=302) - self.status = status - self["Location"] = target - end - - def finish(&block) - @block = block - - if [204, 304].include?(status.to_i) - header.delete "Content-Type" - [status.to_i, header.to_hash, []] - else - [status.to_i, header.to_hash, self] - end - end - alias to_a finish # For *response - - def each(&callback) - @body.each(&callback) - @writer = callback - @block.call(self) if @block - end - - # Append to body and update Content-Length. - # - # NOTE: Do not mix #write and direct #body access! - # - def write(str) - s = str.to_s - @length += Rack::Utils.bytesize(s) - @writer.call s - - header["Content-Length"] = @length.to_s - str - end - - def close - body.close if body.respond_to?(:close) - end - - def empty? - @block == nil && @body.empty? - end - - alias headers header - - module Helpers - def invalid?; @status < 100 || @status >= 600; end - - def informational?; @status >= 100 && @status < 200; end - def successful?; @status >= 200 && @status < 300; end - def redirection?; @status >= 300 && @status < 400; end - def client_error?; @status >= 400 && @status < 500; end - def server_error?; @status >= 500 && @status < 600; end - - def ok?; @status == 200; end - def forbidden?; @status == 403; end - def not_found?; @status == 404; end - - def redirect?; [301, 302, 303, 307].include? @status; end - def empty?; [201, 204, 304].include? @status; end - - # Headers - attr_reader :headers, :original_headers - - def include?(header) - !!headers[header] - end - - def content_type - headers["Content-Type"] - end - - def content_length - cl = headers["Content-Length"] - cl ? cl.to_i : cl - end - - def location - headers["Location"] - end - end - - include Helpers - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb deleted file mode 100644 index 9e9b21ff99..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/rewindable_input.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'tempfile' - -module Rack - # Class which can make any IO object rewindable, including non-rewindable ones. It does - # this by buffering the data into a tempfile, which is rewindable. - # - # rack.input is required to be rewindable, so if your input stream IO is non-rewindable - # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class - # to easily make it rewindable. - # - # Don't forget to call #close when you're done. This frees up temporary resources that - # RewindableInput uses, though it does *not* close the original IO object. - class RewindableInput - def initialize(io) - @io = io - @rewindable_io = nil - @unlinked = false - end - - def gets - make_rewindable unless @rewindable_io - @rewindable_io.gets - end - - def read(*args) - make_rewindable unless @rewindable_io - @rewindable_io.read(*args) - end - - def each(&block) - make_rewindable unless @rewindable_io - @rewindable_io.each(&block) - end - - def rewind - make_rewindable unless @rewindable_io - @rewindable_io.rewind - end - - # Closes this RewindableInput object without closing the originally - # wrapped IO oject. Cleans up any temporary resources that this RewindableInput - # has created. - # - # This method may be called multiple times. It does nothing on subsequent calls. - def close - if @rewindable_io - if @unlinked - @rewindable_io.close - else - @rewindable_io.close! - end - @rewindable_io = nil - end - end - - private - - # Ruby's Tempfile class has a bug. Subclass it and fix it. - class Tempfile < ::Tempfile - def _close - @tmpfile.close if @tmpfile - @data[1] = nil if @data - @tmpfile = nil - end - end - - def make_rewindable - # Buffer all data into a tempfile. Since this tempfile is private to this - # RewindableInput object, we chmod it so that nobody else can read or write - # it. On POSIX filesystems we also unlink the file so that it doesn't - # even have a file entry on the filesystem anymore, though we can still - # access it because we have the file handle open. - @rewindable_io = Tempfile.new('RackRewindableInput') - @rewindable_io.chmod(0000) - if filesystem_has_posix_semantics? - @rewindable_io.unlink - @unlinked = true - end - - buffer = "" - while @io.read(1024 * 4, buffer) - entire_buffer_written_out = false - while !entire_buffer_written_out - written = @rewindable_io.write(buffer) - entire_buffer_written_out = written == buffer.size - if !entire_buffer_written_out - buffer.slice!(0 .. written - 1) - end - end - end - @rewindable_io.rewind - end - - def filesystem_has_posix_semantics? - RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb deleted file mode 100644 index 218144c17f..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/session/abstract/id.rb +++ /dev/null @@ -1,142 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# bugrep: Andreas Zehnder - -require 'time' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - module Abstract - - # ID sets up a basic framework for implementing an id based sessioning - # service. Cookies sent to the client for maintaining sessions will only - # contain an id reference. Only #get_session and #set_session are - # required to be overwritten. - # - # All parameters are optional. - # * :key determines the name of the cookie, by default it is - # 'rack.session' - # * :path, :domain, :expire_after, :secure, and :httponly set the related - # cookie options as by Rack::Response#add_cookie - # * :defer will not set a cookie in the response. - # * :renew (implementation dependent) will prompt the generation of a new - # session id, and migration of data to be referenced at the new id. If - # :defer is set, it will be overridden and the cookie will be set. - # * :sidbits sets the number of bits in length that a generated session - # id will be. - # - # These options can be set on a per request basis, at the location of - # env['rack.session.options']. Additionally the id of the session can be - # found within the options hash at the key :id. It is highly not - # recommended to change its value. - # - # Is Rack::Utils::Context compatible. - - class ID - DEFAULT_OPTIONS = { - :path => '/', - :domain => nil, - :expire_after => nil, - :secure => false, - :httponly => true, - :defer => false, - :renew => false, - :sidbits => 128 - } - - attr_reader :key, :default_options - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @default_options = self.class::DEFAULT_OPTIONS.merge(options) - end - - def call(env) - context(env) - end - - def context(env, app=@app) - load_session(env) - status, headers, body = app.call(env) - commit_session(env, status, headers, body) - end - - private - - # Generate a new session id using Ruby #rand. The size of the - # session id is controlled by the :sidbits option. - # Monkey patch this to use custom methods for session id generation. - - def generate_sid - "%0#{@default_options[:sidbits] / 4}x" % - rand(2**@default_options[:sidbits] - 1) - end - - # Extracts the session id from provided cookies and passes it and the - # environment to #get_session. It then sets the resulting session into - # 'rack.session', and places options and session metadata into - # 'rack.session.options'. - - def load_session(env) - request = Rack::Request.new(env) - session_id = request.cookies[@key] - - begin - session_id, session = get_session(env, session_id) - env['rack.session'] = session - rescue - env['rack.session'] = Hash.new - end - - env['rack.session.options'] = @default_options. - merge(:id => session_id) - end - - # Acquires the session from the environment and the session id from - # the session options and passes them to #set_session. If successful - # and the :defer option is not true, a cookie will be added to the - # response with the session's id. - - def commit_session(env, status, headers, body) - session = env['rack.session'] - options = env['rack.session.options'] - session_id = options[:id] - - if not session_id = set_session(env, session_id, session, options) - env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") - [status, headers, body] - elsif options[:defer] and not options[:renew] - env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE - [status, headers, body] - else - cookie = Hash.new - cookie[:value] = session_id - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - # All thread safety and session retrival proceedures should occur here. - # Should return [session_id, session]. - # If nil is provided as the session id, generation of a new valid id - # should occur within. - - def get_session(env, sid) - raise '#get_session not implemented.' - end - - # All thread safety and session storage proceedures should occur here. - # Should return true or false dependant on whether or not the session - # was saved or not. - def set_session(env, sid, session, options) - raise '#set_session not implemented.' - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb deleted file mode 100644 index eace9bd0c6..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/session/cookie.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'openssl' -require 'rack/request' -require 'rack/response' - -module Rack - - module Session - - # Rack::Session::Cookie provides simple cookie based session management. - # The session is a Ruby Hash stored as base64 encoded marshalled data - # set to :key (default: rack.session). - # When the secret key is set, cookie data is checked for data integrity. - # - # Example: - # - # use Rack::Session::Cookie, :key => 'rack.session', - # :domain => 'foo.com', - # :path => '/', - # :expire_after => 2592000, - # :secret => 'change_me' - # - # All parameters are optional. - - class Cookie - - def initialize(app, options={}) - @app = app - @key = options[:key] || "rack.session" - @secret = options[:secret] - @default_options = {:domain => nil, - :path => "/", - :expire_after => nil}.merge(options) - end - - def call(env) - load_session(env) - status, headers, body = @app.call(env) - commit_session(env, status, headers, body) - end - - private - - def load_session(env) - request = Rack::Request.new(env) - session_data = request.cookies[@key] - - if @secret && session_data - session_data, digest = session_data.split("--") - session_data = nil unless digest == generate_hmac(session_data) - end - - begin - session_data = session_data.unpack("m*").first - session_data = Marshal.load(session_data) - env["rack.session"] = session_data - rescue - env["rack.session"] = Hash.new - end - - env["rack.session.options"] = @default_options.dup - end - - def commit_session(env, status, headers, body) - session_data = Marshal.dump(env["rack.session"]) - session_data = [session_data].pack("m*") - - if @secret - session_data = "#{session_data}--#{generate_hmac(session_data)}" - end - - if session_data.size > (4096 - @key.size) - env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") - [status, headers, body] - else - options = env["rack.session.options"] - cookie = Hash.new - cookie[:value] = session_data - cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a - end - end - - def generate_hmac(data) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) - end - - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb deleted file mode 100644 index 4a65cbf35d..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/session/memcache.rb +++ /dev/null @@ -1,109 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net - -require 'rack/session/abstract/id' -require 'memcache' - -module Rack - module Session - # Rack::Session::Memcache provides simple cookie based session management. - # Session data is stored in memcached. The corresponding session key is - # maintained in the cookie. - # You may treat Session::Memcache as you would Session::Pool with the - # following caveats. - # - # * Setting :expire_after to 0 would note to the Memcache server to hang - # onto the session data until it would drop it according to it's own - # specifications. However, the cookie sent to the client would expire - # immediately. - # - # Note that memcache does drop data before it may be listed to expire. For - # a full description of behaviour, please see memcache's documentation. - - class Memcache < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \ - :namespace => 'rack:session', - :memcache_server => 'localhost:11211' - - def initialize(app, options={}) - super - - @mutex = Mutex.new - @pool = MemCache. - new @default_options[:memcache_server], @default_options - raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} - end - - def generate_sid - loop do - sid = super - break sid unless @pool.get(sid, true) - end - end - - def get_session(env, sid) - session = @pool.get(sid) if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - ret = @pool.add sid, session - raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return [ nil, {} ] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - expiry = options[:expire_after] - expiry = expiry.nil? ? 0 : expiry + 1 - - @mutex.lock if env['rack.multithread'] - session = @pool.get(session_id) || {} - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.add session_id, 0 # so we don't worry about cache miss on #set - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.set session_id, session, expiry - return session_id - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." - warn $!.inspect - return false - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb deleted file mode 100644 index f6f87408bb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/session/pool.rb +++ /dev/null @@ -1,100 +0,0 @@ -# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net -# THANKS: -# apeiros, for session id generation, expiry setup, and threadiness -# sergio, threadiness and bugreps - -require 'rack/session/abstract/id' -require 'thread' - -module Rack - module Session - # Rack::Session::Pool provides simple cookie based session management. - # Session data is stored in a hash held by @pool. - # In the context of a multithreaded environment, sessions being - # committed to the pool is done in a merging manner. - # - # The :drop option is available in rack.session.options if you with to - # explicitly remove the session from the session cache. - # - # Example: - # myapp = MyRackApp.new - # sessioned = Rack::Session::Pool.new(myapp, - # :domain => 'foo.com', - # :expire_after => 2592000 - # ) - # Rack::Handler::WEBrick.run sessioned - - class Pool < Abstract::ID - attr_reader :mutex, :pool - DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false - - def initialize(app, options={}) - super - @pool = Hash.new - @mutex = Mutex.new - end - - def generate_sid - loop do - sid = super - break sid unless @pool.key? sid - end - end - - def get_session(env, sid) - session = @pool[sid] if sid - @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - @pool.store sid, session - end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - ensure - @mutex.unlock if env['rack.multithread'] - end - - def set_session(env, session_id, new_session, options) - @mutex.lock if env['rack.multithread'] - session = @pool[session_id] - if options[:renew] or options[:drop] - @pool.delete session_id - return false if options[:drop] - session_id = generate_sid - @pool.store session_id, 0 - end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session - @pool.store session_id, session - return session_id - rescue - warn "#{new_session.inspect} has been lost." - warn $!.inspect - ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur - end - end - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb deleted file mode 100644 index 697bc41fdb..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/showexceptions.rb +++ /dev/null @@ -1,349 +0,0 @@ -require 'ostruct' -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowExceptions catches all exceptions raised from the app it - # wraps. It shows a useful backtrace with the sourcefile and - # clickable context, the whole Rack environment and the request - # data. - # - # Be careful when you use this on public-facing sites as it could - # reveal information helpful to attackers. - - class ShowExceptions - CONTEXT = 7 - - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - @app.call(env) - rescue StandardError, LoadError, SyntaxError => e - backtrace = pretty(env, e) - [500, - {"Content-Type" => "text/html", - "Content-Length" => backtrace.join.size.to_s}, - backtrace] - end - - def pretty(env, exception) - req = Rack::Request.new(env) - path = (req.script_name + req.path_info).squeeze("/") - - frames = exception.backtrace.map { |line| - frame = OpenStruct.new - if line =~ /(.*?):(\d+)(:in `(.*)')?/ - frame.filename = $1 - frame.lineno = $2.to_i - frame.function = $4 - - begin - lineno = frame.lineno-1 - lines = ::File.readlines(frame.filename) - frame.pre_context_lineno = [lineno-CONTEXT, 0].max - frame.pre_context = lines[frame.pre_context_lineno...lineno] - frame.context_line = lines[lineno].chomp - frame.post_context_lineno = [lineno+CONTEXT, lines.size].min - frame.post_context = lines[lineno+1..frame.post_context_lineno] - rescue - end - - frame - else - nil - end - }.compact - - env["rack.errors"].puts "#{exception.class}: #{exception.message}" - env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } - env["rack.errors"].flush - - [@template.result(binding)] - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - - <%=h exception.class %> at <%=h path %> - - - - - -
-

<%=h exception.class %> at <%=h path %>

-

<%=h exception.message %>

- - - - - - -
Ruby<%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web<%=h req.request_method %> <%=h(req.host + path)%>
- -

Jump to:

- -
- -
-

Traceback (innermost first)

-
    -<% frames.each { |frame| %> -
  • - <%=h frame.filename %>: in <%=h frame.function %> - - <% if frame.context_line %> -
    - <% if frame.pre_context %> -
      - <% frame.pre_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> - -
      -
    1. <%=h frame.context_line %>...
    - - <% if frame.post_context %> -
      - <% frame.post_context.each { |line| %> -
    1. <%=h line %>
    2. - <% } %> -
    - <% end %> -
    - <% end %> -
  • -<% } %> -
-
- -
-

Request information

- -

GET

- <% unless req.GET.empty? %> - - - - - - - - - <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No GET data.

- <% end %> - -

POST

- <% unless req.POST.empty? %> - - - - - - - - - <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No POST data.

- <% end %> - - - - <% unless req.cookies.empty? %> - - - - - - - - - <% req.cookies.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val.inspect %>
- <% else %> -

No cookie data.

- <% end %> - -

Rack ENV

- - - - - - - - - <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> - - - - - <% } %> - -
VariableValue
<%=h key %>
<%=h val %>
- -
- -
-

- You're seeing this error because you use Rack::ShowExceptions. -

-
- - - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb deleted file mode 100644 index 28258c7c89..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/showstatus.rb +++ /dev/null @@ -1,106 +0,0 @@ -require 'erb' -require 'rack/request' -require 'rack/utils' - -module Rack - # Rack::ShowStatus catches all empty responses the app it wraps and - # replaces them with a site explaining the error. - # - # Additional details can be put into rack.showstatus.detail - # and will be shown as HTML. If such details exist, the error page - # is always rendered, even if the reply was not empty. - - class ShowStatus - def initialize(app) - @app = app - @template = ERB.new(TEMPLATE) - end - - def call(env) - status, headers, body = @app.call(env) - headers = Utils::HeaderHash.new(headers) - empty = headers['Content-Length'].to_i <= 0 - - # client or server error, or explicit message - if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] - req = Rack::Request.new(env) - message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s - detail = env["rack.showstatus.detail"] || message - body = @template.result(binding) - size = Rack::Utils.bytesize(body) - [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] - else - [status, headers, body] - end - end - - def h(obj) # :nodoc: - case obj - when String - Utils.escape_html(obj) - else - Utils.escape_html(obj.inspect) - end - end - - # :stopdoc: - -# adapted from Django -# Copyright (c) 2005, the Lawrence Journal-World -# Used under the modified BSD license: -# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -TEMPLATE = <<'HTML' - - - - - <%=h message %> at <%=h req.script_name + req.path_info %> - - - - -
-

<%=h message %> (<%= status.to_i %>)

- - - - - - - - - -
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
-
-
-

<%= detail %>

-
- -
-

- You're seeing this error because you use Rack::ShowStatus. -

-
- - -HTML - - # :startdoc: - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb deleted file mode 100644 index 168e8f83b2..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/static.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Rack - - # The Rack::Static middleware intercepts requests for static files - # (javascript files, images, stylesheets, etc) based on the url prefixes - # passed in the options, and serves them using a Rack::File object. This - # allows a Rack stack to serve both static and dynamic content. - # - # Examples: - # use Rack::Static, :urls => ["/media"] - # will serve all requests beginning with /media from the "media" folder - # located in the current directory (ie media/*). - # - # use Rack::Static, :urls => ["/css", "/images"], :root => "public" - # will serve all requests beginning with /css or /images from the folder - # "public" in the current directory (ie public/css/* and public/images/*) - - class Static - - def initialize(app, options={}) - @app = app - @urls = options[:urls] || ["/favicon.ico"] - root = options[:root] || Dir.pwd - @file_server = Rack::File.new(root) - end - - def call(env) - path = env["PATH_INFO"] - can_serve = @urls.any? { |url| path.index(url) == 0 } - - if can_serve - @file_server.call(env) - else - @app.call(env) - end - end - - end -end diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb deleted file mode 100644 index fcf6616c58..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/urlmap.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Rack - # Rack::URLMap takes a hash mapping urls or paths to apps, and - # dispatches accordingly. Support for HTTP/1.1 host names exists if - # the URLs start with http:// or https://. - # - # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part - # relevant for dispatch is in the SCRIPT_NAME, and the rest in the - # PATH_INFO. This should be taken care of when you need to - # reconstruct the URL in order to create links. - # - # URLMap dispatches in such a way that the longest paths are tried - # first, since they are most specific. - - class URLMap - def initialize(map = {}) - remap(map) - end - - def remap(map) - @mapping = map.map { |location, app| - if location =~ %r{\Ahttps?://(.*?)(/.*)} - host, location = $1, $2 - else - host = nil - end - - unless location[0] == ?/ - raise ArgumentError, "paths need to start with /" - end - location = location.chomp('/') - - [host, location, app] - }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first - end - - def call(env) - path = env["PATH_INFO"].to_s.squeeze("/") - script_name = env['SCRIPT_NAME'] - hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') - @mapping.each { |host, location, app| - next unless (hHost == host || sName == host \ - || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) - next unless location == path[0, location.size] - next unless path[location.size] == nil || path[location.size] == ?/ - - return app.call( - env.merge( - 'SCRIPT_NAME' => (script_name + location), - 'PATH_INFO' => path[location.size..-1])) - } - [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] - end - end -end - diff --git a/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb deleted file mode 100644 index 42e2e698f4..0000000000 --- a/actionpack/lib/action_dispatch/vendor/rack/rack/utils.rb +++ /dev/null @@ -1,516 +0,0 @@ -# -*- encoding: binary -*- - -require 'set' -require 'tempfile' - -module Rack - # Rack::Utils contains a grab-bag of useful methods for writing web - # applications adopted from all kinds of Ruby libraries. - - module Utils - # Performs URI escaping so that you can construct proper - # query strings faster. Use this rather than the cgi.rb - # version since it's faster. (Stolen from Camping). - def escape(s) - s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { - '%'+$1.unpack('H2'*$1.size).join('%').upcase - }.tr(' ', '+') - end - module_function :escape - - # Unescapes a URI escaped string. (Stolen from Camping). - def unescape(s) - s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ - [$1.delete('%')].pack('H*') - } - end - module_function :unescape - - # Stolen from Mongrel, with some small modifications: - # Parses a query string by breaking it up at the '&' - # and ';' characters. You can also use this to parse - # cookies by changing the characters used in the second - # parameter (which defaults to '&;'). - def parse_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - - if cur = params[k] - if cur.class == Array - params[k] << v - else - params[k] = [cur, v] - end - else - params[k] = v - end - end - - return params - end - module_function :parse_query - - def parse_nested_query(qs, d = '&;') - params = {} - - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) - normalize_params(params, k, v) - end - - return params - end - module_function :parse_nested_query - - def normalize_params(params, name, v = nil) - name =~ %r(\A[\[\]]*([^\[\]]+)\]*) - k = $1 || '' - after = $' || '' - - return if k.empty? - - if after == "" - params[k] = v - elsif after == "[]" - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - params[k] << v - elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) - child_key = $1 - params[k] ||= [] - raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) - normalize_params(params[k].last, child_key, v) - else - params[k] << normalize_params({}, child_key, v) - end - else - params[k] ||= {} - raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) - params[k] = normalize_params(params[k], after, v) - end - - return params - end - module_function :normalize_params - - def build_query(params) - params.map { |k, v| - if v.class == Array - build_query(v.map { |x| [k, x] }) - else - escape(k) + "=" + escape(v) - end - }.join("&") - end - module_function :build_query - - def build_nested_query(value, prefix = nil) - case value - when Array - value.map { |v| - build_nested_query(v, "#{prefix}[]") - }.join("&") - when Hash - value.map { |k, v| - build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) - }.join("&") - when String - raise ArgumentError, "value must be a Hash" if prefix.nil? - "#{prefix}=#{escape(value)}" - else - prefix - end - end - module_function :build_nested_query - - # Escape ampersands, brackets and quotes to their HTML/XML entities. - def escape_html(string) - string.to_s.gsub("&", "&"). - gsub("<", "<"). - gsub(">", ">"). - gsub("'", "'"). - gsub('"', """) - end - module_function :escape_html - - def select_best_encoding(available_encodings, accept_encoding) - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - - expanded_accept_encoding = - accept_encoding.map { |m, q| - if m == "*" - (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } - else - [[m, q]] - end - }.inject([]) { |mem, list| - mem + list - } - - encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } - - unless encoding_candidates.include?("identity") - encoding_candidates.push("identity") - end - - expanded_accept_encoding.find_all { |m, q| - q == 0.0 - }.each { |m, _| - encoding_candidates.delete(m) - } - - return (encoding_candidates & available_encodings)[0] - end - module_function :select_best_encoding - - # Return the bytesize of String; uses String#length under Ruby 1.8 and - # String#bytesize under 1.9. - if ''.respond_to?(:bytesize) - def bytesize(string) - string.bytesize - end - else - def bytesize(string) - string.size - end - end - module_function :bytesize - - # Context allows the use of a compatible middleware at different points - # in a request handling stack. A compatible middleware must define - # #context which should take the arguments env and app. The first of which - # would be the request environment. The second of which would be the rack - # application that the request would be forwarded to. - class Context - attr_reader :for, :app - - def initialize(app_f, app_r) - raise 'running context does not respond to #context' unless app_f.respond_to? :context - @for, @app = app_f, app_r - end - - def call(env) - @for.context(env, @app) - end - - def recontext(app) - self.class.new(@for, app) - end - - def context(env, app=@app) - recontext(app).call(env) - end - end - - # A case-insensitive Hash that preserves the original case of a - # header when set. - class HeaderHash < Hash - def initialize(hash={}) - @names = {} - hash.each { |k, v| self[k] = v } - end - - def to_hash - inject({}) do |hash, (k,v)| - if v.respond_to? :to_ary - hash[k] = v.to_ary.join("\n") - else - hash[k] = v - end - hash - end - end - - def [](k) - super @names[k.downcase] - end - - def []=(k, v) - delete k - @names[k.downcase] = k - super k, v - end - - def delete(k) - super @names.delete(k.downcase) - end - - def include?(k) - @names.has_key? k.downcase - end - - alias_method :has_key?, :include? - alias_method :member?, :include? - alias_method :key?, :include? - - def merge!(other) - other.each { |k, v| self[k] = v } - self - end - - def merge(other) - hash = dup - hash.merge! other - end - end - - # Every standard HTTP code mapped to the appropriate message. - # Stolen from Mongrel. - HTTP_STATUS_CODES = { - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' - } - - # Responses with HTTP status codes that should not have an entity body - STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) - - # A multipart form data parser, adapted from IOWA. - # - # Usually, Rack::Request#POST takes care of calling this. - - module Multipart - 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 - - EOL = "\r\n" - MULTIPART_BOUNDARY = "AaB03x" - - def self.parse_multipart(env) - unless env['CONTENT_TYPE'] =~ - %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n - nil - else - boundary = "--#{$1}" - - params = {} - buf = "" - content_length = env['CONTENT_LENGTH'].to_i - input = env['rack.input'] - input.rewind - - boundary_size = Utils.bytesize(boundary) + EOL.size - bufsize = 16384 - - content_length -= boundary_size - - read_buffer = '' - - status = input.read(boundary_size, read_buffer) - raise EOFError, "bad content body" unless status == boundary + EOL - - rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n - - loop { - head = nil - body = '' - filename = content_type = name = nil - - until head && buf =~ rx - if !head && i = buf.index(EOL+EOL) - head = buf.slice!(0, i+2) # First \r\n - buf.slice!(0, 2) # Second \r\n - - filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] - content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] - name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] - - if content_type || filename - body = Tempfile.new("RackMultipart") - body.binmode if body.respond_to?(:binmode) - end - - next - end - - # Save the read body part. - if head && (boundary_size+4 < buf.size) - body << buf.slice!(0, buf.size - (boundary_size+4)) - end - - c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) - raise EOFError, "bad content body" if c.nil? || c.empty? - buf << c - content_length -= c.size - end - - # Save the rest. - if i = buf.index(rx) - body << buf.slice!(0, i) - buf.slice!(0, boundary_size+2) - - content_length = -1 if $1 == "--" - end - - if filename == "" - # filename is blank which means no file has been selected - data = nil - elsif filename - body.rewind - - # Take the basename of the upload's original filename. - # This handles the full Windows paths given by Internet Explorer - # (and perhaps other broken user agents) without affecting - # those which give the lone filename. - filename =~ /^(?:.*[:\\\/])?(.*)/m - filename = $1 - - data = {:filename => filename, :type => content_type, - :name => name, :tempfile => body, :head => head} - elsif !filename && content_type - body.rewind - - # Generic multipart cases, not coming from a form - data = {:type => content_type, - :name => name, :tempfile => body, :head => head} - else - data = body - end - - Utils.normalize_params(params, name, data) unless data.nil? - - break if buf.empty? || content_length == -1 - } - - input.rewind - - params - end - end - - def self.build_multipart(params, first = true) - if first - unless params.is_a?(Hash) - raise ArgumentError, "value must be a Hash" - end - - multipart = false - query = lambda { |value| - case value - when Array - value.each(&query) - when Hash - value.values.each(&query) - when UploadedFile - multipart = true - end - } - params.values.each(&query) - return nil unless multipart - end - - flattened_params = Hash.new - - params.each do |key, value| - k = first ? key.to_s : "[#{key}]" - - case value - when Array - value.map { |v| - build_multipart(v, false).each { |subkey, subvalue| - flattened_params["#{k}[]#{subkey}"] = subvalue - } - } - when Hash - build_multipart(value, false).each { |subkey, subvalue| - flattened_params[k + subkey] = subvalue - } - else - flattened_params[k] = value - end - end - - if first - flattened_params.map { |name, file| - if file.respond_to?(:original_filename) - ::File.open(file.path, "rb") do |f| - f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r -Content-Type: #{file.content_type}\r -Content-Length: #{::File.stat(file.path).size}\r -\r -#{f.read}\r -EOF - end - else -<<-EOF ---#{MULTIPART_BOUNDARY}\r -Content-Disposition: form-data; name="#{name}"\r -\r -#{file}\r -EOF - end - }.join + "--#{MULTIPART_BOUNDARY}--\r" - else - flattened_params - end - end - end - end -end -- cgit v1.2.3 From 3be3470fab788856b4559742434f195cc6b1009a Mon Sep 17 00:00:00 2001 From: Ruy Asan Date: Fri, 1 May 2009 13:49:18 -0700 Subject: Added routing test for irregular ID requirements and custom member action. [#2595 state:committed] Signed-off-by: Jeremy Kemper --- actionpack/test/controller/resources_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index c807e71cd7..30ab110ef7 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -120,6 +120,14 @@ class ResourcesTest < ActionController::TestCase end end + def test_irregular_id_requirements_should_get_passed_to_member_actions + expected_options = {:controller => 'messages', :action => 'custom', :id => '1.1.1'} + + with_restful_routing(:messages, :member => {:custom => :get}, :requirements => {:id => /[0-9]\.[0-9]\.[0-9]/}) do + assert_recognizes(expected_options, :path => 'messages/1.1.1/custom', :method => :get) + end + end + def test_with_path_prefix with_restful_routing :messages, :path_prefix => '/thread/:thread_id' do assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } -- cgit v1.2.3 From 8a4e77b4200946ba4ed42fe5927a7400a846063a Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 27 Apr 2009 18:21:26 -0700 Subject: OMG, a lot of work --- actionpack/Rakefile | 11 +- .../lib/action_controller/abstract/layouts.rb | 5 +- .../lib/action_controller/abstract/renderer.rb | 2 + .../lib/action_controller/dispatch/dispatcher.rb | 2 +- .../lib/action_controller/dispatch/middlewares.rb | 2 +- actionpack/lib/action_controller/new_base.rb | 11 +- actionpack/lib/action_controller/new_base/base.rb | 2 + .../action_controller/new_base/compatibility.rb | 12 +++ .../abstract_controller_test.rb | 22 ++-- .../test/abstract_controller/layouts_test.rb | 2 +- actionpack/test/controller/render_test.rb | 3 + actionpack/test/lib/fixture_template.rb | 115 ++++++++++++++++----- actionpack/test/new_base/base_test.rb | 8 +- actionpack/test/new_base/render_action_test.rb | 8 +- .../test/new_base/render_implicit_action_test.rb | 30 ++++-- actionpack/test/new_base/render_layout_test.rb | 4 +- actionpack/test/new_base/render_template_test.rb | 39 ++++--- actionpack/test/new_base/render_text_test.rb | 4 +- actionpack/test/new_base/test_helper.rb | 14 ++- 19 files changed, 210 insertions(+), 86 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/compatibility.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 300c2ebf81..18610ed773 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -23,14 +23,14 @@ task :default => [ :test ] # Run the unit tests desc "Run all unit tests" -task :test => [:test_action_pack, :test_active_record_integration] +task :test => [:test_action_pack, :test_active_record_integration, :test_new_base] Rake::TestTask.new(:test_action_pack) do |t| t.libs << "test" # 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/[cdft]*/**/*_test.rb" ).sort + t.test_files = Dir.glob( "test/{controller,dispatch,template}/**/*_test.rb" ).sort t.verbose = true #t.warning = true @@ -43,6 +43,13 @@ Rake::TestTask.new(:test_active_record_integration) do |t| t.verbose = true end +desc 'New Controller Tests' +Rake::TestTask.new(:test_new_base) do |t| + t.libs << "test" + t.test_files = Dir.glob("test/{abstract_controller,new_base}/*_test.rb") + t.verbose = true +end + # Genereate the RDoc documentation diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 0039e67c5a..315d6151e9 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -50,6 +50,7 @@ module AbstractController end def _render_template(template, options) + # layout = options[:_layout].is_a?(ActionView::Template) ? options[:_layout] : _layout_for_name(options[:_layout]) _action_view._render_template_with_layout(template, options[:_layout]) end @@ -67,10 +68,10 @@ module AbstractController def _default_layout(require_layout = false) if require_layout && !_layout - raise ArgumentError, + raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" end - + begin layout = _layout_for_name(_layout) rescue NameError => e diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index e31accbbfc..37da2398ec 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -27,9 +27,11 @@ module AbstractController # # :api: plugin def render_to_body(options = {}) + options = {:_template_name => options} if options.is_a?(String) name = options[:_template_name] || action_name template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) + _render_template(template, options) end diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index bb9d8bd063..af2da8bfe5 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -79,7 +79,7 @@ module ActionController run_callbacks :before_dispatch Routing::Routes.call(env) rescue Exception => exception - if controller ||= (::ApplicationController rescue Base) + if !env["rack.test"] && controller ||= (::ApplicationController rescue Base) controller.call_with_exception(env, exception).to_a else raise exception diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index b5adbae746..d87c0f9706 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -9,4 +9,4 @@ use lambda { ActionController::Base.session_store }, use "ActionDispatch::ParamsParser" use "Rack::MethodOverride" -use "Rack::Head" +use "Rack::Head" \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 7c65f1cdc1..51d9c05a1a 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,7 +1,8 @@ module ActionController - autoload :AbstractBase, "action_controller/new_base/base" - autoload :HideActions, "action_controller/new_base/hide_actions" - autoload :Layouts, "action_controller/new_base/layouts" - autoload :Renderer, "action_controller/new_base/renderer" - autoload :UrlFor, "action_controller/new_base/url_for" + autoload :AbstractBase, "action_controller/new_base/base" + autoload :HideActions, "action_controller/new_base/hide_actions" + autoload :Layouts, "action_controller/new_base/layouts" + autoload :Rails2Compatibility, "action_controller/new_base/compatibility" + autoload :Renderer, "action_controller/new_base/renderer" + autoload :UrlFor, "action_controller/new_base/url_for" end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 08e7a1a0e7..75fe012aed 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -50,6 +50,8 @@ module ActionController @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new process(@_request.parameters[:action]) + @_response.prepare! + self end # :api: private diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb new file mode 100644 index 0000000000..8682493c8e --- /dev/null +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -0,0 +1,12 @@ +module ActionController + module Rails2Compatibility + + def render_to_body(options) + if options.is_a?(Hash) && options.key?(:template) + options[:template].sub!(/^\//, '') + end + super + end + + end +end \ No newline at end of file diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index 331797afcf..cf6fb5140d 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -58,11 +58,11 @@ module AbstractController end def rendering_to_body - render_to_body "naked_render.erb" + self.response_body = render_to_body :_template_name => "naked_render.erb" end def rendering_to_string - render_to_string "naked_render.erb" + self.response_body = render_to_string :_template_name => "naked_render.erb" end end @@ -136,6 +136,11 @@ module AbstractController class WithLayouts < PrefixedViews use Layouts + def self.inherited(klass) + klass._write_layout_method + super + end + private def self.layout(formats) begin @@ -147,13 +152,9 @@ module AbstractController end end end - - def _layout - self.class.layout(formats) - end - + def render_to_body(options = {}) - options[:_layout] = options[:layout] || _layout + options[:_layout] = options[:layout] || _default_layout super end end @@ -175,11 +176,6 @@ module AbstractController result = Me4.process(:index) assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", result.response_obj[:body] end - - test "it can fall back to the application layout" do - result = Me5.process(:index) - assert_equal "Application Enter : Hello from me5/index.erb : Exit", result.response_obj[:body] - end end # respond_to_action?(action_name) diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb index 3d4570bfef..078e0037a8 100644 --- a/actionpack/test/abstract_controller/layouts_test.rb +++ b/actionpack/test/abstract_controller/layouts_test.rb @@ -8,7 +8,7 @@ module AbstractControllerTests use AbstractController::Renderer use AbstractController::Layouts - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "layouts/hello.erb" => "With String <%= yield %>", "layouts/hello_override.erb" => "With Override <%= yield %>", "layouts/abstract_controller_tests/layouts/with_string_implied_child.erb" => diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 023bf0eeaa..a97e8ac5c1 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -755,6 +755,7 @@ class RenderTest < ActionController::TestCase @request.host = "www.nextangle.com" end + # :ported: def test_simple_show get :hello_world assert_response 200 @@ -763,11 +764,13 @@ class RenderTest < ActionController::TestCase assert_equal "Hello world!", @response.body end + # :ported: def test_renders_default_template_for_missing_action get :'hyphen-ated' assert_template 'test/hyphen-ated' end + # :ported: def test_render get :render_hello_world assert_template "test/hello_world" diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb index 26f6ec2d0c..e43e329a9e 100644 --- a/actionpack/test/lib/fixture_template.rb +++ b/actionpack/test/lib/fixture_template.rb @@ -1,35 +1,104 @@ module ActionView #:nodoc: - class FixtureTemplate < Template - class FixturePath < Template::Path - def initialize(hash = {}) - @hash = {} - - hash.each do |k, v| - @hash[k.sub(/\.\w+$/, '')] = FixtureTemplate.new(v, k.split("/").last, self) +class Template + class FixturePath < Path + def initialize(hash = {}, options = {}) + super(options) + @hash = hash + end + + def find_templates(name, details, prefix, partial) + if regexp = details_to_regexp(name, details, prefix, partial) + cached(regexp) do + templates = [] + @hash.select { |k,v| k =~ regexp }.each do |path, source| + templates << Template.new(source, path, *path_to_details(path)) + end + templates end - - super("fixtures://root") - end - - def find_template(path) - @hash[path] end end - def initialize(body, *args) - @body = body - super(*args) + private + + def formats_regexp + @formats_regexp ||= begin + formats = Mime::SET.map { |m| m.symbol } + '(?:' + formats.map { |l| "\\.#{Regexp.escape(l.to_s)}" }.join('|') + ')?' + end end - def source - @body + def handler_regexp + e = TemplateHandlers.extensions.map{|h| "\\.#{Regexp.escape(h.to_s)}"}.join("|") + "(?:#{e})?" end - private - - def find_full_path(path, load_paths) - return '/', path + def details_to_regexp(name, details, prefix, partial) + path = "" + path << "#{prefix}/" unless prefix.empty? + path << (partial ? "_#{name}" : name) + + extensions = "" + [:locales, :formats].each do |k| + extensions << if exts = details[k] + '(?:' + exts.map {|e| "\\.#{Regexp.escape(e.to_s)}"}.join('|') + ')?' + else + k == :formats ? formats_regexp : '' + end + end + + %r'#{Regexp.escape(path)}#{extensions}#{handler_regexp}' + end + + # TODO: fix me + # :api: plugin + def path_to_details(path) + # [:erb, :format => :html, :locale => :en, :partial => true/false] + if m = path.match(%r'(_)?[\w-]+(\.[\w-]+)*\.(\w+)$') + partial = m[1] == '_' + details = (m[2]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[3]) + + format = Mime[details.last] && details.pop.to_sym + locale = details.last && details.pop.to_sym + + return handler, :format => format, :locale => locale, :partial => partial + end end - end + + + # class FixtureTemplate < Template + # class FixturePath < Template::Path + # def initialize(hash = {}) + # @hash = {} + # + # hash.each do |k, v| + # @hash[k.sub(/\.\w+$/, '')] = FixtureTemplate.new(v, k.split("/").last, self) + # end + # + # super("fixtures://root") + # end + # + # def find_template(path) + # @hash[path] + # end + # end + # + # def initialize(body, *args) + # @body = body + # super(*args) + # end + # + # def source + # @body + # end + # + # private + # + # def find_full_path(path, load_paths) + # return '/', path + # end + # + # end +end end \ No newline at end of file diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb index 4f46cb6492..b0e87b4f5b 100644 --- a/actionpack/test/new_base/base_test.rb +++ b/actionpack/test/new_base/base_test.rb @@ -34,11 +34,11 @@ module HappyPath end test "sets the content type" do - assert_content_type Mime::HTML + assert_content_type "text/html; charset=utf-8" end test "sets the content length" do - assert_header "Content-Length", 7 + assert_header "Content-Length", "7" end end @@ -52,7 +52,7 @@ module HappyPath end test "setting the body manually sets the content length" do - assert_header "Content-Length", 7 + assert_header "Content-Length", "7" end end @@ -65,7 +65,7 @@ module HappyPath end test "updating the response body updates the content length" do - assert_header "Content-Length", 8 + assert_header "Content-Length", "8" end end end diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index 2bfb374a31..37b83fb681 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -5,7 +5,7 @@ module RenderAction # This has no layout and it works class BasicController < ActionController::Base2 - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "render_action/basic/hello_world.html.erb" => "Hello world!" )] @@ -129,7 +129,7 @@ module RenderActionWithApplicationLayout class BasicController < ::ApplicationController # Set the view path to an application view structure with layouts - self.view_paths = self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( "render_action_with_application_layout/basic/hello_world.html.erb" => "Hello World!", "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI", "layouts/greetings.html.erb" => "Greetings <%= yield %> Bai" @@ -204,7 +204,7 @@ end module RenderActionWithControllerLayout class BasicController < ActionController::Base2 - self.view_paths = self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( "render_action_with_controller_layout/basic/hello_world.html.erb" => "Hello World!", "layouts/render_action_with_controller_layout/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI" )] @@ -267,7 +267,7 @@ end module RenderActionWithBothLayouts class BasicController < ActionController::Base2 - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new({ + self.view_paths = [ActionView::Template::FixturePath.new({ "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!", "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI", "layouts/render_action_with_both_layouts/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI" diff --git a/actionpack/test/new_base/render_implicit_action_test.rb b/actionpack/test/new_base/render_implicit_action_test.rb index 798505b539..0a10c070c3 100644 --- a/actionpack/test/new_base/render_implicit_action_test.rb +++ b/actionpack/test/new_base/render_implicit_action_test.rb @@ -1,16 +1,28 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") -module HappyPath - - class RenderImplicitActionController < ActionController::Base2 - # No actions yet, they are implicit +module RenderImplicitAction + class SimpleController < ::ApplicationController + self.view_paths = [ActionView::Template::FixturePath.new( + "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", + "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated" + )] + + def hello_world() end end - class TestRendersActionImplicitly < SimpleRouteCase - - test "renders action implicitly" do - assert true - end + class TestImplicitRender < SimpleRouteCase + describe "render a simple action with new explicit call to render" + + get "/render_implicit_action/simple/hello_world" + assert_body "Hello world!" + assert_status 200 + end + class TestImplicitWithSpecialCharactersRender < SimpleRouteCase + describe "render an action with a missing method and has special characters" + + get "/render_implicit_action/simple/hyphen-ated" + assert_body "Hello hyphen-ated!" + assert_status 200 end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index facf67ea85..07ea2f191e 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -3,7 +3,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module ControllerLayouts class ImplicitController < ::ApplicationController - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI", "basic.html.erb" => "Hello world!" )] @@ -23,7 +23,7 @@ module ControllerLayouts class ImplicitNameController < ::ApplicationController - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "layouts/controller_layouts/implicit_name.html.erb" => "OMGIMPLICIT <%= yield %> KTHXBAI", "basic.html.erb" => "Hello world!" )] diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index c6c0269b40..fd0519159e 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -4,7 +4,7 @@ module HappyPath class RenderTemplateWithoutLayoutController < ActionController::Base2 - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica" )] @@ -13,10 +13,6 @@ module HappyPath render :template => "test/basic" end - def render_hello_world_with_forward_slash - render :template => "/test/basic" - end - def render_template_in_top_directory render :template => 'shared' end @@ -34,14 +30,6 @@ module HappyPath assert_status 200 end - class TestTemplateRenderWithForwardSlash < SimpleRouteCase - describe "rendering a normal template with full path starting with a leading slash" - - get "/happy_path/render_template_without_layout/render_hello_world_with_forward_slash" - assert_body "Hello from basic.html.erb" - assert_status 200 - end - class TestTemplateRenderInTopDirectory < SimpleRouteCase describe "rendering a template not in a subdirectory" @@ -60,7 +48,7 @@ module HappyPath class RenderTemplateWithLayoutController < ::ApplicationController - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica", "layouts/application.html.erb" => "<%= yield %>, I'm here!", @@ -127,7 +115,26 @@ module HappyPath assert_body "Hello from basic.html.erb, I wish thee well." assert_status 200 end - - +end + +module Compatibility + class RenderTemplateWithoutLayoutController < ActionController::CompatibleBase2 + self.view_paths = [ActionView::Template::FixturePath.new( + "test/basic.html.erb" => "Hello from basic.html.erb", + "shared.html.erb" => "Elastica" + )] + + def render_hello_world_with_forward_slash + render :template => "/test/basic" + end + end + + class TestTemplateRenderWithForwardSlash < SimpleRouteCase + describe "rendering a normal template with full path starting with a leading slash" + + get "/compatibility/render_template_without_layout/render_hello_world_with_forward_slash" + assert_body "Hello from basic.html.erb" + assert_status 200 + end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index a20ca5fb8c..3c11524d1d 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -6,7 +6,7 @@ end module HappyPath class RenderTextWithoutLayoutsController < ActionController::Base2 - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new] + self.view_paths = [ActionView::Template::FixturePath.new] def render_hello_world render :text => "hello david" @@ -14,7 +14,7 @@ module HappyPath end class RenderTextWithLayoutsController < ::ApplicationController - self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( + self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "<%= yield %>, I'm here!", "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well." )] diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index d29449ddc1..091fb77f9f 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -24,6 +24,14 @@ require 'pp' # require 'pp' early to prevent hidden_methods from not picking up require 'rubygems' require 'rack/test' +module Rails + def self.env + x = Object.new + def x.test?() true end + x + end +end + module ActionController class Base2 < AbstractBase use AbstractController::Callbacks @@ -54,6 +62,10 @@ module ActionController CORE_METHODS = self.public_instance_methods end + + class CompatibleBase2 < Base2 + use ActionController::Rails2Compatibility + end end # Temporary base class @@ -91,7 +103,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_body(body) - assert_equal [body], last_response.body + assert_equal body, last_response.body end def self.assert_body(body) -- cgit v1.2.3 From b692fceb6aa08791074dd9f4fc3b962094c0b056 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 11:28:12 -0700 Subject: Renamed ActionController::AbstractBase to ActionController::Http --- actionpack/lib/action_controller/new_base.rb | 2 +- actionpack/lib/action_controller/new_base/base.rb | 2 +- .../test/new_base/render_implicit_action_test.rb | 30 +++++++++++----------- actionpack/test/new_base/test_helper.rb | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 51d9c05a1a..bfd8120e10 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,6 +1,6 @@ module ActionController - autoload :AbstractBase, "action_controller/new_base/base" autoload :HideActions, "action_controller/new_base/hide_actions" + autoload :Http, "action_controller/new_base/base" autoload :Layouts, "action_controller/new_base/layouts" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Renderer, "action_controller/new_base/renderer" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 75fe012aed..6711cd932a 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,5 +1,5 @@ module ActionController - class AbstractBase < AbstractController::Base + class Http < AbstractController::Base # :api: public attr_internal :request, :response, :params diff --git a/actionpack/test/new_base/render_implicit_action_test.rb b/actionpack/test/new_base/render_implicit_action_test.rb index 0a10c070c3..3afa444e3e 100644 --- a/actionpack/test/new_base/render_implicit_action_test.rb +++ b/actionpack/test/new_base/render_implicit_action_test.rb @@ -10,19 +10,19 @@ module RenderImplicitAction def hello_world() end end - class TestImplicitRender < SimpleRouteCase - describe "render a simple action with new explicit call to render" - - get "/render_implicit_action/simple/hello_world" - assert_body "Hello world!" - assert_status 200 - end - - class TestImplicitWithSpecialCharactersRender < SimpleRouteCase - describe "render an action with a missing method and has special characters" - - get "/render_implicit_action/simple/hyphen-ated" - assert_body "Hello hyphen-ated!" - assert_status 200 - end + # class TestImplicitRender < SimpleRouteCase + # describe "render a simple action with new explicit call to render" + # + # get "/render_implicit_action/simple/hello_world" + # assert_body "Hello world!" + # assert_status 200 + # end + # + # class TestImplicitWithSpecialCharactersRender < SimpleRouteCase + # describe "render an action with a missing method and has special characters" + # + # get "/render_implicit_action/simple/hyphen-ated" + # assert_body "Hello hyphen-ated!" + # assert_status 200 + # end end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 091fb77f9f..cc79d6faf7 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -33,7 +33,7 @@ module Rails end module ActionController - class Base2 < AbstractBase + class Base2 < Http use AbstractController::Callbacks use AbstractController::Helpers use AbstractController::Logger -- cgit v1.2.3 From 1b459916039259383808625d1758a8bc4a4516d9 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 11:42:27 -0700 Subject: Renamed the new_base tests --- actionpack/test/controller/render_test.rb | 2 + actionpack/test/new_base/base_test.rb | 43 +++++++------- actionpack/test/new_base/render_template_test.rb | 76 ++++++++++++------------ actionpack/test/new_base/render_text_test.rb | 71 ++++++++++++---------- 4 files changed, 98 insertions(+), 94 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index a97e8ac5c1..648e179a15 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -106,6 +106,7 @@ class TestController < ActionController::Base render :template => '/shared' end + # :ported: def render_hello_world_from_variable @person = "david" render :text => "hello #{@person}" @@ -123,6 +124,7 @@ class TestController < ActionController::Base render :action => :hello_world end + # :ported: def render_text_hello_world render :text => "hello world" end diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb index b0e87b4f5b..95fdfd6b56 100644 --- a/actionpack/test/new_base/base_test.rb +++ b/actionpack/test/new_base/base_test.rb @@ -1,8 +1,8 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") # Tests the controller dispatching happy path -module HappyPath - class SimpleDispatchController < ActionController::Base2 +module Dispatching + class SimpleController < ActionController::Base2 def index render :text => "success" end @@ -23,7 +23,7 @@ module HappyPath class TestSimpleDispatch < SimpleRouteCase - get "/happy_path/simple_dispatch/index" + get "/dispatching/simple/index" test "sets the body" do assert_body "success" @@ -45,7 +45,7 @@ module HappyPath # :api: plugin class TestDirectResponseMod < SimpleRouteCase - get "/happy_path/simple_dispatch/modify_response_body" + get "/dispatching/simple/modify_response_body" test "sets the body" do assert_body "success" @@ -58,7 +58,7 @@ module HappyPath # :api: plugin class TestDirectResponseModTwice < SimpleRouteCase - get "/happy_path/simple_dispatch/modify_response_body_twice" + get "/dispatching/simple/modify_response_body_twice" test "self.response_body= returns the body being set" do assert_body "success!" @@ -68,23 +68,22 @@ module HappyPath assert_header "Content-Length", "8" end end -end - - -class EmptyController < ActionController::Base2 ; end -module Submodule - class ContainedEmptyController < ActionController::Base2 ; end -end + + class EmptyController < ActionController::Base2 ; end + module Submodule + class ContainedEmptyController < ActionController::Base2 ; end + end -class ControllerClassTests < Test::Unit::TestCase - def test_controller_path - assert_equal 'empty', EmptyController.controller_path - assert_equal EmptyController.controller_path, EmptyController.new.controller_path - assert_equal 'submodule/contained_empty', Submodule::ContainedEmptyController.controller_path - assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path + class ControllerClassTests < Test::Unit::TestCase + def test_controller_path + assert_equal 'dispatching/empty', EmptyController.controller_path + assert_equal EmptyController.controller_path, EmptyController.new.controller_path + assert_equal 'dispatching/submodule/contained_empty', Submodule::ContainedEmptyController.controller_path + assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path + end + def test_controller_name + assert_equal 'empty', EmptyController.controller_name + assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name + end end - def test_controller_name - assert_equal 'empty', EmptyController.controller_name - assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name - end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index fd0519159e..bc52eb019f 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -1,31 +1,30 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") -module HappyPath - - class RenderTemplateWithoutLayoutController < ActionController::Base2 +module RenderTemplate + class WithoutLayoutController < ActionController::Base2 self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica" )] - def render_hello_world + def index render :template => "test/basic" end - def render_template_in_top_directory + def in_top_directory render :template => 'shared' end - def render_template_in_top_directory_with_slash + def in_top_directory_with_slash render :template => '/shared' end end - class TestTemplateRenderWithoutLayout < SimpleRouteCase + class TestWithoutLayout < SimpleRouteCase describe "rendering a normal template with full path without layout" - get "/happy_path/render_template_without_layout/render_hello_world" + get "/render_template/without_layout" assert_body "Hello from basic.html.erb" assert_status 200 end @@ -33,7 +32,7 @@ module HappyPath class TestTemplateRenderInTopDirectory < SimpleRouteCase describe "rendering a template not in a subdirectory" - get "/happy_path/render_template_without_layout/render_template_in_top_directory" + get "/render_template/without_layout/in_top_directory" assert_body "Elastica" assert_status 200 end @@ -41,12 +40,12 @@ module HappyPath class TestTemplateRenderInTopDirectoryWithSlash < SimpleRouteCase describe "rendering a template not in a subdirectory with a leading slash" - get "/happy_path/render_template_without_layout/render_template_in_top_directory_with_slash" + get "/render_template/without_layout/in_top_directory_with_slash" assert_body "Elastica" assert_status 200 end - class RenderTemplateWithLayoutController < ::ApplicationController + class WithLayoutController < ::ApplicationController self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", @@ -55,23 +54,23 @@ module HappyPath "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well." )] - def render_hello_world + def index render :template => "test/basic" end - def render_hello_world_with_layout + def with_layout render :template => "test/basic", :layout => true end - def render_hello_world_with_layout_false + def with_layout_false render :template => "test/basic", :layout => false end - def render_hello_world_with_layout_nil + def with_layout_nil render :template => "test/basic", :layout => nil end - def render_hello_world_with_custom_layout + def with_custom_layout render :template => "test/basic", :layout => "greetings" end end @@ -79,7 +78,7 @@ module HappyPath class TestTemplateRenderWithLayout < SimpleRouteCase describe "rendering a normal template with full path with layout" - get "/happy_path/render_template_with_layout/render_hello_world" + get "/render_template/with_layout" assert_body "Hello from basic.html.erb, I'm here!" assert_status 200 end @@ -87,7 +86,7 @@ module HappyPath class TestTemplateRenderWithLayoutTrue < SimpleRouteCase describe "rendering a normal template with full path with layout => :true" - get "/happy_path/render_template_with_layout/render_hello_world_with_layout" + get "/render_template/with_layout/with_layout" assert_body "Hello from basic.html.erb, I'm here!" assert_status 200 end @@ -95,7 +94,7 @@ module HappyPath class TestTemplateRenderWithLayoutFalse < SimpleRouteCase describe "rendering a normal template with full path with layout => :false" - get "/happy_path/render_template_with_layout/render_hello_world_with_layout_false" + get "/render_template/with_layout/with_layout_false" assert_body "Hello from basic.html.erb" assert_status 200 end @@ -103,7 +102,7 @@ module HappyPath class TestTemplateRenderWithLayoutNil < SimpleRouteCase describe "rendering a normal template with full path with layout => :nil" - get "/happy_path/render_template_with_layout/render_hello_world_with_layout_nil" + get "/render_template/with_layout/with_layout_nil" assert_body "Hello from basic.html.erb" assert_status 200 end @@ -111,30 +110,29 @@ module HappyPath class TestTemplateRenderWithCustomLayout < SimpleRouteCase describe "rendering a normal template with full path with layout => 'greetings'" - get "/happy_path/render_template_with_layout/render_hello_world_with_custom_layout" + get "/render_template/with_layout/with_custom_layout" assert_body "Hello from basic.html.erb, I wish thee well." assert_status 200 end + + module Compatibility + class WithoutLayoutController < ActionController::CompatibleBase2 + self.view_paths = [ActionView::Template::FixturePath.new( + "test/basic.html.erb" => "Hello from basic.html.erb", + "shared.html.erb" => "Elastica" + )] -end + def with_forward_slash + render :template => "/test/basic" + end + end -module Compatibility - class RenderTemplateWithoutLayoutController < ActionController::CompatibleBase2 - self.view_paths = [ActionView::Template::FixturePath.new( - "test/basic.html.erb" => "Hello from basic.html.erb", - "shared.html.erb" => "Elastica" - )] - - def render_hello_world_with_forward_slash - render :template => "/test/basic" + class TestTemplateRenderWithForwardSlash < SimpleRouteCase + describe "rendering a normal template with full path starting with a leading slash" + + get "/render_template/compatibility/without_layout/with_forward_slash" + assert_body "Hello from basic.html.erb" + assert_status 200 end end - - class TestTemplateRenderWithForwardSlash < SimpleRouteCase - describe "rendering a normal template with full path starting with a leading slash" - - get "/compatibility/render_template_without_layout/render_hello_world_with_forward_slash" - assert_body "Hello from basic.html.erb" - assert_status 200 - end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index 3c11524d1d..d97c2ca0a6 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -3,75 +3,80 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") class ApplicationController < ActionController::Base2 end -module HappyPath - - class RenderTextWithoutLayoutsController < ActionController::Base2 +module RenderText + class SimpleController < ActionController::Base2 self.view_paths = [ActionView::Template::FixturePath.new] - def render_hello_world + def index render :text => "hello david" end end - class RenderTextWithLayoutsController < ::ApplicationController + class TestSimpleTextRenderWithNoLayout < SimpleRouteCase + describe "Rendering text from a action with default options renders the text with the layout" + + get "/render_text/simple" + assert_body "hello david" + assert_status 200 + end + + class WithLayoutController < ::ApplicationController self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "<%= yield %>, I'm here!", - "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well." + "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well.", + "layouts/ivar.html.erb" => "<%= yield %>, <%= @ivar %>" )] - def render_hello_world + def index render :text => "hello david" end - def render_custom_code + def custom_code render :text => "hello world", :status => 404 end - def render_with_custom_code_as_string + def with_custom_code_as_string render :text => "hello world", :status => "404 Not Found" end - def render_text_with_nil + def with_nil render :text => nil end - def render_text_with_nil_and_status + def with_nil_and_status render :text => nil, :status => 403 end - def render_text_with_false + def with_false render :text => false end - def render_text_with_layout + def with_layout_true render :text => "hello world", :layout => true end - def render_text_with_layout_false + def with_layout_false render :text => "hello world", :layout => false end - def render_text_with_layout_nil + def with_layout_nil render :text => "hello world", :layout => nil end - def render_text_with_custom_layout + def with_custom_layout render :text => "hello world", :layout => "greetings" end - end - - class TestSimpleTextRenderWithNoLayout < SimpleRouteCase - describe "Rendering text from a action with default options renders the text with the layout" - get "/happy_path/render_text_without_layouts/render_hello_world" - assert_body "hello david" - assert_status 200 + def with_ivar_in_layout + @ivar = "hello world" + render :text => "hello world", :layout => "ivar" + end end - + class TestSimpleTextRenderWithLayout < SimpleRouteCase describe "Rendering text from a action with default options renders the text without the layout" - get "/happy_path/render_text_with_layouts/render_hello_world" + get "/render_text/with_layout" assert_body "hello david" assert_status 200 end @@ -79,7 +84,7 @@ module HappyPath class TestTextRenderWithStatus < SimpleRouteCase describe "Rendering text, while also providing a custom status code" - get "/happy_path/render_text_with_layouts/render_custom_code" + get "/render_text/with_layout/custom_code" assert_body "hello world" assert_status 404 end @@ -87,7 +92,7 @@ module HappyPath class TestTextRenderWithNil < SimpleRouteCase describe "Rendering text with nil returns a single space character" - get "/happy_path/render_text_with_layouts/render_text_with_nil" + get "/render_text/with_layout/with_nil" assert_body " " assert_status 200 end @@ -95,7 +100,7 @@ module HappyPath class TestTextRenderWithNilAndStatus < SimpleRouteCase describe "Rendering text with nil and custom status code returns a single space character with the status" - get "/happy_path/render_text_with_layouts/render_text_with_nil_and_status" + get "/render_text/with_layout/with_nil_and_status" assert_body " " assert_status 403 end @@ -103,7 +108,7 @@ module HappyPath class TestTextRenderWithFalse < SimpleRouteCase describe "Rendering text with false returns the string 'false'" - get "/happy_path/render_text_with_layouts/render_text_with_false" + get "/render_text/with_layout/with_false" assert_body "false" assert_status 200 end @@ -111,7 +116,7 @@ module HappyPath class TestTextRenderWithLayoutTrue < SimpleRouteCase describe "Rendering text with :layout => true" - get "/happy_path/render_text_with_layouts/render_text_with_layout" + get "/render_text/with_layout/with_layout_true" assert_body "hello world, I'm here!" assert_status 200 end @@ -119,7 +124,7 @@ module HappyPath class TestTextRenderWithCustomLayout < SimpleRouteCase describe "Rendering text with :layout => 'greetings'" - get "/happy_path/render_text_with_layouts/render_text_with_custom_layout" + get "/render_text/with_layout/with_custom_layout" assert_body "hello world, I wish thee well." assert_status 200 end @@ -127,7 +132,7 @@ module HappyPath class TestTextRenderWithLayoutFalse < SimpleRouteCase describe "Rendering text with :layout => false" - get "/happy_path/render_text_with_layouts/render_text_with_layout_false" + get "/render_text/with_layout/with_layout_false" assert_body "hello world" assert_status 200 end @@ -135,7 +140,7 @@ module HappyPath class TestTextRenderWithLayoutNil < SimpleRouteCase describe "Rendering text with :layout => nil" - get "/happy_path/render_text_with_layouts/render_text_with_layout_nil" + get "/render_text/with_layout/with_layout_nil" assert_body "hello world" assert_status 200 end -- cgit v1.2.3 From 4f68311685831b940936130203c240fa23525c84 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 12:19:17 -0700 Subject: Finished implementing render :text in Base2 --- .../lib/action_controller/abstract/renderer.rb | 13 +++++++++++++ actionpack/lib/action_controller/new_base/base.rb | 8 ++------ .../lib/action_controller/new_base/renderer.rb | 2 +- actionpack/test/controller/render_test.rb | 17 +++++++++++++++++ actionpack/test/new_base/base_test.rb | 2 +- actionpack/test/new_base/render_test.rb | 20 ++++++++++++++++++++ 6 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 actionpack/test/new_base/render_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index 37da2398ec..c1f420f7b4 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -1,6 +1,15 @@ require "action_controller/abstract/logger" module AbstractController + class AbstractControllerError < StandardError; end + class DoubleRenderError < AbstractControllerError + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + module Renderer depends_on AbstractController::Logger @@ -17,6 +26,10 @@ module AbstractController end def render(options = {}) + unless response_body.nil? + raise AbstractController::DoubleRenderError, "OMG" + end + self.response_body = render_to_body(options) end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 6711cd932a..9f7a148b3c 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -40,23 +40,19 @@ module ActionController controller.call(env).to_rack end - # :api: plugin - def response_body=(body) - @_response.body = body - end - # :api: private def call(env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new process(@_request.parameters[:action]) + @_response.body = response_body @_response.prepare! self end # :api: private def to_rack - response.to_a + @_response.to_a end end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index ed34c46aed..9a965c18e8 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -17,7 +17,7 @@ module ActionController _process_options(options) - self.response_body = render_to_body(options) + super(options) end def render_to_body(options) diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 648e179a15..9149212a2d 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -129,6 +129,7 @@ class TestController < ActionController::Base render :text => "hello world" end + # :ported: def render_text_hello_world_with_layout @variable_for_layout = ", I'm here!" render :text => "hello world", :layout => true @@ -220,6 +221,7 @@ class TestController < ActionController::Base render :json => {:hello => render_to_string(:partial => 'partial')} end + # :ported: def render_custom_code render :text => "hello world", :status => 404 end @@ -230,14 +232,17 @@ class TestController < ActionController::Base end end + # :ported: def render_text_with_nil render :text => nil end + # :ported: def render_text_with_false render :text => false end + # :ported: def render_nothing_with_appendix render :text => "appended" end @@ -272,6 +277,7 @@ class TestController < ActionController::Base # let's just rely on the template end + # :ported: def blank_response render :text => ' ' end @@ -405,6 +411,7 @@ class TestController < ActionController::Base render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } end + # :ported: def double_render render :text => "hello" render :text => "world" @@ -508,6 +515,7 @@ class TestController < ActionController::Base # Action template sets variable that's picked up by layout end + # :addressed: def render_text_with_assigns @hello = "world" render :text => "foo" @@ -807,6 +815,7 @@ class RenderTest < ActionController::TestCase assert_equal "Elastica", @response.body end + # :ported: def test_render_from_variable get :render_hello_world_from_variable assert_equal "hello david", @response.body @@ -828,16 +837,19 @@ class RenderTest < ActionController::TestCase assert_template "test/hello_world" end + # :ported: def test_render_text get :render_text_hello_world assert_equal "hello world", @response.body end + # :ported: def test_do_with_render_text_and_layout get :render_text_hello_world_with_layout assert_equal "hello world, I'm here!", @response.body end + # :ported: def test_do_with_render_action_and_layout_false get :hello_world_with_layout_false assert_equal 'Hello world!', @response.body @@ -932,17 +944,20 @@ class RenderTest < ActionController::TestCase assert_equal %(Element.replace("foo", "partial html");), @response.body end + # :ported: def test_render_text_with_nil get :render_text_with_nil assert_response 200 assert_equal ' ', @response.body end + # :ported: def test_render_text_with_false get :render_text_with_false assert_equal 'false', @response.body end + # :ported: def test_render_nothing_with_appendix get :render_nothing_with_appendix assert_response 200 @@ -1209,6 +1224,7 @@ class RenderTest < ActionController::TestCase assert_equal "Hello world!", @response.body end + # :ported: def test_double_render assert_raise(ActionController::DoubleRenderError) { get :double_render } end @@ -1237,6 +1253,7 @@ class RenderTest < ActionController::TestCase assert_equal "Talking to the layout\nAction was here!", @response.body end + # :addressed: def test_render_text_with_assigns get :render_text_with_assigns assert_equal "world", assigns["hello"] diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb index 95fdfd6b56..27d1a7f026 100644 --- a/actionpack/test/new_base/base_test.rb +++ b/actionpack/test/new_base/base_test.rb @@ -84,6 +84,6 @@ module Dispatching def test_controller_name assert_equal 'empty', EmptyController.controller_name assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name - end + end end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb new file mode 100644 index 0000000000..9ad79124b8 --- /dev/null +++ b/actionpack/test/new_base/render_test.rb @@ -0,0 +1,20 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module Render + class DoubleRenderController < ActionController::Base2 + def index + render :text => "hello" + render :text => "world" + end + end + + class TestBasic < SimpleRouteCase + describe "Rendering more than once" + + test "raises an exception" do + assert_raises(AbstractController::DoubleRenderError) do + get "/render/double_render" + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 0c3d9bc4c2b329cb754bfed1e465f99d058e1193 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 16:33:24 -0700 Subject: Ported over render :template tests --- actionpack/lib/action_controller/abstract/layouts.rb | 3 +-- actionpack/lib/action_controller/abstract/renderer.rb | 1 - actionpack/lib/action_controller/new_base/renderer.rb | 4 ---- actionpack/test/controller/render_test.rb | 19 +++++++++++++++++++ actionpack/test/new_base/render_template_test.rb | 15 ++++++++++++++- actionpack/test/new_base/test_helper.rb | 5 +++++ 6 files changed, 39 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 315d6151e9..f56b9dd914 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -50,8 +50,7 @@ module AbstractController end def _render_template(template, options) - # layout = options[:_layout].is_a?(ActionView::Template) ? options[:_layout] : _layout_for_name(options[:_layout]) - _action_view._render_template_with_layout(template, options[:_layout]) + _action_view._render_template_with_layout(template, options[:_layout], options) end private diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index c1f420f7b4..e9a7ab4004 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -40,7 +40,6 @@ module AbstractController # # :api: plugin def render_to_body(options = {}) - options = {:_template_name => options} if options.is_a?(String) name = options[:_template_name] || action_name template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 9a965c18e8..df07edbd90 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -21,10 +21,6 @@ module ActionController end def render_to_body(options) - unless options.is_a?(Hash) - options = {:action => options} - end - if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(_text(options)) template = nil diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 9149212a2d..d4a18a673c 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -80,6 +80,7 @@ class TestController < ActionController::Base fresh_when(:last_modified => Time.now.utc.beginning_of_day, :etag => [ :foo, 123 ]) end + # :ported: def render_hello_world render :template => "test/hello_world" end @@ -94,14 +95,17 @@ class TestController < ActionController::Base render :template => "test/hello_world" end + # :ported: compatibility def render_hello_world_with_forward_slash render :template => "/test/hello_world" end + # :ported: def render_template_in_top_directory render :template => 'shared' end + # :deprecated: def render_template_in_top_directory_with_slash render :template => '/shared' end @@ -251,6 +255,10 @@ class TestController < ActionController::Base render :js => "alert('hello')" end + # This test is testing 3 things: + # render :file in AV :ported: + # render :template in AC :ported: + # setting content type def render_xml_hello @name = "David" render :template => "test/hello" @@ -399,6 +407,7 @@ class TestController < ActionController::Base render :layout => true, :inline => "Hello: <%= params[:name] %>" end + # :ported: def render_with_explicit_template render :template => "test/hello_world" end @@ -407,6 +416,7 @@ class TestController < ActionController::Base render "test/hello_world" end + # :ported: def render_with_explicit_template_with_locals render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } end @@ -443,10 +453,15 @@ class TestController < ActionController::Base render :action => "potential_conflicts" end + # :deprecated: + # Tests being able to pick a .builder template over a .erb + # For instance, being able to have hello.xml.builder and hello.xml.erb + # and select one via "hello.builder" or "hello.erb" def hello_world_from_rxml_using_action render :action => "hello_world_from_rxml.builder" end + # :deprecated: def hello_world_from_rxml_using_template render :template => "test/hello_world_from_rxml.builder" end @@ -798,17 +813,20 @@ class RenderTest < ActionController::TestCase end end + # :ported: compatibility def test_render_with_forward_slash get :render_hello_world_with_forward_slash assert_template "test/hello_world" end + # :ported: def test_render_in_top_directory get :render_template_in_top_directory assert_template "shared" assert_equal "Elastica", @response.body end + # :ported: def test_render_in_top_directory_with_slash get :render_template_in_top_directory_with_slash assert_template "shared" @@ -1259,6 +1277,7 @@ class RenderTest < ActionController::TestCase assert_equal "world", assigns["hello"] end + # :ported: def test_template_with_locals get :render_with_explicit_template_with_locals assert_equal "The secret is area51\n", @response.body diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index bc52eb019f..63769df082 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -5,7 +5,8 @@ module RenderTemplate self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", - "shared.html.erb" => "Elastica" + "shared.html.erb" => "Elastica", + "locals.html.erb" => "The secret is <%= secret %>" )] def index @@ -19,6 +20,10 @@ module RenderTemplate def in_top_directory_with_slash render :template => '/shared' end + + def with_locals + render :template => "locals", :locals => { :secret => 'area51' } + end end class TestWithoutLayout < SimpleRouteCase @@ -44,6 +49,14 @@ module RenderTemplate assert_body "Elastica" assert_status 200 end + + class TestTemplateRenderWithLocals < SimpleRouteCase + describe "rendering a template with local variables" + + get "/render_template/without_layout/with_locals" + assert_body "The secret is area51" + assert_status 200 + end class WithLayoutController < ::ApplicationController diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index cc79d6faf7..b40cbb163f 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -58,6 +58,11 @@ module ActionController end end + def render_to_body(options = {}) + options = {:template => options} if options.is_a?(String) + super + end + # append_view_path File.join(File.dirname(__FILE__), '..', 'fixtures') CORE_METHODS = self.public_instance_methods -- cgit v1.2.3 From 49834e088bf8d02a4f75793a42868f2aea8749a4 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 17:32:39 -0700 Subject: Support implicit render and blank render --- actionpack/lib/action_controller/abstract/base.rb | 13 ++++++++- .../lib/action_controller/abstract/renderer.rb | 4 +-- .../lib/action_controller/new_base/renderer.rb | 9 +----- .../test/new_base/render_implicit_action_test.rb | 32 +++++++++++----------- actionpack/test/new_base/render_test.rb | 18 ++++++++++++ actionpack/test/new_base/test_helper.rb | 20 ++++++++++++++ 6 files changed, 69 insertions(+), 27 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index ade7719cc0..a87a490a2d 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -29,10 +29,21 @@ module AbstractController private + # It is possible for respond_to?(action_name) to be false and + # respond_to?(:action_missing) to be false if respond_to_action? + # is overridden in a subclass. For instance, ActionController::Base + # overrides it to include the case where a template matching the + # action_name is found. def process_action - respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name) + if respond_to?(action_name) then send(action_name) + elsif respond_to?(:action_missing, true) then send(:action_missing, action_name) + end end + # Override this to change the conditions that will raise an + # ActionNotFound error. If you accept a difference case, + # you must handle it by also overriding process_action and + # handling the case. def respond_to_action?(action_name) respond_to?(action_name) || respond_to?(:action_missing, true) end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index e9a7ab4004..716b213c75 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -42,9 +42,9 @@ module AbstractController def render_to_body(options = {}) name = options[:_template_name] || action_name - template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) + options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) - _render_template(template, options) + _render_template(options[:_template], options) end # Raw rendering of a template to a string. diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index df07edbd90..096a63e406 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -7,14 +7,7 @@ module ActionController super end - def render(action, options = {}) - # TODO: Move this into #render_to_body - if action.is_a?(Hash) - options, action = action, nil - else - options.merge! :action => action - end - + def render(options = {}) _process_options(options) super(options) diff --git a/actionpack/test/new_base/render_implicit_action_test.rb b/actionpack/test/new_base/render_implicit_action_test.rb index 3afa444e3e..58f5cec181 100644 --- a/actionpack/test/new_base/render_implicit_action_test.rb +++ b/actionpack/test/new_base/render_implicit_action_test.rb @@ -4,25 +4,25 @@ module RenderImplicitAction class SimpleController < ::ApplicationController self.view_paths = [ActionView::Template::FixturePath.new( "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", - "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated" + "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!" )] def hello_world() end end - # class TestImplicitRender < SimpleRouteCase - # describe "render a simple action with new explicit call to render" - # - # get "/render_implicit_action/simple/hello_world" - # assert_body "Hello world!" - # assert_status 200 - # end - # - # class TestImplicitWithSpecialCharactersRender < SimpleRouteCase - # describe "render an action with a missing method and has special characters" - # - # get "/render_implicit_action/simple/hyphen-ated" - # assert_body "Hello hyphen-ated!" - # assert_status 200 - # end + class TestImplicitRender < SimpleRouteCase + describe "render a simple action with new explicit call to render" + + get "/render_implicit_action/simple/hello_world" + assert_body "Hello world!" + assert_status 200 + end + + class TestImplicitWithSpecialCharactersRender < SimpleRouteCase + describe "render an action with a missing method and has special characters" + + get "/render_implicit_action/simple/hyphen-ated" + assert_body "Hello hyphen-ated!" + assert_status 200 + end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index 9ad79124b8..93bc8d854c 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -1,6 +1,24 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module Render + class BlankRenderController < ActionController::Base2 + self.view_paths = [ActionView::Template::FixturePath.new( + "render/blank_render/index.html.erb" => "Hello world!" + )] + + def index + render + end + end + + class TestBlankRender < SimpleRouteCase + describe "Render with blank" + + get "/render/blank_render" + assert_body "Hello world!" + assert_status 200 + end + class DoubleRenderController < ActionController::Base2 def index render :text => "hello" diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index b40cbb163f..03af5a66a6 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -58,11 +58,31 @@ module ActionController end end + def render(action = action_name, options = {}) + if action.is_a?(Hash) + options, action = action, nil + else + options.merge! :action => action + end + + super(options) + end + def render_to_body(options = {}) options = {:template => options} if options.is_a?(String) super end + def process_action + ret = super + render if response_body.nil? + ret + end + + def respond_to_action?(action_name) + super || view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path) + end + # append_view_path File.join(File.dirname(__FILE__), '..', 'fixtures') CORE_METHODS = self.public_instance_methods -- cgit v1.2.3 From b98e496c039b7bde4a2de9c02809e0b4ee0679ae Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 17:32:55 -0700 Subject: Support implicit and explicit content types --- actionpack/lib/action_controller/new_base.rb | 1 + .../lib/action_controller/new_base/content_type.rb | 15 +++ actionpack/lib/action_view/template/text.rb | 3 +- actionpack/test/controller/content_type_test.rb | 10 ++ actionpack/test/new_base/content_type_test.rb | 111 +++++++++++++++++++++ actionpack/test/new_base/test_helper.rb | 1 + 6 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/content_type.rb create mode 100644 actionpack/test/new_base/content_type_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index bfd8120e10..9c8a6d0216 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,4 +1,5 @@ module ActionController + autoload :ContentType, "action_controller/new_base/content_type" autoload :HideActions, "action_controller/new_base/hide_actions" autoload :Http, "action_controller/new_base/base" autoload :Layouts, "action_controller/new_base/layouts" diff --git a/actionpack/lib/action_controller/new_base/content_type.rb b/actionpack/lib/action_controller/new_base/content_type.rb new file mode 100644 index 0000000000..d2206a31af --- /dev/null +++ b/actionpack/lib/action_controller/new_base/content_type.rb @@ -0,0 +1,15 @@ +module ActionController + module ContentType + + def render_to_body(options = {}) + if content_type = options[:content_type] + response.content_type = content_type + end + + ret = super + response.content_type ||= options[:_template].mime_type + ret + end + + end +end \ No newline at end of file diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index f81174d707..446c735ba3 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -3,7 +3,6 @@ module ActionView #:nodoc: def render(*) self end - def exempt_from_layout?() false end - + def mime_type() Mime::HTML end end end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index 7377546631..64b8b10d5b 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -1,24 +1,29 @@ require 'abstract_unit' class ContentTypeController < ActionController::Base + # :ported: def render_content_type_from_body response.content_type = Mime::RSS render :text => "hello world!" end + # :ported: def render_defaults render :text => "hello world!" end + # :ported: def render_content_type_from_render render :text => "hello world!", :content_type => Mime::RSS end + # :ported: def render_charset_from_body response.charset = "utf-16" render :text => "hello world!" end + # :ported: def render_nil_charset_from_body response.charset = nil render :text => "hello world!" @@ -60,6 +65,7 @@ class ContentTypeTest < ActionController::TestCase @controller.logger = Logger.new(nil) end + # :ported: def test_render_defaults get :render_defaults assert_equal "utf-8", @response.charset @@ -74,24 +80,28 @@ class ContentTypeTest < ActionController::TestCase ContentTypeController.default_charset = "utf-8" end + # :ported: def test_content_type_from_body get :render_content_type_from_body assert_equal "application/rss+xml", @response.content_type assert_equal "utf-8", @response.charset end + # :ported: def test_content_type_from_render get :render_content_type_from_render assert_equal "application/rss+xml", @response.content_type assert_equal "utf-8", @response.charset end + # :ported: def test_charset_from_body get :render_charset_from_body assert_equal Mime::HTML, @response.content_type assert_equal "utf-16", @response.charset end + # :ported: def test_nil_charset_from_body get :render_nil_charset_from_body assert_equal Mime::HTML, @response.content_type diff --git a/actionpack/test/new_base/content_type_test.rb b/actionpack/test/new_base/content_type_test.rb new file mode 100644 index 0000000000..10a28da496 --- /dev/null +++ b/actionpack/test/new_base/content_type_test.rb @@ -0,0 +1,111 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module ContentType + class BaseController < ActionController::Base2 + def index + render :text => "Hello world!" + end + + def set_on_response_obj + response.content_type = Mime::RSS + render :text => "Hello world!" + end + + def set_on_render + render :text => "Hello world!", :content_type => Mime::RSS + end + end + + class TestDefault < SimpleRouteCase + describe "a default response is HTML and UTF8" + + get "/content_type/base" + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-8" + end + + class TestSetOnResponseObj < SimpleRouteCase + describe "setting the content type of the response directly on the response object" + + get "/content_type/base/set_on_response_obj" + assert_body "Hello world!" + assert_header "Content-Type", "application/rss+xml; charset=utf-8" + end + + class TestSetOnRender < SimpleRouteCase + describe "setting the content type of the response as an option to render" + + get "/content_type/base/set_on_render" + assert_body "Hello world!" + assert_header "Content-Type", "application/rss+xml; charset=utf-8" + end + + class ImpliedController < ActionController::Base2 + self.view_paths = [ActionView::Template::FixturePath.new( + "content_type/implied/i_am_html_erb.html.erb" => "Hello world!", + "content_type/implied/i_am_xml_erb.xml.erb" => "Hello world!", + "content_type/implied/i_am_html_builder.html.builder" => "xml.p 'Hello'", + "content_type/implied/i_am_xml_builder.xml.builder" => "xml.awesome 'Hello'" + )] + + def i_am_html_erb() end + def i_am_xml_erb() end + def i_am_html_builder() end + def i_am_xml_builder() end + end + + class TestImpliedController < SimpleRouteCase + describe "the template's mime type is used if no content_type is specified" + + test "sets Content-Type as text/html when rendering *.html.erb" do + get "/content_type/implied/i_am_html_erb" + assert_header "Content-Type", "text/html; charset=utf-8" + end + + test "sets Content-Type as application/xml when rendering *.xml.erb" do + get "/content_type/implied/i_am_xml_erb" + assert_header "Content-Type", "application/xml; charset=utf-8" + end + + test "sets Content-Type as text/html when rendering *.html.builder" do + get "/content_type/implied/i_am_html_builder" + assert_header "Content-Type", "text/html; charset=utf-8" + end + + test "sets Content-Type as application/xml when rendering *.xml.builder" do + get "/content_type/implied/i_am_xml_builder" + assert_header "Content-Type", "application/xml; charset=utf-8" + end + + end +end + +module Charset + class BaseController < ActionController::Base2 + def set_on_response_obj + response.charset = "utf-16" + render :text => "Hello world!" + end + + def set_as_nil_on_response_obj + response.charset = nil + render :text => "Hello world!" + end + end + + class TestSetOnResponseObj < SimpleRouteCase + describe "setting the charset of the response directly on the response object" + + get "/charset/base/set_on_response_obj" + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-16" + end + + class TestSetAsNilOnResponseObj < SimpleRouteCase + describe "setting the charset of the response as nil directly on the response object" + + get "/charset/base/set_as_nil_on_response_obj" + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-8" + end +end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 03af5a66a6..d41c7283b7 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -42,6 +42,7 @@ module ActionController use ActionController::UrlFor use ActionController::Renderer use ActionController::Layouts + use ActionController::ContentType def self.inherited(klass) ::ActionController::Base2.subclasses << klass.to_s -- cgit v1.2.3 From d58b57a3caf4ad434c2be4f63eecd9a1921c7c4a Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 29 Apr 2009 17:50:11 -0700 Subject: Move ContentType inline for now. Trying to avoid premature proliferation of modules. --- actionpack/lib/action_controller/new_base.rb | 1 - actionpack/lib/action_controller/new_base/content_type.rb | 15 --------------- actionpack/lib/action_controller/new_base/renderer.rb | 10 ++++++---- actionpack/test/new_base/test_helper.rb | 1 - 4 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 actionpack/lib/action_controller/new_base/content_type.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 9c8a6d0216..bfd8120e10 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,5 +1,4 @@ module ActionController - autoload :ContentType, "action_controller/new_base/content_type" autoload :HideActions, "action_controller/new_base/hide_actions" autoload :Http, "action_controller/new_base/base" autoload :Layouts, "action_controller/new_base/layouts" diff --git a/actionpack/lib/action_controller/new_base/content_type.rb b/actionpack/lib/action_controller/new_base/content_type.rb deleted file mode 100644 index d2206a31af..0000000000 --- a/actionpack/lib/action_controller/new_base/content_type.rb +++ /dev/null @@ -1,15 +0,0 @@ -module ActionController - module ContentType - - def render_to_body(options = {}) - if content_type = options[:content_type] - response.content_type = content_type - end - - ret = super - response.content_type ||= options[:_template].mime_type - ret - end - - end -end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 096a63e406..f21fd746b7 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -24,7 +24,9 @@ module ActionController options[:_prefix] = _prefix end - super(options) + ret = super(options) + response.content_type ||= options[:_template].mime_type + ret end private @@ -43,9 +45,9 @@ module ActionController end def _process_options(options) - if status = options[:status] - response.status = status.to_i - end + status, content_type = options.values_at(:status, :content_type) + response.status = status.to_i if status + response.content_type = content_type if content_type end end end diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index d41c7283b7..03af5a66a6 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -42,7 +42,6 @@ module ActionController use ActionController::UrlFor use ActionController::Renderer use ActionController::Layouts - use ActionController::ContentType def self.inherited(klass) ::ActionController::Base2.subclasses << klass.to_s -- cgit v1.2.3 From 4ee3e5b094463383891789f484e927b19fccc744 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 30 Apr 2009 15:13:40 -0700 Subject: Ported over the concept of public instance methods on controller child classes as callable action methods --- actionpack/lib/action_controller/abstract/base.rb | 48 +++++++++++++++++++---- actionpack/lib/action_controller/new_base/base.rb | 14 +++---- actionpack/test/controller/render_test.rb | 7 ++++ actionpack/test/new_base/render_test.rb | 10 +++++ actionpack/test/new_base/test_helper.rb | 10 ++--- 5 files changed, 69 insertions(+), 20 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index a87a490a2d..3b85ba5565 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -4,13 +4,44 @@ module AbstractController attr_internal :response_body attr_internal :response_obj attr_internal :action_name - - def self.process(action) - new.process(action) + + class << self + attr_reader :abstract + + def abstract! + @abstract = true + end + + alias_method :abstract?, :abstract + + def internal_methods + controller = self + controller = controller.superclass until controller.abstract? + controller.public_instance_methods(true) + end + + def process(action) + new.process(action) + end + + def hidden_actions + [] + end + + def action_methods + @action_methods ||= + # All public instance methods of this class, including ancestors + public_instance_methods(true).map { |m| m.to_sym }.to_set - + # Except for public instance methods of Base and its ancestors + internal_methods.map { |m| m.to_sym } + + # Be sure to include shadowed public instance methods of this class + public_instance_methods(false).map { |m| m.to_sym } - + # And always exclude explicitly hidden actions + hidden_actions + end end - def self.inherited(klass) - end + abstract! def initialize self.response_obj = {} @@ -29,6 +60,10 @@ module AbstractController private + def action_methods + self.class.action_methods + end + # It is possible for respond_to?(action_name) to be false and # respond_to?(:action_missing) to be false if respond_to_action? # is overridden in a subclass. For instance, ActionController::Base @@ -45,8 +80,7 @@ module AbstractController # you must handle it by also overriding process_action and # handling the case. def respond_to_action?(action_name) - respond_to?(action_name) || respond_to?(:action_missing, true) + action_methods.include?(action_name) || respond_to?(:action_missing, true) end - end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 9f7a148b3c..00d161289e 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,5 +1,6 @@ module ActionController class Http < AbstractController::Base + abstract! # :api: public attr_internal :request, :response, :params @@ -19,18 +20,15 @@ module ActionController # :api: public def controller_path() self.class.controller_path end - - # :api: private - def self.action_methods - @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS) + + # :api: private + def self.internal_methods + ActionController::Http.public_instance_methods(true) end # :api: private def self.action_names() action_methods end - # :api: private - def action_methods() self.class.action_names end - # :api: private def action_names() action_methods end @@ -44,7 +42,7 @@ module ActionController def call(env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new - process(@_request.parameters[:action]) + process(@_request.parameters[:action].to_sym) @_response.body = response_body @_response.prepare! self diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index d4a18a673c..e6b2ee7e9f 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -4,6 +4,7 @@ require 'pathname' module Fun class GamesController < ActionController::Base + # :ported: def hello_world end end @@ -116,6 +117,7 @@ class TestController < ActionController::Base render :text => "hello #{@person}" end + # :ported: def render_action_hello_world render :action => "hello_world" end @@ -839,17 +841,20 @@ class RenderTest < ActionController::TestCase assert_equal "hello david", @response.body end + # :ported: def test_render_action get :render_action_hello_world assert_template "test/hello_world" end + # :ported: def test_render_action_hello_world_as_string get :render_action_hello_world_as_string assert_equal "Hello world!", @response.body assert_template "test/hello_world" end + # :ported: def test_render_action_with_symbol get :render_action_hello_world_with_symbol assert_template "test/hello_world" @@ -949,6 +954,7 @@ class RenderTest < ActionController::TestCase assert_equal 'application/json', @response.content_type end + # :ported: def test_render_custom_code get :render_custom_code assert_response 404 @@ -1082,6 +1088,7 @@ class RenderTest < ActionController::TestCase assert_template "test/hello_world" end + # :ported: def test_nested_rendering @controller = Fun::GamesController.new get :hello_world diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index 93bc8d854c..bc7203f294 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -35,4 +35,14 @@ module Render end end end + + class TestRenderObjectMethod < SimpleRouteCase + describe "Methods on Object are not actions" + + test "raises an exception" do + assert_raises(AbstractController::ActionNotFound) do + get "/render/blank_render/clone" + end + end + end end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 03af5a66a6..d58b83cf7b 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -34,6 +34,8 @@ end module ActionController class Base2 < Http + abstract! + use AbstractController::Callbacks use AbstractController::Helpers use AbstractController::Logger @@ -80,15 +82,13 @@ module ActionController end def respond_to_action?(action_name) - super || view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path) + super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) end - - # append_view_path File.join(File.dirname(__FILE__), '..', 'fixtures') - - CORE_METHODS = self.public_instance_methods end class CompatibleBase2 < Base2 + abstract! + use ActionController::Rails2Compatibility end end -- cgit v1.2.3 From 69fd66916566f402620cc385689c36f61deb6ba1 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 11:40:32 -0700 Subject: Committing the last changes before we start trying to get the old tests to pass on the new base --- actionpack/test/controller/render_test.rb | 11 +++++- actionpack/test/new_base/render_layout_test.rb | 18 ++++++++-- actionpack/test/new_base/render_test.rb | 48 +++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index e6b2ee7e9f..fb9b121fc9 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -292,6 +292,7 @@ class TestController < ActionController::Base render :text => ' ' end + # :ported: def layout_test render :action => "hello_world" end @@ -299,7 +300,8 @@ class TestController < ActionController::Base def builder_layout_test render :action => "hello", :layout => "layouts/builder" end - + + # :move: test this in ActionView def builder_partial_test render :action => "hello_world_container" end @@ -988,14 +990,17 @@ class RenderTest < ActionController::TestCase assert_equal 'appended', @response.body end + # :ported: def test_attempt_to_access_object_method assert_raise(ActionController::UnknownAction, "No action responded to [clone]") { get :clone } end + # :ported: def test_private_methods assert_raise(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout } end + # :ported: def test_access_to_request_in_view get :accessing_request_in_template assert_equal "Hello: www.nextangle.com", @response.body @@ -1006,11 +1011,13 @@ class RenderTest < ActionController::TestCase assert_equal "Logger", @response.body end + # :ported: def test_access_to_action_name_in_view get :accessing_action_name_in_template assert_equal "accessing_action_name_in_template", @response.body end + # :ported: def test_access_to_controller_name_in_view get :accessing_controller_name_in_template assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. @@ -1022,6 +1029,7 @@ class RenderTest < ActionController::TestCase assert_equal "text/javascript", @response.content_type end + # :ported: def test_render_xml get :render_xml_hello assert_equal "\n

Hello David

\n

This is grand!

\n\n", @response.body @@ -1034,6 +1042,7 @@ class RenderTest < ActionController::TestCase assert_equal "application/xml", @response.content_type end + # :ported: def test_render_xml_with_default get :greeting assert_equal "

This is grand!

\n", @response.body diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index 07ea2f191e..5d28926cc6 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -5,12 +5,21 @@ module ControllerLayouts self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI", - "basic.html.erb" => "Hello world!" + "layouts/override.html.erb" => "Override! <%= yield %>", + "basic.html.erb" => "Hello world!" )] def index render :template => "basic" end + + def override + render :template => "basic", :layout => "override" + end + + def builder_override + + end end class TestImplicitLayout < SimpleRouteCase @@ -41,5 +50,10 @@ module ControllerLayouts assert_status 200 end - + class TestOverridingImplicitLayout < SimpleRouteCase + describe "overriding an implicit layout with render :layout option" + + get "/controller_layouts/implicit/override" + assert_body "Override! Hello world!" + end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index bc7203f294..647aa01628 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -3,12 +3,29 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module Render class BlankRenderController < ActionController::Base2 self.view_paths = [ActionView::Template::FixturePath.new( - "render/blank_render/index.html.erb" => "Hello world!" + "render/blank_render/index.html.erb" => "Hello world!", + "render/blank_render/access_request.html.erb" => "The request: <%= request.method.to_s.upcase %>", + "render/blank_render/access_action_name.html.erb" => "Action Name: <%= action_name %>", + "render/blank_render/access_controller_name.html.erb" => "Controller Name: <%= controller_name %>" )] def index render end + + def access_request + render :action => "access_request" + end + + def render_action_name + render :action => "access_action_name" + end + + private + + def secretz + render :text => "FAIL WHALE!" + end end class TestBlankRender < SimpleRouteCase @@ -36,13 +53,36 @@ module Render end end - class TestRenderObjectMethod < SimpleRouteCase - describe "Methods on Object are not actions" + class TestOnlyRenderPublicActions < SimpleRouteCase + describe "Only public methods on actual controllers are callable actions" - test "raises an exception" do + test "raises an exception when a method of Object is called" do assert_raises(AbstractController::ActionNotFound) do get "/render/blank_render/clone" end end + + test "raises an exception when a private method is called" do + assert_raises(AbstractController::ActionNotFound) do + get "/render/blank_render/secretz" + end + end + end + + class TestVariousObjectsAvailableInView < SimpleRouteCase + test "The request object is accessible in the view" do + get "/render/blank_render/access_request" + assert_body "The request: GET" + end + + test "The action_name is accessible in the view" do + get "/render/blank_render/render_action_name" + assert_body "Action Name: render_action_name" + end + + test "The controller_name is accessible in the view" do + get "/render/blank_render/access_controller_name" + assert_body "Controller Name: blank_render" + end end end \ No newline at end of file -- cgit v1.2.3 From b4903a8e34da77b96ea136ccd015c1634a8a5c2b Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 16:01:37 -0700 Subject: Modify new_base to use String action_names for back-compat --- actionpack/lib/action_controller/abstract/base.rb | 8 ++++---- actionpack/lib/action_controller/abstract/callbacks.rb | 4 ++-- actionpack/lib/action_controller/new_base/base.rb | 2 +- actionpack/test/abstract_controller/abstract_controller_test.rb | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 3b85ba5565..8a8e748c0e 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -21,7 +21,7 @@ module AbstractController end def process(action) - new.process(action) + new.process(action.to_s) end def hidden_actions @@ -31,11 +31,11 @@ module AbstractController def action_methods @action_methods ||= # All public instance methods of this class, including ancestors - public_instance_methods(true).map { |m| m.to_sym }.to_set - + public_instance_methods(true).map { |m| m.to_s }.to_set - # Except for public instance methods of Base and its ancestors - internal_methods.map { |m| m.to_sym } + + internal_methods.map { |m| m.to_s } + # Be sure to include shadowed public instance methods of this class - public_instance_methods(false).map { |m| m.to_sym } - + public_instance_methods(false).map { |m| m.to_s } - # And always exclude explicitly hidden actions hidden_actions end diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index c8b509081c..5f1607940a 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -14,11 +14,11 @@ module AbstractController module ClassMethods def _normalize_callback_options(options) if only = options[:only] - only = Array(only).map {|o| "action_name == :#{o}"}.join(" || ") + only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") + except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") options[:per_key] = {:unless => except} end end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 00d161289e..f663900944 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -42,7 +42,7 @@ module ActionController def call(env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new - process(@_request.parameters[:action].to_sym) + process(@_request.parameters[:action]) @_response.body = response_body @_response.prepare! self diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index cf6fb5140d..c283a7319d 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -203,7 +203,7 @@ module AbstractController private def respond_to_action?(action_name) - action_name != :fail + action_name.to_s != "fail" end end -- cgit v1.2.3 From 918b119bd3310c15dab4eb8a3317cc2a32503119 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 16:02:37 -0700 Subject: Add support for stripping "layouts/" from the layout name --- actionpack/lib/action_controller/abstract/layouts.rb | 3 +++ actionpack/lib/action_controller/new_base/compatibility.rb | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index f56b9dd914..eb3b73289d 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -57,6 +57,9 @@ module AbstractController def _layout() end # This will be overwritten + # :api: plugin + # ==== + # Override this to mutate the inbound layout name def _layout_for_name(name) unless [String, FalseClass, NilClass].include?(name.class) raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}" diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 8682493c8e..275a18abfd 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -8,5 +8,10 @@ module ActionController super end + def _layout_for_name(name) + name &&= name.sub(%r{^/?layouts/}, '') + super + end + end end \ No newline at end of file -- cgit v1.2.3 From b1d34b3aa42beaf6a9fb93f114aed8fe08ebd9db Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 16:03:46 -0700 Subject: Starting to get new_base to run on old tests --- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 3 + .../lib/action_controller/new_base/testing.rb | 23 +++ .../lib/action_controller/testing/process2.rb | 68 +++++++ actionpack/test/abstract_controller/test_helper.rb | 7 +- actionpack/test/abstract_unit2.rb | 210 +++++++++++++++++++++ actionpack/test/controller/render_test.rb | 2 +- actionpack/test/new_base/test_helper.rb | 2 + 8 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/testing.rb create mode 100644 actionpack/lib/action_controller/testing/process2.rb create mode 100644 actionpack/test/abstract_unit2.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index bfd8120e10..47621f0847 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -4,5 +4,6 @@ module ActionController autoload :Layouts, "action_controller/new_base/layouts" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Renderer, "action_controller/new_base/renderer" + autoload :Testing, "action_controller/new_base/testing" autoload :UrlFor, "action_controller/new_base/url_for" end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index f663900944..e24c494652 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -53,4 +53,7 @@ module ActionController @_response.to_a end end + + class Base < Http + end end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb new file mode 100644 index 0000000000..428f339b3d --- /dev/null +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -0,0 +1,23 @@ +module ActionController + module Testing + + # OMG MEGA HAX + def process_with_test(request, response) + @_request = request + @_response = response + ret = process(request.parameters[:action]) + @_response.body = self.response_body + set_test_assigns + ret + end + + def set_test_assigns + @assigns = {} + (instance_variable_names - self.class.protected_instance_variables).each do |var| + name, value = var[1..-1], instance_variable_get(var) + @assigns[name] = value + end + end + + end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb new file mode 100644 index 0000000000..7111733d0d --- /dev/null +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -0,0 +1,68 @@ +require "action_controller/testing/process" + +module ActionController + module TestProcess2 + + # Executes a request simulating GET HTTP method and set/volley the response + def get(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "GET") + end + + # Executes a request simulating POST HTTP method and set/volley the response + def post(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "POST") + end + + # Executes a request simulating PUT HTTP method and set/volley the response + def put(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "PUT") + end + + # Executes a request simulating DELETE HTTP method and set/volley the response + def delete(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "DELETE") + end + + # Executes a request simulating HEAD HTTP method and set/volley the response + def head(action, parameters = nil, session = nil, flash = nil) + process(action, parameters, session, flash, "HEAD") + end + + def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET') + # Sanity check for required instance variables so we can give an + # understandable error message. + %w(@controller @request @response).each do |iv_name| + if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil? + raise "#{iv_name} is nil: make sure you set it in your test's setup method." + end + end + + @request.recycle! + @response.recycle! + + @html_document = nil + @request.env['REQUEST_METHOD'] = http_method + + parameters ||= {} + @request.assign_parameters(@controller.class.controller_path, action.to_s, parameters) + + @request.session = ActionController::TestSession.new(session) unless session.nil? + @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash + build_request_uri(action, parameters) + + # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest + @controller.process_with_test(@request, @response) + end + + def build_request_uri(action, parameters) + unless @request.env['REQUEST_URI'] + options = @controller.__send__(:rewrite_options, parameters) + options.update(:only_path => true, :action => action) + + url = ActionController::UrlRewriter.new(@request, parameters) + @request.set_REQUEST_URI(url.rewrite(options)) + end + end + + end +end \ No newline at end of file diff --git a/actionpack/test/abstract_controller/test_helper.rb b/actionpack/test/abstract_controller/test_helper.rb index b9248c6bbd..a0375a0e99 100644 --- a/actionpack/test/abstract_controller/test_helper.rb +++ b/actionpack/test/abstract_controller/test_helper.rb @@ -2,9 +2,13 @@ $:.unshift(File.dirname(__FILE__) + '/../../lib') $:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/../lib') +require 'rubygems' require 'test/unit' -require 'active_support' +require 'active_support/core/all' require 'active_support/test_case' +require 'action_controller/abstract' +require 'action_controller/new_base/base' +require 'action_controller/new_base/renderer' require 'action_controller' require 'action_view/base' require 'fixture_template' @@ -17,7 +21,6 @@ rescue LoadError # Debugging disabled. `gem install ruby-debug` to enable. end -require 'action_controller/abstract' # require 'action_controller/abstract/base' # require 'action_controller/abstract/renderer' # require 'action_controller/abstract/layouts' diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb new file mode 100644 index 0000000000..c1e2631ac2 --- /dev/null +++ b/actionpack/test/abstract_unit2.rb @@ -0,0 +1,210 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib') +$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') +$:.unshift(File.dirname(__FILE__) + '/lib') + +# HAX +module ActionController + +end + +# TestCase +# include TestProcess2 + + +require 'test/unit' +require 'active_support' +require 'active_support/core/all' +require 'active_support/test_case' +require 'action_controller/abstract' +require 'action_controller/new_base' +require 'action_controller/new_base/base' +require 'action_controller/new_base/renderer' # HAX +require 'action_controller' +require 'fixture_template' +require 'action_view/test_case' + +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') + +module ActionController + autoload :TestProcess2, 'action_controller/testing/process2' + + class ActionControllerError < StandardError #:nodoc: + end + + class SessionRestoreError < ActionControllerError #:nodoc: + end + + class RenderError < ActionControllerError #:nodoc: + end + + class RoutingError < ActionControllerError #:nodoc: + attr_reader :failures + def initialize(message, failures=[]) + super(message) + @failures = failures + end + end + + class MethodNotAllowed < ActionControllerError #:nodoc: + attr_reader :allowed_methods + + def initialize(*allowed_methods) + super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.") + @allowed_methods = allowed_methods + end + + def allowed_methods_header + allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', ' + end + + def handle_response!(response) + response.headers['Allow'] ||= allowed_methods_header + end + end + + class NotImplemented < MethodNotAllowed #:nodoc: + end + + class UnknownController < ActionControllerError #:nodoc: + end + + class UnknownAction < ActionControllerError #:nodoc: + end + + class MissingFile < ActionControllerError #:nodoc: + end + + class RenderError < ActionControllerError #:nodoc: + end + + class SessionOverflowError < ActionControllerError #:nodoc: + DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.' + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + + class UnknownHttpMethod < ActionControllerError #:nodoc: + end + + class Base < Http + abstract! + # + cattr_accessor :relative_url_root + self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] + + cattr_reader :protected_instance_variables + # Controller specific instance variables which will not be accessible inside views. + @@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller + @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params + @_flash @_response) + # + + use AbstractController::Callbacks + use AbstractController::Helpers + use AbstractController::Logger + + use ActionController::HideActions + use ActionController::UrlFor + use ActionController::Renderer + use ActionController::Layouts + use ActionController::Rails2Compatibility + use ActionController::Testing + + def self.protect_from_forgery() end + + def self.inherited(klass) + ::ActionController::Base.subclasses << klass.to_s + super + end + + def self.subclasses + @subclasses ||= [] + end + + def self.app_loaded! + @subclasses.each do |subclass| + subclass.constantize._write_layout_method + end + end + + def render(action = action_name, options = {}) + if action.is_a?(Hash) + options, action = action, nil + else + options.merge! :action => action + end + + super(options) + end + + def render_to_body(options = {}) + options = {:template => options} if options.is_a?(String) + super + end + + def process_action + ret = super + render if response_body.nil? + ret + end + + def respond_to_action?(action_name) + super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) + end + end + + Base.view_paths = FIXTURE_LOAD_PATH + + class TestCase + include TestProcess2 + setup do + ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action/:id' + end + end + + def assert_template(options = {}, message = nil) + validate_response! + + clean_backtrace do + case options + when NilClass, String + hax = @controller._action_view.instance_variable_get(:@_rendered) + rendered = (hax[:template] || []).map { |t| t.identifier } + msg = build_message(message, + "expecting but rendering with ", + options, rendered.join(', ')) + assert_block(msg) do + if options.nil? + hax[:template].blank? + else + rendered.any? { |t| t.match(options) } + end + end + when Hash + if expected_partial = options[:partial] + partials = hax[:partials] + if expected_count = options[:count] + found = partials.detect { |p, _| p.identifier.match(expected_partial) } + actual_count = found.nil? ? 0 : found.second + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) + else + msg = build_message(message, + "expecting partial but action rendered ", + options[:partial], partials.keys) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) + end + else + assert hax[:partials].empty?, + "Expected no partials to be rendered" + end + end + end + end + end +end \ No newline at end of file diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index fb9b121fc9..1e69ca894f 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require ENV['new_base'] ? 'abstract_unit2' : 'abstract_unit' require 'controller/fake_models' require 'pathname' diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index d58b83cf7b..6a71bd29c4 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -5,6 +5,8 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') require 'test/unit' require 'active_support' require 'active_support/test_case' +require 'action_controller/new_base/base' +require 'action_controller/new_base/renderer' require 'action_controller' require 'action_view/base' require 'fixture_template' -- cgit v1.2.3 From e046f36824fcc164c284a13524c6b4153010a4e1 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 17:27:44 -0700 Subject: Renamed Base2 to Base and don't require old action_controller for new Base --- actionpack/lib/action_controller/new_base.rb | 17 ++++- actionpack/lib/action_controller/new_base/base.rb | 87 +++++++++++----------- .../action_controller/new_base/compatibility.rb | 21 ++++++ actionpack/lib/action_controller/new_base/http.rb | 56 ++++++++++++++ actionpack/lib/action_dispatch/middleware/stack.rb | 2 - actionpack/test/abstract_controller/test_helper.rb | 13 +--- actionpack/test/new_base/base_test.rb | 6 +- actionpack/test/new_base/content_type_test.rb | 6 +- actionpack/test/new_base/render_action_test.rb | 6 +- actionpack/test/new_base/render_template_test.rb | 4 +- actionpack/test/new_base/render_test.rb | 4 +- actionpack/test/new_base/render_text_test.rb | 6 +- actionpack/test/new_base/test_helper.rb | 70 +---------------- 13 files changed, 157 insertions(+), 141 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/http.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 47621f0847..b292fd579d 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,9 +1,22 @@ module ActionController + autoload :Base, "action_controller/new_base/base" autoload :HideActions, "action_controller/new_base/hide_actions" - autoload :Http, "action_controller/new_base/base" + autoload :Http, "action_controller/new_base/http" autoload :Layouts, "action_controller/new_base/layouts" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Renderer, "action_controller/new_base/renderer" autoload :Testing, "action_controller/new_base/testing" autoload :UrlFor, "action_controller/new_base/url_for" -end \ No newline at end of file + + # Ported modules + # require 'action_controller/routing' + autoload :Dispatcher, 'action_controller/dispatch/dispatcher' + autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes' + autoload :Resources, 'action_controller/routing/resources' + autoload :SessionManagement, 'action_controller/base/session_management' + + require 'action_controller/routing' +end + +require 'action_dispatch' +require 'action_view' \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index e24c494652..8af6ffbc92 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,59 +1,60 @@ module ActionController - class Http < AbstractController::Base + class Base < Http abstract! - # :api: public - attr_internal :request, :response, :params - - # :api: public - def self.controller_name - @controller_name ||= controller_path.split("/").last - end + use AbstractController::Callbacks + use AbstractController::Helpers + use AbstractController::Logger - # :api: public - def controller_name() self.class.controller_name end - - # :api: public - def self.controller_path - @controller_path ||= self.name.sub(/Controller$/, '').underscore - end + use ActionController::HideActions + use ActionController::UrlFor + use ActionController::Renderer + use ActionController::Layouts + + # Legacy modules + include SessionManagement - # :api: public - def controller_path() self.class.controller_path end + # Rails 2.x compatibility + use ActionController::Rails2Compatibility - # :api: private - def self.internal_methods - ActionController::Http.public_instance_methods(true) + def self.inherited(klass) + ::ActionController::Base.subclasses << klass.to_s + super end - # :api: private - def self.action_names() action_methods end + def self.subclasses + @subclasses ||= [] + end - # :api: private - def action_names() action_methods end + def self.app_loaded! + @subclasses.each do |subclass| + subclass.constantize._write_layout_method + end + end - # :api: plugin - def self.call(env) - controller = new - controller.call(env).to_rack + def render(action = action_name, options = {}) + if action.is_a?(Hash) + options, action = action, nil + else + options.merge! :action => action + end + + super(options) end - # :api: private - def call(env) - @_request = ActionDispatch::Request.new(env) - @_response = ActionDispatch::Response.new - process(@_request.parameters[:action]) - @_response.body = response_body - @_response.prepare! - self + def render_to_body(options = {}) + options = {:template => options} if options.is_a?(String) + super end - # :api: private - def to_rack - @_response.to_a + def process_action + ret = super + render if response_body.nil? + ret + end + + def respond_to_action?(action_name) + super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) end end - - class Base < Http - end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 275a18abfd..db471f7658 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -1,6 +1,27 @@ module ActionController module Rails2Compatibility + # Temporary hax + setup do + cattr_accessor :session_options + self.send(:class_variable_set, "@@session_options", {}) + + cattr_accessor :allow_concurrency + self.send(:class_variable_set, "@@allow_concurrency", false) + + cattr_accessor :param_parsers + self.send(:class_variable_set, "@@param_parsers", { Mime::MULTIPART_FORM => :multipart_form, + Mime::URL_ENCODED_FORM => :url_encoded_form, + Mime::XML => :xml_simple, + Mime::JSON => :json }) + + cattr_accessor :relative_url_root + self.send(:class_variable_set, "@@relative_url_root", ENV['RAILS_RELATIVE_URL_ROOT']) + + cattr_accessor :default_charset + self.send(:class_variable_set, "@@default_charset", "utf-8") + end + def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb new file mode 100644 index 0000000000..f663900944 --- /dev/null +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -0,0 +1,56 @@ +module ActionController + class Http < AbstractController::Base + abstract! + + # :api: public + attr_internal :request, :response, :params + + # :api: public + def self.controller_name + @controller_name ||= controller_path.split("/").last + end + + # :api: public + def controller_name() self.class.controller_name end + + # :api: public + def self.controller_path + @controller_path ||= self.name.sub(/Controller$/, '').underscore + end + + # :api: public + def controller_path() self.class.controller_path end + + # :api: private + def self.internal_methods + ActionController::Http.public_instance_methods(true) + end + + # :api: private + def self.action_names() action_methods end + + # :api: private + def action_names() action_methods end + + # :api: plugin + def self.call(env) + controller = new + controller.call(env).to_rack + end + + # :api: private + def call(env) + @_request = ActionDispatch::Request.new(env) + @_response = ActionDispatch::Response.new + process(@_request.parameters[:action]) + @_response.body = response_body + @_response.prepare! + self + end + + # :api: private + def to_rack + @_response.to_a + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index ee5f28d5cb..52abd69a42 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -34,8 +34,6 @@ module ActionDispatch else @klass.to_s.constantize end - rescue NameError - @klass end def active? diff --git a/actionpack/test/abstract_controller/test_helper.rb b/actionpack/test/abstract_controller/test_helper.rb index a0375a0e99..f0556e63e2 100644 --- a/actionpack/test/abstract_controller/test_helper.rb +++ b/actionpack/test/abstract_controller/test_helper.rb @@ -7,10 +7,7 @@ require 'test/unit' require 'active_support/core/all' require 'active_support/test_case' require 'action_controller/abstract' -require 'action_controller/new_base/base' -require 'action_controller/new_base/renderer' -require 'action_controller' -require 'action_view/base' +require 'action_view' require 'fixture_template' begin @@ -19,10 +16,4 @@ begin Debugger.start rescue LoadError # Debugging disabled. `gem install ruby-debug` to enable. -end - -# require 'action_controller/abstract/base' -# require 'action_controller/abstract/renderer' -# require 'action_controller/abstract/layouts' -# require 'action_controller/abstract/callbacks' -# require 'action_controller/abstract/helpers' \ No newline at end of file +end \ No newline at end of file diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb index 27d1a7f026..a32653f128 100644 --- a/actionpack/test/new_base/base_test.rb +++ b/actionpack/test/new_base/base_test.rb @@ -2,7 +2,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") # Tests the controller dispatching happy path module Dispatching - class SimpleController < ActionController::Base2 + class SimpleController < ActionController::Base def index render :text => "success" end @@ -69,9 +69,9 @@ module Dispatching end end - class EmptyController < ActionController::Base2 ; end + class EmptyController < ActionController::Base ; end module Submodule - class ContainedEmptyController < ActionController::Base2 ; end + class ContainedEmptyController < ActionController::Base ; end end class ControllerClassTests < Test::Unit::TestCase diff --git a/actionpack/test/new_base/content_type_test.rb b/actionpack/test/new_base/content_type_test.rb index 10a28da496..a5c04e9cb6 100644 --- a/actionpack/test/new_base/content_type_test.rb +++ b/actionpack/test/new_base/content_type_test.rb @@ -1,7 +1,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module ContentType - class BaseController < ActionController::Base2 + class BaseController < ActionController::Base def index render :text => "Hello world!" end @@ -40,7 +40,7 @@ module ContentType assert_header "Content-Type", "application/rss+xml; charset=utf-8" end - class ImpliedController < ActionController::Base2 + class ImpliedController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( "content_type/implied/i_am_html_erb.html.erb" => "Hello world!", "content_type/implied/i_am_xml_erb.xml.erb" => "Hello world!", @@ -81,7 +81,7 @@ module ContentType end module Charset - class BaseController < ActionController::Base2 + class BaseController < ActionController::Base def set_on_response_obj response.charset = "utf-16" render :text => "Hello world!" diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index 37b83fb681..348d70381b 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -3,7 +3,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module RenderAction # This has no layout and it works - class BasicController < ActionController::Base2 + class BasicController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( "render_action/basic/hello_world.html.erb" => "Hello world!" @@ -203,7 +203,7 @@ end module RenderActionWithControllerLayout - class BasicController < ActionController::Base2 + class BasicController < ActionController::Base self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( "render_action_with_controller_layout/basic/hello_world.html.erb" => "Hello World!", "layouts/render_action_with_controller_layout/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI" @@ -266,7 +266,7 @@ end module RenderActionWithBothLayouts - class BasicController < ActionController::Base2 + class BasicController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new({ "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!", "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI", diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index 63769df082..c09eeb1926 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -1,7 +1,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module RenderTemplate - class WithoutLayoutController < ActionController::Base2 + class WithoutLayoutController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", @@ -129,7 +129,7 @@ module RenderTemplate end module Compatibility - class WithoutLayoutController < ActionController::CompatibleBase2 + class WithoutLayoutController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica" diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index 647aa01628..b1867fdcc2 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -1,7 +1,7 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module Render - class BlankRenderController < ActionController::Base2 + class BlankRenderController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( "render/blank_render/index.html.erb" => "Hello world!", "render/blank_render/access_request.html.erb" => "The request: <%= request.method.to_s.upcase %>", @@ -36,7 +36,7 @@ module Render assert_status 200 end - class DoubleRenderController < ActionController::Base2 + class DoubleRenderController < ActionController::Base def index render :text => "hello" render :text => "world" diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index d97c2ca0a6..39f2f7abbf 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -1,10 +1,10 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") -class ApplicationController < ActionController::Base2 +class ApplicationController < ActionController::Base end module RenderText - class SimpleController < ActionController::Base2 + class SimpleController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new] def index @@ -146,4 +146,4 @@ module RenderText end end -ActionController::Base2.app_loaded! \ No newline at end of file +ActionController::Base.app_loaded! \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 6a71bd29c4..547eb1ef72 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -5,10 +5,7 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') require 'test/unit' require 'active_support' require 'active_support/test_case' -require 'action_controller/new_base/base' -require 'action_controller/new_base/renderer' -require 'action_controller' -require 'action_view/base' +require 'action_view' require 'fixture_template' begin @@ -34,67 +31,6 @@ module Rails end end -module ActionController - class Base2 < Http - abstract! - - use AbstractController::Callbacks - use AbstractController::Helpers - use AbstractController::Logger - - use ActionController::HideActions - use ActionController::UrlFor - use ActionController::Renderer - use ActionController::Layouts - - def self.inherited(klass) - ::ActionController::Base2.subclasses << klass.to_s - super - end - - def self.subclasses - @subclasses ||= [] - end - - def self.app_loaded! - @subclasses.each do |subclass| - subclass.constantize._write_layout_method - end - end - - def render(action = action_name, options = {}) - if action.is_a?(Hash) - options, action = action, nil - else - options.merge! :action => action - end - - super(options) - end - - def render_to_body(options = {}) - options = {:template => options} if options.is_a?(String) - super - end - - def process_action - ret = super - render if response_body.nil? - ret - end - - def respond_to_action?(action_name) - super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) - end - end - - class CompatibleBase2 < Base2 - abstract! - - use ActionController::Rails2Compatibility - end -end - # Temporary base class class Rack::TestCase < ActiveSupport::TestCase include Rack::Test::Methods @@ -103,7 +39,7 @@ class Rack::TestCase < ActiveSupport::TestCase ActionController::Base.session_options[:key] = "abc" ActionController::Base.session_options[:secret] = ("*" * 30) - controllers = ActionController::Base2.subclasses.map do |k| + controllers = ActionController::Base.subclasses.map do |k| k.underscore.sub(/_controller$/, '') end @@ -171,7 +107,7 @@ class Rack::TestCase < ActiveSupport::TestCase end -class ::ApplicationController < ActionController::Base2 +class ::ApplicationController < ActionController::Base end class SimpleRouteCase < Rack::TestCase -- cgit v1.2.3 From 7dd072d333040d2bb1197baa55fddfb9b72053bd Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 17:53:20 -0700 Subject: A few more tweaks to get new Base running old render tests again --- actionpack/lib/action_controller/new_base.rb | 8 ++++++-- actionpack/lib/action_controller/testing/process2.rb | 4 ++-- actionpack/test/abstract_unit2.rb | 15 ++------------- 3 files changed, 10 insertions(+), 17 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index b292fd579d..7098b812f6 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -10,10 +10,14 @@ module ActionController # Ported modules # require 'action_controller/routing' - autoload :Dispatcher, 'action_controller/dispatch/dispatcher' + autoload :Dispatcher, 'action_controller/dispatch/dispatcher' autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes' - autoload :Resources, 'action_controller/routing/resources' + autoload :RecordIdentifier, 'action_controller/record_identifier' + autoload :Resources, 'action_controller/routing/resources' autoload :SessionManagement, 'action_controller/base/session_management' + autoload :TestCase, 'action_controller/testing/test_case' + autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter' + autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 7111733d0d..d9af7add5f 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -1,7 +1,7 @@ require "action_controller/testing/process" module ActionController - module TestProcess2 + module TestProcess # Executes a request simulating GET HTTP method and set/volley the response def get(action, parameters = nil, session = nil, flash = nil) @@ -60,7 +60,7 @@ module ActionController options.update(:only_path => true, :action => action) url = ActionController::UrlRewriter.new(@request, parameters) - @request.set_REQUEST_URI(url.rewrite(options)) + @request.request_uri = url.rewrite(options) end end diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index c1e2631ac2..b95bfa0202 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -2,14 +2,6 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') $:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/lib') -# HAX -module ActionController - -end - -# TestCase -# include TestProcess2 - require 'test/unit' require 'active_support' @@ -17,16 +9,13 @@ require 'active_support/core/all' require 'active_support/test_case' require 'action_controller/abstract' require 'action_controller/new_base' -require 'action_controller/new_base/base' -require 'action_controller/new_base/renderer' # HAX -require 'action_controller' require 'fixture_template' +require 'action_controller/testing/process2' require 'action_view/test_case' FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') module ActionController - autoload :TestProcess2, 'action_controller/testing/process2' class ActionControllerError < StandardError #:nodoc: end @@ -158,7 +147,7 @@ module ActionController Base.view_paths = FIXTURE_LOAD_PATH class TestCase - include TestProcess2 + include TestProcess setup do ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' -- cgit v1.2.3 From ad2a1b5cb1afb0ea810cfdcac2ba1be95c55f1aa Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 1 May 2009 18:17:08 -0700 Subject: Get render :inline working --- actionpack/lib/action_controller/new_base/layouts.rb | 2 +- actionpack/lib/action_controller/new_base/renderer.rb | 4 ++++ actionpack/lib/action_controller/testing/process2.rb | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index a8e0809ac6..79abe40389 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -13,7 +13,7 @@ module ActionController # render :text => ..., :layout => ... # or # render :anything_else - if !options.key?(:text) || options.key?(:layout) + if (!options.key?(:text) && !options.key?(:inline)) || options.key?(:layout) options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index f21fd746b7..4c4a74979b 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -17,6 +17,10 @@ module ActionController if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(_text(options)) template = nil + 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, {}) + options[:_template] = template elsif options.key?(:template) options[:_template_name] = options[:template] elsif options.key?(:action) diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index d9af7add5f..67b5afb9c5 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -49,7 +49,7 @@ module ActionController @request.session = ActionController::TestSession.new(session) unless session.nil? @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash build_request_uri(action, parameters) - + @controller.params.merge!(parameters) # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest @controller.process_with_test(@request, @response) end -- cgit v1.2.3 From 72160d9f89481ea60c8268ff026099f07b1e5ed6 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sat, 2 May 2009 02:15:09 -0700 Subject: Implement FooController.action(:name) * Rails actions are now Rack endpoints, and can be retrieved via FooController.action(name) and called with an env * Updated some tests that relied on the old internal #process/#call implementation --- actionpack/lib/action_controller/base/base.rb | 27 ++++++--------- actionpack/lib/action_controller/new_base/http.rb | 13 +++++-- .../lib/action_controller/routing/route_set.rb | 2 +- .../lib/action_controller/testing/process.rb | 4 +++ actionpack/test/controller/filters_test.rb | 3 +- actionpack/test/controller/helper_test.rb | 40 +++++++++++++++------- actionpack/test/new_base/test_helper.rb | 2 +- 7 files changed, 57 insertions(+), 34 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 99b5963891..243b7f8ae3 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -370,18 +370,18 @@ module ActionController #:nodoc: attr_reader :template class << self - def call(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 - process(request, response) - end - - # Factory for the standard create, process loop where the controller is discarded after processing. - def process(request, response) #:nodoc: - new.process(request, response) + def action(name = nil) + @actions ||= {} + @actions[name] ||= proc do |env| + controller = new + # 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 + controller.action_name = name && name.to_s + controller.process(request, response).to_a + end end - + # Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController". def controller_class_name @controller_class_name ||= name.demodulize @@ -518,7 +518,6 @@ module ActionController #:nodoc: assign_shortcuts(request, response) initialize_template_class(response) initialize_current_url - assign_names log_processing send(method, *arguments) @@ -883,10 +882,6 @@ module ActionController #:nodoc: @performed_render || @performed_redirect end - def assign_names - @action_name = (params['action'] || 'index') - end - def reset_variables_added_to_assigns @template.instance_variable_set("@assigns_added", nil) end diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index f663900944..b7e3bfaa7e 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -39,13 +39,20 @@ module ActionController end # :api: private - def call(env) + def call(name, env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new - process(@_request.parameters[:action]) + process(name) @_response.body = response_body @_response.prepare! - self + to_rack + end + + def self.action(name) + @actions ||= {} + @actions[name] ||= proc do |env| + new.call(name, env) + end end # :api: private diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 70cd1f642d..45ad8a3a3b 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -430,7 +430,7 @@ module ActionController def call(env) request = ActionDispatch::Request.new(env) app = Routing::Routes.recognize(request) - app.call(env).to_a + app.action(request.parameters[:action] || 'index').call(env) end def recognize(request) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 8315a160ad..3aad94cc10 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -131,7 +131,11 @@ module ActionController #:nodoc: @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.request"] = @response + Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest + @controller.action_name = action.to_s @controller.process(@request, @response) end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 9e74538310..3b113131ae 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -602,8 +602,9 @@ class FilterTest < Test::Unit::TestCase 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.process(request, ActionController::TestResponse.new) + response = DynamicDispatchController.action.call(request.env).last assert_equal action, response.body end end diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 58addc123d..19cd5f4db2 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -101,20 +101,30 @@ class HelperTest < Test::Unit::TestCase assert master_helper_methods.include?('delegate_attr=') end - def test_helper_for_nested_controller + def call_controller(klass, action) request = ActionController::TestRequest.new - response = ActionController::TestResponse.new - request.action = 'render_hello_world' + request.env["action_controller.rescue.request"] = request + klass.action(action).call(request.env) + end - assert_equal 'hello: Iz guuut!', Fun::GamesController.process(request, response).body + 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 end def test_helper_for_acronym_controller - request = ActionController::TestRequest.new - response = ActionController::TestResponse.new - request.action = 'test' - - assert_equal 'test: baz', Fun::PdfController.process(request, response).body + assert_equal "test: baz", call_controller(Fun::PdfController, "test").last.body + # + # request = ActionController::TestRequest.new + # response = ActionController::TestResponse.new + # request.action = 'test' + # + # assert_equal 'test: baz', Fun::PdfController.process(request, response).body end def test_all_helpers @@ -204,6 +214,12 @@ class IsolatedHelpersTest < Test::Unit::TestCase end end + def call_controller(klass, action) + request = ActionController::TestRequest.new + request.env["action_controller.rescue.request"] = request + klass.action(action).call(request.env) + end + def setup @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @@ -211,14 +227,14 @@ class IsolatedHelpersTest < Test::Unit::TestCase end def test_helper_in_a - assert_raise(ActionView::TemplateError) { A.process(@request, @response) } + assert_raise(ActionView::TemplateError) { call_controller(A, "index") } end def test_helper_in_b - assert_equal 'B', B.process(@request, @response).body + assert_equal 'B', call_controller(B, "index").last.body end def test_helper_in_c - assert_equal 'C', C.process(@request, @response).body + assert_equal 'C', call_controller(C, "index").last.body end end diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 547eb1ef72..78662dc989 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -66,7 +66,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_body(body) - assert_equal body, last_response.body + assert_equal body, Array.wrap(last_response.body).join end def self.assert_body(body) -- cgit v1.2.3 From 3900f4007ee6463b8936af23c04017a900673866 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 2 May 2009 14:23:44 -0500 Subject: Deprecate assert_redirect_to's partial hash matching --- actionpack/lib/action_controller/base/base.rb | 1 - actionpack/lib/action_controller/base/redirect.rb | 4 ---- actionpack/lib/action_controller/testing/process.rb | 18 +++++++++--------- actionpack/lib/action_dispatch/http/response.rb | 2 -- .../lib/action_dispatch/testing/assertions/response.rb | 9 ++------- .../lib/action_dispatch/testing/test_response.rb | 6 ++++++ .../test/controller/action_pack_assertions_test.rb | 8 +++++--- actionpack/test/controller/redirect_test.rb | 6 ++++-- 8 files changed, 26 insertions(+), 28 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 99b5963891..ef97986c0e 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -820,7 +820,6 @@ module ActionController #:nodoc: @template = ActionView::Base.new(self.class.view_paths, {}, self, formats) response.template = @template if response.respond_to?(:template=) @template.helpers.send :include, self.class.master_helper_module - response.redirected_to = nil @performed_render = @performed_redirect = false end diff --git a/actionpack/lib/action_controller/base/redirect.rb b/actionpack/lib/action_controller/base/redirect.rb index 2e92117e7c..4849caac0a 100644 --- a/actionpack/lib/action_controller/base/redirect.rb +++ b/actionpack/lib/action_controller/base/redirect.rb @@ -48,8 +48,6 @@ module ActionController status = 302 end - response.redirected_to = options - case options # The scheme name consist of a letter followed by any combination of # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") @@ -82,8 +80,6 @@ module ActionController # The response body is not reset here, see +erase_render_results+ def erase_redirect_results #:nodoc: @performed_redirect = false - response.redirected_to = nil - response.redirected_to_method_params = nil response.status = DEFAULT_RENDER_STATUS_CODE response.headers.delete('Location') end diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 8315a160ad..f62d18a1f9 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -45,17 +45,16 @@ module ActionController #:nodoc: end end - # Integration test methods such as ActionController::Integration::Session#get - # and ActionController::Integration::Session#post return objects of class - # TestResponse, which represent the HTTP response results of the requested - # controller actions. - # - # See Response for more information on controller response objects. class TestResponse < ActionDispatch::TestResponse def recycle! - body_parts.clear - headers.delete('ETag') - headers.delete('Last-Modified') + @status = 200 + @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS) + @writer = lambda { |x| @body << x } + @block = nil + @length = 0 + @body = [] + + @request = @template = nil end end @@ -132,6 +131,7 @@ module ActionController #:nodoc: build_request_uri(action, parameters) Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest + @controller.process(@request, @response) end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 2b969323ca..2618e284fe 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -34,8 +34,6 @@ module ActionDispatch # :nodoc: DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request - attr_accessor :redirected_to, :redirected_to_method_params - attr_writer :header alias_method :headers=, :header= diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index a72ce9084f..92e3da580e 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -60,14 +60,9 @@ module ActionDispatch validate_request! assert_response(:redirect, message) - return true if options == @response.redirected_to + return true if options == @response.location - # Support partial arguments for hash redirections - if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash) - return true if options.all? {|(key, value)| @response.redirected_to[key] == value} - end - - redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to) + redirected_to_after_normalisation = normalize_argument_to_redirection(@response.location) options_after_normalisation = normalize_argument_to_redirection(options) if redirected_to_after_normalisation != options_after_normalisation diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 50c6d85828..c5464f1559 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -1,4 +1,10 @@ module ActionDispatch + # Integration test methods such as ActionController::Integration::Session#get + # and ActionController::Integration::Session#post return objects of class + # TestResponse, which represent the HTTP response results of the requested + # controller actions. + # + # See Response for more information on controller response objects. class TestResponse < Response def self.from_response(response) new.tap do |resp| diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 711640f9a9..60957a2f0e 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -514,9 +514,11 @@ class ActionPackHeaderTest < ActionController::TestCase end def test_rendering_xml_respects_content_type - @response.headers['type'] = 'application/pdf' - process :hello_xml_world - assert_equal('application/pdf; charset=utf-8', @response.headers['Content-Type']) + pending do + @response.headers['type'] = 'application/pdf' + process :hello_xml_world + assert_equal('application/pdf; charset=utf-8', @response.headers['Content-Type']) + end end def test_render_text_with_custom_content_type diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 91e21db854..9ad63a1c60 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -234,8 +234,10 @@ class RedirectTest < ActionController::TestCase end def test_redirect_with_partial_params - get :module_redirect - assert_redirected_to :action => 'hello_world' + pending do + get :module_redirect + assert_redirected_to :action => 'hello_world' + end end def test_redirect_to_nil -- cgit v1.2.3 From a8b75c480fc9774252f5976dcf1a614079822e56 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 2 May 2009 14:57:40 -0500 Subject: Functional test runner finalizes response just like the integration test runner. In both runners, the @response object will now behave the same. Some functional tests will need to be updated if they are relying on preprocessed data on the response. --- .../lib/action_controller/testing/process.rb | 5 ++- actionpack/lib/action_dispatch/http/response.rb | 2 +- .../lib/action_dispatch/testing/test_response.rb | 18 ++++------ actionpack/test/controller/cookie_test.rb | 17 +++++---- actionpack/test/controller/render_test.rb | 22 ++++++------ actionpack/test/controller/send_file_test.rb | 8 ++--- actionpack/test/controller/test_test.rb | 4 ++- actionpack/test/template/body_parts_test.rb | 6 +++- actionpack/test/template/output_buffer_test.rb | 42 ++++++++++++---------- 9 files changed, 66 insertions(+), 58 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index f62d18a1f9..b44ec2f94b 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -132,7 +132,10 @@ module ActionController #:nodoc: Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest - @controller.process(@request, @response) + response = Rack::MockResponse.new(*@controller.process(@request, ActionDispatch::Response.new).to_a) + @response.request, @response.template = @request, @controller.template + @response.status, @response.headers, @response.body = response.status, response.headers, response.body + @response end def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 2618e284fe..133b4f7335 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -185,7 +185,7 @@ module ActionDispatch # :nodoc: @writer = lambda { |x| callback.call(x) } @body.call(self, self) else - @body.each(&callback) + @body.each { |part| callback.call(part.to_s) } end @writer = callback diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index c5464f1559..c35982e075 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -93,6 +93,12 @@ module ActionDispatch ActiveSupport::Deprecation.warn("response.has_template_object? has been deprecated. Use tempate.assigns[name].nil? instead", caller) !template_objects[name].nil? end + + # Returns binary content (downloadable file), converted to a String + def binary_content + ActiveSupport::Deprecation.warn("response.binary_content has been deprecated. Use response.body instead", caller) + body + end end include DeprecatedHelpers @@ -121,17 +127,5 @@ module ActionDispatch def client_error? (400..499).include?(response_code) end - - # Returns binary content (downloadable file), converted to a String - def binary_content - raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc) - require 'stringio' - - sio = StringIO.new - body_parts.call(self, sio) - - sio.rewind - sio.read - end end end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index c861982698..0f22714071 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -54,39 +54,38 @@ class CookieTest < ActionController::TestCase def test_setting_cookie get :authenticate - assert_equal ["user_name=david; path=/"], @response.headers["Set-Cookie"] + assert_equal "user_name=david; path=/", @response.headers["Set-Cookie"] 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_equal "that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/", @response.headers["Set-Cookie"] 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_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", @response.headers["Set-Cookie"] 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_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", @response.headers["Set-Cookie"] 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_equal "user_name=david; path=/; HttpOnly", @response.headers["Set-Cookie"] 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", @response.headers["Set-Cookie"][0] - assert_equal "login=XJ-122; path=/", @response.headers["Set-Cookie"][1] + assert_equal "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT\nlogin=XJ-122; path=/", @response.headers["Set-Cookie"] assert_equal({"login" => "XJ-122", "user_name" => "david"}, @response.cookies) end @@ -96,7 +95,7 @@ class CookieTest < ActionController::TestCase 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_equal "user_name=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT", @response.headers["Set-Cookie"] assert_equal({"user_name" => nil}, @response.cookies) end @@ -117,6 +116,6 @@ class CookieTest < ActionController::TestCase 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_equal "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT", @response.headers["Set-Cookie"] end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 023bf0eeaa..dd2dd7a502 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1293,15 +1293,15 @@ class RenderTest < ActionController::TestCase def test_head_with_symbolic_status get :head_with_symbolic_status, :status => "ok" - assert_equal "200 OK", @response.status + assert_equal 200, @response.status assert_response :ok get :head_with_symbolic_status, :status => "not_found" - assert_equal "404 Not Found", @response.status + assert_equal 404, @response.status assert_response :not_found get :head_with_symbolic_status, :status => "no_content" - assert_equal "204 No Content", @response.status + assert_equal 204, @response.status assert !@response.headers.include?('Content-Length') assert_response :no_content @@ -1322,7 +1322,7 @@ class RenderTest < ActionController::TestCase def test_head_with_string_status get :head_with_string_status, :status => "404 Eat Dirt" assert_equal 404, @response.response_code - assert_equal "Eat Dirt", @response.message + assert_equal "Not Found", @response.message assert_response :not_found end @@ -1590,7 +1590,7 @@ class EtagRenderTest < ActionController::TestCase def test_render_against_etag_request_should_304_when_match @request.if_none_match = etag_for("hello david") get :render_hello_world_from_variable - assert_equal "304 Not Modified", @response.status + assert_equal 304, @response.status assert @response.body.empty? end @@ -1603,13 +1603,13 @@ class EtagRenderTest < ActionController::TestCase def test_render_against_etag_request_should_200_when_no_match @request.if_none_match = etag_for("hello somewhere else") get :render_hello_world_from_variable - assert_equal "200 OK", @response.status + assert_equal 200, @response.status assert !@response.body.empty? end def test_render_should_not_set_etag_when_last_modified_has_been_specified get :render_hello_world_with_last_modified_set - assert_equal "200 OK", @response.status + assert_equal 200, @response.status assert_not_nil @response.last_modified assert_nil @response.etag assert @response.body.present? @@ -1623,11 +1623,11 @@ class EtagRenderTest < ActionController::TestCase @request.if_none_match = expected_etag get :render_hello_world_from_variable - assert_equal "304 Not Modified", @response.status + assert_equal 304, @response.status @request.if_none_match = "\"diftag\"" get :render_hello_world_from_variable - assert_equal "200 OK", @response.status + assert_equal 200, @response.status end def render_with_404_shouldnt_have_etag @@ -1695,7 +1695,7 @@ class LastModifiedRenderTest < ActionController::TestCase def test_request_not_modified @request.if_modified_since = @last_modified get :conditional_hello - assert_equal "304 Not Modified", @response.status + assert_equal 304, @response.status assert @response.body.blank?, @response.body assert_equal @last_modified, @response.headers['Last-Modified'] end @@ -1710,7 +1710,7 @@ class LastModifiedRenderTest < ActionController::TestCase def test_request_modified @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT' get :conditional_hello - assert_equal "200 OK", @response.status + assert_equal 200, @response.status assert !@response.body.blank? assert_equal @last_modified, @response.headers['Last-Modified'] end diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 2e14a0a32c..6007ebef7a 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -44,12 +44,12 @@ class SendFileTest < ActionController::TestCase response = nil assert_nothing_raised { response = process('file') } assert_not_nil response - assert_kind_of Proc, response.body_parts + assert_kind_of Array, response.body_parts require 'stringio' output = StringIO.new output.binmode - assert_nothing_raised { response.body_parts.call(response, output) } + assert_nothing_raised { response.body_parts.each { |part| output << part.to_s } } assert_equal file_data, output.string end @@ -149,13 +149,13 @@ class SendFileTest < ActionController::TestCase define_method "test_send_#{method}_status" do @controller.options = { :stream => false, :status => 500 } assert_nothing_raised { assert_not_nil process(method) } - assert_equal '500 Internal Server Error', @response.status + assert_equal 500, @response.status end define_method "test_default_send_#{method}_status" do @controller.options = { :stream => false } assert_nothing_raised { assert_not_nil process(method) } - assert_equal ActionController::DEFAULT_RENDER_STATUS_CODE, @response.status + assert_equal 200, @response.status end end end diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 919f9815ec..9e88188b9a 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -614,7 +614,9 @@ XML def test_binary_content_works_with_send_file get :test_send_file - assert_nothing_raised(NoMethodError) { @response.binary_content } + assert_deprecated do + assert_nothing_raised(NoMethodError) { @response.binary_content } + end end protected diff --git a/actionpack/test/template/body_parts_test.rb b/actionpack/test/template/body_parts_test.rb index 5be8533293..e17092a452 100644 --- a/actionpack/test/template/body_parts_test.rb +++ b/actionpack/test/template/body_parts_test.rb @@ -16,7 +16,11 @@ class BodyPartsTest < ActionController::TestCase def test_body_parts get :index - assert_equal RENDERINGS, @response.body_parts + pending do + # TestProcess buffers body_parts into body + # TODO: Rewrite test w/o going through process + assert_equal RENDERINGS, @response.body_parts + end assert_equal RENDERINGS.join, @response.body end end diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index bc17f36783..3faea64db3 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -10,26 +10,32 @@ class OutputBufferTest < ActionController::TestCase tests TestController def test_flush_output_buffer - # Start with the default body parts - get :index - assert_equal ['foo'], @response.body_parts - assert_nil @controller.template.output_buffer + pending do + # TODO: This tests needs to be rewritten due + # The @response is not the same response object assigned + # to the @controller.template - # Nil output buffer is skipped - @controller.template.flush_output_buffer - assert_nil @controller.template.output_buffer - assert_equal ['foo'], @response.body_parts + # Start with the default body parts + get :index + assert_equal ['foo'], @response.body_parts + assert_nil @controller.template.output_buffer - # Empty output buffer is skipped - @controller.template.output_buffer = '' - @controller.template.flush_output_buffer - assert_equal '', @controller.template.output_buffer - assert_equal ['foo'], @response.body_parts + # Nil output buffer is skipped + @controller.template.flush_output_buffer + assert_nil @controller.template.output_buffer + assert_equal ['foo'], @response.body_parts - # Flushing appends the output buffer to the body parts - @controller.template.output_buffer = 'bar' - @controller.template.flush_output_buffer - assert_equal '', @controller.template.output_buffer - assert_equal ['foo', 'bar'], @response.body_parts + # Empty output buffer is skipped + @controller.template.output_buffer = '' + @controller.template.flush_output_buffer + assert_equal '', @controller.template.output_buffer + assert_equal ['foo'], @response.body_parts + + # Flushing appends the output buffer to the body parts + @controller.template.output_buffer = 'bar' + @controller.template.flush_output_buffer + assert_equal '', @controller.template.output_buffer + assert_equal ['foo', 'bar'], @response.body_parts + end end end -- cgit v1.2.3 From f32cf44870549c6cc5b6e6c84cffc1facf6ec38e Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 2 May 2009 15:29:18 -0500 Subject: Switch functional tests to run through the rack interface instead of process --- actionpack/lib/action_controller/base/base.rb | 12 ++++++++---- actionpack/lib/action_controller/dispatch/dispatcher.rb | 2 +- actionpack/lib/action_controller/dispatch/rescue.rb | 2 +- actionpack/lib/action_controller/routing/route_set.rb | 2 +- actionpack/lib/action_controller/testing/process.rb | 13 +++++++++++-- actionpack/lib/action_dispatch/testing/test_request.rb | 5 +++++ actionpack/test/controller/caching_test.rb | 2 +- 7 files changed, 28 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index ef97986c0e..eb65f59ddd 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -371,10 +371,7 @@ module ActionController #:nodoc: class << self def call(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 - process(request, response) + new.call(env) end # Factory for the standard create, process loop where the controller is discarded after processing. @@ -511,6 +508,13 @@ module ActionController #:nodoc: end public + def call(env) + # HACK: For global rescue to have access to the original request and response + request = env["action_dispatch.rescue.request"] ||= ActionDispatch::Request.new(env) + response = env["action_dispatch.rescue.response"] ||= ActionDispatch::Response.new + process(request, response).to_a + end + # Extracts the action_name from the request parameters and performs that action. def process(request, response, method = :perform_action, *arguments) #:nodoc: response.request = request diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index bb9d8bd063..25844bf2a2 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -80,7 +80,7 @@ module ActionController Routing::Routes.call(env) rescue Exception => exception if controller ||= (::ApplicationController rescue Base) - controller.call_with_exception(env, exception).to_a + controller.call_with_exception(env, exception) else raise exception end diff --git a/actionpack/lib/action_controller/dispatch/rescue.rb b/actionpack/lib/action_controller/dispatch/rescue.rb index df80ac0909..2f3b40c231 100644 --- a/actionpack/lib/action_controller/dispatch/rescue.rb +++ b/actionpack/lib/action_controller/dispatch/rescue.rb @@ -62,7 +62,7 @@ module ActionController #:nodoc: def call_with_exception(env, exception) #:nodoc: request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env) response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new - new.process(request, response, :rescue_action, exception) + new.process(request, response, :rescue_action, exception).to_a end end diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 70cd1f642d..172b867bf0 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -430,7 +430,7 @@ module ActionController def call(env) request = ActionDispatch::Request.new(env) app = Routing::Routes.recognize(request) - app.call(env).to_a + app.call(env) end def recognize(request) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index b44ec2f94b..49e8322491 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -35,12 +35,13 @@ module ActionController #:nodoc: end data = params.to_query - @env['CONTENT_LENGTH'] = data.length + @env['CONTENT_LENGTH'] = data.length.to_s @env['rack.input'] = StringIO.new(data) end def recycle! @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'] = {} end end @@ -132,7 +133,15 @@ module ActionController #:nodoc: Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest - response = Rack::MockResponse.new(*@controller.process(@request, ActionDispatch::Response.new).to_a) + env = @request.env + app = @controller + + # TODO: Enable Lint + # app = Rack::Lint.new(app) + + status, headers, body = app.call(env) + response = Rack::MockResponse.new(status, headers, body) + @response.request, @response.template = @request, @controller.template @response.status, @response.headers, @response.body = response.status, response.headers, response.body @response diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index 5d8cd7e619..20288aa7a5 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -16,6 +16,7 @@ module ActionDispatch def env write_cookies! + delete_nil_values! super end @@ -74,5 +75,9 @@ module ActionDispatch @env['HTTP_COOKIE'] = @cookies.map { |name, value| "#{name}=#{value};" }.join(' ') end end + + def delete_nil_values! + @env.delete_if { |k, v| v.nil? } + end end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 10b904481d..6b9d1056a3 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -111,7 +111,7 @@ class PageCachingTest < ActionController::TestCase end def test_should_cache_ok_at_custom_path - @request.stubs(:path).returns("/index.html") + @request.request_uri = "/index.html" get :ok assert_response :ok assert File.exist?("#{FILE_STORE_PATH}/index.html") -- cgit v1.2.3 From 24affdc88c4a4af03ce1ec5b23c3def18b90effe Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 2 May 2009 15:37:29 -0500 Subject: Deprecate Controller.process interface --- actionpack/lib/action_controller/base/base.rb | 1 + actionpack/test/controller/filters_test.rb | 2 +- actionpack/test/controller/helper_test.rb | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index eb65f59ddd..60567454b1 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -376,6 +376,7 @@ module ActionController #:nodoc: # Factory for the standard create, process loop where the controller is discarded after processing. def process(request, response) #:nodoc: + ActiveSupport::Deprecation.warn("Controller.process has been deprecated. Use Controller.call instead", caller) new.process(request, response) end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 9e74538310..5876f55420 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -603,7 +603,7 @@ class FilterTest < Test::Unit::TestCase %w(foo bar baz).each do |action| request = ActionController::TestRequest.new request.query_parameters[:choose] = action - response = DynamicDispatchController.process(request, ActionController::TestResponse.new) + response = Rack::MockResponse.new(*DynamicDispatchController.call(request.env)) assert_equal action, response.body end end diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 58addc123d..e72bce1791 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -102,19 +102,19 @@ class HelperTest < Test::Unit::TestCase end def test_helper_for_nested_controller - request = ActionController::TestRequest.new - response = ActionController::TestResponse.new + request = ActionController::TestRequest.new request.action = 'render_hello_world' - assert_equal 'hello: Iz guuut!', Fun::GamesController.process(request, response).body + response = Rack::MockResponse.new(*Fun::GamesController.call(request.env)) + assert_equal 'hello: Iz guuut!', response.body end def test_helper_for_acronym_controller - request = ActionController::TestRequest.new - response = ActionController::TestResponse.new + request = ActionController::TestRequest.new request.action = 'test' - assert_equal 'test: baz', Fun::PdfController.process(request, response).body + response = Rack::MockResponse.new(*Fun::PdfController.call(request.env)) + assert_equal 'test: baz', response.body end def test_all_helpers @@ -211,14 +211,16 @@ class IsolatedHelpersTest < Test::Unit::TestCase end def test_helper_in_a - assert_raise(ActionView::TemplateError) { A.process(@request, @response) } + assert_raise(ActionView::TemplateError) { A.call(@request.env) } end def test_helper_in_b - assert_equal 'B', B.process(@request, @response).body + response = Rack::MockResponse.new(*B.call(@request.env)) + assert_equal 'B', response.body end def test_helper_in_c - assert_equal 'C', C.process(@request, @response).body + response = Rack::MockResponse.new(*C.call(@request.env)) + assert_equal 'C', response.body end end -- cgit v1.2.3 From 1c6fcbfd2d67ce2b2faa29d956566b48e9a61188 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 2 May 2009 15:30:00 -0700 Subject: Fix implicit ordering expectation --- actionpack/test/dispatch/test_request_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index 19b5e2988b..5da02b2ea6 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -40,6 +40,6 @@ class TestRequestTest < ActiveSupport::TestCase req.cookies["login"] = "XJ-122" assert_equal({"user_name" => "david", "login" => "XJ-122"}, req.cookies) - assert_equal "login=XJ-122; user_name=david;", req.env["HTTP_COOKIE"] + assert_equal %w(login=XJ-122 user_name=david), req.env["HTTP_COOKIE"].split(/; ?/).sort end end -- cgit v1.2.3 From 9047c9809deeb1aaa3735472287265720e5cd37f Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 2 May 2009 15:30:00 -0700 Subject: Fix implicit ordering expectation --- actionpack/test/dispatch/test_request_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index 19b5e2988b..5da02b2ea6 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -40,6 +40,6 @@ class TestRequestTest < ActiveSupport::TestCase req.cookies["login"] = "XJ-122" assert_equal({"user_name" => "david", "login" => "XJ-122"}, req.cookies) - assert_equal "login=XJ-122; user_name=david;", req.env["HTTP_COOKIE"] + assert_equal %w(login=XJ-122 user_name=david), req.env["HTTP_COOKIE"].split(/; ?/).sort end end -- cgit v1.2.3 From 11af089cee0a0e744e267d32becfe2c66a586d31 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 2 May 2009 23:02:22 -0500 Subject: Extract ActionController rescue templates into Rescue and ShowExceptions middleware. This commit breaks all exception catching plugins like ExceptionNotifier. These plugins should be rewritten as middleware instead overriding Controller#rescue_action_in_public. --- actionpack/lib/action_controller.rb | 2 +- actionpack/lib/action_controller/base/base.rb | 9 +- actionpack/lib/action_controller/base/rescue.rb | 50 +++ .../lib/action_controller/dispatch/dispatcher.rb | 16 +- .../lib/action_controller/dispatch/middlewares.rb | 5 + .../lib/action_controller/dispatch/rescue.rb | 185 ----------- .../templates/rescues/_request_and_response.erb | 24 -- .../dispatch/templates/rescues/_trace.erb | 26 -- .../dispatch/templates/rescues/diagnostics.erb | 10 - .../dispatch/templates/rescues/layout.erb | 29 -- .../templates/rescues/missing_template.erb | 2 - .../dispatch/templates/rescues/routing_error.erb | 10 - .../dispatch/templates/rescues/template_error.erb | 21 -- .../dispatch/templates/rescues/unknown_action.erb | 2 - actionpack/lib/action_dispatch.rb | 2 + .../lib/action_dispatch/middleware/rescue.rb | 14 + .../action_dispatch/middleware/show_exceptions.rb | 142 +++++++++ .../templates/rescues/_request_and_response.erb | 24 ++ .../middleware/templates/rescues/_trace.erb | 26 ++ .../middleware/templates/rescues/diagnostics.erb | 10 + .../middleware/templates/rescues/layout.erb | 29 ++ .../templates/rescues/missing_template.erb | 2 + .../middleware/templates/rescues/routing_error.erb | 10 + .../templates/rescues/template_error.erb | 21 ++ .../templates/rescues/unknown_action.erb | 2 + .../action_dispatch/testing/assertions/response.rb | 8 +- .../test/controller/action_pack_assertions_test.rb | 2 +- actionpack/test/controller/base_test.rb | 9 +- actionpack/test/controller/caching_test.rb | 3 + .../deprecation/deprecated_base_methods_test.rb | 6 - actionpack/test/controller/dispatcher_test.rb | 13 - actionpack/test/controller/filters_test.rb | 5 + actionpack/test/controller/layout_test.rb | 3 +- actionpack/test/controller/rescue_test.rb | 346 +++------------------ actionpack/test/dispatch/show_exceptions_test.rb | 103 ++++++ 35 files changed, 509 insertions(+), 662 deletions(-) create mode 100644 actionpack/lib/action_controller/base/rescue.rb delete mode 100644 actionpack/lib/action_controller/dispatch/rescue.rb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb delete mode 100644 actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb create mode 100644 actionpack/lib/action_dispatch/middleware/rescue.rb create mode 100644 actionpack/lib/action_dispatch/middleware/show_exceptions.rb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb create mode 100644 actionpack/test/dispatch/show_exceptions_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index aee6b9dc9f..ab78bc9222 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -60,7 +60,7 @@ module ActionController autoload :Redirector, 'action_controller/base/redirect' autoload :Renderer, 'action_controller/base/render' autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection' - autoload :Rescue, 'action_controller/dispatch/rescue' + autoload :Rescue, 'action_controller/base/rescue' autoload :Resources, 'action_controller/routing/resources' autoload :Responder, 'action_controller/base/responder' autoload :Routing, 'action_controller/routing' diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 60567454b1..7bbde519cc 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -30,10 +30,6 @@ module ActionController #:nodoc: def allowed_methods_header allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', ' end - - def handle_response!(response) - response.headers['Allow'] ||= allowed_methods_header - end end class NotImplemented < MethodNotAllowed #:nodoc: @@ -510,9 +506,8 @@ module ActionController #:nodoc: public def call(env) - # HACK: For global rescue to have access to the original request and response - request = env["action_dispatch.rescue.request"] ||= ActionDispatch::Request.new(env) - response = env["action_dispatch.rescue.response"] ||= ActionDispatch::Response.new + request = ActionDispatch::Request.new(env) + response = ActionDispatch::Response.new process(request, response).to_a end diff --git a/actionpack/lib/action_controller/base/rescue.rb b/actionpack/lib/action_controller/base/rescue.rb new file mode 100644 index 0000000000..2717a06a37 --- /dev/null +++ b/actionpack/lib/action_controller/base/rescue.rb @@ -0,0 +1,50 @@ +module ActionController #:nodoc: + # Actions that fail to perform as expected throw exceptions. These + # exceptions can either be rescued for the public view (with a nice + # user-friendly explanation) or for the developers view (with tons of + # debugging information). The developers view is already implemented by + # the Action Controller, but the public view should be tailored to your + # specific application. + # + # The default behavior for public exceptions is to render a static html + # file with the name of the error code thrown. If no such file exists, an + # empty response is sent with the correct status code. + # + # You can override what constitutes a local request by overriding the + # local_request? method in your own controller. Custom rescue + # behavior is achieved by overriding the rescue_action_in_public + # and rescue_action_locally methods. + module Rescue + def self.included(base) #:nodoc: + base.send :include, ActiveSupport::Rescuable + base.extend(ClassMethods) + + base.class_eval do + alias_method_chain :perform_action, :rescue + end + end + + module ClassMethods + def rescue_action(env) + exception = env.delete('action_dispatch.rescue.exception') + request = ActionDispatch::Request.new(env) + response = ActionDispatch::Response.new + new.process(request, response, :rescue_action, exception).to_a + end + end + + protected + # Exception handler called when the performance of an action raises + # an exception. + def rescue_action(exception) + rescue_with_handler(exception) || raise(exception) + end + + private + def perform_action_with_rescue + perform_action_without_rescue + rescue Exception => exception + rescue_action(exception) + end + end +end diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index 25844bf2a2..c0eb359547 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -75,18 +75,10 @@ module ActionController end def _call(env) - begin - run_callbacks :before_dispatch - Routing::Routes.call(env) - rescue Exception => exception - if controller ||= (::ApplicationController rescue Base) - controller.call_with_exception(env, exception) - else - raise exception - end - ensure - run_callbacks :after_dispatch, :enumerator => :reverse_each - end + run_callbacks :before_dispatch + Routing::Routes.call(env) + ensure + run_callbacks :after_dispatch, :enumerator => :reverse_each end def flush_logger diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index b5adbae746..31a7b00d28 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -3,6 +3,11 @@ use "Rack::Lock", :if => lambda { } use "ActionDispatch::Failsafe" +use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local } +use "ActionDispatch::Rescue", lambda { + controller = (::ApplicationController rescue ActionController::Base) + controller.method(:rescue_action) +} use lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options } diff --git a/actionpack/lib/action_controller/dispatch/rescue.rb b/actionpack/lib/action_controller/dispatch/rescue.rb deleted file mode 100644 index 2f3b40c231..0000000000 --- a/actionpack/lib/action_controller/dispatch/rescue.rb +++ /dev/null @@ -1,185 +0,0 @@ -module ActionController #:nodoc: - # Actions that fail to perform as expected throw exceptions. These - # exceptions can either be rescued for the public view (with a nice - # user-friendly explanation) or for the developers view (with tons of - # debugging information). The developers view is already implemented by - # the Action Controller, but the public view should be tailored to your - # specific application. - # - # The default behavior for public exceptions is to render a static html - # file with the name of the error code thrown. If no such file exists, an - # empty response is sent with the correct status code. - # - # You can override what constitutes a local request by overriding the - # local_request? method in your own controller. Custom rescue - # behavior is achieved by overriding the rescue_action_in_public - # and rescue_action_locally methods. - module Rescue - LOCALHOST = '127.0.0.1'.freeze - - DEFAULT_RESCUE_RESPONSE = :internal_server_error - DEFAULT_RESCUE_RESPONSES = { - 'ActionController::RoutingError' => :not_found, - 'ActionController::UnknownAction' => :not_found, - 'ActiveRecord::RecordNotFound' => :not_found, - 'ActiveRecord::StaleObjectError' => :conflict, - 'ActiveRecord::RecordInvalid' => :unprocessable_entity, - 'ActiveRecord::RecordNotSaved' => :unprocessable_entity, - 'ActionController::MethodNotAllowed' => :method_not_allowed, - 'ActionController::NotImplemented' => :not_implemented, - 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity - } - - DEFAULT_RESCUE_TEMPLATE = 'diagnostics' - DEFAULT_RESCUE_TEMPLATES = { - 'ActionView::MissingTemplate' => 'missing_template', - 'ActionController::RoutingError' => 'routing_error', - 'ActionController::UnknownAction' => 'unknown_action', - 'ActionView::TemplateError' => 'template_error' - } - - RESCUES_TEMPLATE_PATH = ActionView::Template::FileSystemPath.new( - File.join(File.dirname(__FILE__), "templates")) - - def self.included(base) #:nodoc: - base.cattr_accessor :rescue_responses - base.rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE) - base.rescue_responses.update DEFAULT_RESCUE_RESPONSES - - base.cattr_accessor :rescue_templates - base.rescue_templates = Hash.new(DEFAULT_RESCUE_TEMPLATE) - base.rescue_templates.update DEFAULT_RESCUE_TEMPLATES - - base.extend(ClassMethods) - base.send :include, ActiveSupport::Rescuable - - base.class_eval do - alias_method_chain :perform_action, :rescue - end - end - - module ClassMethods - def call_with_exception(env, exception) #:nodoc: - request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env) - response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new - new.process(request, response, :rescue_action, exception).to_a - end - end - - protected - # Exception handler called when the performance of an action raises - # an exception. - def rescue_action(exception) - rescue_with_handler(exception) || - rescue_action_without_handler(exception) - end - - # Overwrite to implement custom logging of errors. By default - # logs as fatal. - def log_error(exception) #:doc: - ActiveSupport::Deprecation.silence do - if ActionView::TemplateError === exception - logger.fatal(exception.to_s) - else - logger.fatal( - "\n#{exception.class} (#{exception.message}):\n " + - clean_backtrace(exception).join("\n ") + "\n\n" - ) - end - end - end - - # Overwrite to implement public exception handling (for requests - # answering false to local_request?). By default will call - # render_optional_error_file. Override this method to provide more - # user friendly error messages. - def rescue_action_in_public(exception) #:doc: - render_optional_error_file response_code_for_rescue(exception) - end - - # Attempts to render a static error page based on the - # status_code thrown, or just return headers if no such file - # exists. At first, it will try to render a localized static page. - # For example, if a 500 error is being handled Rails and locale is :da, - # it will first attempt to render the file at public/500.da.html - # then attempt to render public/500.html. If none of them exist, - # the body of the response will be left empty. - def render_optional_error_file(status_code) - status = interpret_status(status_code) - locale_path = "#{Rails.public_path}/#{status[0,3]}.#{I18n.locale}.html" if I18n.locale - path = "#{Rails.public_path}/#{status[0,3]}.html" - - if locale_path && File.exist?(locale_path) - render :file => locale_path, :status => status, :content_type => Mime::HTML - elsif File.exist?(path) - render :file => path, :status => status, :content_type => Mime::HTML - else - head status - end - end - - # True if the request came from localhost, 127.0.0.1. Override this - # method if you wish to redefine the meaning of a local request to - # include remote IP addresses or other criteria. - def local_request? #:doc: - request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST - end - - # Render detailed diagnostics for unhandled exceptions rescued from - # a controller action. - def rescue_action_locally(exception) - @template.instance_variable_set("@exception", exception) - @template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH) - @template.instance_variable_set("@contents", - @template._render_template(template_path_for_local_rescue(exception))) - - response.content_type = Mime::HTML - response.status = interpret_status(response_code_for_rescue(exception)) - - content = @template._render_template(rescues_path("layout")) - render_for_text(content) - end - - def rescue_action_without_handler(exception) - log_error(exception) if logger - erase_results if performed? - - # Let the exception alter the response if it wants. - # For example, MethodNotAllowed sets the Allow header. - if exception.respond_to?(:handle_response!) - exception.handle_response!(response) - end - - if consider_all_requests_local || local_request? - rescue_action_locally(exception) - else - rescue_action_in_public(exception) - end - end - - private - def perform_action_with_rescue #:nodoc: - perform_action_without_rescue - rescue Exception => exception - rescue_action(exception) - end - - def rescues_path(template_name) - RESCUES_TEMPLATE_PATH.find_by_parts("rescues/#{template_name}.erb") - end - - def template_path_for_local_rescue(exception) - rescues_path(rescue_templates[exception.class.name]) - end - - def response_code_for_rescue(exception) - rescue_responses[exception.class.name] - end - - def clean_backtrace(exception) - defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ? - Rails.backtrace_cleaner.clean(exception.backtrace) : - exception.backtrace - end - end -end diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb deleted file mode 100644 index 64b34650b1..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb +++ /dev/null @@ -1,24 +0,0 @@ -<% unless @exception.blamed_files.blank? %> - <% if (hide = @exception.blamed_files.length > 8) %> - Show blamed files - <% end %> -
><%=h @exception.describe_blame %>
-<% end %> - -<% - clean_params = request.parameters.clone - clean_params.delete("action") - clean_params.delete("controller") - - request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") -%> - -

Request

-

Parameters:

<%=h request_dump %>

- -

Show session dump

- - - -

Response

-

Headers:

<%=h response ? response.headers.inspect.gsub(',', ",\n") : 'None' %>

diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb deleted file mode 100644 index bb2d8375bd..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb +++ /dev/null @@ -1,26 +0,0 @@ -<% - traces = [ - ["Application Trace", @exception.application_backtrace], - ["Framework Trace", @exception.framework_backtrace], - ["Full Trace", @exception.clean_backtrace] - ] - names = traces.collect {|name, trace| name} -%> - -

RAILS_ROOT: <%= defined?(RAILS_ROOT) ? RAILS_ROOT : "unset" %>

- -
- <% names.each do |name| %> - <% - show = "document.getElementById('#{name.gsub /\s/, '-'}').style.display='block';" - hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub /\s/, '-'}').style.display='none';"} - %> - <%= name %> <%= '|' unless names.last == name %> - <% end %> - - <% traces.each do |name, trace| %> -
;"> -
<%= trace.join "\n" %>
-
- <% end %> -
diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb deleted file mode 100644 index e5c647c826..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb +++ /dev/null @@ -1,10 +0,0 @@ -

- <%=h @exception.class.to_s %> - <% if request.parameters['controller'] %> - in <%=h request.parameters['controller'].humanize %>Controller<% if request.parameters['action'] %>#<%=h request.parameters['action'] %><% end %> - <% end %> -

-
<%=h @exception.clean_message %>
- -<%= @template._render_template(@rescues_path.find_by_parts("rescues/_trace.erb")) %> -<%= @template._render_template(@rescues_path.find_by_parts("rescues/_request_and_response.erb")) %> \ No newline at end of file diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb deleted file mode 100644 index 4a04742e40..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb +++ /dev/null @@ -1,29 +0,0 @@ - - - Action Controller: Exception caught - - - - -<%= @contents %> - - - \ No newline at end of file diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb deleted file mode 100644 index dbfdf76947..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb +++ /dev/null @@ -1,2 +0,0 @@ -

Template is missing

-

<%=h @exception.message %>

diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb deleted file mode 100644 index ccfa858cce..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb +++ /dev/null @@ -1,10 +0,0 @@ -

Routing Error

-

<%=h @exception.message %>

-<% unless @exception.failures.empty? %>

-

Failure reasons:

-
    - <% @exception.failures.each do |route, reason| %> -
  1. <%=h route.inspect.gsub('\\', '') %> failed because <%=h reason.downcase %>
  2. - <% end %> -
-

<% end %> diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb deleted file mode 100644 index 2e34e03bd5..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb +++ /dev/null @@ -1,21 +0,0 @@ -

- <%=h @exception.original_exception.class.to_s %> in - <%=h request.parameters["controller"].capitalize if request.parameters["controller"]%>#<%=h request.parameters["action"] %> -

- -

- Showing <%=h @exception.file_name %> where line #<%=h @exception.line_number %> raised: -

<%=h @exception.message %>
-

- -

Extracted source (around line #<%=h @exception.line_number %>): -

<%=h @exception.source_extract %>

- -

<%=h @exception.sub_template_message %>

- -<% @real_exception = @exception - @exception = @exception.original_exception || @exception %> -<%= render :file => @rescues_path["rescues/_trace.erb"] %> -<% @exception = @real_exception %> - -<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %> diff --git a/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb deleted file mode 100644 index 683379da10..0000000000 --- a/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb +++ /dev/null @@ -1,2 +0,0 @@ -

Unknown action

-

<%=h @exception.message %>

diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 5f6202d153..5a082fa7e3 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -48,6 +48,8 @@ module ActionDispatch autoload :Failsafe, 'action_dispatch/middleware/failsafe' autoload :ParamsParser, 'action_dispatch/middleware/params_parser' autoload :Reloader, 'action_dispatch/middleware/reloader' + autoload :Rescue, 'action_dispatch/middleware/rescue' + autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions' autoload :MiddlewareStack, 'action_dispatch/middleware/stack' autoload :Assertions, 'action_dispatch/testing/assertions' diff --git a/actionpack/lib/action_dispatch/middleware/rescue.rb b/actionpack/lib/action_dispatch/middleware/rescue.rb new file mode 100644 index 0000000000..1456825526 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/rescue.rb @@ -0,0 +1,14 @@ +module ActionDispatch + class Rescue + def initialize(app, rescuer) + @app, @rescuer = app, rescuer + end + + def call(env) + @app.call(env) + rescue Exception => exception + env['action_dispatch.rescue.exception'] = exception + @rescuer.call(env) + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb new file mode 100644 index 0000000000..791254cdf2 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -0,0 +1,142 @@ +module ActionDispatch + class ShowExceptions + include StatusCodes + + LOCALHOST = '127.0.0.1'.freeze + + DEFAULT_RESCUE_RESPONSE = :internal_server_error + DEFAULT_RESCUE_RESPONSES = { + 'ActionController::RoutingError' => :not_found, + 'ActionController::UnknownAction' => :not_found, + 'ActiveRecord::RecordNotFound' => :not_found, + 'ActiveRecord::StaleObjectError' => :conflict, + 'ActiveRecord::RecordInvalid' => :unprocessable_entity, + 'ActiveRecord::RecordNotSaved' => :unprocessable_entity, + 'ActionController::MethodNotAllowed' => :method_not_allowed, + 'ActionController::NotImplemented' => :not_implemented, + 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity + } + + DEFAULT_RESCUE_TEMPLATE = 'diagnostics' + DEFAULT_RESCUE_TEMPLATES = { + '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 + + def initialize(app, consider_all_requests_local = false) + @app = app + @consider_all_requests_local = consider_all_requests_local + end + + def call(env) + @app.call(env) + rescue Exception => exception + 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 + end + + private + # 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] + end + + # Attempts to render a static error page based on the + # status_code thrown, or just return headers if no such file + # exists. At first, it will try to render a localized static page. + # For example, if a 500 error is being handled Rails and locale is :da, + # it will first attempt to render the file at public/500.da.html + # then attempt to render public/500.html. If none of them exist, + # the body of the response will be left empty. + def rescue_action_in_public(exception) + status = status_code(exception) + locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale + path = "#{public_path}/#{status}.html" + + if locale_path && File.exist?(locale_path) + render_public_file(status, locale_path) + elsif File.exist?(path) + render_public_file(status, path) + else + [status, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []] + end + end + + # True if the request came from localhost, 127.0.0.1. + 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 + end + + def log_error(exception) #:doc: + ActiveSupport::Deprecation.silence do + if ActionView::TemplateError === exception + logger.fatal(exception.to_s) + else + logger.fatal( + "\n#{exception.class} (#{exception.message}):\n " + + clean_backtrace(exception).join("\n ") + "\n\n" + ) + end + end + end + + def clean_backtrace(exception) + defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ? + Rails.backtrace_cleaner.clean(exception.backtrace) : + exception.backtrace + end + + def logger + if defined?(Rails.logger) + Rails.logger + end + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb new file mode 100644 index 0000000000..5224403dab --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -0,0 +1,24 @@ +<% unless @exception.blamed_files.blank? %> + <% if (hide = @exception.blamed_files.length > 8) %> + Show blamed files + <% end %> +
><%=h @exception.describe_blame %>
+<% end %> + +<% + clean_params = @request.parameters.clone + clean_params.delete("action") + clean_params.delete("controller") + + request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") +%> + +

Request

+

Parameters:

<%=h request_dump %>

+ +

Show session dump

+ + + +

Response

+

Headers:

<%=h @response ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>

diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb new file mode 100644 index 0000000000..bb2d8375bd --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb @@ -0,0 +1,26 @@ +<% + traces = [ + ["Application Trace", @exception.application_backtrace], + ["Framework Trace", @exception.framework_backtrace], + ["Full Trace", @exception.clean_backtrace] + ] + names = traces.collect {|name, trace| name} +%> + +

RAILS_ROOT: <%= defined?(RAILS_ROOT) ? RAILS_ROOT : "unset" %>

+ +
+ <% names.each do |name| %> + <% + show = "document.getElementById('#{name.gsub /\s/, '-'}').style.display='block';" + hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub /\s/, '-'}').style.display='none';"} + %> + <%= name %> <%= '|' unless names.last == name %> + <% end %> + + <% traces.each do |name, trace| %> +
;"> +
<%= trace.join "\n" %>
+
+ <% end %> +
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb new file mode 100644 index 0000000000..693e56270a --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb @@ -0,0 +1,10 @@ +

+ <%=h @exception.class.to_s %> + <% if @request.parameters['controller'] %> + in <%=h @request.parameters['controller'].humanize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %> + <% end %> +

+
<%=h @exception.clean_message %>
+ +<%= render :file => "rescues/_trace.erb" %> +<%= render :file => "rescues/_request_and_response.erb" %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb new file mode 100644 index 0000000000..6c32fb17b8 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -0,0 +1,29 @@ + + + Action Controller: Exception caught + + + + +<%= yield %> + + + diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb new file mode 100644 index 0000000000..dbfdf76947 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb @@ -0,0 +1,2 @@ +

Template is missing

+

<%=h @exception.message %>

diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb new file mode 100644 index 0000000000..ccfa858cce --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb @@ -0,0 +1,10 @@ +

Routing Error

+

<%=h @exception.message %>

+<% unless @exception.failures.empty? %>

+

Failure reasons:

+
    + <% @exception.failures.each do |route, reason| %> +
  1. <%=h route.inspect.gsub('\\', '') %> failed because <%=h reason.downcase %>
  2. + <% end %> +
+

<% end %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb new file mode 100644 index 0000000000..02fa18211d --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb @@ -0,0 +1,21 @@ +

+ <%=h @exception.original_exception.class.to_s %> in + <%=h @request.parameters["controller"].capitalize if @request.parameters["controller"]%>#<%=h @request.parameters["action"] %> +

+ +

+ Showing <%=h @exception.file_name %> where line #<%=h @exception.line_number %> raised: +

<%=h @exception.message %>
+

+ +

Extracted source (around line #<%=h @exception.line_number %>): +

<%=h @exception.source_extract %>

+ +

<%=h @exception.sub_template_message %>

+ +<% @real_exception = @exception + @exception = @exception.original_exception || @exception %> +<%= render :file => "rescues/_trace.erb" %> +<% @exception = @real_exception %> + +<%= render :file => "rescues/_request_and_response.erb" %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb new file mode 100644 index 0000000000..683379da10 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb @@ -0,0 +1,2 @@ +

Unknown action

+

<%=h @exception.message %>

diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 92e3da580e..501a7c4dfb 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -31,13 +31,7 @@ module ActionDispatch elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type] assert_block("") { true } # to count the assertion else - if @controller && @response.error? - exception = @controller.template.instance_variable_get(:@exception) - exception_message = exception && exception.message - assert_block(build_message(message, "Expected response to be a , but was \n", type, @response.response_code, exception_message.to_s)) { false } - else - assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } - end + assert_block(build_message(message, "Expected response to be a , but was ", type, @response.response_code)) { false } end end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 60957a2f0e..484d3c5ce7 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -489,7 +489,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase get :index assert_response :success flunk 'Expected non-success response' - rescue ActiveSupport::TestCase::Assertion => e + rescue RuntimeError => e assert e.message.include?('FAIL') end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index f4517d06c4..0c54d61426 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -27,6 +27,7 @@ class EmptyController < ActionController::Base end class NonEmptyController < ActionController::Base def public_action + render :nothing => true end hide_action :hidden_action @@ -51,6 +52,7 @@ end class DefaultUrlOptionsController < ActionController::Base def default_url_options_action + render :nothing => true end def default_url_options(options = nil) @@ -151,11 +153,8 @@ class PerformActionTest < ActionController::TestCase def test_get_on_hidden_should_fail use_controller NonEmptyController - get :hidden_action - assert_response 404 - - get :another_hidden_action - assert_response 404 + assert_raise(ActionController::UnknownAction) { get :hidden_action } + assert_raise(ActionController::UnknownAction) { get :another_hidden_action } end def test_namespaced_action_should_log_module_name diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 6b9d1056a3..560c09509b 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -149,6 +149,9 @@ class PageCachingTest < ActionController::TestCase end class ActionCachingTestController < ActionController::Base + rescue_from(Exception) { head 500 } + rescue_from(ActiveRecord::RecordNotFound) { head :not_found } + caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }, :expires_in => 1.hour caches_action :show, :cache_path => 'http://test.host/custom/show' caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" } diff --git a/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb b/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb index dd69a63020..0c02afea36 100644 --- a/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb +++ b/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb @@ -15,12 +15,6 @@ class DeprecatedBaseMethodsTest < ActionController::TestCase tests Target - def test_log_error_silences_deprecation_warnings - get :raises_name_error - rescue => e - assert_not_deprecated { @controller.send :log_error, e } - end - if defined? Test::Unit::Error def test_assertion_failed_error_silences_deprecation_warnings get :raises_name_error diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb index c3bd113b86..b315232a7b 100644 --- a/actionpack/test/controller/dispatcher_test.rb +++ b/actionpack/test/controller/dispatcher_test.rb @@ -45,19 +45,6 @@ class DispatcherTest < Test::Unit::TestCase def log_failsafe_exception(status, exception); end end - def test_failsafe_response - Dispatcher.any_instance.expects(:_call).raises('b00m') - ActionDispatch::Failsafe.any_instance.expects(:log_failsafe_exception) - - assert_nothing_raised do - assert_equal [ - 500, - {"Content-Type" => "text/html"}, - ["

500 Internal Server Error

"] - ], dispatch - end - end - def test_prepare_callbacks a = b = c = nil Dispatcher.to_prepare { |*args| a = b = c = 1 } diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 5876f55420..5fd3eb0446 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -169,6 +169,7 @@ class FilterTest < Test::Unit::TestCase end def public + render :text => 'ok' end end @@ -177,6 +178,10 @@ class FilterTest < Test::Unit::TestCase before_filter :find_record before_filter :ensure_login + def index + render :text => 'ok' + end + private def find_record @ran_filter ||= [] diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index da3f7b0cb8..5b7d40d16d 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -205,8 +205,7 @@ end class LayoutExceptionRaised < ActionController::TestCase def test_exception_raised_when_layout_file_not_found @controller = SetsNonExistentLayoutFile.new - get :hello - assert_kind_of ActionView::MissingTemplate, @controller.template.instance_eval { @exception } + assert_raise(ActionView::MissingTemplate) { get :hello } end end diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index 894420a910..f745926b20 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -138,213 +138,88 @@ class RescueController < ActionController::Base end end -class RescueControllerTest < ActionController::TestCase - FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze - - def setup - super - set_all_requests_local - populate_exception_object - end - - def set_all_requests_local - RescueController.consider_all_requests_local = true - @request.remote_addr = '1.2.3.4' - @request.host = 'example.com' - end - - def populate_exception_object - begin - raise 'foo' - rescue => @exception - end - end - - def test_rescue_exceptions_raised_by_filters - with_rails_root FIXTURE_PUBLIC do - with_all_requests_local false do - get :before_filter_raises - end - end +class ExceptionInheritanceRescueController < ActionController::Base - assert_response :internal_server_error + class ParentException < StandardError end - def test_rescue_action_locally_if_all_requests_local - @controller.expects(:local_request?).never - @controller.expects(:rescue_action_locally).with(@exception) - @controller.expects(:rescue_action_in_public).never - - with_all_requests_local do - @controller.send :rescue_action, @exception - end + class ChildException < ParentException end - def test_rescue_action_locally_if_remote_addr_is_localhost - @controller.expects(:local_request?).returns(true) - @controller.expects(:rescue_action_locally).with(@exception) - @controller.expects(:rescue_action_in_public).never - - with_all_requests_local false do - @controller.send :rescue_action, @exception - end + class GrandchildException < ChildException end - def test_rescue_action_in_public_otherwise - @controller.expects(:local_request?).returns(false) - @controller.expects(:rescue_action_locally).never - @controller.expects(:rescue_action_in_public).with(@exception) + rescue_from ChildException, :with => lambda { head :ok } + rescue_from ParentException, :with => lambda { head :created } + rescue_from GrandchildException, :with => lambda { head :no_content } - with_all_requests_local false do - @controller.send :rescue_action, @exception - end + def raise_parent_exception + raise ParentException end - def test_rescue_action_in_public_with_localized_error_file - # Change locale - old_locale = I18n.locale - I18n.locale = :da - - with_rails_root FIXTURE_PUBLIC do - with_all_requests_local false do - get :raises - end - end - - assert_response :internal_server_error - body = File.read("#{FIXTURE_PUBLIC}/public/500.da.html") - assert_equal body, @response.body - ensure - I18n.locale = old_locale + def raise_child_exception + raise ChildException end - def test_rescue_action_in_public_with_error_file - with_rails_root FIXTURE_PUBLIC do - with_all_requests_local false do - get :raises - end - end - - assert_response :internal_server_error - body = File.read("#{FIXTURE_PUBLIC}/public/500.html") - assert_equal body, @response.body + def raise_grandchild_exception + raise GrandchildException end +end - def test_rescue_action_in_public_without_error_file - with_rails_root '/tmp' do - with_all_requests_local false do - get :raises - end - end - - assert_response :internal_server_error - assert_equal ' ', @response.body +class ExceptionInheritanceRescueControllerTest < ActionController::TestCase + def test_bottom_first + get :raise_grandchild_exception + assert_response :no_content end - def test_rescue_unknown_action_in_public_with_error_file - with_rails_root FIXTURE_PUBLIC do - with_all_requests_local false do - get :foobar_doesnt_exist - end - end - - assert_response :not_found - body = File.read("#{FIXTURE_PUBLIC}/public/404.html") - assert_equal body, @response.body + def test_inheritance_works + get :raise_child_exception + assert_response :created end +end - def test_rescue_unknown_action_in_public_without_error_file - with_rails_root '/tmp' do - with_all_requests_local false do - get :foobar_doesnt_exist - end - end - - assert_response :not_found - assert_equal ' ', @response.body +class ControllerInheritanceRescueController < ExceptionInheritanceRescueController + class FirstExceptionInChildController < StandardError end - def test_rescue_missing_template_in_public - with_rails_root FIXTURE_PUBLIC do - with_all_requests_local true do - get :missing_template - end - end - - assert_response :internal_server_error - assert @response.body.include?('missing_template'), "Response should include the template name." + class SecondExceptionInChildController < StandardError end - def test_rescue_action_locally - get :raises - assert_response :internal_server_error - assert_template 'diagnostics.erb' - assert @response.body.include?('RescueController#raises'), "Response should include controller and action." - assert @response.body.include?("don't panic"), "Response should include exception message." - end + rescue_from FirstExceptionInChildController, 'SecondExceptionInChildController', :with => lambda { head :gone } - def test_local_request_when_remote_addr_is_localhost - @controller.expects(:request).returns(@request).at_least_once - with_remote_addr '127.0.0.1' do - assert @controller.send(:local_request?) - end + def raise_first_exception_in_child_controller + raise FirstExceptionInChildController end - def test_local_request_when_remote_addr_isnt_locahost - @controller.expects(:request).returns(@request) - with_remote_addr '1.2.3.4' do - assert !@controller.send(:local_request?) - end + def raise_second_exception_in_child_controller + raise SecondExceptionInChildController end +end - def test_rescue_responses - responses = ActionController::Base.rescue_responses - - assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses.default - assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses[Exception.new] - - assert_equal :not_found, responses[ActionController::RoutingError.name] - assert_equal :not_found, responses[ActionController::UnknownAction.name] - assert_equal :not_found, responses['ActiveRecord::RecordNotFound'] - assert_equal :conflict, responses['ActiveRecord::StaleObjectError'] - assert_equal :unprocessable_entity, responses['ActiveRecord::RecordInvalid'] - assert_equal :unprocessable_entity, responses['ActiveRecord::RecordNotSaved'] - assert_equal :method_not_allowed, responses['ActionController::MethodNotAllowed'] - assert_equal :not_implemented, responses['ActionController::NotImplemented'] +class ControllerInheritanceRescueControllerTest < ActionController::TestCase + def test_first_exception_in_child_controller + get :raise_first_exception_in_child_controller + assert_response :gone end - def test_rescue_templates - templates = ActionController::Base.rescue_templates - - assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates.default - assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates[Exception.new] - - assert_equal 'missing_template', templates[ActionView::MissingTemplate.name] - assert_equal 'routing_error', templates[ActionController::RoutingError.name] - assert_equal 'unknown_action', templates[ActionController::UnknownAction.name] - assert_equal 'template_error', templates[ActionView::TemplateError.name] + def test_second_exception_in_child_controller + get :raise_second_exception_in_child_controller + assert_response :gone end - def test_not_implemented - with_all_requests_local false do - with_rails_public_path(".") do - head :not_implemented - end - end - assert_response :not_implemented - assert_equal "GET, PUT", @response.headers['Allow'] + def test_exception_in_parent_controller + get :raise_parent_exception + assert_response :created end +end - def test_method_not_allowed - with_all_requests_local false do - with_rails_public_path(".") do - get :method_not_allowed - end - end - assert_response :method_not_allowed - assert_equal "GET, HEAD, PUT", @response.headers['Allow'] +class ApplicationController < ActionController::Base + rescue_from ActionController::RoutingError do + render :text => 'no way' end +end +class RescueControllerTest < ActionController::TestCase def test_rescue_handler get :not_authorized assert_response :forbidden @@ -399,133 +274,6 @@ class RescueControllerTest < ActionController::TestCase get :resource_unavailable_raise_as_string assert_equal "RescueController::ResourceUnavailableToRescueAsString", @response.body end - - protected - def with_all_requests_local(local = true) - old_local, ActionController::Base.consider_all_requests_local = - ActionController::Base.consider_all_requests_local, local - yield - ensure - ActionController::Base.consider_all_requests_local = old_local - end - - def with_remote_addr(addr) - old_remote_addr, @request.remote_addr = @request.remote_addr, addr - yield - ensure - @request.remote_addr = old_remote_addr - end - - def with_rails_public_path(rails_root) - old_rails = Object.const_get(:Rails) rescue nil - mod = Object.const_set(:Rails, Module.new) - (class << mod; self; end).instance_eval do - define_method(:public_path) { "#{rails_root}/public" } - end - yield - ensure - Object.module_eval { remove_const(:Rails) } if defined?(Rails) - Object.const_set(:Rails, old_rails) if old_rails - end - - def with_rails_root(path = nil,&block) - old_rails_root = RAILS_ROOT if defined?(RAILS_ROOT) - if path - silence_warnings { Object.const_set(:RAILS_ROOT, path) } - else - Object.remove_const(:RAILS_ROOT) rescue nil - end - - with_rails_public_path(path, &block) - - ensure - if old_rails_root - silence_warnings { Object.const_set(:RAILS_ROOT, old_rails_root) } - else - Object.remove_const(:RAILS_ROOT) rescue nil - end - end -end - -class ExceptionInheritanceRescueController < ActionController::Base - - class ParentException < StandardError - end - - class ChildException < ParentException - end - - class GrandchildException < ChildException - end - - rescue_from ChildException, :with => lambda { head :ok } - rescue_from ParentException, :with => lambda { head :created } - rescue_from GrandchildException, :with => lambda { head :no_content } - - def raise_parent_exception - raise ParentException - end - - def raise_child_exception - raise ChildException - end - - def raise_grandchild_exception - raise GrandchildException - end -end - -class ExceptionInheritanceRescueControllerTest < ActionController::TestCase - def test_bottom_first - get :raise_grandchild_exception - assert_response :no_content - end - - def test_inheritance_works - get :raise_child_exception - assert_response :created - end -end - -class ControllerInheritanceRescueController < ExceptionInheritanceRescueController - class FirstExceptionInChildController < StandardError - end - - class SecondExceptionInChildController < StandardError - end - - rescue_from FirstExceptionInChildController, 'SecondExceptionInChildController', :with => lambda { head :gone } - - def raise_first_exception_in_child_controller - raise FirstExceptionInChildController - end - - def raise_second_exception_in_child_controller - raise SecondExceptionInChildController - end -end - -class ControllerInheritanceRescueControllerTest < ActionController::TestCase - def test_first_exception_in_child_controller - get :raise_first_exception_in_child_controller - assert_response :gone - end - - def test_second_exception_in_child_controller - get :raise_second_exception_in_child_controller - assert_response :gone - end - - def test_exception_in_parent_controller - get :raise_parent_exception - assert_response :created - end -end - -class ApplicationController < ActionController::Base - rescue_from ActionController::RoutingError do - render :text => 'no way' - end end class RescueTest < ActionController::IntegrationTest diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb new file mode 100644 index 0000000000..f8f562e7c1 --- /dev/null +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -0,0 +1,103 @@ +require 'abstract_unit' + +module ActionDispatch + class ShowExceptions + private + def public_path + "#{FIXTURE_LOAD_PATH}/public" + end + end +end + +class ShowExceptionsTest < ActionController::IntegrationTest + Boomer = lambda do |env| + req = ActionDispatch::Request.new(env) + case req.path + when "/not_found" + raise ActionController::UnknownAction + when "/method_not_allowed" + raise ActionController::MethodNotAllowed + when "/not_implemented" + raise ActionController::NotImplemented + when "/unprocessable_entity" + raise ActionController::InvalidAuthenticityToken + else + raise "puke!" + end + end + + ProductionApp = ActionDispatch::ShowExceptions.new(Boomer, false) + DevelopmentApp = ActionDispatch::ShowExceptions.new(Boomer, true) + + test "rescue in public from a remote ip" do + @integration_session = open_session(ProductionApp) + self.remote_addr = '208.77.188.166' + + get "/" + assert_response 500 + assert_equal "500 error fixture\n", body + + get "/not_found" + assert_response 404 + assert_equal "404 error fixture\n", body + + get "/method_not_allowed" + assert_response 405 + assert_equal "", body + end + + test "rescue locally from a local request" do + @integration_session = open_session(ProductionApp) + self.remote_addr = '127.0.0.1' + + get "/" + assert_response 500 + assert_match /puke/, body + + get "/not_found" + assert_response 404 + assert_match /ActionController::UnknownAction/, body + + get "/method_not_allowed" + assert_response 405 + assert_match /ActionController::MethodNotAllowed/, body + end + + test "localize public rescue message" do + # Change locale + old_locale = I18n.locale + I18n.locale = :da + + begin + @integration_session = open_session(ProductionApp) + self.remote_addr = '208.77.188.166' + + get "/" + assert_response 500 + assert_equal "500 localized error fixture\n", body + + get "/not_found" + assert_response 404 + assert_equal "404 error fixture\n", body + ensure + I18n.locale = old_locale + end + end + + test "always rescue locally in development mode" do + @integration_session = open_session(DevelopmentApp) + self.remote_addr = '208.77.188.166' + + get "/" + assert_response 500 + assert_match /puke/, body + + get "/not_found" + assert_response 404 + assert_match /ActionController::UnknownAction/, body + + get "/method_not_allowed" + assert_response 405 + assert_match /ActionController::MethodNotAllowed/, body + end +end -- cgit v1.2.3 From e0660192806fc1ec8b75654e69211f85c9f1256b Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 3 May 2009 09:24:32 -0500 Subject: Show lazy middleware args in pretty print --- actionpack/lib/action_dispatch/middleware/stack.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index ee5f28d5cb..ec8a9ca76e 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -61,7 +61,7 @@ module ActionDispatch def inspect str = klass.to_s - args.each { |arg| str += ", #{arg.inspect}" } + args.each { |arg| str += ", #{build_args.inspect}" } str end @@ -74,7 +74,6 @@ module ActionDispatch end private - def build_args Array(args).map { |arg| arg.respond_to?(:call) ? arg.call : arg } end -- cgit v1.2.3 From bcc4537f2a0d37fc02d67e9564fa5c9c5555b3d5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 3 May 2009 09:41:40 -0500 Subject: Wrap dispatcher callbacks around the whole middleware chain. Kill unnecessary Reloader middleware. --- .../lib/action_controller/dispatch/dispatcher.rb | 45 +++++++++++----------- actionpack/lib/action_dispatch.rb | 1 - .../lib/action_dispatch/middleware/reloader.rb | 14 ------- 3 files changed, 22 insertions(+), 38 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/reloader.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index c0eb359547..cce3b6175d 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -5,9 +5,9 @@ module ActionController class << self def define_dispatcher_callbacks(cache_classes) unless cache_classes - unless self.middleware.include?(ActionDispatch::Reloader) - self.middleware.insert_after(ActionDispatch::Failsafe, ActionDispatch::Reloader) - end + # Development mode callbacks + before_dispatch :reload_application + after_dispatch :cleanup_application ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false end @@ -40,22 +40,11 @@ module ActionController def run_prepare_callbacks new.send :run_callbacks, :prepare_dispatch end - - def reload_application - # Run prepare callbacks before every request in development mode - run_prepare_callbacks - - Routing::Routes.reload - 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 end + cattr_accessor :router + self.router = Routing::Routes + cattr_accessor :middleware self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") @@ -66,21 +55,31 @@ module ActionController define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch def initialize - @app = @@middleware.build(lambda { |env| self._call(env) }) + @app = @@middleware.build(@@router) freeze end def call(env) - @app.call(env) - end - - def _call(env) run_callbacks :before_dispatch - Routing::Routes.call(env) + @app.call(env) ensure run_callbacks :after_dispatch, :enumerator => :reverse_each end + def reload_application + # Run prepare callbacks before every request in development mode + run_callbacks :prepare_dispatch + + @@router.reload + 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 + def flush_logger Base.logger.flush end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 5a082fa7e3..c882930e64 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -47,7 +47,6 @@ module ActionDispatch autoload :Failsafe, 'action_dispatch/middleware/failsafe' autoload :ParamsParser, 'action_dispatch/middleware/params_parser' - autoload :Reloader, 'action_dispatch/middleware/reloader' autoload :Rescue, 'action_dispatch/middleware/rescue' autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions' autoload :MiddlewareStack, 'action_dispatch/middleware/stack' diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb deleted file mode 100644 index 67313e30e4..0000000000 --- a/actionpack/lib/action_dispatch/middleware/reloader.rb +++ /dev/null @@ -1,14 +0,0 @@ -module ActionDispatch - class Reloader - def initialize(app) - @app = app - end - - def call(env) - ActionController::Dispatcher.reload_application - @app.call(env) - ensure - ActionController::Dispatcher.cleanup_application - end - end -end -- cgit v1.2.3 From d4402c5554a0d3202fc22eb38c5c1a8c4b9afd93 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 May 2009 20:26:43 -0500 Subject: assert_redirect_to's partial hash matching was deprecated in 2-3 stable 7f1f16c01 --- actionpack/test/controller/redirect_test.rb | 7 ------- 1 file changed, 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 9ad63a1c60..13247f2d08 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -233,13 +233,6 @@ class RedirectTest < ActionController::TestCase assert_redirected_to Workshop.new(5, true) end - def test_redirect_with_partial_params - pending do - get :module_redirect - assert_redirected_to :action => 'hello_world' - end - end - def test_redirect_to_nil assert_raise(ActionController::ActionControllerError) do get :redirect_to_nil -- cgit v1.2.3 From 2854535b02bcee3668bda02c76c3105fc24730d3 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 7 May 2009 10:29:22 -0500 Subject: Make module dependency DSL opt in --- actionpack/lib/action_controller/abstract/helpers.rb | 2 ++ actionpack/lib/action_controller/abstract/layouts.rb | 5 +++-- actionpack/lib/action_controller/abstract/logger.rb | 2 ++ actionpack/lib/action_controller/abstract/renderer.rb | 2 ++ actionpack/lib/action_controller/new_base/layouts.rb | 2 ++ actionpack/lib/action_controller/new_base/renderer.rb | 2 ++ actionpack/test/abstract_controller/callbacks_test.rb | 2 +- actionpack/test/abstract_controller/layouts_test.rb | 6 +++--- actionpack/test/new_base/test_helper.rb | 14 +++++++------- 9 files changed, 24 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 1f0b38417b..ffcae29ddc 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -1,5 +1,7 @@ module AbstractController module Helpers + extend ActiveSupport::DependencyModule + depends_on Renderer setup do diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 0039e67c5a..76130f8dc0 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -1,8 +1,9 @@ module AbstractController module Layouts - + extend ActiveSupport::DependencyModule + depends_on Renderer - + module ClassMethods def layout(layout) unless [String, Symbol, FalseClass, NilClass].include?(layout.class) diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 4117369bd4..bdb8defa0c 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -1,5 +1,7 @@ module AbstractController module Logger + extend ActiveSupport::DependencyModule + setup do cattr_accessor :logger end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index e31accbbfc..531eb28dcb 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -2,6 +2,8 @@ require "action_controller/abstract/logger" module AbstractController module Renderer + extend ActiveSupport::DependencyModule + depends_on AbstractController::Logger setup do diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index a8e0809ac6..89d24fe92d 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -1,5 +1,7 @@ module ActionController module Layouts + extend ActiveSupport::DependencyModule + depends_on ActionController::Renderer depends_on AbstractController::Layouts diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index ed34c46aed..be4ea54c3b 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -1,5 +1,7 @@ module ActionController module Renderer + extend ActiveSupport::DependencyModule + depends_on AbstractController::Renderer def initialize(*) diff --git a/actionpack/test/abstract_controller/callbacks_test.rb b/actionpack/test/abstract_controller/callbacks_test.rb index 5fce30f478..89243b631e 100644 --- a/actionpack/test/abstract_controller/callbacks_test.rb +++ b/actionpack/test/abstract_controller/callbacks_test.rb @@ -4,7 +4,7 @@ module AbstractController module Testing class ControllerWithCallbacks < AbstractController::Base - use AbstractController::Callbacks + include AbstractController::Callbacks end class Callback1 < ControllerWithCallbacks diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb index 3d4570bfef..a305a30a54 100644 --- a/actionpack/test/abstract_controller/layouts_test.rb +++ b/actionpack/test/abstract_controller/layouts_test.rb @@ -5,9 +5,9 @@ module AbstractControllerTests # Base controller for these tests class Base < AbstractController::Base - use AbstractController::Renderer - use AbstractController::Layouts - + include AbstractController::Renderer + include AbstractController::Layouts + self.view_paths = [ActionView::FixtureTemplate::FixturePath.new( "layouts/hello.erb" => "With String <%= yield %>", "layouts/hello_override.erb" => "With Override <%= yield %>", diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index d29449ddc1..89c29d9af3 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -26,14 +26,14 @@ require 'rack/test' module ActionController class Base2 < AbstractBase - use AbstractController::Callbacks - use AbstractController::Helpers - use AbstractController::Logger + include AbstractController::Callbacks + include AbstractController::Helpers + include AbstractController::Logger - use ActionController::HideActions - use ActionController::UrlFor - use ActionController::Renderer - use ActionController::Layouts + include ActionController::HideActions + include ActionController::UrlFor + include ActionController::Renderer + include ActionController::Layouts def self.inherited(klass) ::ActionController::Base2.subclasses << klass.to_s -- cgit v1.2.3 From af40fa6d036d86895e7be4ef46a615d44eb41ede Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 7 May 2009 10:38:57 -0500 Subject: Prefer "included" language over "setup" --- actionpack/lib/action_controller/abstract/callbacks.rb | 11 +++++++---- actionpack/lib/action_controller/abstract/helpers.rb | 4 ++-- actionpack/lib/action_controller/abstract/logger.rb | 2 +- actionpack/lib/action_controller/abstract/renderer.rb | 10 +++++----- actionpack/lib/action_controller/new_base/hide_actions.rb | 6 +++--- 5 files changed, 18 insertions(+), 15 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index c8b509081c..d7faaf4236 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -1,10 +1,13 @@ module AbstractController module Callbacks - setup do - include ActiveSupport::NewCallbacks - define_callbacks :process_action + extend ActiveSupport::DependencyModule + + depends_on ActiveSupport::NewCallbacks + + included do + define_callbacks :process_action end - + def process_action _run_process_action_callbacks(action_name) do super diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index ffcae29ddc..62caa119e7 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -3,8 +3,8 @@ module AbstractController extend ActiveSupport::DependencyModule depends_on Renderer - - setup do + + included do extlib_inheritable_accessor :master_helper_module self.master_helper_module = Module.new end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index bdb8defa0c..5fb78f1755 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -2,7 +2,7 @@ module AbstractController module Logger extend ActiveSupport::DependencyModule - setup do + included do cattr_accessor :logger end end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index 531eb28dcb..beb848f90e 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -5,15 +5,15 @@ module AbstractController extend ActiveSupport::DependencyModule depends_on AbstractController::Logger - - setup do + + included do attr_internal :formats - + extlib_inheritable_accessor :_view_paths - + self._view_paths ||= ActionView::PathSet.new end - + def _action_view @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index 473a8ea72b..aa420442fb 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -1,10 +1,10 @@ module ActionController module HideActions - setup do + included do extlib_inheritable_accessor :hidden_actions - self.hidden_actions ||= Set.new + self.hidden_actions ||= Set.new end - + def action_methods() self.class.action_names end def action_names() action_methods end -- cgit v1.2.3 From a747ab5b20b9d543e9d311070e3b720c761ae716 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 7 May 2009 10:45:29 -0500 Subject: Whitespace! --- actionpack/lib/action_controller/abstract.rb | 2 +- actionpack/lib/action_controller/abstract/base.rb | 19 +++++++-------- .../lib/action_controller/abstract/callbacks.rb | 8 +++---- .../lib/action_controller/abstract/exceptions.rb | 2 +- .../lib/action_controller/abstract/helpers.rb | 17 +++++++------- .../lib/action_controller/abstract/layouts.rb | 27 +++++++++++----------- .../lib/action_controller/abstract/logger.rb | 2 +- .../lib/action_controller/abstract/renderer.rb | 19 ++++++++------- actionpack/lib/action_controller/new_base.rb | 2 +- actionpack/lib/action_controller/new_base/base.rb | 27 +++++++++++----------- .../lib/action_controller/new_base/hide_actions.rb | 11 ++++----- .../lib/action_controller/new_base/layouts.rb | 14 +++++------ .../lib/action_controller/new_base/renderer.rb | 23 +++++++++--------- .../lib/action_controller/new_base/url_for.rb | 6 ++--- 14 files changed, 84 insertions(+), 95 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index 3f5c4a185f..9442d4559f 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -7,4 +7,4 @@ module AbstractController autoload :Renderer, "action_controller/abstract/renderer" # === Exceptions autoload :ActionNotFound, "action_controller/abstract/exceptions" -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index ade7719cc0..39e9ad0440 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,41 +1,38 @@ module AbstractController class Base - attr_internal :response_body attr_internal :response_obj attr_internal :action_name - + def self.process(action) new.process(action) end - + def self.inherited(klass) end - + def initialize self.response_obj = {} end - + def process(action_name) unless respond_to_action?(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end - + @_action_name = action_name process_action self.response_obj[:body] = self.response_body self end - + private - def process_action respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name) end - + def respond_to_action?(action_name) respond_to?(action_name) || respond_to?(:action_missing, true) end - end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index d7faaf4236..cb8aade0be 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -13,7 +13,7 @@ module AbstractController super end end - + module ClassMethods def _normalize_callback_options(options) if only = options[:only] @@ -21,11 +21,11 @@ module AbstractController options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") + except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") options[:per_key] = {:unless => except} end end - + [:before, :after, :around].each do |filter| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{filter}_filter(*names, &blk) @@ -40,4 +40,4 @@ module AbstractController end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb index ec4680629b..a7d07868bb 100644 --- a/actionpack/lib/action_controller/abstract/exceptions.rb +++ b/actionpack/lib/action_controller/abstract/exceptions.rb @@ -1,3 +1,3 @@ module AbstractController class ActionNotFound < StandardError ; end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 62caa119e7..38e3ce8127 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -8,14 +8,14 @@ module AbstractController extlib_inheritable_accessor :master_helper_module self.master_helper_module = Module.new end - + # def self.included(klass) # klass.class_eval do # extlib_inheritable_accessor :master_helper_module # self.master_helper_module = Module.new # end # end - + def _action_view @_action_view ||= begin av = super @@ -23,19 +23,19 @@ module AbstractController av end end - + module ClassMethods def inherited(klass) klass.master_helper_module = Module.new klass.master_helper_module.__send__ :include, master_helper_module - + super end - + def add_template_helper(mod) master_helper_module.module_eval { include mod } end - + def helper_method(*meths) meths.flatten.each do |meth| master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 @@ -45,7 +45,7 @@ module AbstractController ruby_eval end end - + def helper(*args, &blk) args.flatten.each do |arg| case arg @@ -56,6 +56,5 @@ module AbstractController master_helper_module.module_eval(&blk) if block_given? end end - end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 76130f8dc0..69fe4efc19 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -9,18 +9,18 @@ module AbstractController unless [String, Symbol, FalseClass, NilClass].include?(layout.class) raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil" end - + @_layout = layout || false # Converts nil to false _write_layout_method end - + def _implied_layout_name name.underscore end - + # Takes the specified layout and creates a _layout method to be called # by _default_layout - # + # # If the specified layout is a: # String:: return the string # Symbol:: call the method specified by the symbol @@ -49,35 +49,34 @@ module AbstractController end end end - + def _render_template(template, options) _action_view._render_template_with_layout(template, options[:_layout]) end - + private - def _layout() end # This will be overwritten - + def _layout_for_name(name) 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") end - + def _default_layout(require_layout = false) if require_layout && !_layout - raise ArgumentError, + raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" end - + begin layout = _layout_for_name(_layout) rescue NameError => e - raise NoMethodError, + raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 5fb78f1755..c3bccd7778 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -6,4 +6,4 @@ module AbstractController cattr_accessor :logger end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index beb848f90e..b5c31a27ee 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -15,22 +15,22 @@ module AbstractController end def _action_view - @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) + @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - + def render(options = {}) self.response_body = render_to_body(options) end - + # Raw rendering of a template to a Rack-compatible body. # ==== # @option _prefix The template's path prefix # @option _layout The relative path to the layout template to use - # + # # :api: plugin def render_to_body(options = {}) name = options[:_template_name] || action_name - + template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) _render_template(template, options) end @@ -39,7 +39,7 @@ module AbstractController # ==== # @option _prefix The template's path prefix # @option _layout The relative path to the layout template to use - # + # # :api: plugin def render_to_string(options = {}) AbstractController::Renderer.body_to_s(render_to_body(options)) @@ -48,7 +48,7 @@ module AbstractController def _render_template(template, options) _action_view._render_template_with_layout(template) end - + def view_paths() _view_paths end # Return a string representation of a Rack-compatible response body. @@ -64,15 +64,14 @@ module AbstractController end module ClassMethods - def append_view_path(path) self.view_paths << path end - + def view_paths self._view_paths end - + def view_paths=(paths) self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 7c65f1cdc1..29dc3aaddc 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -4,4 +4,4 @@ module ActionController autoload :Layouts, "action_controller/new_base/layouts" autoload :Renderer, "action_controller/new_base/renderer" autoload :UrlFor, "action_controller/new_base/url_for" -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 08e7a1a0e7..2dd5390c99 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,6 +1,5 @@ module ActionController class AbstractBase < AbstractController::Base - # :api: public attr_internal :request, :response, :params @@ -12,46 +11,46 @@ module ActionController # :api: public def controller_name() self.class.controller_name end - # :api: public + # :api: public def self.controller_path @controller_path ||= self.name.sub(/Controller$/, '').underscore end - - # :api: public + + # :api: public def controller_path() self.class.controller_path end - - # :api: private + + # :api: private def self.action_methods @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS) end - - # :api: private + + # :api: private def self.action_names() action_methods end - - # :api: private + + # :api: private def action_methods() self.class.action_names end # :api: private def action_names() action_methods end - + # :api: plugin def self.call(env) controller = new controller.call(env).to_rack end - + # :api: plugin def response_body=(body) @_response.body = body end - + # :api: private def call(env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new process(@_request.parameters[:action]) end - + # :api: private def to_rack response.to_a diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index aa420442fb..422ea180c4 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -6,21 +6,20 @@ module ActionController end def action_methods() self.class.action_names end - def action_names() action_methods end - + def action_names() action_methods end + private - def respond_to_action?(action_name) !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing)) end - + module ClassMethods def hide_action(*args) args.each do |arg| self.hidden_actions << arg.to_s end end - + def action_methods @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) end @@ -28,4 +27,4 @@ module ActionController def self.action_names() action_methods end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index 89d24fe92d..228162421d 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -4,13 +4,13 @@ module ActionController depends_on ActionController::Renderer depends_on AbstractController::Layouts - + module ClassMethods def _implied_layout_name controller_path end end - + def render_to_body(options) # render :text => ..., :layout => ... # or @@ -18,22 +18,20 @@ module ActionController if !options.key?(:text) || options.key?(:layout) options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout end - + super end - + private - def _layout_for_option(name) case name when String then _layout_for_name(name) when true then _default_layout(true) when false, nil then nil else - raise ArgumentError, - "String, true, or false, expected for `layout'; you passed #{name.inspect}" + raise ArgumentError, + "String, true, or false, expected for `layout'; you passed #{name.inspect}" end end - end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index be4ea54c3b..d7ea9ec4a5 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -3,22 +3,22 @@ module ActionController extend ActiveSupport::DependencyModule depends_on AbstractController::Renderer - + def initialize(*) self.formats = [:html] super end - + def render(action, options = {}) # TODO: Move this into #render_to_body if action.is_a?(Hash) - options, action = action, nil + options, action = action, nil else options.merge! :action => action end - + _process_options(options) - + self.response_body = render_to_body(options) end @@ -34,18 +34,17 @@ module ActionController options[:_template_name] = options[:template] elsif options.key?(:action) options[:_template_name] = options[:action].to_s - options[:_prefix] = _prefix + options[:_prefix] = _prefix end - + super(options) end - + private - def _prefix controller_path - end - + end + def _text(options) text = options[:text] @@ -54,7 +53,7 @@ module ActionController else text.to_s end end - + def _process_options(options) if status = options[:status] response.status = status.to_i diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index af5b21012b..3179c8cd5b 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -16,7 +16,7 @@ module ActionController # by this method. def default_url_options(options = nil) end - + def rewrite_options(options) #:nodoc: if defaults = default_url_options(options) defaults.merge(options) @@ -24,7 +24,7 @@ module ActionController options end end - + def url_for(options = {}) options ||= {} case options @@ -37,4 +37,4 @@ module ActionController end end end -end \ No newline at end of file +end -- cgit v1.2.3 From 030dfe3f831aacd60bbfa525dfac4cd5921b6530 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 11 May 2009 10:22:07 -0700 Subject: More community code review :) --- actionpack/lib/action_controller/abstract/base.rb | 3 +-- .../lib/action_controller/abstract/helpers.rb | 9 +-------- .../lib/action_controller/abstract/renderer.rb | 4 ++-- actionpack/lib/action_view/template/text.rb | 2 ++ .../abstract_controller_test.rb | 20 ++++++++++---------- .../test/abstract_controller/callbacks_test.rb | 18 +++++++++--------- actionpack/test/abstract_controller/helper_test.rb | 2 +- .../test/abstract_controller/layouts_test.rb | 22 +++++++++++----------- 8 files changed, 37 insertions(+), 43 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 8a8e748c0e..ab9aed0b26 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -54,7 +54,6 @@ module AbstractController @_action_name = action_name process_action - self.response_obj[:body] = self.response_body self end @@ -71,7 +70,7 @@ module AbstractController # action_name is found. def process_action if respond_to?(action_name) then send(action_name) - elsif respond_to?(:action_missing, true) then send(:action_missing, action_name) + elsif respond_to?(:action_missing, true) then action_missing(action_name) end end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 1f0b38417b..370e3a79ee 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -6,14 +6,7 @@ module AbstractController extlib_inheritable_accessor :master_helper_module self.master_helper_module = Module.new end - - # def self.included(klass) - # klass.class_eval do - # extlib_inheritable_accessor :master_helper_module - # self.master_helper_module = Module.new - # end - # end - + def _action_view @_action_view ||= begin av = super diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index 716b213c75..bed7f75b2f 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -20,13 +20,13 @@ module AbstractController self._view_paths ||= ActionView::PathSet.new end - + def _action_view @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end def render(options = {}) - unless response_body.nil? + if response_body raise AbstractController::DoubleRenderError, "OMG" end diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 446c735ba3..8477115211 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,5 +1,7 @@ module ActionView #:nodoc: class TextTemplate < String #:nodoc: + + def identifier() self end def render(*) self end diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index c283a7319d..28f9ac5820 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -20,7 +20,7 @@ module AbstractController class TestBasic < ActiveSupport::TestCase test "dispatching works" do result = Me.process(:index) - assert_equal "Hello world", result.response_obj[:body] + assert_equal "Hello world", result.response_body end end @@ -69,27 +69,27 @@ module AbstractController class TestRenderer < ActiveSupport::TestCase test "rendering templates works" do result = Me2.process(:index) - assert_equal "Hello from index.erb", result.response_obj[:body] + assert_equal "Hello from index.erb", result.response_body end test "rendering passes ivars to the view" do result = Me2.process(:action_with_ivars) - assert_equal "Hello from index_with_ivars.erb", result.response_obj[:body] + assert_equal "Hello from index_with_ivars.erb", result.response_body end test "rendering with no template name" do result = Me2.process(:naked_render) - assert_equal "Hello from naked_render.erb", result.response_obj[:body] + assert_equal "Hello from naked_render.erb", result.response_body end test "rendering to a rack body" do result = Me2.process(:rendering_to_body) - assert_equal "Hello from naked_render.erb", result.response_obj[:body] + assert_equal "Hello from naked_render.erb", result.response_body end test "rendering to a string" do result = Me2.process(:rendering_to_string) - assert_equal "Hello from naked_render.erb", result.response_obj[:body] + assert_equal "Hello from naked_render.erb", result.response_body end end @@ -121,12 +121,12 @@ module AbstractController class TestPrefixedViews < ActiveSupport::TestCase test "templates are located inside their 'prefix' folder" do result = Me3.process(:index) - assert_equal "Hello from me3/index.erb", result.response_obj[:body] + assert_equal "Hello from me3/index.erb", result.response_body end test "templates included their format" do result = Me3.process(:formatted) - assert_equal "Hello from me3/formatted.html.erb", result.response_obj[:body] + assert_equal "Hello from me3/formatted.html.erb", result.response_body end end @@ -174,7 +174,7 @@ module AbstractController class TestLayouts < ActiveSupport::TestCase test "layouts are included" do result = Me4.process(:index) - assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", result.response_obj[:body] + assert_equal "Me4 Enter : Hello from me4/index.erb : Exit", result.response_body end end @@ -211,7 +211,7 @@ module AbstractController class TestRespondToAction < ActiveSupport::TestCase def assert_dispatch(klass, body = "success", action = :index) - response = klass.process(action).response_obj[:body] + response = klass.process(action).response_body assert_equal body, response end diff --git a/actionpack/test/abstract_controller/callbacks_test.rb b/actionpack/test/abstract_controller/callbacks_test.rb index 5fce30f478..7137129823 100644 --- a/actionpack/test/abstract_controller/callbacks_test.rb +++ b/actionpack/test/abstract_controller/callbacks_test.rb @@ -22,7 +22,7 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "basic callbacks work" do result = Callback1.process(:index) - assert_equal "Hello world", result.response_obj[:body] + assert_equal "Hello world", result.response_body end end @@ -53,7 +53,7 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "before_filter works" do result = Callback2.process(:index) - assert_equal "Hello world", result.response_obj[:body] + assert_equal "Hello world", result.response_body end test "after_filter works" do @@ -84,7 +84,7 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "before_filter works with procs" do result = Callback3.process(:index) - assert_equal "Hello world", result.response_obj[:body] + assert_equal "Hello world", result.response_body end test "after_filter works with procs" do @@ -119,12 +119,12 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "when :only is specified, a before filter is triggered on that action" do result = CallbacksWithConditions.process(:index) - assert_equal "Hello, World", result.response_obj[:body] + assert_equal "Hello, World", result.response_body end test "when :only is specified, a before filter is not triggered on other actions" do result = CallbacksWithConditions.process(:sekrit_data) - assert_equal "true", result.response_obj[:body] + assert_equal "true", result.response_body end test "when :except is specified, an after filter is not triggered on that action" do @@ -159,12 +159,12 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "when :only is specified with an array, a before filter is triggered on that action" do result = CallbacksWithArrayConditions.process(:index) - assert_equal "Hello, World", result.response_obj[:body] + assert_equal "Hello, World", result.response_body end test "when :only is specified with an array, a before filter is not triggered on other actions" do result = CallbacksWithArrayConditions.process(:sekrit_data) - assert_equal "true", result.response_obj[:body] + assert_equal "true", result.response_body end test "when :except is specified with an array, an after filter is not triggered on that action" do @@ -184,12 +184,12 @@ module AbstractController class TestCallbacks < ActiveSupport::TestCase test "when a callback is modified in a child with :only, it works for the :only action" do result = ChangedConditions.process(:index) - assert_equal "Hello world", result.response_obj[:body] + assert_equal "Hello world", result.response_body end test "when a callback is modified in a child with :only, it does not work for other actions" do result = ChangedConditions.process(:not_index) - assert_equal "", result.response_obj[:body] + assert_equal "", result.response_body end end diff --git a/actionpack/test/abstract_controller/helper_test.rb b/actionpack/test/abstract_controller/helper_test.rb index 6284fa4f70..15c89b4d24 100644 --- a/actionpack/test/abstract_controller/helper_test.rb +++ b/actionpack/test/abstract_controller/helper_test.rb @@ -35,7 +35,7 @@ module AbstractController class TestHelpers < ActiveSupport::TestCase def test_helpers result = MyHelpers1.process(:index) - assert_equal "Hello World : Included", result.response_obj[:body] + assert_equal "Hello World : Included", result.response_body end end diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb index 078e0037a8..961e7ce6d3 100644 --- a/actionpack/test/abstract_controller/layouts_test.rb +++ b/actionpack/test/abstract_controller/layouts_test.rb @@ -152,12 +152,12 @@ module AbstractControllerTests class TestBase < ActiveSupport::TestCase test "when no layout is specified, and no default is available, render without a layout" do result = Blank.process(:index) - assert_equal "Hello blank!", result.response_obj[:body] + assert_equal "Hello blank!", result.response_body end test "when layout is specified as a string, render with that layout" do result = WithString.process(:index) - assert_equal "With String Hello string!", result.response_obj[:body] + assert_equal "With String Hello string!", result.response_body end test "when layout is specified as a string, but the layout is missing, raise an exception" do @@ -166,22 +166,22 @@ module AbstractControllerTests test "when layout is specified as false, do not use a layout" do result = WithFalseLayout.process(:index) - assert_equal "Hello false!", result.response_obj[:body] + assert_equal "Hello false!", result.response_body end test "when layout is specified as nil, do not use a layout" do result = WithNilLayout.process(:index) - assert_equal "Hello nil!", result.response_obj[:body] + assert_equal "Hello nil!", result.response_body end test "when layout is specified as a symbol, call the requested method and use the layout returned" do result = WithSymbol.process(:index) - assert_equal "OMGHI2U Hello symbol!", result.response_obj[:body] + assert_equal "OMGHI2U Hello symbol!", result.response_body end test "when layout is specified as a symbol and the method returns nil, don't use a layout" do result = WithSymbolReturningNil.process(:index) - assert_equal "Hello nilz!", result.response_obj[:body] + assert_equal "Hello nilz!", result.response_body end test "when the layout is specified as a symbol and the method doesn't exist, raise an exception" do @@ -194,28 +194,28 @@ module AbstractControllerTests test "when a child controller does not have a layout, use the parent controller layout" do result = WithStringChild.process(:index) - assert_equal "With String Hello string!", result.response_obj[:body] + assert_equal "With String Hello string!", result.response_body end test "when a child controller has specified a layout, use that layout and not the parent controller layout" do result = WithStringOverriddenChild.process(:index) - assert_equal "With Override Hello string!", result.response_obj[:body] + assert_equal "With Override Hello string!", result.response_body end test "when a child controller has an implied layout, use that layout and not the parent controller layout" do result = WithStringImpliedChild.process(:index) - assert_equal "With Implied Hello string!", result.response_obj[:body] + assert_equal "With Implied Hello string!", result.response_body end test "when a child controller specifies layout nil, do not use the parent layout" do result = WithNilChild.process(:index) - assert_equal "Hello string!", result.response_obj[:body] + assert_equal "Hello string!", result.response_body end test "when a grandchild has no layout specified, the child has an implied layout, and the " \ "parent has specified a layout, use the child controller layout" do result = WithChildOfImplied.process(:index) - assert_equal "With Implied Hello string!", result.response_obj[:body] + assert_equal "With Implied Hello string!", result.response_body end test "raises an exception when specifying layout true" do -- cgit v1.2.3 From a2f3684cecb361db2bf5f7ec0b6de0603868ffd5 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 10:57:59 -0700 Subject: Ported fresh_when into a ConditionalGet module --- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + .../action_controller/new_base/conditional_get.rb | 42 +++++++++++++++++++ .../lib/action_controller/new_base/testing.rb | 1 + actionpack/test/new_base/etag_test.rb | 47 ++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 actionpack/lib/action_controller/new_base/conditional_get.rb create mode 100644 actionpack/test/new_base/etag_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 7098b812f6..8a7de1476c 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -1,5 +1,6 @@ module ActionController autoload :Base, "action_controller/new_base/base" + autoload :ConditionalGet, "action_controller/new_base/conditional_get" autoload :HideActions, "action_controller/new_base/hide_actions" autoload :Http, "action_controller/new_base/http" autoload :Layouts, "action_controller/new_base/layouts" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 8af6ffbc92..40f507b6e7 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -10,6 +10,7 @@ module ActionController use ActionController::UrlFor use ActionController::Renderer use ActionController::Layouts + use ActionController::ConditionalGet # Legacy modules include SessionManagement diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb new file mode 100644 index 0000000000..16104c51fc --- /dev/null +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -0,0 +1,42 @@ +module ActionController + module ConditionalGet + + # Sets the etag, last_modified, or both on the response and renders a + # "304 Not Modified" response if the request is already fresh. + # + # Parameters: + # * :etag + # * :last_modified + # * :public By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). + # + # Example: + # + # def show + # @article = Article.find(params[:id]) + # fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true) + # end + # + # This will render the show template if the request isn't sending a matching etag or + # If-Modified-Since header and just a "304 Not Modified" response if there's a match. + # + def fresh_when(options) + options.assert_valid_keys(:etag, :last_modified, :public) + + response.etag = options[:etag] if options[:etag] + response.last_modified = options[:last_modified] if options[:last_modified] + + if options[:public] + cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } + cache_control.delete("private") + cache_control.delete("no-cache") + cache_control << "public" + response.headers["Cache-Control"] = cache_control.join(', ') + end + + if request.fresh?(response) + head :not_modified + end + end + + end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 428f339b3d..181c5c0ecd 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -7,6 +7,7 @@ module ActionController @_response = response ret = process(request.parameters[:action]) @_response.body = self.response_body + @_response.prepare! set_test_assigns ret end diff --git a/actionpack/test/new_base/etag_test.rb b/actionpack/test/new_base/etag_test.rb new file mode 100644 index 0000000000..7af5febfb3 --- /dev/null +++ b/actionpack/test/new_base/etag_test.rb @@ -0,0 +1,47 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module Etags + + class BasicController < ActionController::Base + + self.view_paths = [ActionView::Template::FixturePath.new( + "etags/basic/base.html.erb" => "Hello from without_layout.html.erb", + "layouts/etags.html.erb" => "teh <%= yield %> tagz" + )] + + def without_layout + render :action => "base" + end + + def with_layout + render :action => "base", :layout => "etag" + end + + end + + class TestBasic < SimpleRouteCase + describe "Rendering without any special etag options returns an etag that is an MD5 hash of its text" + + test "an action without a layout" do + get "/etags/basic/without_layout" + body = "Hello from without_layout.html.erb" + assert_body body + assert_header "Etag", etag_for(body) + assert_status 200 + end + + test "an action with a layout" do + get "/etags/basic/with_layout" + body = "teh Hello from without_layout.html.erb tagz" + assert_body body + assert_header "Etag", etag_for(body) + assert_status 200 + end + + def etag_for(text) + %("#{Digest::MD5.hexdigest(text)}") + end + end + + +end \ No newline at end of file -- cgit v1.2.3 From c1d120a71e74aa3ccab6dc28a5406b87a51a69c1 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 11:48:38 -0700 Subject: Don't run the action if callbacks are halted. In AbstractController, this means that response_body is not empty --- actionpack/lib/action_controller/abstract/callbacks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 5f1607940a..f3210a040a 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -2,7 +2,7 @@ module AbstractController module Callbacks setup do include ActiveSupport::NewCallbacks - define_callbacks :process_action + define_callbacks :process_action, "response_body" end def process_action -- cgit v1.2.3 From 94ee9d245289a36207847a684b51dbd1c7a6a4eb Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 12:04:43 -0700 Subject: Ported ConditionalGet to new Base --- actionpack/lib/action_controller/new_base/base.rb | 1 + .../action_controller/new_base/compatibility.rb | 3 + .../action_controller/new_base/conditional_get.rb | 91 +++++++++++++++++++++- actionpack/lib/action_controller/new_base/http.rb | 1 + .../lib/action_controller/new_base/testing.rb | 1 + actionpack/lib/action_view/template/text.rb | 2 + actionpack/test/controller/render_test.rb | 8 +- 7 files changed, 102 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 40f507b6e7..313b9a5e1f 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -14,6 +14,7 @@ module ActionController # Legacy modules include SessionManagement + include ActionDispatch::StatusCodes # Rails 2.x compatibility use ActionController::Rails2Compatibility diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index db471f7658..3b1a74ec0c 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -26,6 +26,9 @@ module ActionController if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') end + + options[:text] = nil if options[:nothing] == true + super end diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index 16104c51fc..e1407e671a 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -36,7 +36,96 @@ module ActionController if request.fresh?(response) head :not_modified end - end + end + + # Return a response that has no content (merely headers). The options + # argument is interpreted to be a hash of header names and values. + # This allows you to easily return a response that consists only of + # significant headers: + # + # head :created, :location => person_path(@person) + # + # It can also be used to return exceptional conditions: + # + # return head(:method_not_allowed) unless request.post? + # return head(:bad_request) unless valid_request? + # render + def head(*args) + if args.length > 2 + raise ArgumentError, "too many arguments to head" + elsif args.empty? + raise ArgumentError, "too few arguments to head" + end + options = args.extract_options! + status = interpret_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 + end + + render :nothing => true, :status => status + end + + # Sets the etag and/or last_modified on the response and checks it against + # the client request. If the request doesn't match the options provided, the + # request is considered stale and should be generated from scratch. Otherwise, + # it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent. + # + # Parameters: + # * :etag + # * :last_modified + # * :public By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). + # + # Example: + # + # def show + # @article = Article.find(params[:id]) + # + # if stale?(:etag => @article, :last_modified => @article.created_at.utc) + # @statistics = @article.really_expensive_call + # respond_to do |format| + # # all the supported formats + # end + # end + # end + def stale?(options) + fresh_when(options) + !request.fresh?(response) + end + + # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that + # intermediate caches shouldn't cache the response. + # + # Examples: + # expires_in 20.minutes + # expires_in 3.hours, :public => true + # expires in 3.hours, 'max-stale' => 5.hours, :public => true + # + # This method will overwrite an existing Cache-Control header. + # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. + def expires_in(seconds, options = {}) #:doc: + cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } + + cache_control << "max-age=#{seconds}" + cache_control.delete("no-cache") + if options[:public] + cache_control.delete("private") + cache_control << "public" + else + cache_control << "private" + end + + # This allows for additional headers to be passed through like 'max-stale' => 5.hours + cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"} + + response.headers["Cache-Control"] = cache_control.join(', ') + end + + # Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or + # intermediate caches (like caching proxy servers). + def expires_now #:doc: + response.headers["Cache-Control"] = "no-cache" + end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index b7e3bfaa7e..f269fe70db 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -42,6 +42,7 @@ module ActionController def call(name, env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new + @_response.request = request process(name) @_response.body = response_body @_response.prepare! diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 181c5c0ecd..106990b9ba 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -5,6 +5,7 @@ module ActionController def process_with_test(request, response) @_request = request @_response = response + @_response.request = request ret = process(request.parameters[:action]) @_response.body = self.response_body @_response.prepare! diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 8477115211..a777021a12 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -6,5 +6,7 @@ module ActionView #:nodoc: def render(*) self end def mime_type() Mime::HTML end + + def partial?() false end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 1e69ca894f..635b0f5342 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1660,13 +1660,13 @@ class EtagRenderTest < ActionController::TestCase def test_render_against_etag_request_should_200_when_no_match @request.if_none_match = etag_for("hello somewhere else") get :render_hello_world_from_variable - assert_equal "200 OK", @response.status + assert_equal 200, @response.status.to_i assert !@response.body.empty? end def test_render_should_not_set_etag_when_last_modified_has_been_specified get :render_hello_world_with_last_modified_set - assert_equal "200 OK", @response.status + assert_equal 200, @response.status.to_i assert_not_nil @response.last_modified assert_nil @response.etag assert @response.body.present? @@ -1752,7 +1752,7 @@ class LastModifiedRenderTest < ActionController::TestCase def test_request_not_modified @request.if_modified_since = @last_modified get :conditional_hello - assert_equal "304 Not Modified", @response.status + assert_equal 304, @response.status.to_i assert @response.body.blank?, @response.body assert_equal @last_modified, @response.headers['Last-Modified'] end @@ -1767,7 +1767,7 @@ class LastModifiedRenderTest < ActionController::TestCase def test_request_modified @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT' get :conditional_hello - assert_equal "200 OK", @response.status + assert_equal 200, @response.status.to_i assert !@response.body.blank? assert_equal @last_modified, @response.headers['Last-Modified'] end -- cgit v1.2.3 From 6694bd46f59eb9b9b23afbd0d9484fd87e8fe350 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 12:45:26 -0700 Subject: Aliased AbstractController::ActionNotFound to ActionController::UnknownAction --- actionpack/lib/action_controller/new_base/compatibility.rb | 13 ++++++++----- actionpack/lib/action_controller/testing/process2.rb | 1 + actionpack/test/abstract_unit2.rb | 3 --- actionpack/test/controller/render_test.rb | 5 +++-- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 3b1a74ec0c..b6e15a4e0d 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -3,6 +3,9 @@ module ActionController # Temporary hax setup do + ::ActionController::UnknownAction = ::AbstractController::ActionNotFound + ::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError + cattr_accessor :session_options self.send(:class_variable_set, "@@session_options", {}) @@ -31,11 +34,11 @@ module ActionController super end - - def _layout_for_name(name) - name &&= name.sub(%r{^/?layouts/}, '') - super - end + + def _layout_for_name(name) + name &&= name.sub(%r{^/?layouts/}, '') + super + end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 67b5afb9c5..18b7335450 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -39,6 +39,7 @@ module ActionController @request.recycle! @response.recycle! + @controller.response_body = nil @html_document = nil @request.env['REQUEST_METHOD'] = http_method diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index b95bfa0202..680043fab0 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -57,9 +57,6 @@ module ActionController class UnknownController < ActionControllerError #:nodoc: end - class UnknownAction < ActionControllerError #:nodoc: - end - class MissingFile < ActionControllerError #:nodoc: end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 635b0f5342..414b84c029 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1680,11 +1680,12 @@ class EtagRenderTest < ActionController::TestCase @request.if_none_match = expected_etag get :render_hello_world_from_variable - assert_equal "304 Not Modified", @response.status + assert_equal 304, @response.status.to_i + @response = ActionController::TestResponse.new @request.if_none_match = "\"diftag\"" get :render_hello_world_from_variable - assert_equal "200 OK", @response.status + assert_equal 200, @response.status.to_i end def render_with_404_shouldnt_have_etag -- cgit v1.2.3 From 0f6e764e4060b75ea8a335e6971209a08bf8b40a Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 14:48:58 -0700 Subject: Fixed a bug with handling render options --- .../action_controller/new_base/compatibility.rb | 9 +++ .../lib/action_controller/new_base/renderer.rb | 4 +- actionpack/test/abstract_unit2.rb | 65 +--------------------- 3 files changed, 12 insertions(+), 66 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index b6e15a4e0d..505675ec4d 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -23,6 +23,15 @@ module ActionController cattr_accessor :default_charset self.send(:class_variable_set, "@@default_charset", "utf-8") + + cattr_reader :protected_instance_variables + self.send(:class_variable_set, "@@protected_instance_variables", %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller + @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params + @_flash @_response)) + end + + module ClassMethods + def protect_from_forgery() end end def render_to_body(options) diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 4c4a74979b..bedd1d7a23 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -23,8 +23,8 @@ module ActionController options[:_template] = template elsif options.key?(:template) options[:_template_name] = options[:template] - elsif options.key?(:action) - options[:_template_name] = options[:action].to_s + else + options[:_template_name] = (options[:action] || action_name).to_s options[:_prefix] = _prefix end diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index 680043fab0..95e7b2e273 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -74,71 +74,8 @@ module ActionController class UnknownHttpMethod < ActionControllerError #:nodoc: end - class Base < Http - abstract! - # - cattr_accessor :relative_url_root - self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] - - cattr_reader :protected_instance_variables - # Controller specific instance variables which will not be accessible inside views. - @@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller - @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params - @_flash @_response) - # - - use AbstractController::Callbacks - use AbstractController::Helpers - use AbstractController::Logger - - use ActionController::HideActions - use ActionController::UrlFor - use ActionController::Renderer - use ActionController::Layouts - use ActionController::Rails2Compatibility + class Base use ActionController::Testing - - def self.protect_from_forgery() end - - def self.inherited(klass) - ::ActionController::Base.subclasses << klass.to_s - super - end - - def self.subclasses - @subclasses ||= [] - end - - def self.app_loaded! - @subclasses.each do |subclass| - subclass.constantize._write_layout_method - end - end - - def render(action = action_name, options = {}) - if action.is_a?(Hash) - options, action = action, nil - else - options.merge! :action => action - end - - super(options) - end - - def render_to_body(options = {}) - options = {:template => options} if options.is_a?(String) - super - end - - def process_action - ret = super - render if response_body.nil? - ret - end - - def respond_to_action?(action_name) - super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) - end end Base.view_paths = FIXTURE_LOAD_PATH -- cgit v1.2.3 From 0cac68d3bed3e6bf8ec2eb994858e4a179046941 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 11 May 2009 15:03:24 -0700 Subject: Revert "Whitespace!" This reverts commit a747ab5b20b9d543e9d311070e3b720c761ae716. --- actionpack/lib/action_controller/abstract.rb | 2 +- actionpack/lib/action_controller/abstract/base.rb | 19 ++++++++------- .../lib/action_controller/abstract/callbacks.rb | 8 +++---- .../lib/action_controller/abstract/exceptions.rb | 2 +- .../lib/action_controller/abstract/helpers.rb | 17 +++++++------- .../lib/action_controller/abstract/layouts.rb | 27 +++++++++++----------- .../lib/action_controller/abstract/logger.rb | 2 +- .../lib/action_controller/abstract/renderer.rb | 19 +++++++-------- actionpack/lib/action_controller/new_base.rb | 2 +- actionpack/lib/action_controller/new_base/base.rb | 27 +++++++++++----------- .../lib/action_controller/new_base/hide_actions.rb | 11 +++++---- .../lib/action_controller/new_base/layouts.rb | 14 ++++++----- .../lib/action_controller/new_base/renderer.rb | 23 +++++++++--------- .../lib/action_controller/new_base/url_for.rb | 6 ++--- 14 files changed, 95 insertions(+), 84 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index 9442d4559f..3f5c4a185f 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -7,4 +7,4 @@ module AbstractController autoload :Renderer, "action_controller/abstract/renderer" # === Exceptions autoload :ActionNotFound, "action_controller/abstract/exceptions" -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 39e9ad0440..ade7719cc0 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,38 +1,41 @@ module AbstractController class Base + attr_internal :response_body attr_internal :response_obj attr_internal :action_name - + def self.process(action) new.process(action) end - + def self.inherited(klass) end - + def initialize self.response_obj = {} end - + def process(action_name) unless respond_to_action?(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end - + @_action_name = action_name process_action self.response_obj[:body] = self.response_body self end - + private + def process_action respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name) end - + def respond_to_action?(action_name) respond_to?(action_name) || respond_to?(:action_missing, true) end + end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index cb8aade0be..d7faaf4236 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -13,7 +13,7 @@ module AbstractController super end end - + module ClassMethods def _normalize_callback_options(options) if only = options[:only] @@ -21,11 +21,11 @@ module AbstractController options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") + except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") options[:per_key] = {:unless => except} end end - + [:before, :after, :around].each do |filter| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{filter}_filter(*names, &blk) @@ -40,4 +40,4 @@ module AbstractController end end end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb index a7d07868bb..ec4680629b 100644 --- a/actionpack/lib/action_controller/abstract/exceptions.rb +++ b/actionpack/lib/action_controller/abstract/exceptions.rb @@ -1,3 +1,3 @@ module AbstractController class ActionNotFound < StandardError ; end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 38e3ce8127..62caa119e7 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -8,14 +8,14 @@ module AbstractController extlib_inheritable_accessor :master_helper_module self.master_helper_module = Module.new end - + # def self.included(klass) # klass.class_eval do # extlib_inheritable_accessor :master_helper_module # self.master_helper_module = Module.new # end # end - + def _action_view @_action_view ||= begin av = super @@ -23,19 +23,19 @@ module AbstractController av end end - + module ClassMethods def inherited(klass) klass.master_helper_module = Module.new klass.master_helper_module.__send__ :include, master_helper_module - + super end - + def add_template_helper(mod) master_helper_module.module_eval { include mod } end - + def helper_method(*meths) meths.flatten.each do |meth| master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 @@ -45,7 +45,7 @@ module AbstractController ruby_eval end end - + def helper(*args, &blk) args.flatten.each do |arg| case arg @@ -56,5 +56,6 @@ module AbstractController master_helper_module.module_eval(&blk) if block_given? end end + end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 69fe4efc19..76130f8dc0 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -9,18 +9,18 @@ module AbstractController unless [String, Symbol, FalseClass, NilClass].include?(layout.class) raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil" end - + @_layout = layout || false # Converts nil to false _write_layout_method end - + def _implied_layout_name name.underscore end - + # Takes the specified layout and creates a _layout method to be called # by _default_layout - # + # # If the specified layout is a: # String:: return the string # Symbol:: call the method specified by the symbol @@ -49,34 +49,35 @@ module AbstractController end end end - + def _render_template(template, options) _action_view._render_template_with_layout(template, options[:_layout]) end - + private + def _layout() end # This will be overwritten - + def _layout_for_name(name) 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") end - + def _default_layout(require_layout = false) if require_layout && !_layout - raise ArgumentError, + raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" end - + begin layout = _layout_for_name(_layout) rescue NameError => e - raise NoMethodError, + raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end end end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index c3bccd7778..5fb78f1755 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -6,4 +6,4 @@ module AbstractController cattr_accessor :logger end end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index b5c31a27ee..beb848f90e 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -15,22 +15,22 @@ module AbstractController end def _action_view - @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) + @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - + def render(options = {}) self.response_body = render_to_body(options) end - + # Raw rendering of a template to a Rack-compatible body. # ==== # @option _prefix The template's path prefix # @option _layout The relative path to the layout template to use - # + # # :api: plugin def render_to_body(options = {}) name = options[:_template_name] || action_name - + template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) _render_template(template, options) end @@ -39,7 +39,7 @@ module AbstractController # ==== # @option _prefix The template's path prefix # @option _layout The relative path to the layout template to use - # + # # :api: plugin def render_to_string(options = {}) AbstractController::Renderer.body_to_s(render_to_body(options)) @@ -48,7 +48,7 @@ module AbstractController def _render_template(template, options) _action_view._render_template_with_layout(template) end - + def view_paths() _view_paths end # Return a string representation of a Rack-compatible response body. @@ -64,14 +64,15 @@ module AbstractController end module ClassMethods + def append_view_path(path) self.view_paths << path end - + def view_paths self._view_paths end - + def view_paths=(paths) self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 29dc3aaddc..7c65f1cdc1 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -4,4 +4,4 @@ module ActionController autoload :Layouts, "action_controller/new_base/layouts" autoload :Renderer, "action_controller/new_base/renderer" autoload :UrlFor, "action_controller/new_base/url_for" -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 2dd5390c99..08e7a1a0e7 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,5 +1,6 @@ module ActionController class AbstractBase < AbstractController::Base + # :api: public attr_internal :request, :response, :params @@ -11,46 +12,46 @@ module ActionController # :api: public def controller_name() self.class.controller_name end - # :api: public + # :api: public def self.controller_path @controller_path ||= self.name.sub(/Controller$/, '').underscore end - - # :api: public + + # :api: public def controller_path() self.class.controller_path end - - # :api: private + + # :api: private def self.action_methods @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS) end - - # :api: private + + # :api: private def self.action_names() action_methods end - - # :api: private + + # :api: private def action_methods() self.class.action_names end # :api: private def action_names() action_methods end - + # :api: plugin def self.call(env) controller = new controller.call(env).to_rack end - + # :api: plugin def response_body=(body) @_response.body = body end - + # :api: private def call(env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new process(@_request.parameters[:action]) end - + # :api: private def to_rack response.to_a diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index 422ea180c4..aa420442fb 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -6,20 +6,21 @@ module ActionController end def action_methods() self.class.action_names end - def action_names() action_methods end - + def action_names() action_methods end + private + def respond_to_action?(action_name) !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing)) end - + module ClassMethods def hide_action(*args) args.each do |arg| self.hidden_actions << arg.to_s end end - + def action_methods @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) end @@ -27,4 +28,4 @@ module ActionController def self.action_names() action_methods end end end -end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index 228162421d..89d24fe92d 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -4,13 +4,13 @@ module ActionController depends_on ActionController::Renderer depends_on AbstractController::Layouts - + module ClassMethods def _implied_layout_name controller_path end end - + def render_to_body(options) # render :text => ..., :layout => ... # or @@ -18,20 +18,22 @@ module ActionController if !options.key?(:text) || options.key?(:layout) options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout end - + super end - + private + def _layout_for_option(name) case name when String then _layout_for_name(name) when true then _default_layout(true) when false, nil then nil else - raise ArgumentError, - "String, true, or false, expected for `layout'; you passed #{name.inspect}" + raise ArgumentError, + "String, true, or false, expected for `layout'; you passed #{name.inspect}" end end + end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index d7ea9ec4a5..be4ea54c3b 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -3,22 +3,22 @@ module ActionController extend ActiveSupport::DependencyModule depends_on AbstractController::Renderer - + def initialize(*) self.formats = [:html] super end - + def render(action, options = {}) # TODO: Move this into #render_to_body if action.is_a?(Hash) - options, action = action, nil + options, action = action, nil else options.merge! :action => action end - + _process_options(options) - + self.response_body = render_to_body(options) end @@ -34,17 +34,18 @@ module ActionController options[:_template_name] = options[:template] elsif options.key?(:action) options[:_template_name] = options[:action].to_s - options[:_prefix] = _prefix + options[:_prefix] = _prefix end - + super(options) end - + private + def _prefix controller_path - end - + end + def _text(options) text = options[:text] @@ -53,7 +54,7 @@ module ActionController else text.to_s end end - + def _process_options(options) if status = options[:status] response.status = status.to_i diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index 3179c8cd5b..af5b21012b 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -16,7 +16,7 @@ module ActionController # by this method. def default_url_options(options = nil) end - + def rewrite_options(options) #:nodoc: if defaults = default_url_options(options) defaults.merge(options) @@ -24,7 +24,7 @@ module ActionController options end end - + def url_for(options = {}) options ||= {} case options @@ -37,4 +37,4 @@ module ActionController end end end -end +end \ No newline at end of file -- cgit v1.2.3 From 22c5667c2ef46d6723c1805d3adc52dc8e92429b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 11 May 2009 19:49:11 -0700 Subject: Defer rake/contrib/sshpublisher require so we can use the stdlib rake instead of the full gem --- actionpack/Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 18610ed773..ef76eedfd7 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -4,7 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require 'rake/contrib/sshpublisher' require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version') PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' @@ -143,12 +142,14 @@ task :update_js => [ :update_scriptaculous ] desc "Publish the API documentation" task :pgem => [:package] do + require 'rake/contrib/sshpublisher' Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'` end desc "Publish the API documentation" task :pdoc => [:rdoc] do + require 'rake/contrib/sshpublisher' Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload end -- cgit v1.2.3 From 72ca7c591c9eace150c0ebab1633d691a1ef12cf Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 12 May 2009 10:53:00 -0700 Subject: Fixed new callbacks to not call the action when a callback sets the response body --- .../lib/action_controller/abstract/callbacks.rb | 2 +- actionpack/test/abstract_controller/callbacks_test.rb | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 6e15b3e81b..3aff83a209 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -5,7 +5,7 @@ module AbstractController depends_on ActiveSupport::NewCallbacks included do - define_callbacks :process_action + define_callbacks :process_action, "response_body" end def process_action diff --git a/actionpack/test/abstract_controller/callbacks_test.rb b/actionpack/test/abstract_controller/callbacks_test.rb index 410b1e57a6..1de60868c3 100644 --- a/actionpack/test/abstract_controller/callbacks_test.rb +++ b/actionpack/test/abstract_controller/callbacks_test.rb @@ -193,5 +193,24 @@ module AbstractController end end + class SetsResponseBody < ControllerWithCallbacks + before_filter :set_body + + def index + self.response_body = "Fail" + end + + def set_body + self.response_body = "Success" + end + end + + class TestHalting < ActiveSupport::TestCase + test "when a callback sets the response body, the action should not be invoked" do + result = SetsResponseBody.process(:index) + assert_equal "Success", result.response_body + end + end + end end \ No newline at end of file -- cgit v1.2.3 From 216309c16519d94a9e0aebf758029a78696ab8d6 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 12 May 2009 16:21:34 -0700 Subject: Implemented redirects and partial rendering in new base. --- actionpack/lib/action_controller/abstract/base.rb | 10 +++ .../lib/action_controller/abstract/layouts.rb | 2 +- .../lib/action_controller/abstract/renderer.rb | 29 ++++---- actionpack/lib/action_controller/base/redirect.rb | 4 +- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 79 ++++++++++++++++++++-- .../action_controller/new_base/compatibility.rb | 42 ++++++++---- actionpack/lib/action_controller/new_base/http.rb | 6 ++ .../lib/action_controller/new_base/layouts.rb | 2 +- .../lib/action_controller/new_base/redirector.rb | 19 ++++++ .../lib/action_controller/new_base/renderer.rb | 27 ++++++-- .../lib/action_controller/testing/process.rb | 10 +-- .../lib/action_controller/testing/process2.rb | 1 + actionpack/lib/action_dispatch/http/response.rb | 6 -- actionpack/lib/action_view/render/partials.rb | 32 +++++---- actionpack/lib/action_view/render/rendering.rb | 5 ++ actionpack/test/abstract_unit.rb | 4 ++ actionpack/test/abstract_unit2.rb | 69 ++++++++++--------- actionpack/test/controller/render_test.rb | 4 +- actionpack/test/new_base/redirect_test.rb | 1 + 20 files changed, 251 insertions(+), 102 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/redirector.rb create mode 100644 actionpack/test/new_base/redirect_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index ab9aed0b26..c9e1081b23 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,4 +1,14 @@ module AbstractController + class Error < StandardError; end + + class DoubleRenderError < Error + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + class Base attr_internal :response_body diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index e48b8b2b4b..35d5e85ed9 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -51,7 +51,7 @@ module AbstractController end def _render_template(template, options) - _action_view._render_template_with_layout(template, options[:_layout], options) + _action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial]) end private diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index b58688c9da..f2044a35ec 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -1,15 +1,6 @@ require "action_controller/abstract/logger" module AbstractController - class AbstractControllerError < StandardError; end - class DoubleRenderError < AbstractControllerError - DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." - - def initialize(message = nil) - super(message || DEFAULT_MESSAGE) - end - end - module Renderer extend ActiveSupport::DependencyModule @@ -27,12 +18,12 @@ module AbstractController @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - def render(options = {}) + def render(*args) if response_body raise AbstractController::DoubleRenderError, "OMG" end - self.response_body = render_to_body(options) + self.response_body = render_to_body(*args) end # Raw rendering of a template to a Rack-compatible body. @@ -43,10 +34,16 @@ module AbstractController # :api: plugin def render_to_body(options = {}) name = options[:_template_name] || action_name - - options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) - - _render_template(options[:_template], options) + + # 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) + end end # Raw rendering of a template to a string. @@ -60,7 +57,7 @@ module AbstractController end def _render_template(template, options) - _action_view._render_template_with_layout(template) + _action_view._render_template_from_controller(template, nil, options, options[:_partial]) end def view_paths() _view_paths end diff --git a/actionpack/lib/action_controller/base/redirect.rb b/actionpack/lib/action_controller/base/redirect.rb index 4849caac0a..7e10f614e2 100644 --- a/actionpack/lib/action_controller/base/redirect.rb +++ b/actionpack/lib/action_controller/base/redirect.rb @@ -70,7 +70,9 @@ module ActionController def redirect_to_full_url(url, status) raise DoubleRenderError if performed? logger.info("Redirected to #{url}") if logger && logger.info? - response.redirect(url, interpret_status(status)) + response.status = interpret_status(status) + response.location = url.gsub(/[\r\n]/, '') + response.body = "You are being redirected." @performed_redirect = true end diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 8a7de1476c..1f215bb6f1 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -5,6 +5,7 @@ module ActionController autoload :Http, "action_controller/new_base/http" autoload :Layouts, "action_controller/new_base/layouts" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" + autoload :Redirector, "action_controller/new_base/redirector" autoload :Renderer, "action_controller/new_base/renderer" autoload :Testing, "action_controller/new_base/testing" autoload :UrlFor, "action_controller/new_base/url_for" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 4892886341..1adcc9c71f 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -8,6 +8,7 @@ module ActionController include ActionController::HideActions include ActionController::UrlFor + include ActionController::Redirector include ActionController::Renderer include ActionController::Layouts include ActionController::ConditionalGet @@ -34,19 +35,83 @@ module ActionController end end - def render(action = action_name, options = {}) + def render_to_body(action = nil, options = {}) if action.is_a?(Hash) options, action = action, nil - else - options.merge! :action => action + elsif action.is_a?(String) || action.is_a?(Symbol) + key = case action = action.to_s + when %r{^/} then :file + when %r{/} then :template + else :action + end + options.merge! key => action + elsif action + options.merge! :partial => action + end + + if options.key?(:action) && options[:action].to_s.index("/") + options[:template] = options.delete(:action) end - super(options) + # options = {:template => options.to_s} if options.is_a?(String) || options.is_a?(Symbol) + super(options) || " " end - def render_to_body(options = {}) - options = {:template => options} if options.is_a?(String) - super + # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: + # + # * Hash - The URL will be generated by calling url_for with the +options+. + # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. + # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. + # * String not containing a protocol - The current protocol and host is prepended to the string. + # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. + # Short-hand for redirect_to(request.env["HTTP_REFERER"]) + # + # Examples: + # redirect_to :action => "show", :id => 5 + # redirect_to post + # redirect_to "http://www.rubyonrails.org" + # redirect_to "/images/screenshot.jpg" + # redirect_to articles_url + # redirect_to :back + # + # The redirection happens as a "302 Moved" header unless otherwise specified. + # + # Examples: + # redirect_to post_url(@post), :status=>:found + # redirect_to :action=>'atom', :status=>:moved_permanently + # redirect_to post_url(@post), :status=>301 + # redirect_to :action=>'atom', :status=>302 + # + # When using redirect_to :back, if there is no referrer, + # RedirectBackError will be raised. You may specify some fallback + # behavior for this case by rescuing RedirectBackError. + def redirect_to(options = {}, response_status = {}) #:doc: + raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? + + status = if options.is_a?(Hash) && options.key?(:status) + interpret_status(options.delete(:status)) + elsif response_status.key?(:status) + interpret_status(response_status[:status]) + else + 302 + end + + url = case options + # The scheme name consist of a letter followed by any combination of + # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") + # characters; and is terminated by a colon (":"). + when %r{^\w[\w\d+.-]*:.*} + options + when String + request.protocol + request.host_with_port + options + when :back + raise RedirectBackError unless refer = request.headers["Referer"] + refer + else + url_for(options) + end + + super(url, status) end def process_action diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 4655a94923..d17f498b60 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -8,27 +8,40 @@ module ActionController ::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError cattr_accessor :session_options - self.send(:class_variable_set, "@@session_options", {}) + self.session_options = {} cattr_accessor :allow_concurrency - self.send(:class_variable_set, "@@allow_concurrency", false) + self.allow_concurrency = false cattr_accessor :param_parsers - self.send(:class_variable_set, "@@param_parsers", { Mime::MULTIPART_FORM => :multipart_form, - Mime::URL_ENCODED_FORM => :url_encoded_form, - Mime::XML => :xml_simple, - Mime::JSON => :json }) + self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form, + Mime::URL_ENCODED_FORM => :url_encoded_form, + Mime::XML => :xml_simple, + Mime::JSON => :json } cattr_accessor :relative_url_root - self.send(:class_variable_set, "@@relative_url_root", ENV['RAILS_RELATIVE_URL_ROOT']) + self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] cattr_accessor :default_charset - self.send(:class_variable_set, "@@default_charset", "utf-8") + self.default_charset = "utf-8" - cattr_reader :protected_instance_variables - self.send(:class_variable_set, "@@protected_instance_variables", %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller + # cattr_reader :protected_instance_variables + cattr_accessor :protected_instance_variables + self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params - @_flash @_response)) + @_flash @_response) + + # Indicates whether or not optimise the generated named + # route helper methods + cattr_accessor :optimise_named_routes + self.optimise_named_routes = true + + cattr_accessor :resources_path_names + self.resources_path_names = { :new => 'new', :edit => 'edit' } + + # Controls the resource action separator + cattr_accessor :resource_action_separator + self.resource_action_separator = "/" end module ClassMethods @@ -38,7 +51,12 @@ module ActionController raise env["action_dispatch.rescue.exception"] end end - + + def initialize(*) + super + @template = _action_view + end + def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index f269fe70db..fb6041a04e 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -38,6 +38,12 @@ module ActionController controller.call(env).to_rack end + delegate :headers, :to => "@_response" + + def params + @_params ||= @_request.parameters + end + # :api: private def call(name, env) @_request = ActionDispatch::Request.new(env) diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index e851eb5f9a..bf5b14c4e1 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -15,7 +15,7 @@ module ActionController # render :text => ..., :layout => ... # or # render :anything_else - if (!options.key?(:text) && !options.key?(:inline)) || options.key?(:layout) + 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 diff --git a/actionpack/lib/action_controller/new_base/redirector.rb b/actionpack/lib/action_controller/new_base/redirector.rb new file mode 100644 index 0000000000..ff7b74341c --- /dev/null +++ b/actionpack/lib/action_controller/new_base/redirector.rb @@ -0,0 +1,19 @@ +module ActionController + class RedirectBackError < AbstractController::Error #:nodoc: + DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].' + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + + module Redirector + def redirect_to(url, status) #:doc: + raise AbstractController::DoubleRenderError if response_body + logger.info("Redirected to #{url}") if logger && logger.info? + response.status = status + response.location = url.gsub(/[\r\n]/, '') + self.response_body = "You are being redirected." + end + end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 41e3dfbe23..8a9f230603 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -9,13 +9,9 @@ module ActionController super end - def render(options = {}) + def render_to_body(options) _process_options(options) - super(options) - end - - def render_to_body(options) if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(_text(options)) template = nil @@ -25,12 +21,18 @@ module ActionController options[:_template] = template elsif options.key?(:template) options[:_template_name] = options[:template] + elsif options.key?(:file) + options[:_template_name] = options[:file] + elsif options.key?(:partial) + _render_partial(options[:partial], options) else 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 end @@ -49,6 +51,21 @@ module ActionController else text.to_s end end + + def _render_partial(partial, options) + case partial + when true + options[:_prefix] = _prefix + when String + options[:_prefix] = _prefix unless partial.index('/') + options[:_template_name] = partial + else + options[:_partial_object] = true + return + end + + options[:_partial] = options[:object] || true + end def _process_options(options) status, content_type = options.values_at(:status, :content_type) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 21023ac101..936f97ecb5 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -161,11 +161,13 @@ module ActionController #:nodoc: alias xhr :xml_http_request def assigns(key = nil) - if key.nil? - @controller.template.assigns - else - @controller.template.assigns[key.to_s] + assigns = {} + @controller.instance_variable_names.each do |ivar| + next if ActionController::Base.protected_instance_variables.include?(ivar) + assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar) end + + key.nil? ? assigns : assigns[key.to_s] end def session diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 18b7335450..e9a79369b9 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -50,6 +50,7 @@ module ActionController @request.session = ActionController::TestSession.new(session) unless session.nil? @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash build_request_uri(action, parameters) + @controller.request = @request @controller.params.merge!(parameters) # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest @controller.process_with_test(@request, @response) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 133b4f7335..c3b5a68f40 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -156,12 +156,6 @@ module ActionDispatch # :nodoc: end end - def redirect(url, status) - self.status = status - self.location = url.gsub(/[\r\n]/, '') - self.body = "You are being redirected." - end - def sending_file? headers["Content-Transfer-Encoding"] == "binary" end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 43f8a1edf8..f2429e8cef 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -171,11 +171,21 @@ module ActionView # <% end %> module Partials extend ActiveSupport::Memoizable + extend ActiveSupport::DependencyModule + + included do + attr_accessor :_partial + end + + def _render_partial_from_controller(*args) + @assigns_added = false + _render_partial(*args) + end def _render_partial(options = {}) #:nodoc: options[:locals] ||= {} - case path = partial = options[:partial] + case path = partial = options[:partial] when *_array_like_objects return _render_partial_collection(partial, options) else @@ -222,16 +232,7 @@ module ActionView ensure @_proc_for_layout = nil end - - def _render_partial_with_layout(layout, options) - if layout - prefix = controller && !layout.include?("/") ? controller.controller_path : nil - layout = find_by_parts(layout, {:formats => formats}, prefix, true) - end - content = _render_partial(options) - return _render_content_with_layout(content, layout, options[:locals]) - end - + def _deprecated_ivar_assign(template) if respond_to?(:controller) ivar = :"@#{template.variable_name}" @@ -287,13 +288,17 @@ module ActionView locals = (options[:locals] ||= {}) object ||= locals[:object] || locals[template.variable_name] - _set_locals(object, locals, template, options) + _set_locals(object, locals, template, options) + + self._partial = template + _render_template(template, locals) end end def _set_locals(object, locals, template, options) object ||= _deprecated_ivar_assign(template) + locals[:object] = locals[template.variable_name] = object locals[options[:as]] = object if options[:as] end @@ -316,6 +321,9 @@ module ActionView locals[template.counter_name] = index index += 1 + + self._partial = template + _render_template(template, locals) end.join(spacer) end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 6e368f27eb..fe785e7b20 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -95,6 +95,11 @@ module ActionView layout ? _render_content_with_layout(text, layout, options[:locals]) : text end + def _render_template_from_controller(*args) + @assigns_added = nil + _render_template_with_layout(*args) + end + def _render_template_with_layout(template, layout = nil, options = {}, partial = false) if controller && logger logger.info("Rendering #{template.identifier}" + diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index b07e6e5f3a..825ac9a46c 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -1,3 +1,6 @@ +if ENV["new_base"] + require "abstract_unit2" +else $:.unshift(File.dirname(__FILE__) + '/../lib') $:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') @@ -38,3 +41,4 @@ ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') ActionController::Base.view_paths = FIXTURE_LOAD_PATH +end \ No newline at end of file diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index 95e7b2e273..2fdaba7342 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -75,7 +75,7 @@ module ActionController end class Base - use ActionController::Testing + include ActionController::Testing end Base.view_paths = FIXTURE_LOAD_PATH @@ -89,43 +89,42 @@ module ActionController end def assert_template(options = {}, message = nil) - validate_response! - - clean_backtrace do - case options - when NilClass, String - hax = @controller._action_view.instance_variable_get(:@_rendered) - rendered = (hax[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting but rendering with ", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - hax[:template].blank? - else - rendered.any? { |t| t.match(options) } - end + validate_request! + + hax = @controller._action_view.instance_variable_get(:@_rendered) + + case options + when NilClass, String + rendered = (hax[:template] || []).map { |t| t.identifier } + msg = build_message(message, + "expecting but rendering with ", + options, rendered.join(', ')) + assert_block(msg) do + if options.nil? + hax[:template].blank? + else + rendered.any? { |t| t.match(options) } end - when Hash - if expected_partial = options[:partial] - partials = hax[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found.second - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial but action rendered ", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end + end + when Hash + if expected_partial = options[:partial] + partials = hax[:partials] + if expected_count = options[:count] + found = partials.detect { |p, _| p.identifier.match(expected_partial) } + actual_count = found.nil? ? 0 : found.second + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) else - assert hax[:partials].empty?, - "Expected no partials to be rendered" + msg = build_message(message, + "expecting partial but action rendered ", + options[:partial], partials.keys) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) end + else + assert hax[:partials].empty?, + "Expected no partials to be rendered" end end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index a58d9b08b5..4cea050a1e 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1,4 +1,4 @@ -require ENV['new_base'] ? 'abstract_unit2' : 'abstract_unit' +require 'abstract_unit' require 'controller/fake_models' require 'pathname' @@ -1647,7 +1647,7 @@ class EtagRenderTest < ActionController::TestCase def test_render_against_etag_request_should_304_when_match @request.if_none_match = etag_for("hello david") get :render_hello_world_from_variable - assert_equal 304, @response.status + assert_equal 304, @response.status.to_i assert @response.body.empty? end diff --git a/actionpack/test/new_base/redirect_test.rb b/actionpack/test/new_base/redirect_test.rb new file mode 100644 index 0000000000..e591ebd05f --- /dev/null +++ b/actionpack/test/new_base/redirect_test.rb @@ -0,0 +1 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") \ No newline at end of file -- cgit v1.2.3 From fa5da8ad54d68ea0484825845eb6f6a8e8bca361 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 13 May 2009 01:06:53 -0700 Subject: isolated_test task --- actionpack/Rakefile | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index ef76eedfd7..6ce8179646 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -34,6 +34,12 @@ Rake::TestTask.new(:test_action_pack) do |t| t.verbose = true #t.warning = true 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) + end or raise "Failures" +end desc 'ActiveRecord Integration Tests' Rake::TestTask.new(:test_active_record_integration) do |t| -- cgit v1.2.3 From e8550ee0329586b32de425e905c7af7e65bc78a8 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 13 May 2009 01:10:37 -0700 Subject: Cherry-pick core extensions --- actionpack/lib/action_controller.rb | 13 +++---------- actionpack/lib/action_controller/base/base.rb | 2 ++ .../lib/action_controller/base/chained/benchmarking.rb | 2 +- .../lib/action_controller/base/http_authentication.rb | 6 ++++-- actionpack/lib/action_controller/base/layout.rb | 4 ++++ actionpack/lib/action_controller/record_identifier.rb | 2 ++ actionpack/lib/action_controller/routing/builder.rb | 2 ++ actionpack/lib/action_controller/routing/route.rb | 8 +++++--- actionpack/lib/action_controller/testing/process.rb | 1 + actionpack/lib/action_dispatch.rb | 13 +++---------- actionpack/lib/action_dispatch/http/mime_type.rb | 1 + actionpack/lib/action_dispatch/http/request.rb | 1 + actionpack/lib/action_dispatch/http/response.rb | 1 + actionpack/lib/action_view.rb | 13 +++---------- actionpack/lib/action_view/base.rb | 3 +++ actionpack/lib/action_view/helpers/form_helper.rb | 9 +++++---- actionpack/lib/action_view/template/handlers/erb.rb | 1 + actionpack/test/abstract_controller/test_helper.rb | 4 ++-- actionpack/test/abstract_unit2.rb | 3 +-- actionpack/test/controller/addresses_render_test.rb | 1 + actionpack/test/controller/base_test.rb | 1 + actionpack/test/controller/capture_test.rb | 1 + actionpack/test/controller/helper_test.rb | 1 + 23 files changed, 49 insertions(+), 44 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index ab78bc9222..39083a84e9 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -21,16 +21,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -begin - require 'active_support' -rescue LoadError - activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" - if File.directory?(activesupport_path) - $:.unshift activesupport_path - require 'active_support' - end -end -require 'active_support/core/all' +activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" +$:.unshift activesupport_path if File.directory?(activesupport_path) +require 'active_support' require File.join(File.dirname(__FILE__), "action_pack") diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index d25801b17b..2813e71d12 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -1,5 +1,7 @@ require 'action_controller/deprecated' require 'set' +require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/module/attr_internal' module ActionController #:nodoc: class ActionControllerError < StandardError #:nodoc: diff --git a/actionpack/lib/action_controller/base/chained/benchmarking.rb b/actionpack/lib/action_controller/base/chained/benchmarking.rb index 066150f58a..66e9e9c31d 100644 --- a/actionpack/lib/action_controller/base/chained/benchmarking.rb +++ b/actionpack/lib/action_controller/base/chained/benchmarking.rb @@ -1,4 +1,4 @@ -require 'benchmark' +require 'active_support/core_ext/benchmark' module ActionController #:nodoc: # The benchmarking module times the performance of actions and reports to the logger. If the Active Record diff --git a/actionpack/lib/action_controller/base/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb index b6b5267c66..fa8ecea408 100644 --- a/actionpack/lib/action_controller/base/http_authentication.rb +++ b/actionpack/lib/action_controller/base/http_authentication.rb @@ -1,3 +1,5 @@ +require 'active_support/base64' + module ActionController module HttpAuthentication # Makes it dead easy to do HTTP Basic authentication. @@ -276,7 +278,7 @@ module ActionController t = time.to_i hashed = [t, secret_key] digest = ::Digest::MD5.hexdigest(hashed.join(":")) - Base64.encode64("#{t}:#{digest}").gsub("\n", '') + ActiveSupport::Base64.encode64("#{t}:#{digest}").gsub("\n", '') end # Might want a shorter timeout depending on whether the request @@ -285,7 +287,7 @@ module ActionController # allow a user to use new nonce without prompting user again for their # username and password. def validate_nonce(request, value, seconds_to_timeout=5*60) - t = Base64.decode64(value).split(":").first.to_i + t = ActiveSupport::Base64.decode64(value).split(":").first.to_i nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout end diff --git a/actionpack/lib/action_controller/base/layout.rb b/actionpack/lib/action_controller/base/layout.rb index 1ad5191c73..cf5f46a32b 100644 --- a/actionpack/lib/action_controller/base/layout.rb +++ b/actionpack/lib/action_controller/base/layout.rb @@ -1,3 +1,7 @@ +require 'active_support/core_ext/enumerable' +require 'active_support/core_ext/class/delegating_attributes' +require 'active_support/core_ext/class/inheritable_attributes' + module ActionController #:nodoc: module Layout #:nodoc: def self.included(base) diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 6bda27e23a..b4408e4e1d 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/module' + module ActionController # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index d9590c88b8..42ad12e1ea 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/hash/except' + module ActionController module Routing class RouteBuilder #:nodoc: diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb index e2077edad8..eba05a3c5a 100644 --- a/actionpack/lib/action_controller/routing/route.rb +++ b/actionpack/lib/action_controller/routing/route.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/misc' + module ActionController module Routing class Route #:nodoc: @@ -65,7 +67,7 @@ module ActionController # map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ # def parameter_shell - @parameter_shell ||= returning({}) do |shell| + @parameter_shell ||= {}.tap do |shell| requirements.each do |key, requirement| shell[key] = requirement unless requirement.is_a? Regexp end @@ -76,7 +78,7 @@ module ActionController # includes keys that appear inside the path, and keys that have requirements # placed upon them. def significant_keys - @significant_keys ||= returning([]) do |sk| + @significant_keys ||= [].tap do |sk| segments.each { |segment| sk << segment.key if segment.respond_to? :key } sk.concat requirements.keys sk.uniq! @@ -86,7 +88,7 @@ module ActionController # Return a hash of key/value pairs representing the keys in the route that # have defaults, or which are specified by non-regexp requirements. def defaults - @defaults ||= returning({}) do |hash| + @defaults ||= {}.tap do |hash| segments.each do |segment| next unless segment.respond_to? :default hash[segment.key] = segment.default unless segment.default.nil? diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 936f97ecb5..8f4358c33e 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -1,4 +1,5 @@ require 'rack/session/abstract/id' +require 'active_support/core_ext/object/conversions' module ActionController #:nodoc: class TestRequest < ActionDispatch::TestRequest #:nodoc: diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index c882930e64..27d229835a 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -21,16 +21,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -begin - require 'active_support' -rescue LoadError - activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" - if File.directory?(activesupport_path) - $:.unshift activesupport_path - require 'active_support' - end -end -require 'active_support/core/all' +activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" +$:.unshift activesupport_path if File.directory?(activesupport_path) +require 'active_support' begin gem 'rack', '~> 1.1.pre' diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 02ad7f7d94..dfcf3a558f 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -1,4 +1,5 @@ require 'set' +require 'active_support/core_ext/class/attribute_accessors' module Mime SET = [] diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index e4f3a8f125..13ff049a97 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -3,6 +3,7 @@ require 'stringio' require 'strscan' require 'active_support/memoizable' +require 'active_support/core_ext/hash/indifferent_access' module ActionDispatch class Request < Rack::Request diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index c3b5a68f40..edb522ff49 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -1,4 +1,5 @@ require 'digest/md5' +require 'active_support/core_ext/module/delegation' module ActionDispatch # :nodoc: # Represents an HTTP response generated by a controller action. One can use diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index dd352f9ce0..c3786af439 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -21,16 +21,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -begin - require 'active_support' -rescue LoadError - activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" - if File.directory?(activesupport_path) - $:.unshift activesupport_path - require 'active_support' - end -end -require 'active_support/core/all' +activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" +$:.unshift activesupport_path if File.directory?(activesupport_path) +require 'active_support' require File.join(File.dirname(__FILE__), "action_pack") diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 44bd401631..56f0b5ef4f 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,3 +1,6 @@ +require 'active_support/core_ext/module/attr_internal' +require 'active_support/core_ext/module/delegation' + module ActionView #:nodoc: class ActionViewError < StandardError #:nodoc: end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index a59829b23f..beef661a37 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -2,6 +2,7 @@ require 'cgi' require 'action_view/helpers/date_helper' require 'action_view/helpers/tag_helper' require 'action_view/helpers/form_tag_helper' +require 'active_support/core_ext/class/inheritable_attributes' module ActionView module Helpers @@ -1039,8 +1040,8 @@ module ActionView end end - class Base - cattr_accessor :default_form_builder - self.default_form_builder = ::ActionView::Helpers::FormBuilder + class << Base + attr_accessor :default_form_builder end -end \ No newline at end of file + Base.default_form_builder = ::ActionView::Helpers::FormBuilder +end diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index a20b1b0cd3..fdcb108ffc 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -1,4 +1,5 @@ require 'erb' +require 'active_support/core_ext/class/attribute_accessors' module ActionView module TemplateHandlers diff --git a/actionpack/test/abstract_controller/test_helper.rb b/actionpack/test/abstract_controller/test_helper.rb index a08ab5a6d7..915054f7fb 100644 --- a/actionpack/test/abstract_controller/test_helper.rb +++ b/actionpack/test/abstract_controller/test_helper.rb @@ -4,7 +4,7 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') require 'rubygems' require 'test/unit' -require 'active_support/core/all' +require 'active_support' require 'active_support/test_case' require 'action_controller/abstract' require 'action_view' @@ -18,4 +18,4 @@ begin Debugger.start rescue LoadError # Debugging disabled. `gem install ruby-debug` to enable. -end \ No newline at end of file +end diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index 2fdaba7342..932f594ad2 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -5,7 +5,6 @@ $:.unshift(File.dirname(__FILE__) + '/lib') require 'test/unit' require 'active_support' -require 'active_support/core/all' require 'active_support/test_case' require 'action_controller/abstract' require 'action_controller/new_base' @@ -129,4 +128,4 @@ module ActionController end end end -end \ No newline at end of file +end diff --git a/actionpack/test/controller/addresses_render_test.rb b/actionpack/test/controller/addresses_render_test.rb index 2f092b6731..2d2a2745b0 100644 --- a/actionpack/test/controller/addresses_render_test.rb +++ b/actionpack/test/controller/addresses_render_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'logger' class Address def Address.count(conditions = nil, join = nil) diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 0c54d61426..a09db95d7d 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'logger' require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late # Provide some controller to run the tests on. diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index 9a0976ca9f..06a5af6b32 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'logger' class CaptureController < ActionController::Base def self.controller_name; "test"; end diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 19cd5f4db2..7b8096fccc 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'active_support/core_ext/kernel/reporting' ActionController::Base.helpers_dir = File.dirname(__FILE__) + '/../fixtures/helpers' -- cgit v1.2.3 From 49a84ff69ca4fc4db821ca3b5a5926d07832c845 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 13 May 2009 17:00:36 -0700 Subject: Ported over render :file tests. --- actionpack/test/controller/render_js_test.rb | 37 +++ actionpack/test/controller/render_json_test.rb | 80 ++++++ actionpack/test/controller/render_other_test.rb | 222 ++++++++++++++++ actionpack/test/controller/render_test.rb | 334 +----------------------- actionpack/test/controller/render_xml_test.rb | 81 ++++++ actionpack/test/new_base/render_file_test.rb | 110 ++++++++ actionpack/test/new_base/render_layout_test.rb | 18 +- actionpack/test/new_base/test_helper.rb | 24 ++ 8 files changed, 585 insertions(+), 321 deletions(-) create mode 100644 actionpack/test/controller/render_js_test.rb create mode 100644 actionpack/test/controller/render_json_test.rb create mode 100644 actionpack/test/controller/render_other_test.rb create mode 100644 actionpack/test/controller/render_xml_test.rb create mode 100644 actionpack/test/new_base/render_file_test.rb (limited to 'actionpack') diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb new file mode 100644 index 0000000000..7b50242910 --- /dev/null +++ b/actionpack/test/controller/render_js_test.rb @@ -0,0 +1,37 @@ +require 'abstract_unit' +require 'controller/fake_models' +require 'pathname' + +class TestController < ActionController::Base + protect_from_forgery + + def render_vanilla_js_hello + render :js => "alert('hello')" + end + + def greeting + # let's just rely on the template + end + + def partial + render :partial => 'partial' + end +end + +class RenderTest < ActionController::TestCase + def test_render_vanilla_js + get :render_vanilla_js_hello + assert_equal "alert('hello')", @response.body + assert_equal "text/javascript", @response.content_type + end + + def test_render_with_default_from_accept_header + xhr :get, :greeting + assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body + end + + def test_should_render_js_partial + xhr :get, :partial, :format => 'js' + assert_equal 'partial js', @response.body + end +end \ No newline at end of file diff --git a/actionpack/test/controller/render_json_test.rb b/actionpack/test/controller/render_json_test.rb new file mode 100644 index 0000000000..233b2dfd89 --- /dev/null +++ b/actionpack/test/controller/render_json_test.rb @@ -0,0 +1,80 @@ +require 'abstract_unit' +require 'controller/fake_models' +require 'pathname' + +class TestController < ActionController::Base + protect_from_forgery + + def render_json_nil + render :json => nil + end + + def render_json_hello_world + render :json => ActiveSupport::JSON.encode(:hello => 'world') + end + + def render_json_hello_world_with_callback + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' + end + + def render_json_with_custom_content_type + render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' + end + + def render_symbol_json + render :json => ActiveSupport::JSON.encode(:hello => 'world') + end + + def render_json_with_render_to_string + render :json => {:hello => render_to_string(:partial => 'partial')} + end +end + +class RenderTest < ActionController::TestCase + tests TestController + + def setup + # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get + # a more accurate simulation of what happens in "real life". + super + @controller.logger = Logger.new(nil) + + @request.host = "www.nextangle.com" + end + + def test_render_json_nil + get :render_json_nil + assert_equal 'null', @response.body + assert_equal 'application/json', @response.content_type + end + + def test_render_json + get :render_json_hello_world + assert_equal '{"hello":"world"}', @response.body + assert_equal 'application/json', @response.content_type + end + + def test_render_json_with_callback + get :render_json_hello_world_with_callback + assert_equal 'alert({"hello":"world"})', @response.body + assert_equal 'application/json', @response.content_type + end + + def test_render_json_with_custom_content_type + get :render_json_with_custom_content_type + assert_equal '{"hello":"world"}', @response.body + assert_equal 'text/javascript', @response.content_type + end + + def test_render_symbol_json + get :render_symbol_json + assert_equal '{"hello":"world"}', @response.body + assert_equal 'application/json', @response.content_type + end + + def test_render_json_with_render_to_string + get :render_json_with_render_to_string + assert_equal '{"hello":"partial html"}', @response.body + assert_equal 'application/json', @response.content_type + end +end \ No newline at end of file diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb new file mode 100644 index 0000000000..ddbdd2d213 --- /dev/null +++ b/actionpack/test/controller/render_other_test.rb @@ -0,0 +1,222 @@ +require 'abstract_unit' +require 'controller/fake_models' +require 'pathname' + +class TestController < ActionController::Base + protect_from_forgery + + module RenderTestHelper + def rjs_helper_method_from_module + page.visual_effect :highlight + end + end + + helper RenderTestHelper + helper do + def rjs_helper_method(value) + page.visual_effect :highlight, value + end + end + + def enum_rjs_test + render :update do |page| + page.select('.product').each do |value| + page.rjs_helper_method_from_module + page.rjs_helper_method(value) + page.sortable(value, :url => { :action => "order" }) + page.draggable(value) + end + end + end + + def render_explicit_html_template + end + + def render_custom_code_rjs + render :update, :status => 404 do |page| + page.replace :foo, :partial => 'partial' + end + end + + def render_implicit_html_template + end + + def render_js_with_explicit_template + @project_id = 4 + render :template => 'test/delete_with_js' + end + + def render_js_with_explicit_action_template + @project_id = 4 + render :action => 'delete_with_js' + end + + def delete_with_js + @project_id = 4 + end + + def update_page + render :update do |page| + page.replace_html 'balance', '$37,000,000.00' + page.visual_effect :highlight, 'balance' + end + end + + def update_page_with_instance_variables + @money = '$37,000,000.00' + @div_id = 'balance' + render :update do |page| + page.replace_html @div_id, @money + page.visual_effect :highlight, @div_id + end + end + + def update_page_with_view_method + render :update do |page| + page.replace_html 'person', pluralize(2, 'person') + end + end + + def partial_as_rjs + render :update do |page| + page.replace :foo, :partial => 'partial' + end + end + + def respond_to_partial_as_rjs + respond_to do |format| + format.js do + render :update do |page| + page.replace :foo, :partial => 'partial' + end + end + end + end + + def render_alternate_default + # For this test, the method "default_render" is overridden: + @alternate_default_render = lambda do + render :update do |page| + page.replace :foo, :partial => 'partial' + end + end + end + +private + 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" + + "layouts/standard" + when "action_talk_to_layout", "layout_overriding_layout" + "layouts/talk_from_action" + when "render_implicit_html_template_from_xhr_request" + (request.xhr? ? 'layouts/xhr' : 'layouts/standard') + end + end +end + +class RenderTest < ActionController::TestCase + tests TestController + + def setup + # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get + # a more accurate simulation of what happens in "real life". + super + @controller.logger = Logger.new(nil) + + @request.host = "www.nextangle.com" + end + + def test_enum_rjs_test + ActiveSupport::SecureRandom.stubs(:base64).returns("asdf") + get :enum_rjs_test + body = %{ + $$(".product").each(function(value, index) { + new Effect.Highlight(element,{}); + new Effect.Highlight(value,{}); + Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}}); + new Draggable(value, {}); + }); + }.gsub(/^ /, '').strip + assert_equal body, @response.body + end + + def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template + [:js, "js"].each do |format| + assert_nothing_raised do + get :render_explicit_html_template, :format => format + assert_equal %(document.write("Hello world\\n");), @response.body + end + end + end + + def test_render_custom_code_rjs + get :render_custom_code_rjs + assert_response 404 + assert_equal %(Element.replace("foo", "partial html");), @response.body + end + + def test_render_in_an_rjs_template_should_pick_html_templates_when_available + [:js, "js"].each do |format| + assert_nothing_raised do + get :render_implicit_html_template, :format => format + assert_equal %(document.write("Hello world\\n");), @response.body + end + end + end + + def test_render_rjs_template_explicitly + get :render_js_with_explicit_template + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_rendering_rjs_action_explicitly + get :render_js_with_explicit_action_template + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_render_rjs_with_default + get :delete_with_js + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_update_page + get :update_page + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type'] + assert_equal 2, @response.body.split($/).length + end + + def test_update_page_with_instance_variables + get :update_page_with_instance_variables + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"] + assert_match /balance/, @response.body + assert_match /\$37/, @response.body + end + + def test_update_page_with_view_method + get :update_page_with_view_method + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"] + assert_match /2 people/, @response.body + end + + def test_should_render_html_formatted_partial_with_rjs + xhr :get, :partial_as_rjs + assert_equal %(Element.replace("foo", "partial html");), @response.body + end + + def test_should_render_html_formatted_partial_with_rjs_and_js_format + xhr :get, :respond_to_partial_as_rjs + assert_equal %(Element.replace("foo", "partial html");), @response.body + end + + def test_should_render_with_alternate_default_render + xhr :get, :render_alternate_default + assert_equal %(Element.replace("foo", "partial html");), @response.body + end +end \ No newline at end of file diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 4cea050a1e..469e8601d0 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -145,18 +145,21 @@ class TestController < ActionController::Base render :layout => false end + # :ported: def render_file_with_instance_variables @secret = 'in the sauce' path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') render :file => path end + # :ported: def render_file_as_string_with_instance_variables @secret = 'in the sauce' path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) render path end + # :ported: def render_file_not_using_full_path @secret = 'in the sauce' render :file => 'test/render_file_with_ivar' @@ -203,41 +206,11 @@ class TestController < ActionController::Base render :inline => "<%= controller_name %>" end - def render_json_nil - render :json => nil - end - - def render_json_hello_world - render :json => ActiveSupport::JSON.encode(:hello => 'world') - end - - def render_json_hello_world_with_callback - render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' - end - - def render_json_with_custom_content_type - render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' - end - - def render_symbol_json - render :json => ActiveSupport::JSON.encode(:hello => 'world') - end - - def render_json_with_render_to_string - render :json => {:hello => render_to_string(:partial => 'partial')} - end - # :ported: def render_custom_code render :text => "hello world", :status => 404 end - def render_custom_code_rjs - render :update, :status => 404 do |page| - page.replace :foo, :partial => 'partial' - end - end - # :ported: def render_text_with_nil render :text => nil @@ -253,10 +226,6 @@ class TestController < ActionController::Base render :text => "appended" end - def render_vanilla_js_hello - render :js => "alert('hello')" - end - # This test is testing 3 things: # render :file in AV :ported: # render :template in AC :ported: @@ -271,10 +240,6 @@ class TestController < ActionController::Base render "test/hello" end - def render_xml_with_custom_content_type - render :xml => "", :content_type => "application/atomsvc+xml" - end - def render_line_offset render :inline => '<% raise %>', :locals => {:foo => 'bar'} end @@ -331,12 +296,6 @@ class TestController < ActionController::Base :locals => { :local_name => name } end - def render_implicit_html_template - end - - def render_explicit_html_template - end - def render_implicit_html_template_from_xhr_request end @@ -470,66 +429,6 @@ class TestController < ActionController::Base render :template => "test/hello_world_from_rxml.builder" end - module RenderTestHelper - def rjs_helper_method_from_module - page.visual_effect :highlight - end - end - - helper RenderTestHelper - helper do - def rjs_helper_method(value) - page.visual_effect :highlight, value - end - end - - def enum_rjs_test - render :update do |page| - page.select('.product').each do |value| - page.rjs_helper_method_from_module - page.rjs_helper_method(value) - page.sortable(value, :url => { :action => "order" }) - page.draggable(value) - end - end - end - - def delete_with_js - @project_id = 4 - end - - def render_js_with_explicit_template - @project_id = 4 - render :template => 'test/delete_with_js' - end - - def render_js_with_explicit_action_template - @project_id = 4 - render :action => 'delete_with_js' - end - - def update_page - render :update do |page| - page.replace_html 'balance', '$37,000,000.00' - page.visual_effect :highlight, 'balance' - end - end - - def update_page_with_instance_variables - @money = '$37,000,000.00' - @div_id = 'balance' - render :update do |page| - page.replace_html @div_id, @money - page.visual_effect :highlight, @div_id - end - end - - def update_page_with_view_method - render :update do |page| - page.replace_html 'person', pluralize(2, 'person') - end - end - def action_talk_to_layout # Action template sets variable that's picked up by layout end @@ -573,25 +472,6 @@ class TestController < ActionController::Base head :forbidden, :x_custom_header => "something" end - def render_with_location - render :xml => "", :location => "http://example.com", :status => 201 - end - - def render_with_object_location - customer = Customer.new("Some guy", 1) - render :xml => "", :location => customer_url(customer), :status => :created - end - - def render_with_to_xml - to_xmlable = Class.new do - def to_xml - "" - end - end.new - - render :xml => to_xmlable - end - def render_using_layout_around_block render :action => "using_layout_around_block" end @@ -608,22 +488,6 @@ class TestController < ActionController::Base render :partial => 'partial.html.erb' end - def partial_as_rjs - render :update do |page| - page.replace :foo, :partial => 'partial' - end - end - - def respond_to_partial_as_rjs - respond_to do |format| - format.js do - render :update do |page| - page.replace :foo, :partial => 'partial' - end - end - end - end - def partial render :partial => 'partial' end @@ -880,82 +744,54 @@ class RenderTest < ActionController::TestCase assert_equal 'Hello world!', @response.body end + # :ported: def test_render_file_with_instance_variables get :render_file_with_instance_variables assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_as_string_with_instance_variables get :render_file_as_string_with_instance_variables assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_not_using_full_path get :render_file_not_using_full_path assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_not_using_full_path_with_dot_in_path get :render_file_not_using_full_path_with_dot_in_path assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_using_pathname get :render_file_using_pathname assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_with_locals get :render_file_with_locals assert_equal "The secret is in the sauce\n", @response.body end + # :ported: def test_render_file_as_string_with_locals get :render_file_as_string_with_locals assert_equal "The secret is in the sauce\n", @response.body end + # :assessed: def test_render_file_from_template get :render_file_from_template assert_equal "The secret is in the sauce\n", @response.body end - def test_render_json_nil - get :render_json_nil - assert_equal 'null', @response.body - assert_equal 'application/json', @response.content_type - end - - def test_render_json - get :render_json_hello_world - assert_equal '{"hello":"world"}', @response.body - assert_equal 'application/json', @response.content_type - end - - def test_render_json_with_callback - get :render_json_hello_world_with_callback - assert_equal 'alert({"hello":"world"})', @response.body - assert_equal 'application/json', @response.content_type - end - - def test_render_json_with_custom_content_type - get :render_json_with_custom_content_type - assert_equal '{"hello":"world"}', @response.body - assert_equal 'text/javascript', @response.content_type - end - - def test_render_symbol_json - get :render_symbol_json - assert_equal '{"hello":"world"}', @response.body - assert_equal 'application/json', @response.content_type - end - - def test_render_json_with_render_to_string - get :render_json_with_render_to_string - assert_equal '{"hello":"partial html"}', @response.body - assert_equal 'application/json', @response.content_type - end - # :ported: def test_render_custom_code get :render_custom_code @@ -964,12 +800,6 @@ class RenderTest < ActionController::TestCase assert_equal 'hello world', @response.body end - def test_render_custom_code_rjs - get :render_custom_code_rjs - assert_response 404 - assert_equal %(Element.replace("foo", "partial html");), @response.body - end - # :ported: def test_render_text_with_nil get :render_text_with_nil @@ -1023,12 +853,6 @@ class RenderTest < ActionController::TestCase assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. end - def test_render_vanilla_js - get :render_vanilla_js_hello - assert_equal "alert('hello')", @response.body - assert_equal "text/javascript", @response.content_type - end - # :ported: def test_render_xml get :render_xml_hello @@ -1053,20 +877,6 @@ class RenderTest < ActionController::TestCase assert_equal "\n \n\n", @response.body end - def test_enum_rjs_test - ActiveSupport::SecureRandom.stubs(:base64).returns("asdf") - get :enum_rjs_test - body = %{ - $$(".product").each(function(value, index) { - new Effect.Highlight(element,{}); - new Effect.Highlight(value,{}); - Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}}); - new Draggable(value, {}); - }); - }.gsub(/^ /, '').strip - assert_equal body, @response.body - end - def test_layout_rendering get :layout_test assert_equal "Hello world!", @response.body @@ -1114,29 +924,10 @@ class RenderTest < ActionController::TestCase assert_equal "Goodbye, Local David", @response.body end - def test_render_in_an_rjs_template_should_pick_html_templates_when_available - [:js, "js"].each do |format| - assert_nothing_raised do - get :render_implicit_html_template, :format => format - assert_equal %(document.write("Hello world\\n");), @response.body - end - end - end - - def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template - [:js, "js"].each do |format| - assert_nothing_raised do - get :render_explicit_html_template, :format => format - assert_equal %(document.write("Hello world\\n");), @response.body - end - end - end - def test_should_implicitly_render_html_template_from_xhr_request - pending do - xhr :get, :render_implicit_html_template_from_xhr_request - assert_equal "XHR!\nHello HTML!", @response.body - end + pending + # xhr :get, :render_implicit_html_template_from_xhr_request + # assert_equal "XHR!\nHello HTML!", @response.body end def test_should_implicitly_render_js_template_without_layout @@ -1151,11 +942,6 @@ class RenderTest < ActionController::TestCase assert_equal 'formatted html erb', @response.body end - def test_should_render_formatted_xml_erb_template - get :formatted_xml_erb, :format => :xml - assert_equal 'passed formatted xml erb', @response.body - end - def test_should_render_formatted_html_erb_template get :formatted_xml_erb assert_equal 'passed formatted html erb', @response.body @@ -1167,31 +953,6 @@ class RenderTest < ActionController::TestCase assert_equal 'passed formatted html erb', @response.body end - def test_should_render_xml_but_keep_custom_content_type - get :render_xml_with_custom_content_type - assert_equal "application/atomsvc+xml", @response.content_type - end - - def test_render_with_default_from_accept_header - xhr :get, :greeting - assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body - end - - def test_render_rjs_with_default - get :delete_with_js - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - - def test_render_rjs_template_explicitly - get :render_js_with_explicit_template - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - - def test_rendering_rjs_action_explicitly - get :render_js_with_explicit_action_template - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - def test_layout_test_with_different_layout get :layout_test_with_different_layout assert_equal "Hello world!", @response.body @@ -1299,28 +1060,6 @@ class RenderTest < ActionController::TestCase assert_equal "The secret is area51\n", @response.body end - def test_update_page - get :update_page - assert_template nil - assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type'] - assert_equal 2, @response.body.split($/).length - end - - def test_update_page_with_instance_variables - get :update_page_with_instance_variables - assert_template nil - assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"] - assert_match /balance/, @response.body - assert_match /\$37/, @response.body - end - - def test_update_page_with_view_method - get :update_page_with_view_method - assert_template nil - assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"] - assert_match /2 people/, @response.body - end - def test_yield_content_for assert_not_deprecated { get :yield_content_for } assert_equal "Putting stuff in the title!\n\nGreat stuff!\n", @response.body @@ -1391,31 +1130,6 @@ class RenderTest < ActionController::TestCase assert_response :forbidden end - def test_rendering_with_location_should_set_header - get :render_with_location - assert_equal "http://example.com", @response.headers["Location"] - end - - def test_rendering_xml_should_call_to_xml_if_possible - get :render_with_to_xml - assert_equal "", @response.body - end - - def test_rendering_with_object_location_should_set_header_with_url_for - ActionController::Routing::Routes.draw do |map| - map.resources :customers - map.connect ':controller/:action/:id' - end - - get :render_with_object_location - assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] - end - - def test_should_use_implicit_content_type - get :implicit_content_type, :format => 'atom' - assert_equal Mime::ATOM, @response.content_type - end - def test_using_layout_around_block get :render_using_layout_around_block assert_equal "Before (David)\nInside from block\nAfter", @response.body @@ -1446,26 +1160,6 @@ class RenderTest < ActionController::TestCase assert_equal 'partial html', @response.body end - def test_should_render_html_formatted_partial_with_rjs - xhr :get, :partial_as_rjs - assert_equal %(Element.replace("foo", "partial html");), @response.body - end - - def test_should_render_html_formatted_partial_with_rjs_and_js_format - xhr :get, :respond_to_partial_as_rjs - assert_equal %(Element.replace("foo", "partial html");), @response.body - end - - def test_should_render_js_partial - xhr :get, :partial, :format => 'js' - assert_equal 'partial js', @response.body - end - - def test_should_render_with_alternate_default_render - xhr :get, :render_alternate_default - assert_equal %(Element.replace("foo", "partial html");), @response.body - end - def test_partial_only_with_layout get :partial_only_with_layout assert_equal "only partial", @response.body diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb new file mode 100644 index 0000000000..052b4f0b52 --- /dev/null +++ b/actionpack/test/controller/render_xml_test.rb @@ -0,0 +1,81 @@ +require 'abstract_unit' +require 'controller/fake_models' +require 'pathname' + +class TestController < ActionController::Base + protect_from_forgery + + def render_with_location + render :xml => "", :location => "http://example.com", :status => 201 + end + + def render_with_object_location + customer = Customer.new("Some guy", 1) + render :xml => "", :location => customer_url(customer), :status => :created + end + + def render_with_to_xml + to_xmlable = Class.new do + def to_xml + "" + end + end.new + + render :xml => to_xmlable + end + + def formatted_xml_erb + end + + def render_xml_with_custom_content_type + render :xml => "", :content_type => "application/atomsvc+xml" + end +end + +class RenderTest < ActionController::TestCase + tests TestController + + def setup + # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get + # a more accurate simulation of what happens in "real life". + super + @controller.logger = Logger.new(nil) + + @request.host = "www.nextangle.com" + end + + def test_rendering_with_location_should_set_header + get :render_with_location + assert_equal "http://example.com", @response.headers["Location"] + end + + def test_rendering_xml_should_call_to_xml_if_possible + get :render_with_to_xml + assert_equal "", @response.body + end + + def test_rendering_with_object_location_should_set_header_with_url_for + ActionController::Routing::Routes.draw do |map| + map.resources :customers + map.connect ':controller/:action/:id' + end + + get :render_with_object_location + assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] + end + + def test_should_render_formatted_xml_erb_template + get :formatted_xml_erb, :format => :xml + assert_equal 'passed formatted xml erb', @response.body + end + + def test_should_render_xml_but_keep_custom_content_type + get :render_xml_with_custom_content_type + assert_equal "application/atomsvc+xml", @response.content_type + end + + def test_should_use_implicit_content_type + get :implicit_content_type, :format => 'atom' + assert_equal Mime::ATOM, @response.content_type + end +end \ No newline at end of file diff --git a/actionpack/test/new_base/render_file_test.rb b/actionpack/test/new_base/render_file_test.rb new file mode 100644 index 0000000000..769949be0c --- /dev/null +++ b/actionpack/test/new_base/render_file_test.rb @@ -0,0 +1,110 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module RenderFile + + class BasicController < ActionController::Base + self.view_paths = "." + + def index + render :file => File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world]) + end + + def with_instance_variables + @secret = 'in the sauce' + render :file => File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') + end + + def without_file_key + render File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world]) + end + + def without_file_key_with_instance_variable + @secret = 'in the sauce' + render File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') + end + + def relative_path + @secret = 'in the sauce' + render :file => '../fixtures/test/render_file_with_ivar' + end + + def relative_path_with_dot + @secret = 'in the sauce' + render :file => '../fixtures/test/dot.directory/render_file_with_ivar' + end + + def pathname + @secret = 'in the sauce' + render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. fixtures test dot.directory render_file_with_ivar.erb]) + end + + def with_locals + path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb') + render :file => path, :locals => {:secret => 'in the sauce'} + end + + def without_file_key_with_locals + path = File.expand_path('../fixtures/test/render_file_with_locals.erb') + render path, :locals => {:secret => 'in the sauce'} + end + end + + class TestBasic < SimpleRouteCase + testing RenderFile::BasicController + + def setup + @old_pwd = Dir.pwd + Dir.chdir(File.dirname(__FILE__)) + end + + def teardown + Dir.chdir(@old_pwd) + end + + test "rendering simple template" do + get :index + assert_response "Hello world!" + end + + test "rendering template with ivar" do + get :with_instance_variables + assert_response "The secret is in the sauce\n" + end + + test "rendering path without specifying the :file key" do + get :without_file_key + assert_response "Hello world!" + end + + test "rendering path without specifying the :file key with ivar" do + get :without_file_key_with_instance_variable + assert_response "The secret is in the sauce\n" + end + + test "rendering a relative path" do + get :relative_path + assert_response "The secret is in the sauce\n" + end + + test "rendering a relative path with dot" do + get :relative_path_with_dot + assert_response "The secret is in the sauce\n" + end + + test "rendering a Pathname" do + get :pathname + assert_response "The secret is in the sauce\n" + end + + test "rendering file with locals" do + get :with_locals + assert_response "The secret is in the sauce\n" + end + + test "rendering path without specifying the :file key with locals" do + get :without_file_key_with_locals + assert_response "The secret is in the sauce\n" + end + end + +end \ No newline at end of file diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index 5d28926cc6..7f627f86ec 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -6,7 +6,8 @@ module ControllerLayouts self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI", "layouts/override.html.erb" => "Override! <%= yield %>", - "basic.html.erb" => "Hello world!" + "basic.html.erb" => "Hello world!", + "controller_layouts/implicit/layout_false.html.erb" => "hai(layout_false.html.erb)" )] def index @@ -17,6 +18,12 @@ module ControllerLayouts render :template => "basic", :layout => "override" end + def layout_false + render :layout => false + end + + + def builder_override end @@ -56,4 +63,13 @@ module ControllerLayouts get "/controller_layouts/implicit/override" assert_body "Override! Hello world!" end + + class TestLayoutOptions < SimpleRouteCase + testing ControllerLayouts::ImplicitController + + test "rendering with :layout => false leaves out the implicit layout" do + get :layout_false + assert_response "hai(layout_false.html.erb)" + end + end end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 78662dc989..a7302af060 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -59,12 +59,28 @@ class Rack::TestCase < ActiveSupport::TestCase @app ||= ActionController::Dispatcher.new end + def self.testing(klass = nil) + if klass + @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') + else + @testing + end + end + def self.get(url) setup do |test| test.get url end end + def get(thing, *args) + if thing.is_a?(Symbol) + super("#{self.class.testing}/#{thing}") + else + super + end + end + def assert_body(body) assert_equal body, Array.wrap(last_response.body).join end @@ -85,6 +101,14 @@ class Rack::TestCase < ActiveSupport::TestCase end end + def assert_response(body, status = 200, headers = {}) + assert_body body + assert_status status + headers.each do |header, value| + assert_header header, value + end + end + def assert_content_type(type) assert_equal type, last_response.headers["Content-Type"] end -- cgit v1.2.3 From 29bd8f7b8975bc0442f0b63e7da077f9a3f22dc6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 13 May 2009 16:15:18 -0700 Subject: Simple example for require profiling --- actionpack/examples/simple.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 actionpack/examples/simple.rb (limited to 'actionpack') diff --git a/actionpack/examples/simple.rb b/actionpack/examples/simple.rb new file mode 100644 index 0000000000..4ecb824688 --- /dev/null +++ b/actionpack/examples/simple.rb @@ -0,0 +1,17 @@ +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" +require 'action_controller' + +class PeopleController < ActionController::Base + def index + head :ok + end +end + +status, headers, body = PeopleController.action(:index).call({ 'rack.input' => StringIO.new('') }) + +puts status +puts headers.to_yaml +puts '---' +body.each do |part| + puts part +end -- cgit v1.2.3 From 5dd29c466c38a1bc395da579fd4b22c5e5a8e9fd Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 13 May 2009 16:15:37 -0700 Subject: Cherry-picking Active Support extensions --- actionpack/lib/action_dispatch/http/status_codes.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb index 830de2a6db..5bac842ec1 100644 --- a/actionpack/lib/action_dispatch/http/status_codes.rb +++ b/actionpack/lib/action_dispatch/http/status_codes.rb @@ -1,3 +1,5 @@ +require 'active_support/inflector' + module ActionDispatch module StatusCodes #:nodoc: STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.merge({ @@ -16,7 +18,7 @@ module ActionDispatch # :created or :not_implemented) into its corresponding HTTP status # code (like 200 or 501). SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) { |hash, (code, message)| - hash[message.gsub(/ /, "").underscore.to_sym] = code + hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code hash }.freeze @@ -37,4 +39,4 @@ module ActionDispatch end end end -end \ No newline at end of file +end -- cgit v1.2.3 From c286952050e8fe16b0f6d64ba0687b52cc8f2ae1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 14 May 2009 01:56:07 -0700 Subject: Minimal base/new_base comparison --- actionpack/examples/minimal.rb | 34 ++++++++++++++++++++++ actionpack/examples/simple.rb | 17 ----------- actionpack/lib/action_controller/abstract/base.rb | 6 ++-- .../lib/action_controller/abstract/logger.rb | 4 ++- actionpack/lib/action_controller/new_base/http.rb | 5 +++- actionpack/lib/action_controller/routing.rb | 5 ++++ 6 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 actionpack/examples/minimal.rb delete mode 100644 actionpack/examples/simple.rb (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb new file mode 100644 index 0000000000..84a8499daf --- /dev/null +++ b/actionpack/examples/minimal.rb @@ -0,0 +1,34 @@ +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" +require 'action_controller' +require 'action_controller/new_base' if ENV['NEW'] +require 'benchmark' + +class BaseController < ActionController::Base + def index + render :text => '' + 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 }) + 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 + end + puts '---' +end + +elapsed = Benchmark.realtime { call_index BaseController, input, n } + +puts "%dms elapsed, %d requests/sec" % [1000 * elapsed, n / elapsed] diff --git a/actionpack/examples/simple.rb b/actionpack/examples/simple.rb deleted file mode 100644 index 4ecb824688..0000000000 --- a/actionpack/examples/simple.rb +++ /dev/null @@ -1,17 +0,0 @@ -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" -require 'action_controller' - -class PeopleController < ActionController::Base - def index - head :ok - end -end - -status, headers, body = PeopleController.action(:index).call({ 'rack.input' => StringIO.new('') }) - -puts status -puts headers.to_yaml -puts '---' -body.each do |part| - puts part -end diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index c9e1081b23..4b8d953643 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/module/attr_internal' + module AbstractController class Error < StandardError; end @@ -89,7 +91,7 @@ module AbstractController # you must handle it by also overriding process_action and # handling the case. def respond_to_action?(action_name) - action_methods.include?(action_name) || respond_to?(:action_missing, true) + action_methods.include?(action_name.to_s) || respond_to?(:action_missing, true) end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 5fb78f1755..b154be754b 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute_accessors' + module AbstractController module Logger extend ActiveSupport::DependencyModule @@ -6,4 +8,4 @@ module AbstractController cattr_accessor :logger end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index fb6041a04e..6852eb200a 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -1,3 +1,6 @@ +require 'action_controller/abstract' +require 'active_support/core_ext/module/delegation' + module ActionController class Http < AbstractController::Base abstract! @@ -57,7 +60,7 @@ module ActionController def self.action(name) @actions ||= {} - @actions[name] ||= proc do |env| + @actions[name.to_s] ||= proc do |env| new.call(name, env) end end diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb index c0eb61340b..7edd379bc0 100644 --- a/actionpack/lib/action_controller/routing.rb +++ b/actionpack/lib/action_controller/routing.rb @@ -1,5 +1,10 @@ require 'cgi' require 'uri' +require 'set' + +require 'active_support/core_ext/module/aliasing' +require 'active_support/core_ext/module/attribute_accessors' + require 'action_controller/routing/optimisations' require 'action_controller/routing/routing_ext' require 'action_controller/routing/route' -- cgit v1.2.3 From 8fac2c88cae0f2fd42fad3c2c2c6c860df14d629 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 14 May 2009 15:30:35 -0700 Subject: Cleaning up more render tests --- actionpack/lib/action_controller/abstract.rb | 3 + actionpack/lib/action_controller/abstract/base.rb | 9 +++ actionpack/lib/action_view.rb | 1 + actionpack/lib/action_view/helpers/tag_helper.rb | 2 +- actionpack/test/controller/render_test.rb | 5 ++ actionpack/test/new_base/render_action_test.rb | 17 ++++- actionpack/test/new_base/render_layout_test.rb | 2 - actionpack/test/new_base/render_partial_test.rb | 27 ++++++++ actionpack/test/new_base/render_template_test.rb | 76 ++++++++++++++--------- actionpack/test/new_base/render_xml_test.rb | 11 ++++ actionpack/test/new_base/test_helper.rb | 2 +- 11 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 actionpack/test/new_base/render_partial_test.rb create mode 100644 actionpack/test/new_base/render_xml_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index 3f5c4a185f..48e33282ec 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -1,3 +1,6 @@ +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/delegation" + module AbstractController autoload :Base, "action_controller/abstract/base" autoload :Callbacks, "action_controller/abstract/callbacks" diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index c9e1081b23..8f2bfb5711 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -23,6 +23,15 @@ module AbstractController end alias_method :abstract?, :abstract + + def inherited(klass) + ::AbstractController::Base.subclasses << klass.to_s + super + end + + def subclasses + @subclasses ||= [] + end def internal_methods controller = self diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index c3786af439..94138097e3 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -24,6 +24,7 @@ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib" $:.unshift activesupport_path if File.directory?(activesupport_path) require 'active_support' +require 'active_support/core_ext/class/attribute_accessors' require File.join(File.dirname(__FILE__), "action_pack") diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index af8c4d5e21..66d7592874 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -9,7 +9,7 @@ module ActionView include ERB::Util BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked).to_set - BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym)) + BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|attr| attr.to_sym }) # Returns an empty HTML tag of type +name+ which by default is XHTML # compliant. Set +open+ to true to create an open tag compatible diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 469e8601d0..a750f018b8 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -262,6 +262,7 @@ class TestController < ActionController::Base render :action => "hello_world" end + # :ported: def builder_layout_test render :action => "hello", :layout => "layouts/builder" end @@ -271,6 +272,7 @@ class TestController < ActionController::Base render :action => "hello_world_container" end + # :ported: def partials_list @test_unchanged = 'hello' @customers = [ Customer.new("david"), Customer.new("mary") ] @@ -860,6 +862,7 @@ class RenderTest < ActionController::TestCase assert_equal "application/xml", @response.content_type end + # :ported: def test_render_xml_as_string_template get :render_xml_hello_as_string_template assert_equal "\n

Hello David

\n

This is grand!

\n\n", @response.body @@ -872,11 +875,13 @@ class RenderTest < ActionController::TestCase assert_equal "

This is grand!

\n", @response.body end + # :move: test in AV def test_render_xml_with_partial get :builder_partial_test assert_equal "\n \n\n", @response.body end + # :ported: def test_layout_rendering get :layout_test assert_equal "Hello world!", @response.body diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index 348d70381b..f25faee433 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -131,8 +131,10 @@ module RenderActionWithApplicationLayout # Set the view path to an application view structure with layouts self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( "render_action_with_application_layout/basic/hello_world.html.erb" => "Hello World!", + "render_action_with_application_layout/basic/hello.html.builder" => "xml.p 'Omg'", "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI", - "layouts/greetings.html.erb" => "Greetings <%= yield %> Bai" + "layouts/greetings.html.erb" => "Greetings <%= yield %> Bai", + "layouts/builder.html.builder" => "xml.html do\n xml << yield\nend" )] def hello_world @@ -154,6 +156,10 @@ module RenderActionWithApplicationLayout def hello_world_with_custom_layout render :action => "hello_world", :layout => "greetings" end + + def with_builder_and_layout + render :action => "hello", :layout => "builder" + end end class TestDefaultLayout < SimpleRouteCase @@ -199,6 +205,15 @@ module RenderActionWithApplicationLayout assert_status 200 end + class TestLayout < SimpleRouteCase + testing BasicController + + test "builder works with layouts" do + get :with_builder_and_layout + assert_response "\n

Omg

\n\n" + end + end + end module RenderActionWithControllerLayout diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index 7f627f86ec..dc858b4f5c 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -22,8 +22,6 @@ module ControllerLayouts render :layout => false end - - def builder_override end diff --git a/actionpack/test/new_base/render_partial_test.rb b/actionpack/test/new_base/render_partial_test.rb new file mode 100644 index 0000000000..3a300afe5c --- /dev/null +++ b/actionpack/test/new_base/render_partial_test.rb @@ -0,0 +1,27 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module RenderPartial + + class BasicController < ActionController::Base + + self.view_paths = [ActionView::Template::FixturePath.new( + "render_partial/basic/_basic.html.erb" => "OMG!", + "render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>" + )] + + def changing + @test_unchanged = 'hello' + render :action => "basic" + end + end + + class TestPartial < SimpleRouteCase + testing BasicController + + test "rendering a partial in ActionView doesn't pull the ivars again from the controller" do + get :changing + assert_response("goodbyeOMG!goodbye") + end + end + +end \ No newline at end of file diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index c09eeb1926..6c50ae4203 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -4,14 +4,19 @@ module RenderTemplate class WithoutLayoutController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( - "test/basic.html.erb" => "Hello from basic.html.erb", - "shared.html.erb" => "Elastica", - "locals.html.erb" => "The secret is <%= secret %>" + "test/basic.html.erb" => "Hello from basic.html.erb", + "shared.html.erb" => "Elastica", + "locals.html.erb" => "The secret is <%= secret %>", + "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend" )] def index render :template => "test/basic" end + + def index_without_key + render "test/basic" + end def in_top_directory render :template => 'shared' @@ -21,41 +26,56 @@ module RenderTemplate render :template => '/shared' end + def in_top_directory_with_slash_without_key + render '/shared' + end + def with_locals render :template => "locals", :locals => { :secret => 'area51' } end + + def builder_template + render :template => "xml_template" + end end class TestWithoutLayout < SimpleRouteCase - describe "rendering a normal template with full path without layout" + testing RenderTemplate::WithoutLayoutController - get "/render_template/without_layout" - assert_body "Hello from basic.html.erb" - assert_status 200 - end - - class TestTemplateRenderInTopDirectory < SimpleRouteCase - describe "rendering a template not in a subdirectory" + test "rendering a normal template with full path without layout" do + get :index + assert_response "Hello from basic.html.erb" + end - get "/render_template/without_layout/in_top_directory" - assert_body "Elastica" - assert_status 200 - end - - class TestTemplateRenderInTopDirectoryWithSlash < SimpleRouteCase - describe "rendering a template not in a subdirectory with a leading slash" + test "rendering a normal template with full path without layout without key" do + get :index_without_key + assert_response "Hello from basic.html.erb" + end - get "/render_template/without_layout/in_top_directory_with_slash" - assert_body "Elastica" - assert_status 200 - end - - class TestTemplateRenderWithLocals < SimpleRouteCase - describe "rendering a template with local variables" + test "rendering a template not in a subdirectory" do + get :in_top_directory + assert_response "Elastica" + end - get "/render_template/without_layout/with_locals" - assert_body "The secret is area51" - assert_status 200 + test "rendering a template not in a subdirectory with a leading slash" do + get :in_top_directory_with_slash + assert_response "Elastica" + end + + test "rendering a template not in a subdirectory with a leading slash without key" do + get :in_top_directory_with_slash_without_key + assert_response "Elastica" + end + + test "rendering a template with local variables" do + get :with_locals + assert_response "The secret is area51" + end + + test "rendering a builder template" do + get :builder_template + assert_response "\n

Hello

\n\n" + end end class WithLayoutController < ::ApplicationController diff --git a/actionpack/test/new_base/render_xml_test.rb b/actionpack/test/new_base/render_xml_test.rb new file mode 100644 index 0000000000..e6c40b1533 --- /dev/null +++ b/actionpack/test/new_base/render_xml_test.rb @@ -0,0 +1,11 @@ +require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") + +module RenderXml + + # This has no layout and it works + class BasicController < ActionController::Base + self.view_paths = [ActionView::Template::FixturePath.new( + "render_xml/basic/with_render_erb" => "Hello world!" + )] + end +end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index a7302af060..ec7dbffaae 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -46,7 +46,7 @@ class Rack::TestCase < ActiveSupport::TestCase ActionController::Routing.use_controllers!(controllers) # Move into a bootloader - AbstractController::Base.subclasses.each do |klass| + ActionController::Base.subclasses.each do |klass| klass = klass.constantize next unless klass < AbstractController::Layouts klass.class_eval do -- cgit v1.2.3 From da65320433088548bc4cff33758e5acd71fd137a Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 14 May 2009 17:25:10 -0700 Subject: Got new base to pass controller/base_test.rb, implemented method_missing action semantics in compatibility mode, and fixed a few action_missing bugs. --- actionpack/lib/action_controller/abstract/base.rb | 10 +++++-- .../lib/action_controller/abstract/logger.rb | 33 ++++++++++++++++++++++ .../action_controller/new_base/compatibility.rb | 15 ++++++++++ .../lib/action_controller/new_base/hide_actions.rb | 4 +-- actionpack/lib/action_controller/new_base/http.rb | 5 ---- actionpack/lib/action_controller/routing.rb | 1 + actionpack/test/abstract_unit.rb | 2 +- actionpack/test/controller/base_test.rb | 2 +- 8 files changed, 61 insertions(+), 11 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 8f2bfb5711..483356a4be 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -67,6 +67,8 @@ module AbstractController end def process(action_name) + action_name = action_name.to_s + unless respond_to_action?(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end @@ -82,13 +84,17 @@ module AbstractController self.class.action_methods end + def action_method?(action) + action_methods.include?(action) + end + # It is possible for respond_to?(action_name) to be false and # respond_to?(:action_missing) to be false if respond_to_action? # is overridden in a subclass. For instance, ActionController::Base # overrides it to include the case where a template matching the # action_name is found. def process_action - if respond_to?(action_name) then send(action_name) + if action_method?(action_name) then send(action_name) elsif respond_to?(:action_missing, true) then action_missing(action_name) end end @@ -98,7 +104,7 @@ module AbstractController # you must handle it by also overriding process_action and # handling the case. def respond_to_action?(action_name) - action_methods.include?(action_name) || respond_to?(:action_missing, true) + action_method?(action_name) || respond_to?(:action_missing, true) end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 5fb78f1755..d0603a4ad7 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -2,8 +2,41 @@ module AbstractController module Logger extend ActiveSupport::DependencyModule + class DelayedLog + def initialize(&blk) + @blk = blk + end + + def to_s + @blk.call + end + alias to_str to_s + end + included do cattr_accessor :logger end + + def process(action) + ret = super + + if logger + log = DelayedLog.new do + "\n\nProcessing #{self.class.name}\##{action_name} " \ + "to #{request.formats} " \ + "(for #{request_origin}) [#{request.method.to_s.upcase}]" + end + + logger.info(log) + end + + ret + end + + def request_origin + # this *needs* to be cached! + # otherwise you'd get different results if calling it more than once + @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}" + end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index d17f498b60..993e571aba 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -42,6 +42,9 @@ module ActionController # Controls the resource action separator cattr_accessor :resource_action_separator self.resource_action_separator = "/" + + cattr_accessor :use_accept_header + self.use_accept_header = true end module ClassMethods @@ -66,6 +69,18 @@ module ActionController super end + + def respond_to_action?(action_name) + if respond_to?(:method_missing) && !respond_to?(:action_missing) + self.class.class_eval do + private + def action_missing(name, *args) + method_missing(name.to_sym, *args) + end + end + end + super + end def _layout_for_name(name) name &&= name.sub(%r{^/?layouts/}, '') diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index d1857a9169..a29b09a893 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -12,8 +12,8 @@ module ActionController private - def respond_to_action?(action_name) - !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing)) + def action_method?(action_name) + !hidden_actions.include?(action_name) && super end module ClassMethods diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index fb6041a04e..f3a60b3bf8 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -21,11 +21,6 @@ module ActionController # :api: public def controller_path() self.class.controller_path end - # :api: private - def self.internal_methods - ActionController::Http.public_instance_methods(true) - end - # :api: private def self.action_names() action_methods end diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb index c0eb61340b..06a07a4d0a 100644 --- a/actionpack/lib/action_controller/routing.rb +++ b/actionpack/lib/action_controller/routing.rb @@ -1,5 +1,6 @@ require 'cgi' require 'uri' +require 'set' require 'action_controller/routing/optimisations' require 'action_controller/routing/routing_ext' require 'action_controller/routing/route' diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 825ac9a46c..7982f06545 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -37,7 +37,7 @@ ActionController::Base.session_store = nil # Register danish language for testing I18n.backend.store_translations 'da', {} I18n.backend.store_translations 'pt-BR', {} -ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort +ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') ActionController::Base.view_paths = FIXTURE_LOAD_PATH diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index a09db95d7d..3a4cdb81d9 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -117,7 +117,7 @@ class PerformActionTest < ActionController::TestCase end def method_missing(method, *args) - @logged << args.first + @logged << args.first.to_s end end -- cgit v1.2.3 From 628110d7eeb446fee7f9e043f113c083d24883c1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 14 May 2009 17:42:20 -0700 Subject: Active Support dependencies --- actionpack/lib/action_view/helpers/active_record_helper.rb | 1 + actionpack/test/abstract_controller/layouts_test.rb | 1 + 2 files changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb index 7c0dfdab10..b4b9f6e34b 100644 --- a/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -1,5 +1,6 @@ require 'cgi' require 'action_view/helpers/form_helper' +require 'active_support/core_ext/class/attribute_accessors' module ActionView class Base diff --git a/actionpack/test/abstract_controller/layouts_test.rb b/actionpack/test/abstract_controller/layouts_test.rb index 6e1c2bf9e8..d3440c3de0 100644 --- a/actionpack/test/abstract_controller/layouts_test.rb +++ b/actionpack/test/abstract_controller/layouts_test.rb @@ -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 -- cgit v1.2.3 From eb021707f53be46140b55a48e5ef03ed0577a45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 1 Apr 2009 12:44:56 +0200 Subject: Allow strings to be sent as collection to select. Signed-off-by: Michael Koziarski --- .../lib/action_view/helpers/form_options_helper.rb | 2 ++ .../test/template/form_options_helper_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 6b385ef77d..6adbab175f 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -230,6 +230,8 @@ module ActionView # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. def options_for_select(container, selected = nil) + return container if String === container + container = container.to_a if Hash === container selected, disabled = extract_selected_and_disabled(selected) diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 78db87971b..73624406be 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -80,6 +80,14 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_string_options_for_select + options = "" + assert_dom_equal( + options, + options_for_select(options) + ) + end + def test_array_options_for_select assert_dom_equal( "\n\n", @@ -324,6 +332,20 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_select_under_fields_for_with_string_and_given_prompt + @post = Post.new + options = "" + + fields_for :post, @post do |f| + concat f.select(:category, options, :prompt => 'The prompt') + end + + assert_dom_equal( + "", + output_buffer + ) + end + def test_select_with_blank @post = Post.new @post.category = "" -- cgit v1.2.3 From 7e10504bdeab14ea70a942110a1b1ef6d8467ed3 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 15 May 2009 15:57:12 -0700 Subject: Refactored AbstractController to provide better hook points for overriding aspects of action dispatching --- actionpack/lib/action_controller/abstract/base.rb | 27 ++++++++++++---------- .../lib/action_controller/abstract/callbacks.rb | 4 ++-- actionpack/lib/action_controller/new_base/base.rb | 16 +++++++++---- .../action_controller/new_base/compatibility.rb | 18 ++++++--------- .../abstract_controller_test.rb | 7 +++--- 5 files changed, 39 insertions(+), 33 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index f2db201063..1f2f096dae 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -69,14 +69,13 @@ module AbstractController end def process(action_name) - action_name = action_name.to_s + @_action_name = action_name = action_name.to_s - unless respond_to_action?(action_name) + unless action_name = method_for_action(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end - - @_action_name = action_name - process_action + + process_action(action_name) self end @@ -95,18 +94,22 @@ module AbstractController # is overridden in a subclass. For instance, ActionController::Base # overrides it to include the case where a template matching the # action_name is found. - def process_action - if action_method?(action_name) then send(action_name) - elsif respond_to?(:action_missing, true) then action_missing(action_name) - end + def process_action(method_name) + send(method_name) end - + + def _handle_action_missing + action_missing(@_action_name) + end + # Override this to change the conditions that will raise an # ActionNotFound error. If you accept a difference case, # you must handle it by also overriding process_action and # handling the case. - def respond_to_action?(action_name) - action_method?(action_name) || respond_to?(:action_missing, true) + def method_for_action(action_name) + if action_method?(action_name) then action_name + elsif respond_to?(:action_missing, true) then "_handle_action_missing" + end end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 3aff83a209..51b968c694 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -8,8 +8,8 @@ module AbstractController define_callbacks :process_action, "response_body" end - def process_action - _run_process_action_callbacks(action_name) do + def process_action(method_name) + _run_process_action_callbacks(method_name) do super end end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 1adcc9c71f..3ee17769a8 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -114,14 +114,22 @@ module ActionController super(url, status) end - def process_action + def process_action(method_name) ret = super render if response_body.nil? ret end - - def respond_to_action?(action_name) - super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) + + def _implicit_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" + end + end end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 993e571aba..9884ed12e5 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -69,17 +69,13 @@ module ActionController super end - - def respond_to_action?(action_name) - if respond_to?(:method_missing) && !respond_to?(:action_missing) - self.class.class_eval do - private - def action_missing(name, *args) - method_missing(name.to_sym, *args) - end - end - end - super + + def _handle_method_missing + method_missing(@_action_name.to_sym) + end + + def method_for_action(action_name) + super || (respond_to?(:method_missing) && "_handle_method_missing") end def _layout_for_name(name) diff --git a/actionpack/test/abstract_controller/abstract_controller_test.rb b/actionpack/test/abstract_controller/abstract_controller_test.rb index 689aa99fd8..9c028e7d1e 100644 --- a/actionpack/test/abstract_controller/abstract_controller_test.rb +++ b/actionpack/test/abstract_controller/abstract_controller_test.rb @@ -201,11 +201,10 @@ module AbstractController def fail() self.response_body = "fail" end private - - def respond_to_action?(action_name) - action_name.to_s != "fail" + + def method_for_action(action_name) + action_name.to_s != "fail" && action_name end - end class TestRespondToAction < ActiveSupport::TestCase -- cgit v1.2.3 From 5a45446cff0daf4ca747257a8779dcd5d9cae1d7 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 15 May 2009 17:49:11 -0700 Subject: Ported Rescuable to new base --- .../lib/action_controller/base/chained/filters.rb | 2 +- .../lib/action_controller/dispatch/middlewares.rb | 1 + actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 50 +++++++++++--------- .../action_controller/new_base/compatibility.rb | 13 ++++++ actionpack/lib/action_controller/new_base/http.rb | 4 +- .../lib/action_controller/new_base/rescuable.rb | 53 ++++++++++++++++++++++ .../lib/action_controller/new_base/testing.rb | 2 +- actionpack/test/abstract_unit2.rb | 12 ++++- 9 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/rescuable.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/chained/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb index 9022b8b279..98fe306fd5 100644 --- a/actionpack/lib/action_controller/base/chained/filters.rb +++ b/actionpack/lib/action_controller/base/chained/filters.rb @@ -160,7 +160,7 @@ module ActionController #:nodoc: def convert_only_and_except_options_to_sets_of_strings(opts) [:only, :except].each do |key| if values = opts[key] - opts[key] = Array(values).map(&:to_s).to_set + opts[key] = Array(values).map {|val| val.to_s }.to_set end end end diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index f99637b109..0e4ab6fa39 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -6,6 +6,7 @@ use "ActionDispatch::Failsafe" use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local } use "ActionDispatch::Rescue", lambda { controller = (::ApplicationController rescue ActionController::Base) + # TODO: Replace with controller.action(:_rescue_action) controller.method(:rescue_action) } diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 1f215bb6f1..bc47713529 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -7,6 +7,7 @@ module ActionController autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Redirector, "action_controller/new_base/redirector" autoload :Renderer, "action_controller/new_base/renderer" + autoload :Rescue, "action_controller/new_base/rescuable" autoload :Testing, "action_controller/new_base/testing" autoload :UrlFor, "action_controller/new_base/url_for" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 3ee17769a8..c25ffd5c84 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -12,14 +12,40 @@ module ActionController include ActionController::Renderer include ActionController::Layouts include ActionController::ConditionalGet - + # Legacy modules include SessionManagement include ActionDispatch::StatusCodes - + # Rails 2.x compatibility include ActionController::Rails2Compatibility - + + # 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? + ret + end + + def _implicit_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" + end + end + end + end + + include ImplicitRender + + include ActionController::Rescue + def self.inherited(klass) ::ActionController::Base.subclasses << klass.to_s super @@ -113,23 +139,5 @@ module ActionController super(url, status) end - - def process_action(method_name) - ret = super - render if response_body.nil? - ret - end - - def _implicit_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" - end - end - end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 9884ed12e5..0a283887b6 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -45,6 +45,14 @@ module ActionController cattr_accessor :use_accept_header self.use_accept_header = true + + cattr_accessor :page_cache_directory + self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" + + cattr_reader :cache_store + + cattr_accessor :consider_all_requests_local + self.consider_all_requests_local = true end module ClassMethods @@ -53,6 +61,11 @@ module ActionController def rescue_action(env) raise env["action_dispatch.rescue.exception"] end + + # Defines the storage option for cached fragments + def cache_store=(store_option) + @@cache_store = ActiveSupport::Cache.lookup_store(store_option) + end end def initialize(*) diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index e9a1d5b12f..8891a2a8c3 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -48,8 +48,6 @@ module ActionController @_response = ActionDispatch::Response.new @_response.request = request process(name) - @_response.body = response_body - @_response.prepare! to_rack end @@ -62,6 +60,8 @@ module ActionController # :api: private def to_rack + @_response.body = response_body + @_response.prepare! @_response.to_a end end diff --git a/actionpack/lib/action_controller/new_base/rescuable.rb b/actionpack/lib/action_controller/new_base/rescuable.rb new file mode 100644 index 0000000000..29ffe19d5f --- /dev/null +++ b/actionpack/lib/action_controller/new_base/rescuable.rb @@ -0,0 +1,53 @@ +module ActionController #:nodoc: + # Actions that fail to perform as expected throw exceptions. These + # exceptions can either be rescued for the public view (with a nice + # user-friendly explanation) or for the developers view (with tons of + # debugging information). The developers view is already implemented by + # the Action Controller, but the public view should be tailored to your + # specific application. + # + # The default behavior for public exceptions is to render a static html + # file with the name of the error code thrown. If no such file exists, an + # empty response is sent with the correct status code. + # + # You can override what constitutes a local request by overriding the + # local_request? method in your own controller. Custom rescue + # behavior is achieved by overriding the rescue_action_in_public + # and rescue_action_locally methods. + module Rescue + extend ActiveSupport::DependencyModule + + included do + include ActiveSupport::Rescuable + end + + module ClassMethods + # This can be removed once we can move action(:_rescue_action) into middlewares.rb + # Currently, it does controller.method(:rescue_action), which is hiding the implementation + # difference between the old and new base. + def rescue_action(env) + action(:_rescue_action).call(env) + end + end + + attr_internal :rescued_exception + + private + + def method_for_action(action_name) + return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception") + super + end + + def _rescue_action + rescue_with_handler(rescued_exception) || raise(rescued_exception) + end + + def process_action(*) + super + rescue Exception => exception + self.rescued_exception = exception + _rescue_action + end + end +end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 106990b9ba..b39d8d539d 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -7,7 +7,7 @@ module ActionController @_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 diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb index 932f594ad2..519e6bea36 100644 --- a/actionpack/test/abstract_unit2.rb +++ b/actionpack/test/abstract_unit2.rb @@ -11,11 +11,19 @@ require 'action_controller/new_base' require 'fixture_template' require 'action_controller/testing/process2' require 'action_view/test_case' +require 'action_controller/testing/integration' +require 'active_support/dependencies' + +ActiveSupport::Dependencies.hook! FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') module ActionController - + Base.session = { + :key => '_testing_session', + :secret => '8273f16463985e2b3747dc25e30f2528' +} + class ActionControllerError < StandardError #:nodoc: end @@ -126,6 +134,6 @@ module ActionController "Expected no partials to be rendered" end end - end + end end end -- cgit v1.2.3 From 7f318c3ec535afe53733c55cd0ecaccc16a8b944 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 14:15:26 -0400 Subject: Instead of checking Rails.env.test? in Failsafe middleware, check env["rails.raise_exceptions"] --- actionpack/lib/action_dispatch/middleware/failsafe.rb | 5 ++--- actionpack/test/new_base/render_action_test.rb | 6 ++++-- actionpack/test/new_base/render_test.rb | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb index 836098482c..389accbc36 100644 --- a/actionpack/lib/action_dispatch/middleware/failsafe.rb +++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb @@ -10,9 +10,8 @@ module ActionDispatch def call(env) @app.call(env) rescue Exception => exception - # Reraise exception in test environment - if defined?(Rails) && Rails.env.test? - raise exception + if env["rails.raise_exceptions"] + raise else failsafe_response(exception) end diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index f25faee433..96666077d2 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -92,7 +92,7 @@ module RenderAction test "raises an exception when requesting a layout and none exist" do assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do - get "/render_action/basic/hello_world_with_layout" + get "/render_action/basic/hello_world_with_layout", {}, "rails.raise_exceptions" => true end end end @@ -117,7 +117,9 @@ module RenderAction describe "rendering a normal template with full path with layout => 'greetings'" test "raises an exception when requesting a layout that does not exist" do - assert_raise(ActionView::MissingTemplate) { get "/render_action/basic/hello_world_with_custom_layout" } + assert_raise(ActionView::MissingTemplate) do + get "/render_action/basic/hello_world_with_custom_layout", {}, "rails.raise_exceptions" => true + end end end diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index b1867fdcc2..16578fbc82 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -48,7 +48,7 @@ module Render test "raises an exception" do assert_raises(AbstractController::DoubleRenderError) do - get "/render/double_render" + get "/render/double_render", {}, "rails.raise_exceptions" => true end end end @@ -58,13 +58,13 @@ module Render test "raises an exception when a method of Object is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/clone" + get "/render/blank_render/clone", {}, "rails.raise_exceptions" => true end end test "raises an exception when a private method is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/secretz" + get "/render/blank_render/secretz", {}, "rails.raise_exceptions" => true end end end -- cgit v1.2.3 From 59c4d9a5b40dca45b095430d43c04d6c6541992d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 14:18:10 -0400 Subject: Changelog --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 204f5ae272..c1dc6f2ab4 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* 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] -- cgit v1.2.3 From db1bf3650d7450811f5dfddc5c5163a70683e37a Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sat, 16 May 2009 12:13:41 -0700 Subject: Fix ActionMailer Symbol#to_proc instance --- actionpack/lib/action_view/template/handlers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 0590372d09..faf54b9fe5 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -33,7 +33,7 @@ module ActionView #:nodoc: 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) -- cgit v1.2.3 From 842dab0c29bb05b98856aeb333bb0c2d14601a50 Mon Sep 17 00:00:00 2001 From: Jeffrey Chupp Date: Sat, 4 Apr 2009 09:36:32 -0500 Subject: Ensure WhiteListSanitizer allows dl tag [#2393 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index ae20f9947c..a992f7d912 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -73,7 +73,7 @@ module HTML # 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 -- cgit v1.2.3 From a9e8c4b37480564d27883dffe9134a9f95796a15 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 17 May 2009 14:31:54 +0200 Subject: Ensure rake test does not run new base tests as that requires rack/test --- actionpack/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 6ce8179646..41b190130e 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -22,7 +22,7 @@ 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] Rake::TestTask.new(:test_action_pack) do |t| t.libs << "test" -- cgit v1.2.3 From 53dda29f8b34073a4b135ee224c1d09c1f10de02 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Sun, 17 May 2009 10:37:30 -0500 Subject: Add support for parsing XML and JSON from an IO as well as a string [#2659 state:resolved] Signed-off-by: Joshua Peek --- actionpack/lib/action_dispatch/middleware/params_parser.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 58d527a6e7..a42c6598e0 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -32,16 +32,14 @@ module ActionDispatch 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) 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 -- cgit v1.2.3 From 11bac700784efe232083f94e3d28d171957e667e Mon Sep 17 00:00:00 2001 From: Lance Ivy Date: Wed, 15 Apr 2009 16:46:30 -0700 Subject: Ensure auto_link does not ignore multiple trailing punctuations [#2504 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/text_helper.rb | 13 +++++++------ actionpack/test/template/text_helper_test.rb | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 573b99b96e..8136a1cb13 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -535,7 +535,7 @@ module ActionView 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 +543,18 @@ module ActionView 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 diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index be7163888e..a780bfc606 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -401,6 +401,13 @@ class TextHelperTest < ActionView::TestCase auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.", :link => :all, :html => { :class => "menu", :target => "_blank" }) end + + def test_auto_link_with_multiple_trailing_punctuations + url = "http://youtube.com" + url_result = generate_result(url) + assert_equal url_result, auto_link(url) + assert_equal "(link: #{url_result}).", auto_link("(link: #{url}).") + end def test_cycle_class value = Cycle.new("one", 2, "3") -- cgit v1.2.3 From e41984c5f7f38b62c05dfcb54940bf51f6961aeb Mon Sep 17 00:00:00 2001 From: "Thomas E. Glasgow" Date: Sun, 17 May 2009 18:54:34 +0200 Subject: Simplify filter_chain method implementation [#2327 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_controller/base/chained/filters.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/chained/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb index 98fe306fd5..e121c0129d 100644 --- a/actionpack/lib/action_controller/base/chained/filters.rb +++ b/actionpack/lib/action_controller/base/chained/filters.rb @@ -571,12 +571,7 @@ module ActionController #:nodoc: # 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. -- cgit v1.2.3 From 98eaa2c6834e418959f2a1a18421e4811167e03b Mon Sep 17 00:00:00 2001 From: Travis Briggs Date: Wed, 18 Mar 2009 21:51:26 -0400 Subject: Ensure number_to_human_size does not strip zeros from the end [#1763 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/number_helper.rb | 7 ++++++- actionpack/test/template/number_helper_test.rb | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index c02692b09a..999d5b34fc 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -248,6 +248,11 @@ module ActionView # 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 number_to_human_size 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 @@ module ActionView :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 diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index 29cb60fd73..b6542ef29d 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -118,6 +118,10 @@ class NumberHelperTest < ActionView::TestCase assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2) assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4) assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4) + assert_equal '1 TB', number_to_human_size(1234567890123, :precision => 0) + assert_equal '500 MB', number_to_human_size(524288000, :precision=>0) + assert_equal '40 KB', number_to_human_size(41010, :precision => 0) + assert_equal '40 KB', number_to_human_size(41100, :precision => 0) end def test_number_to_human_size_with_custom_delimiter_and_separator -- cgit v1.2.3 From c3319504f066c9362b4b30e1e15bbd1cadde8e25 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 17 May 2009 11:09:14 -0500 Subject: Rescue hack was supposed to be removed. Some how it crept back in. --- actionpack/lib/action_controller/base/base.rb | 5 ++--- actionpack/lib/action_controller/testing/process.rb | 3 --- actionpack/test/controller/filters_test.rb | 1 - actionpack/test/controller/helper_test.rb | 3 --- 4 files changed, 2 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 2813e71d12..c59068c628 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -368,9 +368,8 @@ module ActionController #:nodoc: 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 diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 8f4358c33e..8831ff57e2 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -132,9 +132,6 @@ module ActionController #:nodoc: @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 diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 9ad49e9282..afefc6a77e 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -607,7 +607,6 @@ class FilterTest < Test::Unit::TestCase 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 diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 7b8096fccc..3bbda9eb3a 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -104,7 +104,6 @@ class HelperTest < Test::Unit::TestCase 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 @@ class HelperTest < Test::Unit::TestCase 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 @@ -217,7 +215,6 @@ class IsolatedHelpersTest < Test::Unit::TestCase def call_controller(klass, action) request = ActionController::TestRequest.new - request.env["action_controller.rescue.request"] = request klass.action(action).call(request.env) end -- cgit v1.2.3 From 8118fca9beec675fba19395e7d1027eaa4b5703a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 17 May 2009 12:24:42 -0500 Subject: Merge Failsafe middleware into ShowExceptions --- .../lib/action_controller/dispatch/middlewares.rb | 1 - actionpack/lib/action_dispatch.rb | 1 - .../lib/action_dispatch/middleware/failsafe.rb | 51 ------------- .../action_dispatch/middleware/show_exceptions.rb | 87 ++++++++++------------ actionpack/test/controller/rescue_test.rb | 14 ++++ actionpack/test/dispatch/show_exceptions_test.rb | 5 ++ actionpack/test/new_base/render_action_test.rb | 4 +- actionpack/test/new_base/render_test.rb | 6 +- 8 files changed, 64 insertions(+), 105 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/failsafe.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index 0e4ab6fa39..e4e3a704c0 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -2,7 +2,6 @@ use "Rack::Lock", :if => lambda { !ActionController::Base.allow_concurrency } -use "ActionDispatch::Failsafe" use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local } use "ActionDispatch::Rescue", lambda { controller = (::ApplicationController rescue ActionController::Base) diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 27d229835a..f3c91d8624 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -38,7 +38,6 @@ module ActionDispatch autoload :Response, 'action_dispatch/http/response' autoload :StatusCodes, 'action_dispatch/http/status_codes' - autoload :Failsafe, 'action_dispatch/middleware/failsafe' autoload :ParamsParser, 'action_dispatch/middleware/params_parser' autoload :Rescue, 'action_dispatch/middleware/rescue' autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions' diff --git a/actionpack/lib/action_dispatch/middleware/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb deleted file mode 100644 index 389accbc36..0000000000 --- a/actionpack/lib/action_dispatch/middleware/failsafe.rb +++ /dev/null @@ -1,51 +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 - if env["rails.raise_exceptions"] - raise - 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 - ["

500 Internal Server Error

"] - 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 diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 71c1e1b9a9..108355da63 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -4,8 +4,11 @@ module ActionDispatch 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 @@ module ActionDispatch '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'}, + ['

500 Internal Server Error

']] def initialize(app, consider_all_requests_local = false) @app = app @@ -43,34 +40,35 @@ module ActionDispatch def call(env) @app.call(env) rescue Exception => exception - raise exception if env['rack.test'] + raise exception if env['action_dispatch.show_exceptions'] == false + render_exception(env, exception) + end - log_error(exception) if logger + 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) + 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 - end - private # 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 @@ module ActionDispatch 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 @@ module ActionDispatch 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 render(status, body) + [status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, body] + end + def public_path - if defined?(Rails) - Rails.public_path - else - "public" - end + defined?(Rails.public_path) ? Rails.public_path : 'public_path' end - def log_error(exception) #:doc: + def log_error(exception) + return unless logger + ActiveSupport::Deprecation.silence do if ActionView::TemplateError === exception logger.fatal(exception.to_s) @@ -136,9 +131,7 @@ module ActionDispatch end def logger - if defined?(Rails.logger) - Rails.logger - end + defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) end end end diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index f745926b20..490a4ff3b3 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -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 diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index f8f562e7c1..0c0c087340 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -6,6 +6,11 @@ module ActionDispatch def public_path "#{FIXTURE_LOAD_PATH}/public" end + + # Silence logger + def logger + nil + end end end diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index 96666077d2..626c7b3540 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -92,7 +92,7 @@ module RenderAction test "raises an exception when requesting a layout and none exist" do assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do - get "/render_action/basic/hello_world_with_layout", {}, "rails.raise_exceptions" => true + get "/render_action/basic/hello_world_with_layout", {}, "action_dispatch.show_exceptions" => false end end end @@ -118,7 +118,7 @@ module RenderAction test "raises an exception when requesting a layout that does not exist" do assert_raise(ActionView::MissingTemplate) do - get "/render_action/basic/hello_world_with_custom_layout", {}, "rails.raise_exceptions" => true + get "/render_action/basic/hello_world_with_custom_layout", {}, "action_dispatch.show_exceptions" => false end end end diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index 16578fbc82..ef5e7d89c5 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -48,7 +48,7 @@ module Render test "raises an exception" do assert_raises(AbstractController::DoubleRenderError) do - get "/render/double_render", {}, "rails.raise_exceptions" => true + get "/render/double_render", {}, "action_dispatch.show_exceptions" => false end end end @@ -58,13 +58,13 @@ module Render test "raises an exception when a method of Object is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/clone", {}, "rails.raise_exceptions" => true + get "/render/blank_render/clone", {}, "action_dispatch.show_exceptions" => false end end test "raises an exception when a private method is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/secretz", {}, "rails.raise_exceptions" => true + get "/render/blank_render/secretz", {}, "action_dispatch.show_exceptions" => false end end end -- cgit v1.2.3 From edc9c226d11e6104d191ceeb6416c7062ceda54a Mon Sep 17 00:00:00 2001 From: Mike Breen Date: Sun, 17 May 2009 19:48:15 +0200 Subject: Add tests for assert_template :template Signed-off-by: Pratik Naik --- .../test/controller/action_pack_assertions_test.rb | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 484d3c5ce7..c3c769919a 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -12,6 +12,9 @@ class ActionPackAssertionsController < ActionController::Base # 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 @@ -331,6 +334,26 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase 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 -- cgit v1.2.3 From 092089015b79752c5e9d664b3eeefef9e2223e36 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 17 May 2009 13:39:44 -0500 Subject: Extract generic callbacks middleware from dispatcher --- .../lib/action_controller/dispatch/dispatcher.rb | 100 ++++++++------------- .../lib/action_controller/dispatch/middlewares.rb | 1 + actionpack/lib/action_dispatch.rb | 1 + .../lib/action_dispatch/middleware/callbacks.rb | 40 +++++++++ actionpack/test/controller/dispatcher_test.rb | 34 ++++--- 5 files changed, 101 insertions(+), 75 deletions(-) create mode 100644 actionpack/lib/action_dispatch/middleware/callbacks.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index 63866caed9..9ad1cadfd3 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -1,87 +1,65 @@ +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 + cattr_accessor :prepare_each_request + self.prepare_each_request = false + + cattr_accessor :router + self.router = Routing::Routes + + cattr_accessor :middleware + self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| + middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") + middleware.instance_eval(File.read(middlewares), middlewares, 1) + end + 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 + # Development mode callbacks - before_dispatch :reload_application - after_dispatch :cleanup_application + ActionDispatch::Callbacks.before_dispatch do |app| + ActionController::Dispatcher.router.reload + 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 ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false end if defined?(ActiveRecord) - to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } + to_prepare(:activerecord_instantiate_observers) do + ActiveRecord::Base.instantiate_observers + end end - after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush) + if Base.logger && Base.logger.respond_to?(:flush) + after_dispatch do + Base.logger.flush + end + end 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 + delegate :to_prepare, :prepare_dispatch, :before_dispatch, :after_dispatch, + :to => ActionDispatch::Callbacks - def run_prepare_callbacks - new.send :run_callbacks, :prepare_dispatch + def new + @@middleware.build(@@router) end end - - cattr_accessor :router - self.router = Routing::Routes - - cattr_accessor :middleware - self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| - middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") - middleware.instance_eval(File.read(middlewares), middlewares, 1) - end - - include ActiveSupport::Callbacks - define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch - - def initialize - @app = @@middleware.build(@@router) - freeze - end - - def call(env) - run_callbacks :before_dispatch - @app.call(env) - ensure - run_callbacks :after_dispatch, :enumerator => :reverse_each - end - - def reload_application - # Run prepare callbacks before every request in development mode - run_callbacks :prepare_dispatch - - @@router.reload - 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 - - def flush_logger - Base.logger.flush - end end end diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index e4e3a704c0..b25ed3fd3f 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -3,6 +3,7 @@ use "Rack::Lock", :if => lambda { } 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) diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index f3c91d8624..6fc4ad3f21 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -38,6 +38,7 @@ module ActionDispatch autoload :Response, 'action_dispatch/http/response' autoload :StatusCodes, 'action_dispatch/http/status_codes' + 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' diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb new file mode 100644 index 0000000000..0a2b4cf5f7 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -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 diff --git a/actionpack/test/controller/dispatcher_test.rb b/actionpack/test/controller/dispatcher_test.rb index b315232a7b..9fae1fcf63 100644 --- a/actionpack/test/controller/dispatcher_test.rb +++ b/actionpack/test/controller/dispatcher_test.rb @@ -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 @@ class DispatcherTest < Test::Unit::TestCase 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 @@ class DispatcherTest < Test::Unit::TestCase assert_nil a || b || c # Run callbacks - Dispatcher.run_prepare_callbacks + dispatch assert_equal 1, a assert_equal 2, b @@ -72,16 +72,22 @@ class DispatcherTest < Test::Unit::TestCase 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) -- cgit v1.2.3 From 01d7acd11d631d980497870aad1af42a0c66115c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 17 May 2009 14:42:36 -0500 Subject: Fix reset_session with ActiveRecord store [#2200 state:resolved] --- actionpack/test/activerecord/active_record_store_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 663cd259c8..47f8496181 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -28,9 +28,9 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end def call_reset_session - session[:bar] + session[:foo] reset_session - session[:bar] = "baz" + session[:foo] = "baz" head :ok end @@ -91,7 +91,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest 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 -- cgit v1.2.3 From b0de061e7b8d3c291a328f6b0b9bfc5f48b2f907 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Sun, 17 May 2009 16:09:28 -0500 Subject: Allow ParamsParser to parse YAML from the request body IO directly Signed-off-by: Joshua Peek --- actionpack/lib/action_dispatch/middleware/params_parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index a42c6598e0..e83cf9236b 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -34,7 +34,7 @@ module ActionDispatch when :xml_simple, :xml_node 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 if request.body.size == 0 {} -- cgit v1.2.3 From 195fadbfd31294d43634afb7bbf4f0ffc86b470a Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 18 May 2009 16:59:37 +0200 Subject: Ensure HTTP Digest auth uses appropriate HTTP method [#2490 state:resolved] [Steve Madsen] --- .../action_controller/base/http_authentication.rb | 3 ++- .../controller/http_digest_authentication_test.rb | 23 +++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb index fa8ecea408..2893290efb 100644 --- a/actionpack/lib/action_controller/base/http_authentication.rb +++ b/actionpack/lib/action_controller/base/http_authentication.rb @@ -194,9 +194,10 @@ module ActionController 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 diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb index 7bebc8cd2a..b8a2205ce6 100644 --- a/actionpack/test/controller/http_digest_authentication_test.rb +++ b/actionpack/test/controller/http_digest_authentication_test.rb @@ -149,6 +149,16 @@ class HttpDigestAuthenticationTest < ActionController::TestCase 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) @@ -159,15 +169,22 @@ class HttpDigestAuthenticationTest < ActionController::TestCase # to prevent tampering of timestamp ActionController::Base.session_options[:secret] = "session_options_secret" - # Perform unauthenticated GET to retrieve digest parameters to use on subsequent request - get :index + # Perform unauthenticated request to retrieve digest parameters to use on subsequent request + method = options.delete(:method) || 'GET' + + 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) -- cgit v1.2.3 From 5e190ef138a034bf86419ce4f4c343ae16bfc77b Mon Sep 17 00:00:00 2001 From: Andy Stewart Date: Wed, 28 Jan 2009 16:45:28 +0000 Subject: Truncate helper accepts a :separator for a more legible result [#1807 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/text_helper.rb | 7 ++++++- actionpack/test/template/text_helper_test.rb | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 8136a1cb13..ad0733a7e1 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -34,12 +34,16 @@ module ActionView # Truncates a given +text+ after a given :length if +text+ is longer than :length # (defaults to 30). The last characters will be replaced with the :omission (defaults to "..."). + # Pass a :separator 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 @@ module ActionView 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 diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index a780bfc606..706b5085f4 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -49,6 +49,9 @@ class TextHelperTest < ActionView::TestCase assert_equal "This is a string that wil[...]", truncate("This is a string that will go longer then the default truncate length of 30", :omission => "[...]") assert_equal "Hello W...", truncate("Hello World!", :length => 10) assert_equal "Hello[...]", truncate("Hello World!", :omission => "[...]", :length => 10) + assert_equal "Hello[...]", truncate("Hello Big World!", :omission => "[...]", :length => 13, :separator => ' ') + assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 14, :separator => ' ') + assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 15, :separator => ' ') end if RUBY_VERSION < '1.9.0' -- cgit v1.2.3 From 07f733c6315980bde120c98c6b8a25e2773ee6bf Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 18 May 2009 16:15:43 -0700 Subject: Ported simple benchmarking in new base --- actionpack/Rakefile | 4 ++-- actionpack/lib/action_controller/abstract.rb | 1 + .../lib/action_controller/abstract/benchmarker.rb | 28 ++++++++++++++++++++++ .../lib/action_controller/abstract/logger.rb | 1 + .../action_controller/base/chained/benchmarking.rb | 2 +- actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/test/controller/logging_test.rb | 5 ++++ 7 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 actionpack/lib/action_controller/abstract/benchmarker.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 41b190130e..57c3276cb9 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -21,8 +21,8 @@ task :default => [ :test ] # Run the unit tests -desc "Run all unit tests" -task :test => [:test_action_pack, :test_active_record_integration] +desc "Run all unit tests" # Do not remove :test_new_base +task :test => [:test_action_pack, :test_active_record_integration, :test_new_base] Rake::TestTask.new(:test_action_pack) do |t| t.libs << "test" diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index 48e33282ec..d6b7a44f5f 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -3,6 +3,7 @@ require "active_support/core_ext/module/delegation" 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" diff --git a/actionpack/lib/action_controller/abstract/benchmarker.rb b/actionpack/lib/action_controller/abstract/benchmarker.rb new file mode 100644 index 0000000000..9f5889c704 --- /dev/null +++ b/actionpack/lib/action_controller/abstract/benchmarker.rb @@ -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 \ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 750a5c9fb6..980ede0bed 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/class/attribute_accessors' +require 'active_support/core_ext/logger' module AbstractController module Logger diff --git a/actionpack/lib/action_controller/base/chained/benchmarking.rb b/actionpack/lib/action_controller/base/chained/benchmarking.rb index 66e9e9c31d..57a1ac8314 100644 --- a/actionpack/lib/action_controller/base/chained/benchmarking.rb +++ b/actionpack/lib/action_controller/base/chained/benchmarking.rb @@ -21,7 +21,7 @@ module ActionController #:nodoc: # 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)") diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index c25ffd5c84..756a0799fe 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -2,6 +2,7 @@ module ActionController class Base < Http abstract! + include AbstractController::Benchmarker include AbstractController::Callbacks include AbstractController::Helpers include AbstractController::Logger diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 1f3ff4ef52..75afa2d133 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -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 ||= [] -- cgit v1.2.3 From 4a6f4b92ad2f48dc7906d223fe4708d36624bd50 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 19 May 2009 23:48:05 +0200 Subject: Change integration test helpers to accept Rack environment instead of just HTTP Headers. Before : get '/path', {}, 'Accept' => 'text/javascript' After : get '/path', {}, 'HTTP_ACCEPT' => 'text/javascript' --- .../lib/action_controller/testing/integration.rb | 10 ++++----- actionpack/test/controller/integration_test.rb | 24 +++++++++++----------- 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index d6991ab4f5..a8e8f16d6c 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -62,8 +62,8 @@ module ActionController # 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 @@ -228,7 +228,7 @@ module ActionController 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 @@ -265,9 +265,7 @@ module ActionController } 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 diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index c616107324..a2b3ad2106 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -123,8 +123,8 @@ class SessionTest < Test::Unit::TestCase 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 +133,8 @@ class SessionTest < Test::Unit::TestCase 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 +143,8 @@ class SessionTest < Test::Unit::TestCase 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 +153,8 @@ class SessionTest < Test::Unit::TestCase 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 +163,17 @@ class SessionTest < Test::Unit::TestCase 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) -- cgit v1.2.3 From f503a5dc97d18794cc0eda5ffe77e2cd7d762d47 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 19 May 2009 23:57:49 +0200 Subject: Missing CHANGELOG entry for 4a6f4b92ad2f --- actionpack/CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index c1dc6f2ab4..e3ad19558e 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,10 @@ *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] -- cgit v1.2.3 From d8fffe7b23acce42bc3941d7bba47e07a66aed67 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 20 May 2009 00:06:14 +0200 Subject: Replace ad hoc Rack::Test with ActionController::IntegrationTest --- actionpack/Rakefile | 2 +- actionpack/test/new_base/test_helper.rb | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 57c3276cb9..6ce8179646 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -21,7 +21,7 @@ task :default => [ :test ] # Run the unit tests -desc "Run all unit tests" # Do not remove :test_new_base +desc "Run all unit tests" task :test => [:test_action_pack, :test_active_record_integration, :test_new_base] Rake::TestTask.new(:test_action_pack) do |t| diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index ec7dbffaae..9401e692f1 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -20,8 +20,8 @@ require 'action_controller/abstract' require 'action_controller/new_base' require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late -require 'rubygems' -require 'rack/test' +require 'action_controller/testing/process' +require 'action_controller/testing/integration' module Rails def self.env @@ -32,9 +32,7 @@ module Rails end # Temporary base class -class Rack::TestCase < ActiveSupport::TestCase - include Rack::Test::Methods - +class Rack::TestCase < ActionController::IntegrationTest setup do ActionController::Base.session_options[:key] = "abc" ActionController::Base.session_options[:secret] = ("*" * 30) @@ -82,7 +80,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_body(body) - assert_equal body, Array.wrap(last_response.body).join + assert_equal body, Array.wrap(response.body).join end def self.assert_body(body) @@ -92,7 +90,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_status(code) - assert_equal code, last_response.status + assert_equal code, response.status end def self.assert_status(code) @@ -110,7 +108,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_content_type(type) - assert_equal type, last_response.headers["Content-Type"] + assert_equal type, response.headers["Content-Type"] end def self.assert_content_type(type) @@ -120,7 +118,7 @@ class Rack::TestCase < ActiveSupport::TestCase end def assert_header(name, value) - assert_equal value, last_response.headers[name] + assert_equal value, response.headers[name] end def self.assert_header(name, value) -- cgit v1.2.3 From 26f2be01c2d537aac6d484c8a1ed2df92aa52f00 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 19 May 2009 18:02:03 -0700 Subject: Modify caching to use new included helper --- actionpack/lib/action_controller/caching.rb | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index ffd8081edc..2f2eec10f6 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -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 -- cgit v1.2.3 From 0e7da0e4a06f78ab39b0e90daadfc223b8f1738a Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 19 May 2009 18:04:17 -0700 Subject: Include caching module into new base --- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + 2 files changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index bc47713529..078f66ced1 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -13,6 +13,7 @@ module ActionController # Ported modules # require 'action_controller/routing' + autoload :Caching, 'action_controller/caching' autoload :Dispatcher, 'action_controller/dispatch/dispatcher' autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes' autoload :RecordIdentifier, 'action_controller/record_identifier' diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 756a0799fe..7f830307b6 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -17,6 +17,7 @@ module ActionController # Legacy modules include SessionManagement include ActionDispatch::StatusCodes + include ActionController::Caching # Rails 2.x compatibility include ActionController::Rails2Compatibility -- cgit v1.2.3 From 67cc021d019515c94d4bcc4c3c7060c9a2594c87 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 19 May 2009 18:05:16 -0700 Subject: Modified caching implementation to work with NewBase --- .../lib/action_controller/caching/actions.rb | 22 +++++++++++++++++++--- .../lib/action_controller/new_base/renderer.rb | 5 +++++ 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 2b822b52c8..430db3932f 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -61,8 +61,14 @@ module ActionController #:nodoc: 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 @@ module ActionController #:nodoc: @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 @@ module ActionController #:nodoc: 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 diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 8a9f230603..9253df53a1 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -9,6 +9,11 @@ module ActionController super end + def response_body=(body) + response.body = body if response + super + end + def render_to_body(options) _process_options(options) -- cgit v1.2.3 From 321168b17bce2e73ab7ba22309491ad5c245dcf8 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 19 May 2009 18:08:04 -0700 Subject: Make old caching tests pass on new base. --- actionpack/lib/action_controller/new_base/compatibility.rb | 4 ++++ actionpack/lib/action_controller/new_base/http.rb | 1 - actionpack/lib/action_controller/new_base/url_for.rb | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 0a283887b6..0098c0747e 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -55,6 +55,10 @@ module ActionController self.consider_all_requests_local = true end + # For old tests + def initialize_template_class(*) end + def assign_shortcuts(*) end + module ClassMethods def protect_from_forgery() end def consider_all_requests_local() end diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 8891a2a8c3..17466a2d52 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -60,7 +60,6 @@ module ActionController # :api: private def to_rack - @_response.body = response_body @_response.prepare! @_response.to_a end diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index af5b21012b..94de9fab50 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -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 -- cgit v1.2.3 From 0029d5e5943dd20d38485ac7127cc150659da9e5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 11 May 2009 23:04:39 -0400 Subject: Integrating Rack::MockSession (from Rack::Test) --- .../lib/action_controller/testing/integration.rb | 25 +++++++++++----------- actionpack/test/controller/integration_test.rb | 6 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index a8e8f16d6c..31afd54258 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -1,6 +1,8 @@ require 'stringio' require 'uri' require 'active_support/test_case' +require 'rack/test' +require 'rack/mock_session' module ActionController module Integration #:nodoc: @@ -121,6 +123,8 @@ module ActionController # 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 +149,9 @@ module ActionController # 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 +178,11 @@ module ActionController # 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,6 +233,7 @@ module ActionController end private + # Performs the actual request. def process(method, path, parameters = nil, rack_environment = nil) if path =~ %r{://} @@ -258,10 +265,7 @@ module ActionController "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) @@ -269,15 +273,12 @@ module ActionController env[key] = value end - app = Rack::Lint.new(@app) - status, headers, body = app.call(env) - mock_response = ::Rack::MockResponse.new(status, headers, body) + @mock_session.request(URI.parse(path), env) @request_count += 1 @request = ActionDispatch::Request.new(env) - @response = ActionDispatch::TestResponse.from_response(mock_response) + @response = ActionDispatch::TestResponse.from_response(@mock_session.last_response) - @cookies.merge!(@response.cookies) @html_document = nil if @controller = ActionController::Base.last_instantiation diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index a2b3ad2106..eae6835714 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -253,7 +253,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest 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 +269,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest 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 +287,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest 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 -- cgit v1.2.3 From df0faea378034b031f49995f06c8bf108a0b5530 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 12 May 2009 01:37:19 -0400 Subject: Refactor ActionController instantiation capture --- .../lib/action_controller/testing/integration.rb | 24 +++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 31afd54258..717b77674c 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -249,8 +249,6 @@ module ActionController end end - ActionController::Base.clear_last_instantiation! - opts = { :method => method, :params => parameters, @@ -273,18 +271,15 @@ module ActionController env[key] = value end - @mock_session.request(URI.parse(path), env) + @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_session.last_response) - @html_document = nil - if @controller = ActionController::Base.last_instantiation - @controller.send(:set_test_assigns) - end - return response.status end @@ -305,11 +300,10 @@ module ActionController # 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) @@ -320,8 +314,10 @@ module ActionController 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 -- cgit v1.2.3 From 6761759a90c08b9db8d5720a8ee4c4329a547caf Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 19 May 2009 22:42:59 -0500 Subject: Temporarily bundle rack-test while MockSession is baking --- .../lib/action_controller/testing/integration.rb | 3 +- actionpack/lib/action_dispatch.rb | 2 + .../vendor/rack-test/rack/mock_session.rb | 50 +++++ .../action_dispatch/vendor/rack-test/rack/test.rb | 239 +++++++++++++++++++++ .../vendor/rack-test/rack/test/cookie_jar.rb | 169 +++++++++++++++ .../vendor/rack-test/rack/test/methods.rb | 45 ++++ .../rack-test/rack/test/mock_digest_request.rb | 27 +++ .../vendor/rack-test/rack/test/uploaded_file.rb | 36 ++++ .../vendor/rack-test/rack/test/utils.rb | 75 +++++++ 9 files changed, 645 insertions(+), 1 deletion(-) create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb create mode 100644 actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index 717b77674c..cc157816e2 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -1,8 +1,9 @@ require 'stringio' require 'uri' require 'active_support/test_case' -require 'rack/test' + require 'rack/mock_session' +require 'rack/test/cookie_jar' module ActionController module Integration #:nodoc: diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 6fc4ad3f21..f9003c51ea 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -33,6 +33,8 @@ 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' diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb new file mode 100644 index 0000000000..eba6226538 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb new file mode 100644 index 0000000000..70384b1d76 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb new file mode 100644 index 0000000000..d58c914c9b --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb new file mode 100644 index 0000000000..a191fa23d8 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb new file mode 100644 index 0000000000..81c398ba51 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb new file mode 100644 index 0000000000..239302fbe4 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb @@ -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 diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb new file mode 100644 index 0000000000..d25b849709 --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb @@ -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 -- cgit v1.2.3 From c03b0ca7eb7e73587005e1440bf90cd01ed10aa5 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 20 May 2009 21:15:06 +0200 Subject: Replace the class level Rack::Test DSL with the regular integration tests DSL --- actionpack/test/new_base/base_test.rb | 80 ++--- actionpack/test/new_base/content_type_test.rb | 120 +++---- actionpack/test/new_base/etag_test.rb | 23 +- actionpack/test/new_base/render_action_test.rb | 388 ++++++++++----------- .../test/new_base/render_implicit_action_test.rb | 28 +- actionpack/test/new_base/render_layout_test.rb | 64 ++-- actionpack/test/new_base/render_template_test.rb | 87 +++-- actionpack/test/new_base/render_test.rb | 45 ++- actionpack/test/new_base/render_text_test.rb | 151 ++++---- actionpack/test/new_base/test_helper.rb | 55 +-- 10 files changed, 477 insertions(+), 564 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/new_base/base_test.rb b/actionpack/test/new_base/base_test.rb index a32653f128..d9d552f9e5 100644 --- a/actionpack/test/new_base/base_test.rb +++ b/actionpack/test/new_base/base_test.rb @@ -10,78 +10,60 @@ module Dispatching def modify_response_body self.response_body = "success" end - + def modify_response_body_twice ret = (self.response_body = "success") self.response_body = "#{ret}!" end - + def modify_response_headers - end end - - class TestSimpleDispatch < SimpleRouteCase - - get "/dispatching/simple/index" - - test "sets the body" do + + class EmptyController < ActionController::Base ; end + + module Submodule + class ContainedEmptyController < ActionController::Base ; end + end + + class BaseTest < SimpleRouteCase + # :api: plugin + test "simple dispatching" do + get "/dispatching/simple/index" + assert_body "success" - end - - test "sets the status code" do assert_status 200 - end - - test "sets the content type" do assert_content_type "text/html; charset=utf-8" - end - - test "sets the content length" do assert_header "Content-Length", "7" end - - end - - # :api: plugin - class TestDirectResponseMod < SimpleRouteCase - get "/dispatching/simple/modify_response_body" - - test "sets the body" do + + # :api: plugin + test "directly modifying response body" do + get "/dispatching/simple/modify_response_body" + assert_body "success" + assert_header "Content-Length", "7" # setting the body manually sets the content length end - - test "setting the body manually sets the content length" do - assert_header "Content-Length", "7" - end - end - - # :api: plugin - class TestDirectResponseModTwice < SimpleRouteCase - get "/dispatching/simple/modify_response_body_twice" - - test "self.response_body= returns the body being set" do + + # :api: plugin + test "directly modifying response body twice" do + get "/dispatching/simple/modify_response_body_twice" + assert_body "success!" - end - - test "updating the response body updates the content length" do assert_header "Content-Length", "8" end - end - - class EmptyController < ActionController::Base ; end - module Submodule - class ContainedEmptyController < ActionController::Base ; end - end - class ControllerClassTests < Test::Unit::TestCase - def test_controller_path + test "controller path" do assert_equal 'dispatching/empty', EmptyController.controller_path assert_equal EmptyController.controller_path, EmptyController.new.controller_path + end + + test "namespaced controller path" do assert_equal 'dispatching/submodule/contained_empty', Submodule::ContainedEmptyController.controller_path assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path end - def test_controller_name + + test "controller name" do assert_equal 'empty', EmptyController.controller_name assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name end diff --git a/actionpack/test/new_base/content_type_test.rb b/actionpack/test/new_base/content_type_test.rb index a5c04e9cb6..82b817a5a3 100644 --- a/actionpack/test/new_base/content_type_test.rb +++ b/actionpack/test/new_base/content_type_test.rb @@ -5,107 +5,107 @@ module ContentType def index render :text => "Hello world!" end - + def set_on_response_obj response.content_type = Mime::RSS render :text => "Hello world!" end - + def set_on_render render :text => "Hello world!", :content_type => Mime::RSS end end - - class TestDefault < SimpleRouteCase - describe "a default response is HTML and UTF8" - - get "/content_type/base" - assert_body "Hello world!" - assert_header "Content-Type", "text/html; charset=utf-8" - end - - class TestSetOnResponseObj < SimpleRouteCase - describe "setting the content type of the response directly on the response object" - - get "/content_type/base/set_on_response_obj" - assert_body "Hello world!" - assert_header "Content-Type", "application/rss+xml; charset=utf-8" - end - - class TestSetOnRender < SimpleRouteCase - describe "setting the content type of the response as an option to render" - - get "/content_type/base/set_on_render" - assert_body "Hello world!" - assert_header "Content-Type", "application/rss+xml; charset=utf-8" - end - + class ImpliedController < ActionController::Base + # Template's mime type is used if no content_type is specified + self.view_paths = [ActionView::Template::FixturePath.new( "content_type/implied/i_am_html_erb.html.erb" => "Hello world!", "content_type/implied/i_am_xml_erb.xml.erb" => "Hello world!", "content_type/implied/i_am_html_builder.html.builder" => "xml.p 'Hello'", "content_type/implied/i_am_xml_builder.xml.builder" => "xml.awesome 'Hello'" )] - + def i_am_html_erb() end def i_am_xml_erb() end def i_am_html_builder() end def i_am_xml_builder() end end - - class TestImpliedController < SimpleRouteCase - describe "the template's mime type is used if no content_type is specified" - + + class CharsetController < ActionController::Base + def set_on_response_obj + response.charset = "utf-16" + render :text => "Hello world!" + end + + def set_as_nil_on_response_obj + response.charset = nil + render :text => "Hello world!" + end + end + + class ExplicitContentTypeTest < SimpleRouteCase + test "default response is HTML and UTF8" do + get "/content_type/base" + + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-8" + end + + test "setting the content type of the response directly on the response object" do + get "/content_type/base/set_on_response_obj" + + assert_body "Hello world!" + assert_header "Content-Type", "application/rss+xml; charset=utf-8" + end + + test "setting the content type of the response as an option to render" do + get "/content_type/base/set_on_render" + + assert_body "Hello world!" + assert_header "Content-Type", "application/rss+xml; charset=utf-8" + end + end + + class ImpliedContentTypeTest < SimpleRouteCase test "sets Content-Type as text/html when rendering *.html.erb" do get "/content_type/implied/i_am_html_erb" + assert_header "Content-Type", "text/html; charset=utf-8" end test "sets Content-Type as application/xml when rendering *.xml.erb" do get "/content_type/implied/i_am_xml_erb" + assert_header "Content-Type", "application/xml; charset=utf-8" end test "sets Content-Type as text/html when rendering *.html.builder" do get "/content_type/implied/i_am_html_builder" + assert_header "Content-Type", "text/html; charset=utf-8" end test "sets Content-Type as application/xml when rendering *.xml.builder" do get "/content_type/implied/i_am_xml_builder" + assert_header "Content-Type", "application/xml; charset=utf-8" end - end -end -module Charset - class BaseController < ActionController::Base - def set_on_response_obj - response.charset = "utf-16" - render :text => "Hello world!" + class ExplicitCharsetTest < SimpleRouteCase + test "setting the charset of the response directly on the response object" do + get "/content_type/charset/set_on_response_obj" + + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-16" end - - def set_as_nil_on_response_obj - response.charset = nil - render :text => "Hello world!" + + test "setting the charset of the response as nil directly on the response object" do + get "/content_type/charset/set_as_nil_on_response_obj" + + assert_body "Hello world!" + assert_header "Content-Type", "text/html; charset=utf-8" end end - - class TestSetOnResponseObj < SimpleRouteCase - describe "setting the charset of the response directly on the response object" - - get "/charset/base/set_on_response_obj" - assert_body "Hello world!" - assert_header "Content-Type", "text/html; charset=utf-16" - end - - class TestSetAsNilOnResponseObj < SimpleRouteCase - describe "setting the charset of the response as nil directly on the response object" - - get "/charset/base/set_as_nil_on_response_obj" - assert_body "Hello world!" - assert_header "Content-Type", "text/html; charset=utf-8" - end -end \ No newline at end of file +end diff --git a/actionpack/test/new_base/etag_test.rb b/actionpack/test/new_base/etag_test.rb index 7af5febfb3..c77636bb64 100644 --- a/actionpack/test/new_base/etag_test.rb +++ b/actionpack/test/new_base/etag_test.rb @@ -1,47 +1,46 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module Etags - class BasicController < ActionController::Base - self.view_paths = [ActionView::Template::FixturePath.new( "etags/basic/base.html.erb" => "Hello from without_layout.html.erb", "layouts/etags.html.erb" => "teh <%= yield %> tagz" )] - + def without_layout render :action => "base" end - + def with_layout render :action => "base", :layout => "etag" end - end - - class TestBasic < SimpleRouteCase + + class EtagTest < SimpleRouteCase describe "Rendering without any special etag options returns an etag that is an MD5 hash of its text" - + test "an action without a layout" do get "/etags/basic/without_layout" + body = "Hello from without_layout.html.erb" assert_body body assert_header "Etag", etag_for(body) assert_status 200 end - + test "an action with a layout" do get "/etags/basic/with_layout" + body = "teh Hello from without_layout.html.erb tagz" assert_body body assert_header "Etag", etag_for(body) assert_status 200 end - + + private + def etag_for(text) %("#{Digest::MD5.hexdigest(text)}") end end - - end \ No newline at end of file diff --git a/actionpack/test/new_base/render_action_test.rb b/actionpack/test/new_base/render_action_test.rb index 626c7b3540..4402eadf42 100644 --- a/actionpack/test/new_base/render_action_test.rb +++ b/actionpack/test/new_base/render_action_test.rb @@ -1,26 +1,24 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module RenderAction - # This has no layout and it works class BasicController < ActionController::Base - self.view_paths = [ActionView::Template::FixturePath.new( "render_action/basic/hello_world.html.erb" => "Hello world!" )] - + def hello_world render :action => "hello_world" end - + def hello_world_as_string render "hello_world" end - + def hello_world_as_string_with_options render "hello_world", :status => 404 end - + def hello_world_as_symbol render :hello_world end @@ -28,107 +26,95 @@ module RenderAction def hello_world_with_symbol render :action => :hello_world end - + def hello_world_with_layout render :action => "hello_world", :layout => true end - + def hello_world_with_layout_false render :action => "hello_world", :layout => false end - + def hello_world_with_layout_nil render :action => "hello_world", :layout => nil end - + def hello_world_with_custom_layout render :action => "hello_world", :layout => "greetings" end - - end - - class TestBasic < SimpleRouteCase - describe "Rendering an action using :action => " - - get "/render_action/basic/hello_world" - assert_body "Hello world!" - assert_status 200 - end - - class TestWithString < SimpleRouteCase - describe "Render an action using 'hello_world'" - - get "/render_action/basic/hello_world_as_string" - assert_body "Hello world!" - assert_status 200 - end - - class TestWithStringAndOptions < SimpleRouteCase - describe "Render an action using 'hello_world'" - - get "/render_action/basic/hello_world_as_string_with_options" - assert_body "Hello world!" - assert_status 404 - end - - class TestAsSymbol < SimpleRouteCase - describe "Render an action using :hello_world" - - get "/render_action/basic/hello_world_as_symbol" - assert_body "Hello world!" - assert_status 200 + end - - class TestWithSymbol < SimpleRouteCase - describe "Render an action using :action => :hello_world" - - get "/render_action/basic/hello_world_with_symbol" - assert_body "Hello world!" - assert_status 200 + + class RenderActionTest < SimpleRouteCase + test "rendering an action using :action => " do + get "/render_action/basic/hello_world" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering an action using ''" do + get "/render_action/basic/hello_world_as_string" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering an action using '' and options" do + get "/render_action/basic/hello_world_as_string_with_options" + + assert_body "Hello world!" + assert_status 404 + end + + test "rendering an action using :action" do + get "/render_action/basic/hello_world_as_symbol" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering an action using :action => :hello_world" do + get "/render_action/basic/hello_world_with_symbol" + + assert_body "Hello world!" + assert_status 200 + end end - - class TestLayoutTrue < SimpleRouteCase - describe "rendering a normal template with full path with layout => true" - - test "raises an exception when requesting a layout and none exist" do - assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do + + class RenderLayoutTest < SimpleRouteCase + describe "Both .html.erb and application.html.erb are missing" + + test "rendering with layout => true" do + assert_raise(ArgumentError, /no default layout for RenderAction::BasicController in/) do get "/render_action/basic/hello_world_with_layout", {}, "action_dispatch.show_exceptions" => false end end - end - - class TestLayoutFalse < SimpleRouteCase - describe "rendering a normal template with full path with layout => false" - - get "/render_action/basic/hello_world_with_layout_false" - assert_body "Hello world!" - assert_status 200 - end - - class TestLayoutNil < SimpleRouteCase - describe "rendering a normal template with full path with layout => :nil" - - get "/render_action/basic/hello_world_with_layout_nil" - assert_body "Hello world!" - assert_status 200 - end - - class TestCustomLayout < SimpleRouteCase - describe "rendering a normal template with full path with layout => 'greetings'" - - test "raises an exception when requesting a layout that does not exist" do + + test "rendering with layout => false" do + get "/render_action/basic/hello_world_with_layout_false" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering with layout => :nil" do + get "/render_action/basic/hello_world_with_layout_nil" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering with layout => 'greetings'" do assert_raise(ActionView::MissingTemplate) do get "/render_action/basic/hello_world_with_custom_layout", {}, "action_dispatch.show_exceptions" => false end end end - end module RenderActionWithApplicationLayout - # # ==== Render actions with layouts ==== - class BasicController < ::ApplicationController # Set the view path to an application view structure with layouts self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( @@ -138,205 +124,197 @@ module RenderActionWithApplicationLayout "layouts/greetings.html.erb" => "Greetings <%= yield %> Bai", "layouts/builder.html.builder" => "xml.html do\n xml << yield\nend" )] - + def hello_world render :action => "hello_world" end - + def hello_world_with_layout render :action => "hello_world", :layout => true end - + def hello_world_with_layout_false render :action => "hello_world", :layout => false end - + def hello_world_with_layout_nil render :action => "hello_world", :layout => nil end - + def hello_world_with_custom_layout render :action => "hello_world", :layout => "greetings" end - + def with_builder_and_layout render :action => "hello", :layout => "builder" end end - - class TestDefaultLayout < SimpleRouteCase - describe %( - Render hello_world and implicitly use application.html.erb as a layout if - no layout is specified and no controller layout is present - ) - - get "/render_action_with_application_layout/basic/hello_world" - assert_body "OHAI Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutTrue < SimpleRouteCase - describe "rendering a normal template with full path with layout => true" - - get "/render_action_with_application_layout/basic/hello_world_with_layout" - assert_body "OHAI Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutFalse < SimpleRouteCase - describe "rendering a normal template with full path with layout => false" - - get "/render_action_with_application_layout/basic/hello_world_with_layout_false" - assert_body "Hello World!" - assert_status 200 - end - - class TestLayoutNil < SimpleRouteCase - describe "rendering a normal template with full path with layout => :nil" - - get "/render_action_with_application_layout/basic/hello_world_with_layout_nil" - assert_body "Hello World!" - assert_status 200 - end - - class TestCustomLayout < SimpleRouteCase - describe "rendering a normal template with full path with layout => 'greetings'" - - get "/render_action_with_application_layout/basic/hello_world_with_custom_layout" - assert_body "Greetings Hello World! Bai" - assert_status 200 + + class LayoutTest < SimpleRouteCase + describe "Only application.html.erb is present and .html.erb is missing" + + test "rendering implicit application.html.erb as layout" do + get "/render_action_with_application_layout/basic/hello_world" + + assert_body "OHAI Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => true" do + get "/render_action_with_application_layout/basic/hello_world_with_layout" + + assert_body "OHAI Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => false" do + get "/render_action_with_application_layout/basic/hello_world_with_layout_false" + + assert_body "Hello World!" + assert_status 200 + end + + test "rendering with layout => :nil" do + get "/render_action_with_application_layout/basic/hello_world_with_layout_nil" + + assert_body "Hello World!" + assert_status 200 + end + + test "rendering with layout => 'greetings'" do + get "/render_action_with_application_layout/basic/hello_world_with_custom_layout" + + assert_body "Greetings Hello World! Bai" + assert_status 200 + end end - + class TestLayout < SimpleRouteCase testing BasicController - + test "builder works with layouts" do get :with_builder_and_layout assert_response "\n

Omg

\n\n" end end - + end module RenderActionWithControllerLayout - class BasicController < ActionController::Base self.view_paths = self.view_paths = [ActionView::Template::FixturePath.new( "render_action_with_controller_layout/basic/hello_world.html.erb" => "Hello World!", "layouts/render_action_with_controller_layout/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI" )] - + def hello_world render :action => "hello_world" end - + def hello_world_with_layout render :action => "hello_world", :layout => true end - + def hello_world_with_layout_false render :action => "hello_world", :layout => false end - + def hello_world_with_layout_nil render :action => "hello_world", :layout => nil end - + def hello_world_with_custom_layout render :action => "hello_world", :layout => "greetings" end end - - class TestControllerLayout < SimpleRouteCase - describe "Render hello_world and implicitly use .html.erb as a layout." - get "/render_action_with_controller_layout/basic/hello_world" - assert_body "With Controller Layout! Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutTrue < SimpleRouteCase - describe "rendering a normal template with full path with layout => true" - - get "/render_action_with_controller_layout/basic/hello_world_with_layout" - assert_body "With Controller Layout! Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutFalse < SimpleRouteCase - describe "rendering a normal template with full path with layout => false" - - get "/render_action_with_controller_layout/basic/hello_world_with_layout_false" - assert_body "Hello World!" - assert_status 200 - end - - class TestLayoutNil < SimpleRouteCase - describe "rendering a normal template with full path with layout => :nil" - - get "/render_action_with_controller_layout/basic/hello_world_with_layout_nil" - assert_body "Hello World!" - assert_status 200 + class ControllerLayoutTest < SimpleRouteCase + describe "Only .html.erb is present and application.html.erb is missing" + + test "render hello_world and implicitly use .html.erb as a layout." do + get "/render_action_with_controller_layout/basic/hello_world" + + assert_body "With Controller Layout! Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => true" do + get "/render_action_with_controller_layout/basic/hello_world_with_layout" + + assert_body "With Controller Layout! Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => false" do + get "/render_action_with_controller_layout/basic/hello_world_with_layout_false" + + assert_body "Hello World!" + assert_status 200 + end + + test "rendering with layout => :nil" do + get "/render_action_with_controller_layout/basic/hello_world_with_layout_nil" + + assert_body "Hello World!" + assert_status 200 + end end - end module RenderActionWithBothLayouts - class BasicController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new({ "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!", "layouts/application.html.erb" => "OHAI <%= yield %> KTHXBAI", "layouts/render_action_with_both_layouts/basic.html.erb" => "With Controller Layout! <%= yield %> KTHXBAI" })] - + def hello_world render :action => "hello_world" end - + def hello_world_with_layout render :action => "hello_world", :layout => true end - + def hello_world_with_layout_false render :action => "hello_world", :layout => false end - + def hello_world_with_layout_nil render :action => "hello_world", :layout => nil end end - - class TestControllerLayoutFirst < SimpleRouteCase - describe "Render hello_world and implicitly use .html.erb over application.html.erb as a layout" - get "/render_action_with_both_layouts/basic/hello_world" - assert_body "With Controller Layout! Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutTrue < SimpleRouteCase - describe "rendering a normal template with full path with layout => true" - - get "/render_action_with_both_layouts/basic/hello_world_with_layout" - assert_body "With Controller Layout! Hello World! KTHXBAI" - assert_status 200 - end - - class TestLayoutFalse < SimpleRouteCase - describe "rendering a normal template with full path with layout => false" - - get "/render_action_with_both_layouts/basic/hello_world_with_layout_false" - assert_body "Hello World!" - assert_status 200 - end - - class TestLayoutNil < SimpleRouteCase - describe "rendering a normal template with full path with layout => :nil" - - get "/render_action_with_both_layouts/basic/hello_world_with_layout_nil" - assert_body "Hello World!" - assert_status 200 + class ControllerLayoutTest < SimpleRouteCase + describe "Both .html.erb and application.html.erb are present" + + test "rendering implicitly use .html.erb over application.html.erb as a layout" do + get "/render_action_with_both_layouts/basic/hello_world" + + assert_body "With Controller Layout! Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => true" do + get "/render_action_with_both_layouts/basic/hello_world_with_layout" + + assert_body "With Controller Layout! Hello World! KTHXBAI" + assert_status 200 + end + + test "rendering with layout => false" do + get "/render_action_with_both_layouts/basic/hello_world_with_layout_false" + + assert_body "Hello World!" + assert_status 200 + end + + test "rendering with layout => :nil" do + get "/render_action_with_both_layouts/basic/hello_world_with_layout_nil" + + assert_body "Hello World!" + assert_status 200 + end end - end \ No newline at end of file diff --git a/actionpack/test/new_base/render_implicit_action_test.rb b/actionpack/test/new_base/render_implicit_action_test.rb index 58f5cec181..2846df48da 100644 --- a/actionpack/test/new_base/render_implicit_action_test.rb +++ b/actionpack/test/new_base/render_implicit_action_test.rb @@ -10,19 +10,19 @@ module RenderImplicitAction def hello_world() end end - class TestImplicitRender < SimpleRouteCase - describe "render a simple action with new explicit call to render" - - get "/render_implicit_action/simple/hello_world" - assert_body "Hello world!" - assert_status 200 - end - - class TestImplicitWithSpecialCharactersRender < SimpleRouteCase - describe "render an action with a missing method and has special characters" - - get "/render_implicit_action/simple/hyphen-ated" - assert_body "Hello hyphen-ated!" - assert_status 200 + class RenderImplicitActionTest < SimpleRouteCase + test "render a simple action with new explicit call to render" do + get "/render_implicit_action/simple/hello_world" + + assert_body "Hello world!" + assert_status 200 + end + + test "render an action with a missing method and has special characters" do + get "/render_implicit_action/simple/hyphen-ated" + + assert_body "Hello hyphen-ated!" + assert_status 200 + end end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index dc858b4f5c..76bd5175a3 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -2,69 +2,65 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") module ControllerLayouts class ImplicitController < ::ApplicationController - self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "OMG <%= yield %> KTHXBAI", "layouts/override.html.erb" => "Override! <%= yield %>", "basic.html.erb" => "Hello world!", "controller_layouts/implicit/layout_false.html.erb" => "hai(layout_false.html.erb)" )] - + def index render :template => "basic" end - + def override render :template => "basic", :layout => "override" end - + def layout_false render :layout => false end - + def builder_override - end end - - class TestImplicitLayout < SimpleRouteCase - describe "rendering a normal template, but using the implicit layout" - - get "/controller_layouts/implicit/index" - assert_body "OMG Hello world! KTHXBAI" - assert_status 200 - end - + class ImplicitNameController < ::ApplicationController - self.view_paths = [ActionView::Template::FixturePath.new( "layouts/controller_layouts/implicit_name.html.erb" => "OMGIMPLICIT <%= yield %> KTHXBAI", "basic.html.erb" => "Hello world!" )] - + def index render :template => "basic" end end - - class TestImplicitNamedLayout < SimpleRouteCase - describe "rendering a normal template, but using an implicit NAMED layout" - - get "/controller_layouts/implicit_name/index" - assert_body "OMGIMPLICIT Hello world! KTHXBAI" - assert_status 200 - end - - class TestOverridingImplicitLayout < SimpleRouteCase - describe "overriding an implicit layout with render :layout option" - - get "/controller_layouts/implicit/override" - assert_body "Override! Hello world!" + + class RenderLayoutTest < SimpleRouteCase + test "rendering a normal template, but using the implicit layout" do + get "/controller_layouts/implicit/index" + + assert_body "OMG Hello world! KTHXBAI" + assert_status 200 + end + + test "rendering a normal template, but using an implicit NAMED layout" do + get "/controller_layouts/implicit_name/index" + + assert_body "OMGIMPLICIT Hello world! KTHXBAI" + assert_status 200 + end + + test "overriding an implicit layout with render :layout option" do + get "/controller_layouts/implicit/override" + assert_body "Override! Hello world!" + end + end - - class TestLayoutOptions < SimpleRouteCase + + class LayoutOptionsTest < SimpleRouteCase testing ControllerLayouts::ImplicitController - + test "rendering with :layout => false leaves out the implicit layout" do get :layout_false assert_response "hai(layout_false.html.erb)" diff --git a/actionpack/test/new_base/render_template_test.rb b/actionpack/test/new_base/render_template_test.rb index 6c50ae4203..face5b7571 100644 --- a/actionpack/test/new_base/render_template_test.rb +++ b/actionpack/test/new_base/render_template_test.rb @@ -79,7 +79,6 @@ module RenderTemplate end class WithLayoutController < ::ApplicationController - self.view_paths = [ActionView::Template::FixturePath.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica", @@ -108,46 +107,45 @@ module RenderTemplate end end - class TestTemplateRenderWithLayout < SimpleRouteCase - describe "rendering a normal template with full path with layout" - - get "/render_template/with_layout" - assert_body "Hello from basic.html.erb, I'm here!" - assert_status 200 - end - - class TestTemplateRenderWithLayoutTrue < SimpleRouteCase - describe "rendering a normal template with full path with layout => :true" - - get "/render_template/with_layout/with_layout" - assert_body "Hello from basic.html.erb, I'm here!" - assert_status 200 - end - - class TestTemplateRenderWithLayoutFalse < SimpleRouteCase - describe "rendering a normal template with full path with layout => :false" - - get "/render_template/with_layout/with_layout_false" - assert_body "Hello from basic.html.erb" - assert_status 200 - end - - class TestTemplateRenderWithLayoutNil < SimpleRouteCase - describe "rendering a normal template with full path with layout => :nil" - - get "/render_template/with_layout/with_layout_nil" - assert_body "Hello from basic.html.erb" - assert_status 200 - end - - class TestTemplateRenderWithCustomLayout < SimpleRouteCase - describe "rendering a normal template with full path with layout => 'greetings'" - - get "/render_template/with_layout/with_custom_layout" - assert_body "Hello from basic.html.erb, I wish thee well." - assert_status 200 + class TestWithLayout < SimpleRouteCase + describe "Rendering with :template using implicit or explicit layout" + + test "rendering with implicit layout" do + get "/render_template/with_layout" + + assert_body "Hello from basic.html.erb, I'm here!" + assert_status 200 + end + + test "rendering with layout => :true" do + get "/render_template/with_layout/with_layout" + + assert_body "Hello from basic.html.erb, I'm here!" + assert_status 200 + end + + test "rendering with layout => :false" do + get "/render_template/with_layout/with_layout_false" + + assert_body "Hello from basic.html.erb" + assert_status 200 + end + + test "rendering with layout => :nil" do + get "/render_template/with_layout/with_layout_nil" + + assert_body "Hello from basic.html.erb" + assert_status 200 + end + + test "rendering layout => 'greetings'" do + get "/render_template/with_layout/with_custom_layout" + + assert_body "Hello from basic.html.erb, I wish thee well." + assert_status 200 + end end - + module Compatibility class WithoutLayoutController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new( @@ -161,11 +159,12 @@ module RenderTemplate end class TestTemplateRenderWithForwardSlash < SimpleRouteCase - describe "rendering a normal template with full path starting with a leading slash" + test "rendering a normal template with full path starting with a leading slash" do + get "/render_template/compatibility/without_layout/with_forward_slash" - get "/render_template/compatibility/without_layout/with_forward_slash" - assert_body "Hello from basic.html.erb" - assert_status 200 + assert_body "Hello from basic.html.erb" + assert_status 200 + end end end end \ No newline at end of file diff --git a/actionpack/test/new_base/render_test.rb b/actionpack/test/new_base/render_test.rb index ef5e7d89c5..ed3d50fa0b 100644 --- a/actionpack/test/new_base/render_test.rb +++ b/actionpack/test/new_base/render_test.rb @@ -8,60 +8,57 @@ module Render "render/blank_render/access_action_name.html.erb" => "Action Name: <%= action_name %>", "render/blank_render/access_controller_name.html.erb" => "Controller Name: <%= controller_name %>" )] - + def index render end - + def access_request render :action => "access_request" end - + def render_action_name render :action => "access_action_name" end - - private - + + private + def secretz render :text => "FAIL WHALE!" end end - - class TestBlankRender < SimpleRouteCase - describe "Render with blank" - get "/render/blank_render" - assert_body "Hello world!" - assert_status 200 - end - class DoubleRenderController < ActionController::Base def index render :text => "hello" render :text => "world" end end - - class TestBasic < SimpleRouteCase - describe "Rendering more than once" - - test "raises an exception" do + + class RenderTest < SimpleRouteCase + test "render with blank" do + get "/render/blank_render" + + assert_body "Hello world!" + assert_status 200 + end + + test "rendering more than once raises an exception" do assert_raises(AbstractController::DoubleRenderError) do get "/render/double_render", {}, "action_dispatch.show_exceptions" => false end end end - + class TestOnlyRenderPublicActions < SimpleRouteCase describe "Only public methods on actual controllers are callable actions" - + test "raises an exception when a method of Object is called" do assert_raises(AbstractController::ActionNotFound) do get "/render/blank_render/clone", {}, "action_dispatch.show_exceptions" => false end end - + test "raises an exception when a private method is called" do assert_raises(AbstractController::ActionNotFound) do get "/render/blank_render/secretz", {}, "action_dispatch.show_exceptions" => false @@ -74,12 +71,12 @@ module Render get "/render/blank_render/access_request" assert_body "The request: GET" end - + test "The action_name is accessible in the view" do get "/render/blank_render/render_action_name" assert_body "Action Name: render_action_name" end - + test "The controller_name is accessible in the view" do get "/render/blank_render/access_controller_name" assert_body "Controller Name: blank_render" diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index 39f2f7abbf..69594e4b64 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -11,15 +11,7 @@ module RenderText render :text => "hello david" end end - - class TestSimpleTextRenderWithNoLayout < SimpleRouteCase - describe "Rendering text from a action with default options renders the text with the layout" - - get "/render_text/simple" - assert_body "hello david" - assert_status 200 - end - + class WithLayoutController < ::ApplicationController self.view_paths = [ActionView::Template::FixturePath.new( "layouts/application.html.erb" => "<%= yield %>, I'm here!", @@ -73,76 +65,77 @@ module RenderText end end - class TestSimpleTextRenderWithLayout < SimpleRouteCase - describe "Rendering text from a action with default options renders the text without the layout" - - get "/render_text/with_layout" - assert_body "hello david" - assert_status 200 - end - - class TestTextRenderWithStatus < SimpleRouteCase - describe "Rendering text, while also providing a custom status code" - - get "/render_text/with_layout/custom_code" - assert_body "hello world" - assert_status 404 - end - - class TestTextRenderWithNil < SimpleRouteCase - describe "Rendering text with nil returns a single space character" - - get "/render_text/with_layout/with_nil" - assert_body " " - assert_status 200 - end - - class TestTextRenderWithNilAndStatus < SimpleRouteCase - describe "Rendering text with nil and custom status code returns a single space character with the status" - - get "/render_text/with_layout/with_nil_and_status" - assert_body " " - assert_status 403 - end - - class TestTextRenderWithFalse < SimpleRouteCase - describe "Rendering text with false returns the string 'false'" - - get "/render_text/with_layout/with_false" - assert_body "false" - assert_status 200 - end - - class TestTextRenderWithLayoutTrue < SimpleRouteCase - describe "Rendering text with :layout => true" - - get "/render_text/with_layout/with_layout_true" - assert_body "hello world, I'm here!" - assert_status 200 - end - - class TestTextRenderWithCustomLayout < SimpleRouteCase - describe "Rendering text with :layout => 'greetings'" - - get "/render_text/with_layout/with_custom_layout" - assert_body "hello world, I wish thee well." - assert_status 200 - end - - class TestTextRenderWithLayoutFalse < SimpleRouteCase - describe "Rendering text with :layout => false" - - get "/render_text/with_layout/with_layout_false" - assert_body "hello world" - assert_status 200 - end - - class TestTextRenderWithLayoutNil < SimpleRouteCase - describe "Rendering text with :layout => nil" - - get "/render_text/with_layout/with_layout_nil" - assert_body "hello world" - assert_status 200 + class RenderTextTest < SimpleRouteCase + describe "Rendering text using render :text" + + test "rendering text from a action with default options renders the text with the layout" do + get "/render_text/simple" + assert_body "hello david" + assert_status 200 + end + + test "rendering text from a action with default options renders the text without the layout" do + get "/render_text/with_layout" + + assert_body "hello david" + assert_status 200 + end + + test "rendering text, while also providing a custom status code" do + get "/render_text/with_layout/custom_code" + + assert_body "hello world" + assert_status 404 + end + + test "rendering text with nil returns a single space character" do + get "/render_text/with_layout/with_nil" + + assert_body " " + assert_status 200 + end + + test "Rendering text with nil and custom status code returns a single space character with the status" do + get "/render_text/with_layout/with_nil_and_status" + + assert_body " " + assert_status 403 + end + + test "rendering text with false returns the string 'false'" do + get "/render_text/with_layout/with_false" + + assert_body "false" + assert_status 200 + end + + test "rendering text with :layout => true" do + get "/render_text/with_layout/with_layout_true" + + assert_body "hello world, I'm here!" + assert_status 200 + end + + test "rendering text with :layout => 'greetings'" do + get "/render_text/with_layout/with_custom_layout" + + assert_body "hello world, I wish thee well." + assert_status 200 + end + + test "rendering text with :layout => false" do + get "/render_text/with_layout/with_layout_false" + + assert_body "hello world" + assert_status 200 + end + + test "rendering text with :layout => nil" do + get "/render_text/with_layout/with_layout_nil" + + assert_body "hello world" + assert_status 200 + end end end diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 9401e692f1..89c1290063 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -36,13 +36,13 @@ class Rack::TestCase < ActionController::IntegrationTest setup do ActionController::Base.session_options[:key] = "abc" ActionController::Base.session_options[:secret] = ("*" * 30) - + controllers = ActionController::Base.subclasses.map do |k| k.underscore.sub(/_controller$/, '') end - + ActionController::Routing.use_controllers!(controllers) - + # Move into a bootloader ActionController::Base.subclasses.each do |klass| klass = klass.constantize @@ -50,13 +50,13 @@ class Rack::TestCase < ActionController::IntegrationTest klass.class_eval do _write_layout_method end - end + end end - + def app @app ||= ActionController::Dispatcher.new end - + def self.testing(klass = nil) if klass @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') @@ -64,13 +64,7 @@ class Rack::TestCase < ActionController::IntegrationTest @testing end end - - def self.get(url) - setup do |test| - test.get url - end - end - + def get(thing, *args) if thing.is_a?(Symbol) super("#{self.class.testing}/#{thing}") @@ -78,27 +72,15 @@ class Rack::TestCase < ActionController::IntegrationTest super end end - + def assert_body(body) assert_equal body, Array.wrap(response.body).join end - - def self.assert_body(body) - test "body is set to '#{body}'" do - assert_body body - end - end - + def assert_status(code) assert_equal code, response.status end - - def self.assert_status(code) - test "status code is set to #{code}" do - assert_status code - end - end - + def assert_response(body, status = 200, headers = {}) assert_body body assert_status status @@ -106,27 +88,14 @@ class Rack::TestCase < ActionController::IntegrationTest assert_header header, value end end - + def assert_content_type(type) assert_equal type, response.headers["Content-Type"] end - - def self.assert_content_type(type) - test "content type is set to #{type}" do - assert_content_type(type) - end - end - + def assert_header(name, value) assert_equal value, response.headers[name] end - - def self.assert_header(name, value) - test "'#{name}' header is set to #{value.inspect}" do - assert_header(name, value) - end - end - end class ::ApplicationController < ActionController::Base -- cgit v1.2.3 From 01f032f256f96f65e154061b582fbb4b32e4a692 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 20 May 2009 15:33:08 -0700 Subject: Added responds_to to new base. --- .../lib/action_controller/abstract/layouts.rb | 7 +- .../lib/action_controller/base/mime_responds.rb | 215 ++++++++++----------- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + .../action_controller/new_base/compatibility.rb | 11 +- .../lib/action_controller/new_base/renderer.rb | 2 +- .../lib/action_controller/new_base/testing.rb | 2 +- .../lib/action_controller/testing/process.rb | 1 + actionpack/lib/action_view/template/text.rb | 7 +- actionpack/test/controller/caching_test.rb | 2 + actionpack/test/controller/mime_responds_test.rb | 24 ++- 11 files changed, 148 insertions(+), 125 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 35d5e85ed9..96cb05972f 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -66,7 +66,12 @@ module AbstractController 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, {:formats => formats}, _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) diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb index 1003e61a0b..e560376e0d 100644 --- a/actionpack/lib/action_controller/base/mime_responds.rb +++ b/actionpack/lib/action_controller/base/mime_responds.rb @@ -1,111 +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: - # - # - # ... - # ... - # - # ... - # ... - # ... - # - # - # - # 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): - # - # - # ... - # - # ... - # - # - # - # 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 + # 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: + # + # + # ... + # ... + # + # ... + # ... + # ... + # + # + # + # 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): + # + # + # ... + # + # ... + # + # + # + # 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: @@ -127,8 +119,15 @@ module ActionController #:nodoc: @order << mime_type @responses[mime_type] ||= Proc.new do - @controller.template.formats = [mime_type.to_sym] - @response.content_type = mime_type.to_s + # TODO: Remove this when new base is merged in + if defined?(Http) + @controller.formats = [mime_type.to_sym] + @controller.template.formats = [mime_type.to_sym] + else + @controller.template.formats = [mime_type.to_sym] + @response.content_type = mime_type.to_s + end + block_given? ? block.call : @controller.send(:render, :action => @controller.action_name) end end diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 078f66ced1..3fc5d82d01 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -15,6 +15,7 @@ module ActionController # 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' diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 7f830307b6..3d8d46c9c2 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -18,6 +18,7 @@ module ActionController include SessionManagement include ActionDispatch::StatusCodes include ActionController::Caching + include ActionController::MimeResponds # Rails 2.x compatibility include ActionController::Rails2Compatibility diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 0098c0747e..c861af2fa2 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -59,6 +59,11 @@ module ActionController 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 @@ -95,10 +100,8 @@ module ActionController 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 - end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 9253df53a1..276816a6f5 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -18,7 +18,7 @@ module ActionController _process_options(options) if options.key?(:text) - options[:_template] = ActionView::TextTemplate.new(_text(options)) + options[:_template] = ActionView::TextTemplate.new(_text(options), formats.first) template = nil elsif options.key?(:inline) handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb") diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index b39d8d539d..0659d81710 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -7,7 +7,7 @@ module ActionController @_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 diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 8831ff57e2..9647f8ce45 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -41,6 +41,7 @@ module ActionController #:nodoc: 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'] = {} diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index a777021a12..927a0d7a72 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,11 +1,16 @@ module ActionView #:nodoc: class TextTemplate < String #:nodoc: + def initialize(string, content_type = Mime[:html]) + super(string) + @content_type = Mime[content_type] + 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 diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 560c09509b..c286976315 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -48,6 +48,8 @@ class PageCachingTest < ActionController::TestCase 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' diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 7cd5145a2f..3b8babb84c 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -437,7 +437,7 @@ class MimeControllerTest < ActionController::TestCase @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 +490,15 @@ class PostController < AbstractPostController 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 +510,11 @@ class SuperPostController < PostController end end +if ENV["new_base"] + PostController._write_layout_method + SuperPostController._write_layout_method +end + class MimeControllerLayoutsTest < ActionController::TestCase tests PostController -- cgit v1.2.3 From 77d955c51740216131fc0b130d5cb37fcd18d071 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 20 May 2009 15:54:29 -0700 Subject: Added passing old tests on new base to the main test runner --- actionpack/Rakefile | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 6ce8179646..f1f407c008 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -22,7 +22,7 @@ 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] Rake::TestTask.new(:test_action_pack) do |t| t.libs << "test" @@ -55,6 +55,17 @@ Rake::TestTask.new(:test_new_base) do |t| t.verbose = true end +desc 'Old Controller Tests on New Base' +Rake::TestTask.new(:test_new_base_on_old_tests) do |t| + ENV['new_base'] = "true" + t.libs << "test" + # content_type mime_responds layout + t.test_files = %w( + addresses_render base benchmark caching capture dispatcher record_identifier + redirect render rescue url_rewriter webservice + ).map { |name| "test/controller/#{name}_test.rb" } +end + # Genereate the RDoc documentation -- cgit v1.2.3 From b46c9071c382b48c5ff349fbe61854683663a866 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 20 May 2009 16:00:16 -0700 Subject: Ruby 1.9 stdlib gems don't recognize .pre yet --- actionpack/lib/action_dispatch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index f9003c51ea..ee162765cb 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -27,7 +27,7 @@ require 'active_support' 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 -- cgit v1.2.3 From c86ec82cf63938f691c9ae4f5a4d72bea9e8a9c7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 20 May 2009 16:00:50 -0700 Subject: Wrap string body in an array --- actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 108355da63..4d598669c7 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -102,7 +102,7 @@ module ActionDispatch end def render(status, body) - [status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, body] + [status, {'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s}, [body]] end def public_path -- cgit v1.2.3 From 205cfe2163d9eb6ee801a23f550e960136b5680e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 20 May 2009 16:23:55 -0700 Subject: Massage setup for old tests on new base --- actionpack/Rakefile | 3 +- actionpack/test/abstract_unit.rb | 4 - actionpack/test/abstract_unit2.rb | 139 ----------------------------- actionpack/test/new_base/abstract_unit.rb | 141 ++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 145 deletions(-) delete mode 100644 actionpack/test/abstract_unit2.rb create mode 100644 actionpack/test/new_base/abstract_unit.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index f1f407c008..af14e592c0 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -57,8 +57,7 @@ end desc 'Old Controller Tests on New Base' Rake::TestTask.new(:test_new_base_on_old_tests) do |t| - ENV['new_base'] = "true" - t.libs << "test" + t.libs << "test/new_base" << "test" # content_type mime_responds layout t.test_files = %w( addresses_render base benchmark caching capture dispatcher record_identifier diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 7982f06545..f6f62bcf83 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -1,6 +1,3 @@ -if ENV["new_base"] - require "abstract_unit2" -else $:.unshift(File.dirname(__FILE__) + '/../lib') $:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') @@ -41,4 +38,3 @@ ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') ActionController::Base.view_paths = FIXTURE_LOAD_PATH -end \ No newline at end of file diff --git a/actionpack/test/abstract_unit2.rb b/actionpack/test/abstract_unit2.rb deleted file mode 100644 index 519e6bea36..0000000000 --- a/actionpack/test/abstract_unit2.rb +++ /dev/null @@ -1,139 +0,0 @@ -$:.unshift(File.dirname(__FILE__) + '/../lib') -$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') -$:.unshift(File.dirname(__FILE__) + '/lib') - - -require 'test/unit' -require 'active_support' -require 'active_support/test_case' -require 'action_controller/abstract' -require 'action_controller/new_base' -require 'fixture_template' -require 'action_controller/testing/process2' -require 'action_view/test_case' -require 'action_controller/testing/integration' -require 'active_support/dependencies' - -ActiveSupport::Dependencies.hook! - -FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') - -module ActionController - Base.session = { - :key => '_testing_session', - :secret => '8273f16463985e2b3747dc25e30f2528' -} - - class ActionControllerError < StandardError #:nodoc: - end - - class SessionRestoreError < ActionControllerError #:nodoc: - end - - class RenderError < ActionControllerError #:nodoc: - end - - class RoutingError < ActionControllerError #:nodoc: - attr_reader :failures - def initialize(message, failures=[]) - super(message) - @failures = failures - end - end - - class MethodNotAllowed < ActionControllerError #:nodoc: - attr_reader :allowed_methods - - def initialize(*allowed_methods) - super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.") - @allowed_methods = allowed_methods - end - - def allowed_methods_header - allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', ' - end - - def handle_response!(response) - response.headers['Allow'] ||= allowed_methods_header - end - end - - class NotImplemented < MethodNotAllowed #:nodoc: - end - - class UnknownController < ActionControllerError #:nodoc: - end - - class MissingFile < ActionControllerError #:nodoc: - end - - class RenderError < ActionControllerError #:nodoc: - end - - class SessionOverflowError < ActionControllerError #:nodoc: - DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.' - - def initialize(message = nil) - super(message || DEFAULT_MESSAGE) - end - end - - class UnknownHttpMethod < ActionControllerError #:nodoc: - end - - class Base - include ActionController::Testing - end - - Base.view_paths = FIXTURE_LOAD_PATH - - class TestCase - include TestProcess - setup do - ActionController::Routing::Routes.draw do |map| - map.connect ':controller/:action/:id' - end - end - - def assert_template(options = {}, message = nil) - validate_request! - - hax = @controller._action_view.instance_variable_get(:@_rendered) - - case options - when NilClass, String - rendered = (hax[:template] || []).map { |t| t.identifier } - msg = build_message(message, - "expecting but rendering with ", - options, rendered.join(', ')) - assert_block(msg) do - if options.nil? - hax[:template].blank? - else - rendered.any? { |t| t.match(options) } - end - end - when Hash - if expected_partial = options[:partial] - partials = hax[:partials] - if expected_count = options[:count] - found = partials.detect { |p, _| p.identifier.match(expected_partial) } - actual_count = found.nil? ? 0 : found.second - msg = build_message(message, - "expecting ? to be rendered ? time(s) but rendered ? time(s)", - expected_partial, expected_count, actual_count) - assert(actual_count == expected_count.to_i, msg) - else - msg = build_message(message, - "expecting partial but action rendered ", - options[:partial], partials.keys) - assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) - end - else - assert hax[:partials].empty?, - "Expected no partials to be rendered" - end - end - end - end -end diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb new file mode 100644 index 0000000000..e72165ee67 --- /dev/null +++ b/actionpack/test/new_base/abstract_unit.rb @@ -0,0 +1,141 @@ +$:.unshift(File.dirname(__FILE__) + '/../../lib') +$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib') +$:.unshift(File.dirname(__FILE__) + '/../lib') + +ENV['new_base'] = "true" +$stderr.puts "Running old tests on new_base" + +require 'test/unit' +require 'active_support' +require 'active_support/test_case' +require 'action_controller/abstract' +require 'action_controller/new_base' +require 'fixture_template' +require 'action_controller/testing/process2' +require 'action_view/test_case' +require 'action_controller/testing/integration' +require 'active_support/dependencies' + +ActiveSupport::Dependencies.hook! + +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), '../fixtures') + +module ActionController + Base.session = { + :key => '_testing_session', + :secret => '8273f16463985e2b3747dc25e30f2528' +} + + class ActionControllerError < StandardError #:nodoc: + end + + class SessionRestoreError < ActionControllerError #:nodoc: + end + + class RenderError < ActionControllerError #:nodoc: + end + + class RoutingError < ActionControllerError #:nodoc: + attr_reader :failures + def initialize(message, failures=[]) + super(message) + @failures = failures + end + end + + class MethodNotAllowed < ActionControllerError #:nodoc: + attr_reader :allowed_methods + + def initialize(*allowed_methods) + super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.") + @allowed_methods = allowed_methods + end + + def allowed_methods_header + allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', ' + end + + def handle_response!(response) + response.headers['Allow'] ||= allowed_methods_header + end + end + + class NotImplemented < MethodNotAllowed #:nodoc: + end + + class UnknownController < ActionControllerError #:nodoc: + end + + class MissingFile < ActionControllerError #:nodoc: + end + + class RenderError < ActionControllerError #:nodoc: + end + + class SessionOverflowError < ActionControllerError #:nodoc: + DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.' + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + + class UnknownHttpMethod < ActionControllerError #:nodoc: + end + + class Base + include ActionController::Testing + end + + Base.view_paths = FIXTURE_LOAD_PATH + + class TestCase + include TestProcess + setup do + ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action/:id' + end + end + + def assert_template(options = {}, message = nil) + validate_request! + + hax = @controller._action_view.instance_variable_get(:@_rendered) + + case options + when NilClass, String + rendered = (hax[:template] || []).map { |t| t.identifier } + msg = build_message(message, + "expecting but rendering with ", + options, rendered.join(', ')) + assert_block(msg) do + if options.nil? + hax[:template].blank? + else + rendered.any? { |t| t.match(options) } + end + end + when Hash + if expected_partial = options[:partial] + partials = hax[:partials] + if expected_count = options[:count] + found = partials.detect { |p, _| p.identifier.match(expected_partial) } + actual_count = found.nil? ? 0 : found.second + msg = build_message(message, + "expecting ? to be rendered ? time(s) but rendered ? time(s)", + expected_partial, expected_count, actual_count) + assert(actual_count == expected_count.to_i, msg) + else + msg = build_message(message, + "expecting partial but action rendered ", + options[:partial], partials.keys) + assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg) + end + else + assert hax[:partials].empty?, + "Expected no partials to be rendered" + end + end + end + end +end -- cgit v1.2.3 From 8e7a87d299483fce6af3be89e50deae43055a96f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 01:38:48 +0200 Subject: Make ActionController::Flash work with new_base --- actionpack/Rakefile | 2 +- .../lib/action_controller/base/chained/flash.rb | 74 +++++++++++++++------- actionpack/lib/action_controller/new_base.rb | 5 +- actionpack/lib/action_controller/new_base/base.rb | 3 + actionpack/lib/action_controller/new_base/http.rb | 2 +- .../lib/action_controller/new_base/session.rb | 11 ++++ actionpack/test/controller/flash_test.rb | 49 +++++++------- 7 files changed, 97 insertions(+), 49 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/session.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index af14e592c0..2a456ebb05 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -61,7 +61,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # content_type mime_responds layout t.test_files = %w( addresses_render base benchmark caching capture dispatcher record_identifier - redirect render rescue url_rewriter webservice + redirect render rescue url_rewriter webservice flash ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/base/chained/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb index 56ee9c67e2..6bd482d85a 100644 --- a/actionpack/lib/action_controller/base/chained/flash.rb +++ b/actionpack/lib/action_controller/base/chained/flash.rb @@ -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 @@ module ActionController #:nodoc: 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 flash["notice"] to - # read a notice you put there or flash["notice"] = "hello" - # 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 flash["notice"] to + # read a notice you put there or flash["notice"] = "hello" + # to put a new one. + def flash #:doc: + unless defined?(@_flash) + @_flash = session["flash"] ||= FlashHash.new + @_flash.sweep + end + + @_flash end end end diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 3fc5d82d01..d2f6514ff9 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -10,7 +10,8 @@ module ActionController 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" + # Ported modules # require 'action_controller/routing' autoload :Caching, 'action_controller/caching' @@ -23,6 +24,8 @@ 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 :Flash, 'action_controller/base/chained/flash' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 3d8d46c9c2..eff7297973 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -14,6 +14,9 @@ module ActionController include ActionController::Layouts include ActionController::ConditionalGet + include ActionController::Session + include ActionController::Flash + # Legacy modules include SessionManagement include ActionDispatch::StatusCodes diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 17466a2d52..2525e221a6 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -37,7 +37,7 @@ module ActionController end delegate :headers, :to => "@_response" - + def params @_params ||= @_request.parameters end diff --git a/actionpack/lib/action_controller/new_base/session.rb b/actionpack/lib/action_controller/new_base/session.rb new file mode 100644 index 0000000000..a8715555fb --- /dev/null +++ b/actionpack/lib/action_controller/new_base/session.rb @@ -0,0 +1,11 @@ +module ActionController + module Session + def session + @_request.session + end + + def reset_session + @_request.reset_session + end + end +end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index ef60cae0ff..84e27d7779 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -60,6 +60,7 @@ class FlashTest < ActionController::TestCase def std_action @flash_copy = {}.update(flash) + render :nothing => true end def filter_halting_action @@ -79,64 +80,64 @@ class FlashTest < ActionController::TestCase 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 -- cgit v1.2.3 From c4a6109286909c394e8c5bfc471a1eb9de245d2b Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 20 May 2009 16:52:56 -0700 Subject: Got controller/mime_responds_test.rb running on the new base --- actionpack/Rakefile | 7 ++++--- actionpack/test/abstract_unit.rb | 2 ++ actionpack/test/controller/mime_responds_test.rb | 26 ++++++++++++++---------- actionpack/test/new_base/abstract_unit.rb | 3 +++ 4 files changed, 24 insertions(+), 14 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 2a456ebb05..86f7adaee3 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -58,10 +58,11 @@ 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" - # content_type mime_responds layout + # content_type layout + # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( - addresses_render base benchmark caching capture dispatcher record_identifier - redirect render rescue url_rewriter webservice flash + addresses_render base benchmark caching capture dispatcher flash mime_responds + record_identifier redirect render rescue url_rewriter webservice ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index f6f62bcf83..5ae54d097a 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -23,6 +23,8 @@ require 'action_controller' 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 diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 3b8babb84c..56b49251c6 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -375,9 +375,11 @@ class MimeControllerTest < ActionController::TestCase 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 @@ -510,7 +512,7 @@ class SuperPostController < PostController end end -if ENV["new_base"] +if defined?(ActionController::Http) PostController._write_layout_method SuperPostController._write_layout_method end @@ -532,14 +534,16 @@ class MimeControllerLayoutsTest < ActionController::TestCase 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 '
Super iPhone
', @response.body + @request.accept = "text/iphone" + get :index + assert_equal '
Super iPhone
', @response.body + end end end diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index e72165ee67..c045247702 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -16,6 +16,9 @@ require 'action_view/test_case' require 'action_controller/testing/integration' require 'active_support/dependencies' +$tags[:new_base] = true + + ActiveSupport::Dependencies.hook! FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), '../fixtures') -- cgit v1.2.3 From c8eda9ade49700abce104de1ce7e8e1a754fc97e Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 20 May 2009 17:22:29 -0700 Subject: Fixed new_base tests on ruby 1.9 --- actionpack/lib/action_controller/new_base/renderer.rb | 4 ++-- actionpack/lib/action_dispatch/http/mime_types.rb | 2 +- actionpack/test/lib/fixture_template.rb | 2 +- actionpack/test/new_base/etag_test.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 276816a6f5..6176212970 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -4,8 +4,8 @@ module ActionController depends_on AbstractController::Renderer - def initialize(*) - self.formats = [:html] + def process_action(*) + self.formats = request.formats.map {|x| x.to_sym} super end diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 2d7fba1173..7c28cac419 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -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 diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/test/lib/fixture_template.rb index e43e329a9e..59fb6819ed 100644 --- a/actionpack/test/lib/fixture_template.rb +++ b/actionpack/test/lib/fixture_template.rb @@ -46,7 +46,7 @@ class Template end end - %r'#{Regexp.escape(path)}#{extensions}#{handler_regexp}' + %r'^#{Regexp.escape(path)}#{extensions}#{handler_regexp}$' end # TODO: fix me diff --git a/actionpack/test/new_base/etag_test.rb b/actionpack/test/new_base/etag_test.rb index c77636bb64..a40d3c936a 100644 --- a/actionpack/test/new_base/etag_test.rb +++ b/actionpack/test/new_base/etag_test.rb @@ -12,7 +12,7 @@ module Etags end def with_layout - render :action => "base", :layout => "etag" + render :action => "base", :layout => "etags" end end -- cgit v1.2.3 From 7f7fdc407a90c9ce75ce0a77bc0f631115514d2f Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 20 May 2009 17:42:04 -0700 Subject: Make controller/content_type_test.rb pass on new base --- actionpack/Rakefile | 7 ++++--- actionpack/lib/action_controller/new_base/renderer.rb | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 86f7adaee3..684b828254 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -58,11 +58,12 @@ 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" - # content_type layout + # layout # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( - addresses_render base benchmark caching capture dispatcher flash mime_responds - record_identifier redirect render rescue url_rewriter webservice + addresses_render base benchmark caching capture content_type dispatcher + flash mime_responds record_identifier redirect render rescue url_rewriter + webservice ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 6176212970..81685ca9d6 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -38,7 +38,11 @@ module ActionController ret = super(options) options[:_template] ||= _action_view._partial - response.content_type ||= options[:_template].mime_type + response.content_type ||= begin + mime = options[:_template].mime_type + mime &&= mime.to_sym + formats.include?(mime) ? mime : formats.first + end ret end -- cgit v1.2.3 From e21d1614bb9006e69bf4bb2467b823aa12e64485 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 02:55:25 +0200 Subject: Made ActionController::Verification work with new_base --- actionpack/Rakefile | 2 +- actionpack/lib/action_controller/base/verification.rb | 12 +++++++++--- actionpack/lib/action_controller/new_base.rb | 5 +++-- actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/lib/action_controller/new_base/compatibility.rb | 4 ++++ actionpack/lib/action_controller/new_base/testing.rb | 2 +- actionpack/lib/action_controller/testing/process2.rb | 2 +- actionpack/test/controller/verification_test.rb | 14 ++++++-------- 8 files changed, 26 insertions(+), 16 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 684b828254..3a6a54768e 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -63,7 +63,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| t.test_files = %w( addresses_render base benchmark caching capture content_type dispatcher flash mime_responds record_identifier redirect render rescue url_rewriter - webservice + webservice verification ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/base/verification.rb b/actionpack/lib/action_controller/base/verification.rb index c62b81b666..a513e9f40c 100644 --- a/actionpack/lib/action_controller/base/verification.rb +++ b/actionpack/lib/action_controller/base/verification.rb @@ -1,7 +1,13 @@ 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 + depends_on Session + depends_on Flash + depends_on Renderer end # This module provides a class-level method for specifying that certain @@ -102,7 +108,7 @@ module ActionController #: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 diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index d2f6514ff9..8bc15d2450 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -25,8 +25,9 @@ module ActionController autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter' autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter' - autoload :Flash, 'action_controller/base/chained/flash' - + autoload :Verification, 'action_controller/base/verification' + autoload :Flash, 'action_controller/base/chained/flash' + require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index eff7297973..a419a80b6a 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -16,6 +16,7 @@ module ActionController include ActionController::Session include ActionController::Flash + include ActionController::Verification # Legacy modules include SessionManagement diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index c861af2fa2..9b85b39052 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -103,5 +103,9 @@ module ActionController def _layout_prefix(name) super unless name =~ /\blayouts/ end + + def performed? + response_body + end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 0659d81710..bc3bc70404 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -2,7 +2,7 @@ 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 diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index e9a79369b9..2dafcaa5a9 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -53,7 +53,7 @@ module ActionController @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) end def build_request_uri(action, parameters) diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb index 418a81baa8..85134a8264 100644 --- a/actionpack/test/controller/verification_test.rb +++ b/actionpack/test/controller/verification_test.rb @@ -103,17 +103,15 @@ class VerificationTest < ActionController::TestCase 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 -- cgit v1.2.3 From 5a036457620b7fb22027dc4f0c399871db6ed0c3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 03:04:17 +0200 Subject: Allow Module#depends_on to accept multiple modules --- actionpack/lib/action_controller/base/verification.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/verification.rb b/actionpack/lib/action_controller/base/verification.rb index a513e9f40c..3fa5a105b1 100644 --- a/actionpack/lib/action_controller/base/verification.rb +++ b/actionpack/lib/action_controller/base/verification.rb @@ -4,10 +4,7 @@ module ActionController #:nodoc: # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) - depends_on AbstractController::Callbacks - depends_on Session - depends_on Flash - depends_on Renderer + depends_on AbstractController::Callbacks, Session, Flash, Renderer end # This module provides a class-level method for specifying that certain -- cgit v1.2.3 From 59b32f2883b58a1e7bf2c246801a605b673e3fb6 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 11:50:34 +0200 Subject: RequestForgeryProtection now works with the new base --- actionpack/Rakefile | 2 +- .../base/request_forgery_protection.rb | 24 +++++++++++++++++----- actionpack/lib/action_controller/new_base.rb | 5 +++-- actionpack/lib/action_controller/new_base/base.rb | 9 ++++---- .../action_controller/new_base/compatibility.rb | 6 ++++-- actionpack/lib/action_dispatch.rb | 1 + 6 files changed, 33 insertions(+), 14 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 3a6a54768e..84b42b4eb3 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -63,7 +63,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| t.test_files = %w( addresses_render base benchmark caching capture content_type dispatcher flash mime_responds record_identifier redirect render rescue url_rewriter - webservice verification + webservice verification request_forgery_protection ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/base/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb index 3067122ceb..0a0e20e1f1 100644 --- a/actionpack/lib/action_controller/base/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb @@ -3,12 +3,26 @@ module ActionController #: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 :authenticity_token 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 diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 8bc15d2450..93c54174b7 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -25,8 +25,9 @@ module ActionController 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 :Verification, 'action_controller/base/verification' + autoload :Flash, 'action_controller/base/chained/flash' + autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index a419a80b6a..3d8f785280 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -14,10 +14,6 @@ module ActionController include ActionController::Layouts include ActionController::ConditionalGet - include ActionController::Session - include ActionController::Flash - include ActionController::Verification - # Legacy modules include SessionManagement include ActionDispatch::StatusCodes @@ -27,6 +23,11 @@ module ActionController # Rails 2.x compatibility include ActionController::Rails2Compatibility + include ActionController::Session + include ActionController::Flash + include ActionController::Verification + include ActionController::RequestForgeryProtection + # TODO: Extract into its own module # This should be moved together with other normalizing behavior module ImplicitRender diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 9b85b39052..522a9fe23b 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -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 @@ -65,7 +68,6 @@ module ActionController end module ClassMethods - def protect_from_forgery() end def consider_all_requests_local() end def rescue_action(env) raise env["action_dispatch.rescue.exception"] diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index ee162765cb..884828a01a 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -46,6 +46,7 @@ module ActionDispatch 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' -- cgit v1.2.3 From 386ff66e5ed4fbe1e060610d4226a4eb22dca766 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 21:48:26 +0200 Subject: Add Streaming to new base --- actionpack/Rakefile | 2 +- actionpack/lib/action_controller/base/streaming.rb | 1 + actionpack/lib/action_controller/new_base.rb | 2 +- actionpack/lib/action_controller/new_base/base.rb | 1 + .../lib/action_controller/new_base/testing.rb | 9 ++++++-- .../lib/action_controller/testing/process2.rb | 1 + actionpack/test/controller/send_file_test.rb | 24 ++++++++++++---------- 7 files changed, 25 insertions(+), 15 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 84b42b4eb3..5968317c60 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -63,7 +63,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| t.test_files = %w( addresses_render base benchmark caching capture content_type dispatcher flash mime_responds record_identifier redirect render rescue url_rewriter - webservice verification request_forgery_protection + webservice verification request_forgery_protection send_file ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/base/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb index 9f80f48c3d..b69b13eea8 100644 --- a/actionpack/lib/action_controller/base/streaming.rb +++ b/actionpack/lib/action_controller/base/streaming.rb @@ -88,6 +88,7 @@ module ActionController #:nodoc: 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 diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 93c54174b7..58c7382661 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -28,7 +28,7 @@ module ActionController 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' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 3d8f785280..142699326e 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -27,6 +27,7 @@ module ActionController include ActionController::Flash include ActionController::Verification include ActionController::RequestForgeryProtection + include ActionController::Streaming # TODO: Extract into its own module # This should be moved together with other normalizing behavior diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index bc3bc70404..6a92c292bd 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -1,6 +1,6 @@ module ActionController module Testing - + # OMG MEGA HAX def process_with_new_base_test(request, response) @_request = request @@ -20,6 +20,11 @@ module ActionController @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 \ No newline at end of file diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 2dafcaa5a9..6a95e638cd 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -54,6 +54,7 @@ module ActionController @controller.params.merge!(parameters) # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest @controller.process_with_new_base_test(@request, @response) + @response end def build_request_uri(action, parameters) diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 6007ebef7a..3a99774ae0 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -40,17 +40,19 @@ class SendFileTest < ActionController::TestCase 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 - - 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 + 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 + end end def test_file_url_based_filename -- cgit v1.2.3 From e693f45e155a81b6c337b8766870b56716a05105 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 14:22:07 -0700 Subject: Remove some response content type concepts from ActionView --- .../lib/action_controller/base/mime_responds.rb | 7 +++---- actionpack/lib/action_controller/new_base/base.rb | 20 ++++++++++++++++---- .../lib/action_controller/new_base/renderer.rb | 20 +++++++++++--------- actionpack/lib/action_controller/testing/process2.rb | 1 + actionpack/lib/action_dispatch/http/mime_type.rb | 2 +- actionpack/lib/action_dispatch/http/request.rb | 2 +- actionpack/lib/action_view/base.rb | 7 +++++-- actionpack/lib/action_view/template/handler.rb | 5 +++++ .../lib/action_view/template/handlers/builder.rb | 2 ++ actionpack/lib/action_view/template/handlers/erb.rb | 2 ++ actionpack/lib/action_view/template/handlers/rjs.rb | 6 ++++++ actionpack/lib/action_view/template/template.rb | 15 ++++++++------- actionpack/test/controller/content_type_test.rb | 3 ++- 13 files changed, 63 insertions(+), 29 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb index e560376e0d..3c17dda1a1 100644 --- a/actionpack/lib/action_controller/base/mime_responds.rb +++ b/actionpack/lib/action_controller/base/mime_responds.rb @@ -122,12 +122,11 @@ module ActionController #:nodoc: # TODO: Remove this when new base is merged in if defined?(Http) @controller.formats = [mime_type.to_sym] - @controller.template.formats = [mime_type.to_sym] - else - @controller.template.formats = [mime_type.to_sym] - @response.content_type = mime_type.to_s 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 diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 142699326e..b8674d5099 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -70,7 +70,7 @@ module ActionController end end - def render_to_body(action = nil, options = {}) + def _normalize_options(action = nil, options = {}) if action.is_a?(Hash) options, action = action, nil elsif action.is_a?(String) || action.is_a?(Symbol) @@ -87,9 +87,21 @@ module ActionController 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) || " " + options + end + + def render(action = nil, options = {}) + options = _normalize_options(action, options) + super(options) + end + + def render_to_string(action = nil, options = {}) + options = _normalize_options(action, options) + super(options) + end + + def render_to_body(options) + super || [" "] end # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 81685ca9d6..840168397d 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -14,6 +14,16 @@ module ActionController 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) @@ -35,15 +45,7 @@ module ActionController options[:_prefix] = _prefix end - ret = super(options) - - options[:_template] ||= _action_view._partial - response.content_type ||= begin - mime = options[:_template].mime_type - mime &&= mime.to_sym - formats.include?(mime) ? mime : formats.first - end - ret + super end private diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 6a95e638cd..bee82c280e 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -40,6 +40,7 @@ module ActionController @request.recycle! @response.recycle! @controller.response_body = nil + @controller.formats = nil @html_document = nil @request.env['REQUEST_METHOD'] = http_method diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index dfcf3a558f..25156a4c75 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/class/attribute_accessors' 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) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 13ff049a97..4831b89bde 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -175,7 +175,7 @@ module ActionDispatch if ActionController::Base.use_accept_header Array(Mime[parameters[:format]] || accepts) else - [format] + [format, Mime[:all]] end end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 56f0b5ef4f..6b72d406af 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -288,8 +288,11 @@ module ActionView #: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 diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index 672da0ed2b..3481a4a4e7 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/class/inheritable_attributes" + # Legacy TemplateHandler stub module ActionView module TemplateHandlers #:nodoc: @@ -19,6 +21,9 @@ module ActionView 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 diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb index 788dc93326..f412228752 100644 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ b/actionpack/lib/action_view/template/handlers/builder.rb @@ -5,6 +5,8 @@ module ActionView 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);" + diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index fdcb108ffc..95f11d6490 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -13,6 +13,8 @@ module ActionView 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 diff --git a/actionpack/lib/action_view/template/handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb index 802a79b3fc..a36744c2b7 100644 --- a/actionpack/lib/action_view/template/handlers/rjs.rb +++ b/actionpack/lib/action_view/template/handlers/rjs.rb @@ -3,11 +3,17 @@ module ActionView 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 diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index dcc5006103..0eedc596d2 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -7,13 +7,19 @@ require "action_view/template/path" module ActionView class Template extend TemplateHandlers - attr_reader :source, :identifier, :handler + attr_reader :source, :identifier, :handler, :mime_type def initialize(source, identifier, handler, details) @source = source @identifier = identifier @handler = handler @details = details + + format = details[: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) end def render(view, locals, &blk) @@ -35,12 +41,7 @@ module ActionView 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) diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index 64b8b10d5b..d622ac1e85 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -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 -- cgit v1.2.3 From 2daac47d585c5b8f37e4749d6a9a3aea4b989bd0 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 14:34:42 -0700 Subject: Added the ability to register methods to handle specific render option keys and render :json --- actionpack/Rakefile | 5 +-- actionpack/lib/action_controller/new_base.rb | 2 ++ actionpack/lib/action_controller/new_base/base.rb | 2 ++ .../action_controller/new_base/render_options.rb | 39 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/render_options.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 5968317c60..2041f5a844 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -62,8 +62,9 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( addresses_render base benchmark caching capture content_type dispatcher - flash mime_responds record_identifier redirect render rescue url_rewriter - webservice verification request_forgery_protection send_file + flash mime_responds record_identifier redirect + render render_json + send_file request_forgery_protection rescue url_rewriter verification webservice ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 58c7382661..95808decd5 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -7,6 +7,8 @@ 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" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index b8674d5099..6e1f92c45d 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -11,6 +11,8 @@ module ActionController include ActionController::UrlFor include ActionController::Redirector include ActionController::Renderer + include ActionController::RenderOptions + include ActionController::Renderers::Json include ActionController::Layouts include ActionController::ConditionalGet diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb new file mode 100644 index 0000000000..e7ed2bd278 --- /dev/null +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -0,0 +1,39 @@ +module ActionController + module RenderOptions + extend ActiveSupport::DependencyModule + + included do + extlib_inheritable_accessor :_renderers + self._renderers = [] + end + + def render_to_body(options) + _renderers.each do |renderer| + if options.key?(renderer) + _process_options(options) + return send("_render_#{renderer}", options[renderer], options) + end + end + super + end + end + + module Renderers + module Json + extend ActiveSupport::DependencyModule + + depends_on RenderOptions + + included do + _renderers << :json + end + + 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 + end +end \ No newline at end of file -- cgit v1.2.3 From ad1c90de3a766d12a0906c7cf3772f3bc0e1b445 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 14:51:29 -0700 Subject: Added the :xml render option --- actionpack/Rakefile | 2 +- actionpack/lib/action_controller/new_base/base.rb | 2 +- .../action_controller/new_base/render_options.rb | 30 +++++++++++++++++----- .../lib/action_controller/new_base/renderer.rb | 3 ++- 4 files changed, 28 insertions(+), 9 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 2041f5a844..d192a2e3bf 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -63,7 +63,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| t.test_files = %w( addresses_render base benchmark caching capture content_type dispatcher flash mime_responds record_identifier redirect - render render_json + render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 6e1f92c45d..08ffafb27e 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -11,8 +11,8 @@ module ActionController include ActionController::UrlFor include ActionController::Redirector include ActionController::Renderer - include ActionController::RenderOptions include ActionController::Renderers::Json + include ActionController::Renderers::Xml include ActionController::Layouts include ActionController::ConditionalGet diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index e7ed2bd278..a9ac0e0a41 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -18,15 +18,23 @@ module ActionController end end - module Renderers - module Json + module RenderOption + extend ActiveSupport::DependencyModule + + included do extend ActiveSupport::DependencyModule - depends_on RenderOptions - - included do - _renderers << :json + + def self.register_renderer(name) + included { _renderers << 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) @@ -35,5 +43,15 @@ module ActionController self.response_body = json 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 end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 840168397d..2a52eedb59 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -79,9 +79,10 @@ module ActionController end def _process_options(options) - status, content_type = options.values_at(:status, :content_type) + status, content_type, location = options.values_at(:status, :content_type, :location) response.status = status.to_i if status response.content_type = content_type if content_type + response.headers["Location"] = url_for(location) if location end end end -- cgit v1.2.3 From 9d3d7746702b65ddc09364c260ee4ace4b178281 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 15:23:52 -0700 Subject: Update render options to remove performance implications of many render options types --- .../action_controller/new_base/render_options.rb | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index a9ac0e0a41..aa6593b957 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -7,14 +7,32 @@ module ActionController self._renderers = [] end - def render_to_body(options) - _renderers.each do |renderer| - if options.key?(renderer) - _process_options(options) - return send("_render_#{renderer}", options[renderer], options) + 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 - super + end + + def render_to_body(options) + _handle_render_options(options) || super end end @@ -26,7 +44,7 @@ module ActionController depends_on RenderOptions def self.register_renderer(name) - included { _renderers << name } + included { _add_render_option(name) } end end end -- cgit v1.2.3 From d2cac9dd0e28b99bd45fd9eaa1d5a6b3dee8fa8f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 May 2009 22:03:52 +0200 Subject: Add missing dependency in Streaming --- actionpack/lib/action_controller/base/streaming.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb index b69b13eea8..5872ba99a2 100644 --- a/actionpack/lib/action_controller/base/streaming.rb +++ b/actionpack/lib/action_controller/base/streaming.rb @@ -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, -- cgit v1.2.3 From 1a52b246eb245d159a1c331417a4b14923e9bc4e Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 May 2009 00:26:58 +0200 Subject: Add HTTP Authentication to the new base --- actionpack/Rakefile | 1 + actionpack/lib/action_controller/new_base.rb | 2 ++ actionpack/lib/action_controller/new_base/base.rb | 7 +++++++ .../lib/action_controller/new_base/conditional_get.rb | 2 +- actionpack/lib/action_controller/new_base/renderer.rb | 2 +- .../test/controller/http_digest_authentication_test.rb | 13 +++++++++---- actionpack/test/controller/send_file_test.rb | 13 +++++++++---- 7 files changed, 30 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index d192a2e3bf..012f5384e2 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -65,6 +65,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| flash mime_responds record_identifier redirect render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice + http_basic_authentication http_digest_authentication ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 95808decd5..14f73e1edd 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -31,6 +31,8 @@ module ActionController 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' + require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 08ffafb27e..b432060bc1 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -30,6 +30,8 @@ module ActionController include ActionController::Verification include ActionController::RequestForgeryProtection include ActionController::Streaming + include ActionController::HttpAuthentication::Basic::ControllerMethods + include ActionController::HttpAuthentication::Digest::ControllerMethods # TODO: Extract into its own module # This should be moved together with other normalizing behavior @@ -89,6 +91,11 @@ module ActionController if options.key?(:action) && options[:action].to_s.index("/") options[:template] = options.delete(:action) end + + if options[:status] + options[:status] = interpret_status(options.delete(:status)).to_i + end + options end diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index e1407e671a..116ce34494 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -57,7 +57,7 @@ module ActionController 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 diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 2a52eedb59..878859f3e6 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -80,7 +80,7 @@ module ActionController def _process_options(options) status, content_type, location = options.values_at(:status, :content_type, :location) - response.status = status.to_i if status + response.status = status if status response.content_type = content_type if content_type response.headers["Location"] = url_for(location) if location end diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb index b8a2205ce6..15a11395bb 100644 --- a/actionpack/test/controller/http_digest_authentication_test.rb +++ b/actionpack/test/controller/http_digest_authentication_test.rb @@ -38,6 +38,15 @@ class HttpDigestAuthenticationTest < ActionController::TestCase 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') @@ -165,10 +174,6 @@ class HttpDigestAuthenticationTest < ActionController::TestCase 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' diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 3a99774ae0..0bc0eb2df6 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -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 -- cgit v1.2.3 From e773d0e68ac64bd26d86860a9a8e0048e2b6bb48 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 16:31:05 -0700 Subject: Renamed #implicit_render to #default_render in new base to support the default_render API --- actionpack/lib/action_controller/new_base/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index b432060bc1..034e614d6e 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -38,18 +38,18 @@ module ActionController 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 -- cgit v1.2.3 From 6923b392b740f2346326634532b40cf24a0f26ef Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 16:35:40 -0700 Subject: Added the :rjs render option --- actionpack/lib/action_controller/new_base/base.rb | 14 ++++++++------ .../lib/action_controller/new_base/render_options.rb | 11 +++++++++++ actionpack/lib/action_view/base.rb | 17 +++++++++-------- actionpack/lib/action_view/helpers/prototype_helper.rb | 2 ++ actionpack/lib/action_view/template/handler.rb | 1 + actionpack/test/controller/render_other_test.rb | 8 ++++++++ actionpack/test/template/javascript_helper_test.rb | 4 ++++ actionpack/test/template/prototype_helper_test.rb | 4 ++++ 8 files changed, 47 insertions(+), 14 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 034e614d6e..fae08c58b2 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -13,6 +13,7 @@ module ActionController include ActionController::Renderer include ActionController::Renderers::Json include ActionController::Renderers::Xml + include ActionController::Renderers::Rjs include ActionController::Layouts include ActionController::ConditionalGet @@ -74,7 +75,7 @@ module ActionController end end - def _normalize_options(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) @@ -93,19 +94,20 @@ module ActionController end if options[:status] - options[:status] = interpret_status(options.delete(:status)).to_i + options[:status] = interpret_status(options[:status]).to_i end + options[:update] = blk if block_given? options end - def render(action = nil, options = {}) - options = _normalize_options(action, options) + def render(action = nil, options = {}, &blk) + options = _normalize_options(action, options, &blk) super(options) end - def render_to_string(action = nil, options = {}) - options = _normalize_options(action, options) + def render_to_string(action = nil, options = {}, &blk) + options = _normalize_options(action, options, &blk) super(options) end diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index aa6593b957..1df23deee7 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -71,5 +71,16 @@ module ActionController 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 end end \ No newline at end of file diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 6b72d406af..4ab568b44c 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -269,15 +269,16 @@ module ActionView #:nodoc: 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 diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 1fbe012a95..c0f5df3468 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -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 @@ module ActionView # #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 diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index 3481a4a4e7..3071c78174 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -1,4 +1,5 @@ require "active_support/core_ext/class/inheritable_attributes" +require "action_dispatch/http/mime_type" # Legacy TemplateHandler stub module ActionView diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb index ddbdd2d213..3c52b7036d 100644 --- a/actionpack/test/controller/render_other_test.rb +++ b/actionpack/test/controller/render_other_test.rb @@ -103,6 +103,14 @@ class TestController < ActionController::Base 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", diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index f9bc92c7c9..8caabfc3e1 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -3,6 +3,8 @@ require 'abstract_unit' class JavaScriptHelperTest < ActionView::TestCase tests ActionView::Helpers::JavaScriptHelper + def _evaluate_assigns_and_ivars() end + attr_accessor :formats, :output_buffer def setup @@ -10,6 +12,8 @@ class JavaScriptHelperTest < ActionView::TestCase @template = self end + def _evaluate_assigns_and_ivars() end + def test_escape_javascript assert_equal '', escape_javascript(nil) assert_equal %(This \\"thing\\" is really\\n netos\\'), escape_javascript(%(This "thing" is really\n netos')) diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 28851f113f..f9f418aec9 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -61,6 +61,8 @@ class PrototypeHelperBaseTest < ActionView::TestCase end class PrototypeHelperTest < PrototypeHelperBaseTest + def _evaluate_assigns_and_ivars() end + def setup @record = @author = Author.new @article = Article.new @@ -304,6 +306,8 @@ class JavaScriptGeneratorTest < PrototypeHelperBaseTest @generator = create_generator end + def _evaluate_assigns_and_ivars() end + def test_insert_html_with_string assert_equal 'Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });', @generator.insert_html(:top, 'element', '

This is a test

') -- cgit v1.2.3 From 68a207ccf6dffa58c9a9a3e221b99af72859ce27 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Thu, 21 May 2009 18:14:20 -0700 Subject: Implemented layout conditions in new base --- .../lib/action_controller/abstract/layouts.rb | 25 ++++++++++++++++++--- actionpack/test/controller/layout_test.rb | 26 ++++++++++++++-------- .../layouts/third_party_template_library.mab | 2 +- 3 files changed, 40 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 96cb05972f..557d68d866 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -4,11 +4,19 @@ module AbstractController 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 @@ -75,17 +83,28 @@ module AbstractController end def _default_layout(require_layout = false) - if require_layout && !_layout + if require_layout && _action_has_layout? && !_layout 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) 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 \ No newline at end of file diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 5b7d40d16d..1cd448d5e8 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -9,8 +9,11 @@ ActionView::Template::register_template_handler :mab, ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ] +require "lib/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 @@ end 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 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase 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 @@ class LayoutSetInResponseTest < ActionController::TestCase 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 @@ class LayoutSetInResponseTest < ActionController::TestCase 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 diff --git a/actionpack/test/fixtures/layout_tests/layouts/third_party_template_library.mab b/actionpack/test/fixtures/layout_tests/layouts/third_party_template_library.mab index 018abfb0ac..fcee620d82 100644 --- a/actionpack/test/fixtures/layout_tests/layouts/third_party_template_library.mab +++ b/actionpack/test/fixtures/layout_tests/layouts/third_party_template_library.mab @@ -1 +1 @@ -Mab \ No newline at end of file +layouts/third_party_template_library.mab \ No newline at end of file -- cgit v1.2.3 From e0e124757a98a22a3a1ff7cfbceb1d0e4c4c7533 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 21 May 2009 19:44:02 -0700 Subject: Fewer runs by default --- actionpack/examples/minimal.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index 84a8499daf..76668b375d 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -9,7 +9,7 @@ class BaseController < ActionController::Base end end -n = (ENV['N'] || 10000).to_i +n = (ENV['N'] || 1000).to_i input = StringIO.new('') def call_index(controller, input, n) -- cgit v1.2.3 From 8f3cbb477375071cfa2ca9b3b01d8a4e3034ccf5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 21 May 2009 19:45:15 -0700 Subject: Dead local --- actionpack/lib/action_controller/new_base/renderer.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 878859f3e6..71b79fbc42 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -29,7 +29,6 @@ module ActionController if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(_text(options), formats.first) - template = nil 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, {}) -- cgit v1.2.3 From 4c52ba278b8e349bc18cb89086af765d0828f0af Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 21 May 2009 20:22:18 -0700 Subject: Move Safari response-padding fix to Rails2Compatibility. Should be a Rack concern. --- actionpack/lib/action_controller/new_base/base.rb | 8 ++------ actionpack/lib/action_controller/new_base/compatibility.rb | 6 ++++-- actionpack/lib/action_controller/new_base/renderer.rb | 13 ++----------- actionpack/lib/action_controller/new_base/testing.rb | 4 ++-- actionpack/lib/action_view/template/text.rb | 2 +- actionpack/test/controller/verification_test.rb | 2 +- actionpack/test/controller/webservice_test.rb | 4 ++-- actionpack/test/new_base/render_text_test.rb | 6 +++--- 8 files changed, 17 insertions(+), 28 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index fae08c58b2..88686d29d0 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -110,11 +110,7 @@ module ActionController options = _normalize_options(action, options, &blk) super(options) end - - def render_to_body(options) - super || [" "] - end - + # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: # # * Hash - The URL will be generated by calling url_for with the +options+. @@ -172,4 +168,4 @@ module ActionController super(url, status) end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 522a9fe23b..250e7f0dff 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -91,7 +91,9 @@ module ActionController options[:text] = nil if options[:nothing] == true - super + body = super + body = [' '] if body.blank? + body end def _handle_method_missing @@ -110,4 +112,4 @@ module ActionController response_body end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 71b79fbc42..59df3c51da 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -28,7 +28,7 @@ module ActionController _process_options(options) if options.key?(:text) - options[:_template] = ActionView::TextTemplate.new(_text(options), formats.first) + 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, {}) @@ -51,17 +51,8 @@ module ActionController 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 diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 6a92c292bd..d8c3421587 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -7,7 +7,7 @@ module ActionController @_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 @@ -27,4 +27,4 @@ module ActionController @_response.headers.replace(new_headers) end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 927a0d7a72..a86c3915c2 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -2,7 +2,7 @@ module ActionView #:nodoc: class TextTemplate < String #:nodoc: def initialize(string, content_type = Mime[:html]) - super(string) + super(string.to_s) @content_type = Mime[content_type] end diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb index 85134a8264..d568030e41 100644 --- a/actionpack/test/controller/verification_test.rb +++ b/actionpack/test/controller/verification_test.rb @@ -182,7 +182,7 @@ class VerificationTest < ActionController::TestCase def test_unguarded_without_params get :unguarded - assert_equal "", @response.body + assert @response.body.blank? end def test_guarded_in_session_with_prereqs diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index e89d6bb960..9bf8da7276 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -34,7 +34,7 @@ class WebServiceTest < ActionController::IntegrationTest 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 @@ class WebServiceTest < ActionController::IntegrationTest 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 diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index 69594e4b64..aed903ee8a 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -88,14 +88,14 @@ module RenderText assert_status 404 end - test "rendering text with nil returns a single space character" do + test "rendering text with nil returns an empty body padded for Safari" do get "/render_text/with_layout/with_nil" assert_body " " assert_status 200 end - test "Rendering text with nil and custom status code returns a single space character with the status" do + test "Rendering text with nil and custom status code returns an empty body padded for Safari and the status" do get "/render_text/with_layout/with_nil_and_status" assert_body " " @@ -139,4 +139,4 @@ module RenderText end end -ActionController::Base.app_loaded! \ No newline at end of file +ActionController::Base.app_loaded! -- cgit v1.2.3 From 1fa7e3322dc8ceac0da3b2b516ca338ee36c89a9 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 21 May 2009 20:54:28 -0700 Subject: Ruby 1.9 compat: don't rely on lexical scoping since the included block is called from dependency_module --- actionpack/lib/action_controller/new_base/render_options.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 1df23deee7..2ce9d0c7ae 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -41,7 +41,7 @@ module ActionController included do extend ActiveSupport::DependencyModule - depends_on RenderOptions + depends_on ::ActionController::RenderOptions def self.register_renderer(name) included { _add_render_option(name) } @@ -83,4 +83,4 @@ module ActionController end end end -end \ No newline at end of file +end -- cgit v1.2.3 From d1d9a6c26113cf4a0decb504c46e4e7fe4351ce6 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 May 2009 18:15:43 +0200 Subject: Require ruby-debug from new_base/abstract_unit --- actionpack/test/new_base/abstract_unit.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index c045247702..1d4bcbd91d 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -18,6 +18,13 @@ require 'active_support/dependencies' $tags[:new_base] = true +begin + require 'ruby-debug' + Debugger.settings[:autoeval] = true + Debugger.start +rescue LoadError + # Debugging disabled. `gem install ruby-debug` to enable. +end ActiveSupport::Dependencies.hook! -- cgit v1.2.3 From 9d08f86cd45ed939ecf2e24e81655371910c8045 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 May 2009 18:40:26 +0200 Subject: Make assertion tests pass with the new base --- actionpack/Rakefile | 1 + actionpack/lib/action_controller/testing/process2.rb | 1 + actionpack/lib/action_view/test_case.rb | 2 +- actionpack/test/controller/action_pack_assertions_test.rb | 6 +++--- actionpack/test/new_base/abstract_unit.rb | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 012f5384e2..494286fa4c 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,6 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice http_basic_authentication http_digest_authentication + action_pack_assertions ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index bee82c280e..677dd41781 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -41,6 +41,7 @@ module ActionController @response.recycle! @controller.response_body = nil @controller.formats = nil + @controller.params = nil @html_document = nil @request.env['REQUEST_METHOD'] = http_method diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 22adf97304..7355af4192 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -11,7 +11,7 @@ module ActionView 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 diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index c3c769919a..24686ab4b6 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'action_controller/vendor/html-scanner' # a controller class to facilitate the tests class ActionPackAssertionsController < ActionController::Base @@ -295,8 +296,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase # 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 @@ -444,7 +445,6 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase 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 diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index 1d4bcbd91d..5df3467ff5 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -113,7 +113,7 @@ module ActionController hax = @controller._action_view.instance_variable_get(:@_rendered) case options - when NilClass, String + when NilClass, String rendered = (hax[:template] || []).map { |t| t.identifier } msg = build_message(message, "expecting but rendering with ", -- cgit v1.2.3 From faaff383e6f52e1c077684bfa49619139db728fb Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 May 2009 19:03:27 +0200 Subject: Add assert_select tests to the new base --- actionpack/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 494286fa4c..bc30fc7308 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,7 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice http_basic_authentication http_digest_authentication - action_pack_assertions + action_pack_assertions assert_select ).map { |name| "test/controller/#{name}_test.rb" } end -- cgit v1.2.3 From 1d168afcb146872cb7e49b6d513629fbb19e39b0 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 22 May 2009 19:51:11 +0200 Subject: Move FilterParameterLogging to a stand alone module and make it work on new base --- actionpack/Rakefile | 2 +- actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_controller/base/base.rb | 58 +------------ .../base/filter_parameter_logging.rb | 97 ++++++++++++++++++++++ actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/test/controller/filter_params_test.rb | 45 +++++++++- 7 files changed, 144 insertions(+), 61 deletions(-) create mode 100644 actionpack/lib/action_controller/base/filter_parameter_logging.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index bc30fc7308..c9ed9ac532 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,7 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice http_basic_authentication http_digest_authentication - action_pack_assertions assert_select + action_pack_assertions assert_select filter_params ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 39083a84e9..dd22bfd617 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -66,6 +66,7 @@ module ActionController 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' diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index c59068c628..2586037965 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -448,55 +448,6 @@ module ActionController #:nodoc: @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] @@ -853,13 +804,6 @@ module ActionController #:nodoc: 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 @@ -933,7 +877,7 @@ module ActionController #:nodoc: [ 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 diff --git a/actionpack/lib/action_controller/base/filter_parameter_logging.rb b/actionpack/lib/action_controller/base/filter_parameter_logging.rb new file mode 100644 index 0000000000..8e012b2a25 --- /dev/null +++ b/actionpack/lib/action_controller/base/filter_parameter_logging.rb @@ -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) + + 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 diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 14f73e1edd..41b2a859bc 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -32,6 +32,7 @@ module ActionController 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' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 88686d29d0..0c85896a00 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -33,6 +33,7 @@ module ActionController include ActionController::Streaming include ActionController::HttpAuthentication::Basic::ControllerMethods include ActionController::HttpAuthentication::Digest::ControllerMethods + include ActionController::FilterParameterLogging # TODO: Extract into its own module # This should be moved together with other normalizing behavior diff --git a/actionpack/test/controller/filter_params_test.rb b/actionpack/test/controller/filter_params_test.rb index 0b259a7980..8c9e4f81de 100644 --- a/actionpack/test/controller/filter_params_test.rb +++ b/actionpack/test/controller/filter_params_test.rb @@ -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 @@ class FilterParamTest < Test::Unit::TestCase 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 -- cgit v1.2.3 From e976c489e6416cdc4714721df78dd43dd6d13d99 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 00:17:05 +0200 Subject: Add all the existing helpers related features to the new base --- actionpack/Rakefile | 2 +- .../lib/action_controller/abstract/helpers.rb | 27 ++++- actionpack/lib/action_controller/base/helpers.rb | 22 ++-- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 4 +- .../lib/action_controller/new_base/helpers.rb | 133 +++++++++++++++++++++ actionpack/test/controller/helper_test.rb | 6 +- actionpack/test/new_base/abstract_unit.rb | 3 + actionpack/test/new_base/render_text_test.rb | 3 - 9 files changed, 175 insertions(+), 26 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/helpers.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index c9ed9ac532..0ce6f7823b 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,7 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| render render_json render_xml send_file request_forgery_protection rescue url_rewriter verification webservice http_basic_authentication http_digest_authentication - action_pack_assertions assert_select filter_params + action_pack_assertions assert_select filter_params helper ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 968d3080c1..41decfd0c7 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -24,11 +24,30 @@ module AbstractController 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 @@ module AbstractController 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 diff --git a/actionpack/lib/action_controller/base/helpers.rb b/actionpack/lib/action_controller/base/helpers.rb index ba65032f6a..96fa7896a9 100644 --- a/actionpack/lib/action_controller/base/helpers.rb +++ b/actionpack/lib/action_controller/base/helpers.rb @@ -3,23 +3,19 @@ require 'active_support/dependencies' # 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") - - # Extend base with class methods to declare helpers. - base.extend(ClassMethods) + class_inheritable_accessor :helpers_dir + self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers") - 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 diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 41b2a859bc..d6107d3653 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -13,6 +13,7 @@ module ActionController 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' diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 0c85896a00..6340b7fde9 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -4,9 +4,9 @@ module ActionController include AbstractController::Benchmarker include AbstractController::Callbacks - include AbstractController::Helpers include AbstractController::Logger - + + include ActionController::Helpers include ActionController::HideActions include ActionController::UrlFor include ActionController::Redirector diff --git a/actionpack/lib/action_controller/new_base/helpers.rb b/actionpack/lib/action_controller/new_base/helpers.rb new file mode 100644 index 0000000000..401741c249 --- /dev/null +++ b/actionpack/lib/action_controller/new_base/helpers.rb @@ -0,0 +1,133 @@ +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.master_helper_module = Module.new + # klass.master_helper_module.__send__ :include, master_helper_module + klass.__send__ :default_helper_module! + super + end + + # The +helper+ class method can take a series of helper module names, a block, or both. + # + # * *args: One or more modules, strings or symbols, or the special symbol :all. + # * &block: 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 :all, the controller will include all helpers beneath + # ActionController::Base.helpers_dir (defaults to app/helpers/**/*.rb 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 + + add_template_helper(class_name.constantize) + else + # Explcit 'return' here so that the supplied block ( if any ) doesn't get included twice + return super + 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 name= 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 diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 3bbda9eb3a..5b9feb3630 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -27,7 +27,7 @@ module Fun end end -class ApplicationController < ActionController::Base +class AllHelpersController < ActionController::Base helper :all end @@ -127,7 +127,7 @@ class HelperTest < Test::Unit::TestCase 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') @@ -154,7 +154,7 @@ class HelperTest < Test::Unit::TestCase end def test_helper_proxy - methods = ApplicationController.helpers.methods.map(&:to_s) + methods = AllHelpersController.helpers.methods.map(&:to_s) # ActionView assert methods.include?('pluralize') diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index 5df3467ff5..569e4e764f 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -2,6 +2,9 @@ $:.unshift(File.dirname(__FILE__) + '/../../lib') $:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/../lib') +$:.unshift(File.dirname(__FILE__) + '/../fixtures/helpers') +$:.unshift(File.dirname(__FILE__) + '/../fixtures/alternate_helpers') + ENV['new_base'] = "true" $stderr.puts "Running old tests on new_base" diff --git a/actionpack/test/new_base/render_text_test.rb b/actionpack/test/new_base/render_text_test.rb index aed903ee8a..ffc149283b 100644 --- a/actionpack/test/new_base/render_text_test.rb +++ b/actionpack/test/new_base/render_text_test.rb @@ -1,8 +1,5 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper") -class ApplicationController < ActionController::Base -end - module RenderText class SimpleController < ActionController::Base self.view_paths = [ActionView::Template::FixturePath.new] -- cgit v1.2.3 From 01129534cde293e3561dd7cc3cb5ae9ac3de9e8c Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 12:28:40 -0700 Subject: Cleaned up the #render_to_body chain by extracting determining the templates to render to a separate hook point. --- .../lib/action_controller/abstract/layouts.rb | 4 ---- .../lib/action_controller/abstract/renderer.rb | 24 ++++++++++++++-------- .../lib/action_controller/new_base/renderer.rb | 24 ++++++++++++++-------- 3 files changed, 30 insertions(+), 22 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 557d68d866..dec394a021 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -57,10 +57,6 @@ module AbstractController end end end - - def _render_template(template, options) - _action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial]) - end private diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index f2044a35ec..d7c68549e1 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -33,16 +33,12 @@ module AbstractController # # :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 @@ module AbstractController 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 @@ module AbstractController 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) diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 59df3c51da..987751a601 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -27,6 +27,20 @@ module ActionController 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(options[:text], formats.first) elsif options.key?(:inline) @@ -37,21 +51,13 @@ module ActionController 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 super end - - private - - def _prefix - controller_path - end def _render_partial(partial, options) case partial -- cgit v1.2.3 From 72a574b5073b1debd58c954b34c54d3bdee7749f Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 15:16:28 -0700 Subject: Get controller/layout_test.rb running on new base except for ActionController::Base.exempt_from_layout which is going to be deprecated. --- actionpack/Rakefile | 13 +++++++------ .../lib/action_controller/abstract/layouts.rb | 6 +++--- .../lib/action_controller/new_base/layouts.rb | 21 +++++++++------------ actionpack/lib/action_view/template/template.rb | 2 +- actionpack/lib/action_view/template/text.rb | 4 ++++ actionpack/test/controller/layout_test.rb | 17 ++++++++++------- 6 files changed, 34 insertions(+), 29 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 0ce6f7823b..6c820636d5 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -61,12 +61,13 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # layout # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( - addresses_render base benchmark caching capture content_type dispatcher - flash mime_responds record_identifier redirect - render render_json render_xml - send_file request_forgery_protection rescue url_rewriter verification webservice - http_basic_authentication http_digest_authentication - action_pack_assertions assert_select filter_params helper + action_pack_assertions addresses_render assert_select + base benchmark caching capture content_type dispatcher + filter_params flash helper http_basic_authentication + http_digest_authentication layout mime_responds + record_identifier redirect render render_json render_xml + send_file request_forgery_protection rescue url_rewriter + verification webservice ).map { |name| "test/controller/#{name}_test.rb" } end diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index dec394a021..b3b743d6e8 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -65,12 +65,12 @@ module AbstractController # :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}, _layout_prefix(name)) + name && view_paths.find_by_parts(name, details, _layout_prefix(name)) end # TODO: Decide if this is the best hook point for the feature @@ -78,7 +78,7 @@ module AbstractController "layouts" end - def _default_layout(require_layout = false) + def _default_layout(require_layout = false, details = {:formats => formats}) if require_layout && _action_has_layout? && !_layout raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index bf5b14c4e1..35068db770 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -11,23 +11,20 @@ module ActionController end end - def render_to_body(options) - # render :text => ..., :layout => ... - # or - # render :anything_else + private + + def _determine_template(options) + super 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 + options[:_layout] = _layout_for_option(options.key?(:layout) ? options[:layout] : :none, options[:_template].details) end - - super end - - private - 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, diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 0eedc596d2..d58f4ec19e 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -7,7 +7,7 @@ require "action_view/template/path" module ActionView class Template extend TemplateHandlers - attr_reader :source, :identifier, :handler, :mime_type + attr_reader :source, :identifier, :handler, :mime_type, :details def initialize(source, identifier, handler, details) @source = source diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index a86c3915c2..fd57b1677e 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -6,6 +6,10 @@ module ActionView #:nodoc: @content_type = Mime[content_type] end + def details + {:formats => [@content_type.to_sym]} + end + def identifier() self end def render(*) self end diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 1cd448d5e8..04da0a7f86 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -174,15 +174,18 @@ class LayoutSetInResponseTest < ActionController::TestCase 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 -- cgit v1.2.3 From 8a336d01d2c403f0a2fb818edb8db836ddc367ef Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 00:30:11 +0200 Subject: Use super wherever possible in ActionController::Helpers#helper --- actionpack/lib/action_controller/new_base/helpers.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/helpers.rb b/actionpack/lib/action_controller/new_base/helpers.rb index 401741c249..e00c3c338b 100644 --- a/actionpack/lib/action_controller/new_base/helpers.rb +++ b/actionpack/lib/action_controller/new_base/helpers.rb @@ -16,8 +16,6 @@ module ActionController module ClassMethods def inherited(klass) - # klass.master_helper_module = Module.new - # klass.master_helper_module.__send__ :include, master_helper_module klass.__send__ :default_helper_module! super end @@ -78,10 +76,9 @@ module ActionController end end - add_template_helper(class_name.constantize) + super class_name.constantize else - # Explcit 'return' here so that the supplied block ( if any ) doesn't get included twice - return super + super args end end -- cgit v1.2.3 From df2d96a7f05aebca3e9d2367c2a248125b24dca6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 11:10:41 -0700 Subject: Move misplaced test --- actionpack/test/adv_attr_test.rb | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 actionpack/test/adv_attr_test.rb (limited to 'actionpack') diff --git a/actionpack/test/adv_attr_test.rb b/actionpack/test/adv_attr_test.rb deleted file mode 100644 index fdda4ad92d..0000000000 --- a/actionpack/test/adv_attr_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/abstract_unit' -require 'action_mailer/adv_attr_accessor' - -class AdvAttrTest < Test::Unit::TestCase - class Person - include ActionMailer::AdvAttrAccessor - adv_attr_accessor :name - end - - def test_adv_attr - bob = Person.new - assert_nil bob.name - bob.name 'Bob' - assert_equal 'Bob', bob.name - - assert_raise(ArgumentError) {bob.name 'x', 'y'} - end - - -end \ No newline at end of file -- cgit v1.2.3 From 3c13551aa2c7f43f7863349ef5699d42dd255801 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 11:12:51 -0700 Subject: Complain if new_base/abstract_unit was already loaded --- actionpack/test/abstract_unit.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 5ae54d097a..c71da7fa6c 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -1,3 +1,7 @@ +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') -- cgit v1.2.3 From 98f856d7723bd8aa8ccc05dfb7219c897b4dcab7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 11:13:34 -0700 Subject: Set ENV['NEW'] to run any test task with the new Base. --- actionpack/Rakefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 6c820636d5..79a582033a 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -24,8 +24,9 @@ task :default => [ :test ] desc "Run all unit tests" task :test => [:test_action_pack, :test_active_record_integration, :test_new_base, :test_new_base_on_old_tests] +test_lib_dir = ENV["NEW"] ? "test/new_base" : "test" Rake::TestTask.new(:test_action_pack) do |t| - t.libs << "test" + t.libs << test_lib_dir # 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 @@ -37,27 +38,27 @@ 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_dir}", file) end or raise "Failures" end desc 'ActiveRecord Integration Tests' Rake::TestTask.new(:test_active_record_integration) do |t| - t.libs << "test" + t.libs << test_lib_dir 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" 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" + t.libs << "test/new_base" # layout # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( @@ -71,7 +72,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| ).map { |name| "test/controller/#{name}_test.rb" } end - # Genereate the RDoc documentation Rake::RDocTask.new { |rdoc| -- cgit v1.2.3 From ca7207838844f02f50afbb18beb0f535903f7929 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 16:11:54 -0700 Subject: Move fake controllers and models to a common load path --- actionpack/Rakefile | 12 ++++---- actionpack/test/controller/fake_controllers.rb | 33 ---------------------- actionpack/test/controller/fake_models.rb | 19 ------------- actionpack/test/controller/layout_test.rb | 2 +- actionpack/test/lib/controller/fake_controllers.rb | 33 ++++++++++++++++++++++ actionpack/test/lib/controller/fake_models.rb | 19 +++++++++++++ 6 files changed, 59 insertions(+), 59 deletions(-) delete mode 100644 actionpack/test/controller/fake_controllers.rb delete mode 100644 actionpack/test/controller/fake_models.rb create mode 100644 actionpack/test/lib/controller/fake_controllers.rb create mode 100644 actionpack/test/lib/controller/fake_models.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 79a582033a..6ad061b0b1 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -24,9 +24,9 @@ task :default => [ :test ] desc "Run all unit tests" task :test => [:test_action_pack, :test_active_record_integration, :test_new_base, :test_new_base_on_old_tests] -test_lib_dir = ENV["NEW"] ? "test/new_base" : "test" +test_lib_dirs = [ENV["NEW"] ? "test/new_base" : "test", "test/lib"] Rake::TestTask.new(:test_action_pack) do |t| - t.libs << test_lib_dir + 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 @@ -38,27 +38,27 @@ 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_lib_dir}", 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_lib_dir + 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/new_base" + 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" + t.libs << "test/new_base" << "test/lib" # layout # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + t.test_files = %w( diff --git a/actionpack/test/controller/fake_controllers.rb b/actionpack/test/controller/fake_controllers.rb deleted file mode 100644 index 75c114c103..0000000000 --- a/actionpack/test/controller/fake_controllers.rb +++ /dev/null @@ -1,33 +0,0 @@ -class << Object; alias_method :const_available?, :const_defined?; end - -class ContentController < Class.new(ActionController::Base) -end -class NotAController -end -module Admin - class << self; alias_method :const_available?, :const_defined?; end - class UserController < Class.new(ActionController::Base); end - class NewsFeedController < Class.new(ActionController::Base); end -end - -# For speed test -class SpeedController < ActionController::Base; end -class SearchController < SpeedController; end -class VideosController < SpeedController; end -class VideoFileController < SpeedController; end -class VideoSharesController < SpeedController; end -class VideoAbusesController < SpeedController; end -class VideoUploadsController < SpeedController; end -class VideoVisitsController < SpeedController; end -class UsersController < SpeedController; end -class SettingsController < SpeedController; end -class ChannelsController < SpeedController; end -class ChannelVideosController < SpeedController; end -class SessionsController < SpeedController; end -class LostPasswordsController < SpeedController; end -class PagesController < SpeedController; end - -ActionController::Routing::Routes.draw do |map| - map.route_one 'route_one', :controller => 'elsewhere', :action => 'flash_me' - map.connect ':controller/:action/:id' -end diff --git a/actionpack/test/controller/fake_models.rb b/actionpack/test/controller/fake_models.rb deleted file mode 100644 index 0b30c79b10..0000000000 --- a/actionpack/test/controller/fake_models.rb +++ /dev/null @@ -1,19 +0,0 @@ -class Customer < Struct.new(:name, :id) - def to_param - id.to_s - end -end - -class BadCustomer < Customer -end - -class GoodCustomer < Customer -end - -module Quiz - class Question < Struct.new(:name, :id) - def to_param - id.to_s - end - end -end diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 04da0a7f86..cb9bdf57bb 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -9,7 +9,7 @@ ActionView::Template::register_template_handler :mab, ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ] -require "lib/fixture_template" +require "fixture_template" class LayoutTest < ActionController::Base def self.controller_path; 'views' end diff --git a/actionpack/test/lib/controller/fake_controllers.rb b/actionpack/test/lib/controller/fake_controllers.rb new file mode 100644 index 0000000000..75c114c103 --- /dev/null +++ b/actionpack/test/lib/controller/fake_controllers.rb @@ -0,0 +1,33 @@ +class << Object; alias_method :const_available?, :const_defined?; end + +class ContentController < Class.new(ActionController::Base) +end +class NotAController +end +module Admin + class << self; alias_method :const_available?, :const_defined?; end + class UserController < Class.new(ActionController::Base); end + class NewsFeedController < Class.new(ActionController::Base); end +end + +# For speed test +class SpeedController < ActionController::Base; end +class SearchController < SpeedController; end +class VideosController < SpeedController; end +class VideoFileController < SpeedController; end +class VideoSharesController < SpeedController; end +class VideoAbusesController < SpeedController; end +class VideoUploadsController < SpeedController; end +class VideoVisitsController < SpeedController; end +class UsersController < SpeedController; end +class SettingsController < SpeedController; end +class ChannelsController < SpeedController; end +class ChannelVideosController < SpeedController; end +class SessionsController < SpeedController; end +class LostPasswordsController < SpeedController; end +class PagesController < SpeedController; end + +ActionController::Routing::Routes.draw do |map| + map.route_one 'route_one', :controller => 'elsewhere', :action => 'flash_me' + map.connect ':controller/:action/:id' +end diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb new file mode 100644 index 0000000000..0b30c79b10 --- /dev/null +++ b/actionpack/test/lib/controller/fake_models.rb @@ -0,0 +1,19 @@ +class Customer < Struct.new(:name, :id) + def to_param + id.to_s + end +end + +class BadCustomer < Customer +end + +class GoodCustomer < Customer +end + +module Quiz + class Question < Struct.new(:name, :id) + def to_param + id.to_s + end + end +end -- cgit v1.2.3 From b7c031f52ecca11558edd494d292ff6b99dd21b7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 16:21:21 -0700 Subject: Move active_record_unit to shared load path --- actionpack/test/active_record_unit.rb | 104 ------------------------------ actionpack/test/lib/active_record_unit.rb | 104 ++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 104 deletions(-) delete mode 100644 actionpack/test/active_record_unit.rb create mode 100644 actionpack/test/lib/active_record_unit.rb (limited to 'actionpack') diff --git a/actionpack/test/active_record_unit.rb b/actionpack/test/active_record_unit.rb deleted file mode 100644 index 9e0c66055d..0000000000 --- a/actionpack/test/active_record_unit.rb +++ /dev/null @@ -1,104 +0,0 @@ -require 'abstract_unit' - -# Define the essentials -class ActiveRecordTestConnector - cattr_accessor :able_to_connect - cattr_accessor :connected - - # Set our defaults - self.connected = false - self.able_to_connect = true -end - -# Try to grab AR -if defined?(ActiveRecord) && defined?(Fixtures) - $stderr.puts 'Active Record is already loaded, running tests' -else - $stderr.print 'Attempting to load Active Record... ' - begin - PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib" - raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) - $LOAD_PATH.unshift PATH_TO_AR - require 'active_record' - require 'active_record/fixtures' - $stderr.puts 'success' - rescue LoadError => e - $stderr.print "failed. Skipping Active Record assertion tests: #{e}" - ActiveRecordTestConnector.able_to_connect = false - end -end -$stderr.flush - - -# Define the rest of the connector -class ActiveRecordTestConnector - class << self - def setup - unless self.connected || !self.able_to_connect - setup_connection - load_schema - require_fixture_models - self.connected = true - end - rescue Exception => e # errors from ActiveRecord setup - $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}" - #$stderr.puts " #{e.backtrace.join("\n ")}\n" - self.able_to_connect = false - end - - private - def setup_connection - if Object.const_defined?(:ActiveRecord) - defaults = { :database => ':memory:' } - begin - adapter = defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' - options = defaults.merge :adapter => adapter, :timeout => 500 - ActiveRecord::Base.establish_connection(options) - ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } - ActiveRecord::Base.connection - rescue Exception # errors from establishing a connection - $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.' - options = defaults.merge :adapter => 'sqlite' - ActiveRecord::Base.establish_connection(options) - ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options } - ActiveRecord::Base.connection - end - - Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) - else - raise "Can't setup connection since ActiveRecord isn't loaded." - end - end - - # Load actionpack sqlite tables - def load_schema - File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql| - ActiveRecord::Base.connection.execute(sql) unless sql.blank? - end - end - - def require_fixture_models - Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f} - end - end -end - -class ActiveRecordTestCase < ActionController::TestCase - include ActiveRecord::TestFixtures - - # Set our fixture path - if ActiveRecordTestConnector.able_to_connect - self.fixture_path = [FIXTURE_LOAD_PATH] - self.use_transactional_fixtures = false - end - - def self.fixtures(*args) - super if ActiveRecordTestConnector.connected - end - - def run(*args) - super if ActiveRecordTestConnector.connected - end -end - -ActiveRecordTestConnector.setup diff --git a/actionpack/test/lib/active_record_unit.rb b/actionpack/test/lib/active_record_unit.rb new file mode 100644 index 0000000000..1ba308e9d7 --- /dev/null +++ b/actionpack/test/lib/active_record_unit.rb @@ -0,0 +1,104 @@ +require 'abstract_unit' + +# Define the essentials +class ActiveRecordTestConnector + cattr_accessor :able_to_connect + cattr_accessor :connected + + # Set our defaults + self.connected = false + self.able_to_connect = true +end + +# Try to grab AR +if defined?(ActiveRecord) && defined?(Fixtures) + $stderr.puts 'Active Record is already loaded, running tests' +else + $stderr.print 'Attempting to load Active Record... ' + begin + PATH_TO_AR = "#{File.dirname(__FILE__)}/../../../activerecord/lib" + raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) + $LOAD_PATH.unshift PATH_TO_AR + require 'active_record' + require 'active_record/fixtures' + $stderr.puts 'success' + rescue LoadError => e + $stderr.print "failed. Skipping Active Record assertion tests: #{e}" + ActiveRecordTestConnector.able_to_connect = false + end +end +$stderr.flush + + +# Define the rest of the connector +class ActiveRecordTestConnector + class << self + def setup + unless self.connected || !self.able_to_connect + setup_connection + load_schema + require_fixture_models + self.connected = true + end + rescue Exception => e # errors from ActiveRecord setup + $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}" + #$stderr.puts " #{e.backtrace.join("\n ")}\n" + self.able_to_connect = false + end + + private + def setup_connection + if Object.const_defined?(:ActiveRecord) + defaults = { :database => ':memory:' } + begin + adapter = defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' + options = defaults.merge :adapter => adapter, :timeout => 500 + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.connection + rescue Exception # errors from establishing a connection + $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.' + options = defaults.merge :adapter => 'sqlite' + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options } + ActiveRecord::Base.connection + end + + Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) + else + raise "Can't setup connection since ActiveRecord isn't loaded." + end + end + + # Load actionpack sqlite tables + def load_schema + File.read(File.dirname(__FILE__) + "/../fixtures/db_definitions/sqlite.sql").split(';').each do |sql| + ActiveRecord::Base.connection.execute(sql) unless sql.blank? + end + end + + def require_fixture_models + Dir.glob(File.dirname(__FILE__) + "/../fixtures/*.rb").each {|f| require f} + end + end +end + +class ActiveRecordTestCase < ActionController::TestCase + include ActiveRecord::TestFixtures + + # Set our fixture path + if ActiveRecordTestConnector.able_to_connect + self.fixture_path = [FIXTURE_LOAD_PATH] + self.use_transactional_fixtures = false + end + + def self.fixtures(*args) + super if ActiveRecordTestConnector.connected + end + + def run(*args) + super if ActiveRecordTestConnector.connected + end +end + +ActiveRecordTestConnector.setup -- cgit v1.2.3 From 444480c9a5d9c75568a243bb73a040b3cf050814 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 16:23:48 -0700 Subject: Verbose test_new_base_on_old_tests --- actionpack/Rakefile | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 6ad061b0b1..18e5b3d96a 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -70,6 +70,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| send_file request_forgery_protection rescue url_rewriter verification webservice ).map { |name| "test/controller/#{name}_test.rb" } + t.verbose = true end # Genereate the RDoc documentation -- cgit v1.2.3 From a01d2a25867dbe5235c29557673f3a5692b82aec Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 16:25:49 -0700 Subject: Remove gratuitous filter_chain internal testing. Not part of the API and other tests are sufficient to catch regressions. --- actionpack/test/controller/filters_test.rb | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index afefc6a77e..490061ed9b 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' -# FIXME: crashes Ruby 1.9 class FilterTest < Test::Unit::TestCase include ActionController::TestProcess @@ -141,14 +140,6 @@ class FilterTest < Test::Unit::TestCase 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 +446,6 @@ class FilterTest < Test::Unit::TestCase 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 @@ -614,7 +599,6 @@ class FilterTest < Test::Unit::TestCase 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 @@ -818,15 +802,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') } -- cgit v1.2.3 From f766f669464fa9900197d6b3559c2e00e53de9cd Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 01:36:09 +0200 Subject: Make logging_test pass with the new base --- actionpack/Rakefile | 2 +- actionpack/lib/action_controller/base/filter_parameter_logging.rb | 2 +- actionpack/test/controller/logging_test.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 18e5b3d96a..2b48b2cad5 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -68,7 +68,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| http_digest_authentication layout mime_responds record_identifier redirect render render_json render_xml send_file request_forgery_protection rescue url_rewriter - verification webservice + verification webservice logging ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true end diff --git a/actionpack/lib/action_controller/base/filter_parameter_logging.rb b/actionpack/lib/action_controller/base/filter_parameter_logging.rb index 8e012b2a25..f5a678ca03 100644 --- a/actionpack/lib/action_controller/base/filter_parameter_logging.rb +++ b/actionpack/lib/action_controller/base/filter_parameter_logging.rb @@ -71,7 +71,7 @@ module ActionController if logger parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup - parameters = parameters.except!(:controller, :action, :format, :_method) + parameters = parameters.except!(:controller, :action, :format, :_method, :only_path) unless parameters.empty? # TODO : Move DelayedLog to AS diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 75afa2d133..a7ed1b8665 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -35,7 +35,7 @@ class LoggingTest < ActionController::TestCase 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/ } @@ -49,6 +49,6 @@ class LoggingTest < ActionController::TestCase 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 -- cgit v1.2.3 From b77602824afe07dfd8fd8e48407a6086802ec7ef Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 01:40:50 +0200 Subject: Add some more tests to the test_new_base_on_old_tests task --- actionpack/Rakefile | 2 +- actionpack/test/controller/routing_test.rb | 1 + actionpack/test/controller/selector_test.rb | 1 + actionpack/test/new_base/abstract_unit.rb | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 2b48b2cad5..448acf20cb 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -68,7 +68,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| http_digest_authentication layout mime_responds record_identifier redirect render render_json render_xml send_file request_forgery_protection rescue url_rewriter - verification webservice logging + verification webservice logging resources routing ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 77abb68f32..11bffdb42e 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'controller/fake_controllers' +require 'active_support/dependencies' class MilestonesController < ActionController::Base def index() head :ok end diff --git a/actionpack/test/controller/selector_test.rb b/actionpack/test/controller/selector_test.rb index 9d0613d1e2..5a5dc840b5 100644 --- a/actionpack/test/controller/selector_test.rb +++ b/actionpack/test/controller/selector_test.rb @@ -5,6 +5,7 @@ require 'abstract_unit' require 'controller/fake_controllers' +require 'action_controller/vendor/html-scanner' class SelectorTest < Test::Unit::TestCase # diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index 569e4e764f..0b71488bd6 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -10,6 +10,7 @@ $stderr.puts "Running old tests on new_base" require 'test/unit' require 'active_support' +require 'active_support/core_ext' require 'active_support/test_case' require 'action_controller/abstract' require 'action_controller/new_base' -- cgit v1.2.3 From 63ed43cb9901cc7adc352a51fa256c3ba7b6637f Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 15:50:31 -0700 Subject: Added render_other_test.rb to the new base test runner --- actionpack/Rakefile | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 448acf20cb..99ef542f3e 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -61,14 +61,24 @@ 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 + # * cookie + # * filters + # * integration + # * render_js + # * selector + # * test + # * translation + # * view_paths t.test_files = %w( action_pack_assertions addresses_render assert_select base benchmark caching capture content_type dispatcher filter_params flash helper http_basic_authentication - http_digest_authentication layout mime_responds - record_identifier redirect render render_json render_xml - send_file request_forgery_protection rescue url_rewriter - verification webservice logging resources routing + http_digest_authentication layout logging mime_responds + record_identifier redirect render render_json render_other render_xml + request_forgery_protection rescue resources routing send_file + url_rewriter verification webservice ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true end -- cgit v1.2.3 From 28dbeb3a643eeb35767df55ed579f54438c3ee18 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 16:50:26 -0700 Subject: Get controller/render_other_test.rb to pass on new base and fixed a bug in new base with regards to rendering layouts. --- actionpack/lib/action_controller/abstract/layouts.rb | 2 +- actionpack/lib/action_view/template/template.rb | 3 ++- actionpack/test/controller/render_other_test.rb | 14 +++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index b3b743d6e8..8721e5f4dc 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -85,7 +85,7 @@ module AbstractController end begin - _layout_for_name(_layout) if _action_has_layout? + _layout_for_name(_layout, details) if _action_has_layout? rescue NameError => e raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index d58f4ec19e..f61dd591a5 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -15,11 +15,12 @@ module ActionView @handler = handler @details = details - format = details[:format] || begin + 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) diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb index 3c52b7036d..05645e47fa 100644 --- a/actionpack/test/controller/render_other_test.rb +++ b/actionpack/test/controller/render_other_test.rb @@ -4,6 +4,7 @@ require 'pathname' class TestController < ActionController::Base protect_from_forgery + layout :determine_layout module RenderTestHelper def rjs_helper_method_from_module @@ -113,9 +114,16 @@ private 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" -- cgit v1.2.3 From c90f613ad68253cb253bf47cb812f9e027c35d10 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 01:59:23 +0200 Subject: Add Translation to the new base --- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/test/new_base/abstract_unit.rb | 3 +++ 3 files changed, 5 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index d6107d3653..ad0e07e261 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -34,6 +34,7 @@ module ActionController 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' require 'action_controller/routing' end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 6340b7fde9..85354bfea3 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -34,6 +34,7 @@ module ActionController 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 diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index 0b71488bd6..5df2576916 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -10,7 +10,10 @@ $stderr.puts "Running old tests on new_base" require 'test/unit' require 'active_support' + +# TODO : Revisit requiring all the core extensions here require 'active_support/core_ext' + require 'active_support/test_case' require 'action_controller/abstract' require 'action_controller/new_base' -- cgit v1.2.3 From f9dde8fe4e14e7750e9a00c666b052bb409ead05 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 16:57:45 -0700 Subject: Port cookies to new base --- actionpack/Rakefile | 3 +- actionpack/lib/action_controller/new_base.rb | 3 +- actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/test/controller/cookie_test.rb | 40 +++++++++++++++-------- 4 files changed, 31 insertions(+), 16 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 99ef542f3e..c31d11503c 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -63,7 +63,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + # ==== Not ported - # * cookie # * filters # * integration # * render_js @@ -73,7 +72,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # * view_paths t.test_files = %w( action_pack_assertions addresses_render assert_select - base benchmark caching capture content_type dispatcher + 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_json render_other render_xml diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index ad0e07e261..276be50614 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -35,9 +35,10 @@ module ActionController 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' \ No newline at end of file +require 'action_view' diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 85354bfea3..e321d97ac1 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -26,6 +26,7 @@ module ActionController # Rails 2.x compatibility include ActionController::Rails2Compatibility + include ActionController::Cookies include ActionController::Session include ActionController::Flash include ActionController::Verification diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 0f22714071..39d0017dd8 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -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 @@ class CookieTest < ActionController::TestCase 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 @@ class CookieTest < ActionController::TestCase 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 @@ class CookieTest < ActionController::TestCase 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 -- cgit v1.2.3 From 3a72b55229f63d2cba3337c39cd118cf532ebbbc Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 02:07:50 +0200 Subject: Add missing selector_test to the list --- actionpack/Rakefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index c31d11503c..ea12adb921 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,9 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # * filters # * integration # * render_js - # * selector # * test - # * translation # * view_paths t.test_files = %w( action_pack_assertions addresses_render assert_select @@ -76,8 +74,8 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| filter_params flash helper http_basic_authentication http_digest_authentication layout logging mime_responds record_identifier redirect render render_json render_other render_xml - request_forgery_protection rescue resources routing send_file - url_rewriter verification webservice + request_forgery_protection rescue resources routing selector send_file + translation url_rewriter verification webservice ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true end -- cgit v1.2.3 From 7b3fb1d43f57d6ebe3edb75434cae01e140483d0 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 17:07:40 -0700 Subject: Got controller/render_js_test.rb to pass on new base --- actionpack/Rakefile | 7 +++---- actionpack/lib/action_controller/new_base/base.rb | 1 + actionpack/lib/action_controller/new_base/render_options.rb | 10 ++++++++++ actionpack/test/controller/render_js_test.rb | 2 ++ 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index ea12adb921..b9819d4a83 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -65,7 +65,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # ==== Not ported # * filters # * integration - # * render_js # * test # * view_paths t.test_files = %w( @@ -73,9 +72,9 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| 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_json render_other render_xml - request_forgery_protection rescue resources routing selector send_file - translation url_rewriter verification webservice + 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 diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index e321d97ac1..adb760ea7e 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -12,6 +12,7 @@ module ActionController include ActionController::Redirector include ActionController::Renderer include ActionController::Renderers::Json + include ActionController::Renderers::Js include ActionController::Renderers::Xml include ActionController::Renderers::Rjs include ActionController::Layouts diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 2ce9d0c7ae..33f8957f6e 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -62,6 +62,16 @@ module ActionController 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 diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb index 7b50242910..d02fd3fd4c 100644 --- a/actionpack/test/controller/render_js_test.rb +++ b/actionpack/test/controller/render_js_test.rb @@ -19,6 +19,8 @@ class TestController < ActionController::Base end class RenderTest < ActionController::TestCase + tests TestController + def test_render_vanilla_js get :render_vanilla_js_hello assert_equal "alert('hello')", @response.body -- cgit v1.2.3 From 8a03a999ef2ed47c7f2ead1a9dd639120c569e03 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 17:15:56 -0700 Subject: Cordon off missing filter methods --- actionpack/test/controller/filters_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 490061ed9b..22aa50adb2 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -1,5 +1,13 @@ require 'abstract_unit' +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 -- cgit v1.2.3 From da9e53ec3b92fd583346896dd15c5b2533c8af6a Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 22 May 2009 17:17:14 -0700 Subject: Move testing_sandbox to test/lib --- actionpack/test/lib/testing_sandbox.rb | 15 +++++++++++++++ actionpack/test/testing_sandbox.rb | 15 --------------- 2 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 actionpack/test/lib/testing_sandbox.rb delete mode 100644 actionpack/test/testing_sandbox.rb (limited to 'actionpack') diff --git a/actionpack/test/lib/testing_sandbox.rb b/actionpack/test/lib/testing_sandbox.rb new file mode 100644 index 0000000000..c36585104f --- /dev/null +++ b/actionpack/test/lib/testing_sandbox.rb @@ -0,0 +1,15 @@ +module TestingSandbox + # Temporarily replaces KCODE for the block + def with_kcode(kcode) + if RUBY_VERSION < '1.9' + old_kcode, $KCODE = $KCODE, kcode + begin + yield + ensure + $KCODE = old_kcode + end + else + yield + end + end +end diff --git a/actionpack/test/testing_sandbox.rb b/actionpack/test/testing_sandbox.rb deleted file mode 100644 index c36585104f..0000000000 --- a/actionpack/test/testing_sandbox.rb +++ /dev/null @@ -1,15 +0,0 @@ -module TestingSandbox - # Temporarily replaces KCODE for the block - def with_kcode(kcode) - if RUBY_VERSION < '1.9' - old_kcode, $KCODE = $KCODE, kcode - begin - yield - ensure - $KCODE = old_kcode - end - else - yield - end - end -end -- cgit v1.2.3 From 69a1ea8b5d4befe93ca4d11c052e831c7bd2e2b2 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Fri, 22 May 2009 17:15:46 -0700 Subject: Created an ActionController::Renderers::All that includes all the default render options (:json, :js, :rjs, :xml) --- actionpack/lib/action_controller/new_base/base.rb | 5 +---- actionpack/lib/action_controller/new_base/render_options.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index adb760ea7e..ffe608ade4 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -11,10 +11,7 @@ module ActionController include ActionController::UrlFor include ActionController::Redirector include ActionController::Renderer - include ActionController::Renderers::Json - include ActionController::Renderers::Js - include ActionController::Renderers::Xml - include ActionController::Renderers::Rjs + include ActionController::Renderers::All include ActionController::Layouts include ActionController::ConditionalGet diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 33f8957f6e..581a92cb7b 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -92,5 +92,16 @@ module ActionController 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 -- cgit v1.2.3 From 595107f22e6a26e20860d0023478437a51daa5c6 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 23 May 2009 02:20:28 +0200 Subject: Move html-scanner tests one dir up --- actionpack/Rakefile | 2 +- .../controller/html-scanner/cdata_node_test.rb | 15 -- .../test/controller/html-scanner/document_test.rb | 148 ----------- .../test/controller/html-scanner/node_test.rb | 89 ------- .../test/controller/html-scanner/sanitizer_test.rb | 273 --------------------- .../test/controller/html-scanner/tag_node_test.rb | 238 ------------------ .../test/controller/html-scanner/text_node_test.rb | 50 ---- .../test/controller/html-scanner/tokenizer_test.rb | 131 ---------- actionpack/test/html-scanner/cdata_node_test.rb | 15 ++ actionpack/test/html-scanner/document_test.rb | 148 +++++++++++ actionpack/test/html-scanner/node_test.rb | 89 +++++++ actionpack/test/html-scanner/sanitizer_test.rb | 273 +++++++++++++++++++++ actionpack/test/html-scanner/tag_node_test.rb | 238 ++++++++++++++++++ actionpack/test/html-scanner/text_node_test.rb | 50 ++++ actionpack/test/html-scanner/tokenizer_test.rb | 131 ++++++++++ 15 files changed, 945 insertions(+), 945 deletions(-) delete mode 100644 actionpack/test/controller/html-scanner/cdata_node_test.rb delete mode 100644 actionpack/test/controller/html-scanner/document_test.rb delete mode 100644 actionpack/test/controller/html-scanner/node_test.rb delete mode 100644 actionpack/test/controller/html-scanner/sanitizer_test.rb delete mode 100644 actionpack/test/controller/html-scanner/tag_node_test.rb delete mode 100644 actionpack/test/controller/html-scanner/text_node_test.rb delete mode 100644 actionpack/test/controller/html-scanner/tokenizer_test.rb create mode 100644 actionpack/test/html-scanner/cdata_node_test.rb create mode 100644 actionpack/test/html-scanner/document_test.rb create mode 100644 actionpack/test/html-scanner/node_test.rb create mode 100644 actionpack/test/html-scanner/sanitizer_test.rb create mode 100644 actionpack/test/html-scanner/tag_node_test.rb create mode 100644 actionpack/test/html-scanner/text_node_test.rb create mode 100644 actionpack/test/html-scanner/tokenizer_test.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index b9819d4a83..9ce897aae8 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -30,7 +30,7 @@ Rake::TestTask.new(:test_action_pack) do |t| # 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 diff --git a/actionpack/test/controller/html-scanner/cdata_node_test.rb b/actionpack/test/controller/html-scanner/cdata_node_test.rb deleted file mode 100644 index 1822cc565a..0000000000 --- a/actionpack/test/controller/html-scanner/cdata_node_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'abstract_unit' - -class CDATANodeTest < Test::Unit::TestCase - def setup - @node = HTML::CDATA.new(nil, 0, 0, "

howdy

") - end - - def test_to_s - assert_equal "howdy

]]>", @node.to_s - end - - def test_content - assert_equal "

howdy

", @node.content - end -end diff --git a/actionpack/test/controller/html-scanner/document_test.rb b/actionpack/test/controller/html-scanner/document_test.rb deleted file mode 100644 index c68f04fa75..0000000000 --- a/actionpack/test/controller/html-scanner/document_test.rb +++ /dev/null @@ -1,148 +0,0 @@ -require 'abstract_unit' - -class DocumentTest < Test::Unit::TestCase - def test_handle_doctype - doc = nil - assert_nothing_raised do - doc = HTML::Document.new <<-HTML.strip - - - - HTML - end - assert_equal 3, doc.root.children.length - assert_equal %{}, doc.root.children[0].content - assert_match %r{\s+}m, doc.root.children[1].content - assert_equal "html", doc.root.children[2].name - end - - def test_find_img - doc = HTML::Document.new <<-HTML.strip - - -

- - - HTML - assert doc.find(:tag=>"img", :attributes=>{"src"=>"hello.gif"}) - end - - def test_find_all - doc = HTML::Document.new <<-HTML.strip - - -

-
-

something

-

here is more

-
- - - HTML - all = doc.find_all :attributes => { :class => "test" } - assert_equal 3, all.length - assert_equal [ "p", "p", "em" ], all.map { |n| n.name } - end - - def test_find_with_text - doc = HTML::Document.new <<-HTML.strip - - -

Some text

- - - HTML - assert doc.find(:content => "Some text") - assert doc.find(:tag => "p", :child => { :content => "Some text" }) - assert doc.find(:tag => "p", :child => "Some text") - assert doc.find(:tag => "p", :content => "Some text") - end - - def test_parse_xml - assert_nothing_raised { HTML::Document.new("", true, true) } - assert_nothing_raised { HTML::Document.new("something", true, true) } - end - - def test_parse_document - doc = HTML::Document.new(<<-HTML) -
-

blah

- -
-
- HTML - assert_not_nil doc.find(:tag => "div", :children => { :count => 1, :only => { :tag => "table" } }) - end - - def test_tag_nesting_nothing_to_s - doc = HTML::Document.new("") - assert_equal "", doc.root.to_s - end - - def test_tag_nesting_space_to_s - doc = HTML::Document.new(" ") - assert_equal " ", doc.root.to_s - end - - def test_tag_nesting_text_to_s - doc = HTML::Document.new("text") - assert_equal "text", doc.root.to_s - end - - def test_tag_nesting_tag_to_s - doc = HTML::Document.new("") - assert_equal "", doc.root.to_s - end - - def test_parse_cdata - doc = HTML::Document.new(<<-HTML) - - - - <![CDATA[<br>]]> - - -

this document has <br> for a title

- - -HTML - - assert_nil doc.find(:tag => "title", :descendant => { :tag => "br" }) - assert doc.find(:tag => "title", :child => "
") - end - - def test_find_empty_tag - doc = HTML::Document.new("
") - assert_nil doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /./) - assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /\A\Z/) - assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /^$/) - assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "") - assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil) - end - - def test_parse_invalid_document - assert_nothing_raised do - doc = HTML::Document.new(" - - - - -
About Us
- ") - end - end - - def test_invalid_document_raises_exception_when_strict - assert_raise RuntimeError do - doc = HTML::Document.new(" - - - - -
About Us
- ", true) - end - end - -end diff --git a/actionpack/test/controller/html-scanner/node_test.rb b/actionpack/test/controller/html-scanner/node_test.rb deleted file mode 100644 index b0df36877e..0000000000 --- a/actionpack/test/controller/html-scanner/node_test.rb +++ /dev/null @@ -1,89 +0,0 @@ -require 'abstract_unit' - -class NodeTest < Test::Unit::TestCase - - class MockNode - def initialize(matched, value) - @matched = matched - @value = value - end - - def find(conditions) - @matched && self - end - - def to_s - @value.to_s - end - end - - def setup - @node = HTML::Node.new("parent") - @node.children.concat [MockNode.new(false,1), MockNode.new(true,"two"), MockNode.new(false,:three)] - end - - def test_match - assert !@node.match("foo") - end - - def test_tag - assert !@node.tag? - end - - def test_to_s - assert_equal "1twothree", @node.to_s - end - - def test_find - assert_equal "two", @node.find('blah').to_s - end - - def test_parse_strict - s = "" - assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) } - end - - def test_parse_relaxed - s = "" - node = nil - assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } - assert node.attributes.has_key?("foo") - assert !node.attributes.has_key?("bar") - end - - def test_to_s_with_boolean_attrs - s = "" - node = HTML::Node.parse(nil,0,0,s) - assert node.attributes.has_key?("foo") - assert node.attributes.has_key?("bar") - assert "", node.to_s - end - - def test_parse_with_unclosed_tag - s = "contents', node.content - end - - def test_parse_strict_with_unterminated_cdata_section - s = "")) - assert_equal("Dont touch me", sanitizer.sanitize("Dont touch me")) - assert_equal("This is a test.", sanitizer.sanitize("

This is a test.

")) - assert_equal("Weirdos", sanitizer.sanitize("Wei<a onclick='alert(document.cookie);'/>rdos")) - assert_equal("This is a test.", sanitizer.sanitize("This is a test.")) - assert_equal( - %{This is a test.\n\n\nIt no longer contains any HTML.\n}, sanitizer.sanitize( - %{This is <b>a <a href="" target="_blank">test</a></b>.\n\n\n\n

It no longer contains any HTML.

\n})) - assert_equal "This has a here.", sanitizer.sanitize("This has a here.") - assert_equal "This has a here.", sanitizer.sanitize("This has a ]]> here.") - assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed ]] here...") - [nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) } - end - - def test_strip_links - sanitizer = HTML::LinkSanitizer.new - assert_equal "Dont touch me", sanitizer.sanitize("Dont touch me") - assert_equal "on my mind\nall day long", sanitizer.sanitize("on my mind\nall day long") - assert_equal "0wn3d", sanitizer.sanitize("0wn3d") - assert_equal "Magic", sanitizer.sanitize("Magic") - assert_equal "FrrFox", sanitizer.sanitize("FrrFox") - assert_equal "My mind\nall day long", sanitizer.sanitize("My mind\nall day long") - assert_equal "all day long", sanitizer.sanitize("<a href='hello'>all day long</a>") - - assert_equal "", '' - end - - def test_sanitize_plaintext - raw = "<span>foo</span></plaintext>" - assert_sanitized raw, "<span>foo</span>" - end - - def test_sanitize_script - assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f" - end - - # fucked - def test_sanitize_js_handlers - raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>} - assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>} - end - - def test_sanitize_javascript_href - raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>} - assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>} - end - - def test_sanitize_image_src - raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>} - assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>} - end - - HTML::WhiteListSanitizer.allowed_tags.each do |tag_name| - define_method "test_should_allow_#{tag_name}_tag" do - assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end) - end - end - - def test_should_allow_anchors - assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>) - end - - # RFC 3986, sec 4.2 - def test_allow_colons_in_path_component - assert_sanitized("<a href=\"./this:that\">foo</a>") - end - - %w(src width height alt).each do |img_attr| - define_method "test_should_allow_image_#{img_attr}_attribute" do - assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />) - end - end - - def test_should_handle_non_html - assert_sanitized 'abc' - end - - def test_should_handle_blank_text - assert_sanitized nil - assert_sanitized '' - end - - def test_should_allow_custom_tags - text = "<u>foo</u>" - sanitizer = HTML::WhiteListSanitizer.new - assert_equal(text, sanitizer.sanitize(text, :tags => %w(u))) - end - - def test_should_allow_only_custom_tags - text = "<u>foo</u> with <i>bar</i>" - sanitizer = HTML::WhiteListSanitizer.new - assert_equal("<u>foo</u> with bar", sanitizer.sanitize(text, :tags => %w(u))) - end - - def test_should_allow_custom_tags_with_attributes - text = %(<blockquote cite="http://example.com/">foo</blockquote>) - sanitizer = HTML::WhiteListSanitizer.new - assert_equal(text, sanitizer.sanitize(text)) - end - - def test_should_allow_custom_tags_with_custom_attributes - text = %(<blockquote foo="bar">Lorem ipsum</blockquote>) - sanitizer = HTML::WhiteListSanitizer.new - assert_equal(text, sanitizer.sanitize(text, :attributes => ['foo'])) - end - - [%w(img src), %w(a href)].each do |(tag, attr)| - define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do - assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>) - end - end - - def test_should_flag_bad_protocols - sanitizer = HTML::WhiteListSanitizer.new - %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto| - assert sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://bad") - end - end - - def test_should_accept_good_protocols - sanitizer = HTML::WhiteListSanitizer.new - HTML::WhiteListSanitizer.allowed_protocols.each do |proto| - assert !sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://good") - end - end - - def test_should_reject_hex_codes_in_protocol - assert_sanitized %(<a href="&#37;6A&#37;61&#37;76&#37;61&#37;73&#37;63&#37;72&#37;69&#37;70&#37;74&#37;3A&#37;61&#37;6C&#37;65&#37;72&#37;74&#37;28&#37;22&#37;58&#37;53&#37;53&#37;22&#37;29">1</a>), "<a>1</a>" - assert @sanitizer.send(:contains_bad_protocols?, 'src', "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29") - end - - def test_should_block_script_tag - assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), "" - end - - [%(<IMG SRC="javascript:alert('XSS');">), - %(<IMG SRC=javascript:alert('XSS')>), - %(<IMG SRC=JaVaScRiPt:alert('XSS')>), - %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">), - %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>), - %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>), - %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>), - %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>), - %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>), - %(<IMG SRC="jav\tascript:alert('XSS');">), - %(<IMG SRC="jav&#x09;ascript:alert('XSS');">), - %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">), - %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">), - %(<IMG SRC=" &#14; javascript:alert('XSS');">), - %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i| - define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do - assert_sanitized img_hack, "<img>" - end - end - - def test_should_sanitize_tag_broken_up_by_null - assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "alert(\"XSS\")" - end - - def test_should_sanitize_invalid_script_tag - assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), "" - end - - def test_should_sanitize_script_tag_with_multiple_open_brackets - assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "&lt;" - assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), %(&lt;a) - end - - def test_should_sanitize_unclosed_script - assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>" - end - - def test_should_sanitize_half_open_scripts - assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>" - end - - def test_should_not_fall_for_ridiculous_hack - img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>) - assert_sanitized img_hack, "<img>" - end - - # fucked - def test_should_sanitize_attributes - assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>) - end - - def test_should_sanitize_illegal_style_properties - raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;) - expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;) - assert_equal expected, sanitize_css(raw) - end - - def test_should_sanitize_with_trailing_space - raw = "display:block; " - expected = "display: block;" - assert_equal expected, sanitize_css(raw) - end - - def test_should_sanitize_xul_style_attributes - raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')) - assert_equal '', sanitize_css(raw) - end - - def test_should_sanitize_invalid_tag_names - assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f") - end - - def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags - assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>") - end - - def test_should_sanitize_invalid_tag_names_in_single_tags - assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />") - end - - def test_should_sanitize_img_dynsrc_lowsrc - assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />") - end - - def test_should_sanitize_div_background_image_unicode_encoded - raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029) - assert_equal '', sanitize_css(raw) - end - - def test_should_sanitize_div_style_expression - raw = %(width: expression(alert('XSS'));) - assert_equal '', sanitize_css(raw) - end - - def test_should_sanitize_img_vbscript - assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />' - end - - def test_should_sanitize_cdata_section - assert_sanitized "<![CDATA[<span>section</span>]]>", "&lt;![CDATA[&lt;span>section&lt;/span>]]>" - end - - def test_should_sanitize_unterminated_cdata_section - assert_sanitized "<![CDATA[<span>neverending...", "&lt;![CDATA[&lt;span>neverending...]]>" - end - - def test_should_not_mangle_urls_with_ampersand - assert_sanitized %{<a href=\"http://www.domain.com?var1=1&amp;var2=2\">my link</a>} - end - -protected - def assert_sanitized(input, expected = nil) - @sanitizer ||= HTML::WhiteListSanitizer.new - if input - assert_dom_equal expected || input, @sanitizer.sanitize(input) - else - assert_nil @sanitizer.sanitize(input) - end - end - - def sanitize_css(input) - (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input) - end -end diff --git a/actionpack/test/controller/html-scanner/tag_node_test.rb b/actionpack/test/controller/html-scanner/tag_node_test.rb deleted file mode 100644 index d1d4667378..0000000000 --- a/actionpack/test/controller/html-scanner/tag_node_test.rb +++ /dev/null @@ -1,238 +0,0 @@ -require 'abstract_unit' - -class TagNodeTest < Test::Unit::TestCase - def test_open_without_attributes - node = tag("<tag>") - assert_equal "tag", node.name - assert_equal Hash.new, node.attributes - assert_nil node.closing - end - - def test_open_with_attributes - node = tag("<TAG1 foo=hey_ho x:bar=\"blah blah\" BAZ='blah blah blah' >") - assert_equal "tag1", node.name - assert_equal "hey_ho", node["foo"] - assert_equal "blah blah", node["x:bar"] - assert_equal "blah blah blah", node["baz"] - end - - def test_self_closing_without_attributes - node = tag("<tag/>") - assert_equal "tag", node.name - assert_equal Hash.new, node.attributes - assert_equal :self, node.closing - end - - def test_self_closing_with_attributes - node = tag("<tag a=b/>") - assert_equal "tag", node.name - assert_equal( { "a" => "b" }, node.attributes ) - assert_equal :self, node.closing - end - - def test_closing_without_attributes - node = tag("</tag>") - assert_equal "tag", node.name - assert_nil node.attributes - assert_equal :close, node.closing - end - - def test_bracket_op_when_no_attributes - node = tag("</tag>") - assert_nil node["foo"] - end - - def test_bracket_op_when_attributes - node = tag("<tag a=b/>") - assert_equal "b", node["a"] - end - - def test_attributes_with_escaped_quotes - node = tag("<tag a='b\\'c' b=\"bob \\\"float\\\"\">") - assert_equal "b\\'c", node["a"] - assert_equal "bob \\\"float\\\"", node["b"] - end - - def test_to_s - node = tag("<a b=c d='f' g=\"h 'i'\" />") - assert_equal %(<a b='c' d='f' g='h \\'i\\'' />), node.to_s - end - - def test_tag - assert tag("<tag>").tag? - end - - def test_match_tag_as_string - assert tag("<tag>").match(:tag => "tag") - assert !tag("<tag>").match(:tag => "b") - end - - def test_match_tag_as_regexp - assert tag("<tag>").match(:tag => /t.g/) - assert !tag("<tag>").match(:tag => /t[bqs]g/) - end - - def test_match_attributes_as_string - t = tag("<tag a=something b=else />") - assert t.match(:attributes => {"a" => "something"}) - assert t.match(:attributes => {"b" => "else"}) - end - - def test_match_attributes_as_regexp - t = tag("<tag a=something b=else />") - assert t.match(:attributes => {"a" => /^something$/}) - assert t.match(:attributes => {"b" => /e.*e/}) - assert t.match(:attributes => {"a" => /me..i/, "b" => /.ls.$/}) - end - - def test_match_attributes_as_number - t = tag("<tag a=15 b=3.1415 />") - assert t.match(:attributes => {"a" => 15}) - assert t.match(:attributes => {"b" => 3.1415}) - assert t.match(:attributes => {"a" => 15, "b" => 3.1415}) - end - - def test_match_attributes_exist - t = tag("<tag a=15 b=3.1415 />") - assert t.match(:attributes => {"a" => true}) - assert t.match(:attributes => {"b" => true}) - assert t.match(:attributes => {"a" => true, "b" => true}) - end - - def test_match_attributes_not_exist - t = tag("<tag a=15 b=3.1415 />") - assert t.match(:attributes => {"c" => false}) - assert t.match(:attributes => {"c" => nil}) - assert t.match(:attributes => {"a" => true, "c" => false}) - end - - def test_match_parent_success - t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) - assert t.match(:parent => {:tag => "foo", :attributes => {"k" => /v.l/, "j" => false}}) - end - - def test_match_parent_fail - t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) - assert !t.match(:parent => {:tag => /kafka/}) - end - - def test_match_child_success - t = tag("<tag x:k='something'>") - tag("<child v=john a=kelly>", t) - tag("<sib m=vaughn v=james>", t) - assert t.match(:child => { :tag => "sib", :attributes => {"v" => /j/}}) - assert t.match(:child => { :attributes => {"a" => "kelly"}}) - end - - def test_match_child_fail - t = tag("<tag x:k='something'>") - tag("<child v=john a=kelly>", t) - tag("<sib m=vaughn v=james>", t) - assert !t.match(:child => { :tag => "sib", :attributes => {"v" => /r/}}) - assert !t.match(:child => { :attributes => {"v" => false}}) - end - - def test_match_ancestor_success - t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) - assert t.match(:ancestor => {:tag => "parent", :attributes => {"a" => /ll/}}) - assert t.match(:ancestor => {:attributes => {"m" => "vaughn"}}) - end - - def test_match_ancestor_fail - t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) - assert !t.match(:ancestor => {:tag => /^parent/, :attributes => {"v" => /m/}}) - assert !t.match(:ancestor => {:attributes => {"v" => false}}) - end - - def test_match_descendant_success - tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) - assert t.match(:descendant => {:tag => "child", :attributes => {"a" => /ll/}}) - assert t.match(:descendant => {:attributes => {"m" => "vaughn"}}) - end - - def test_match_descendant_fail - tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) - assert !t.match(:descendant => {:tag => /^child/, :attributes => {"v" => /m/}}) - assert !t.match(:descendant => {:attributes => {"v" => false}}) - end - - def test_match_child_count - t = tag("<tag x:k='something'>") - tag("hello", t) - tag("<child v=john a=kelly>", t) - tag("<sib m=vaughn v=james>", t) - assert t.match(:children => { :count => 2 }) - assert t.match(:children => { :count => 2..4 }) - assert t.match(:children => { :less_than => 4 }) - assert t.match(:children => { :greater_than => 1 }) - assert !t.match(:children => { :count => 3 }) - end - - def test_conditions_as_strings - t = tag("<tag x:k='something'>") - assert t.match("tag" => "tag") - assert t.match("attributes" => { "x:k" => "something" }) - assert !t.match("tag" => "gat") - assert !t.match("attributes" => { "x:j" => "something" }) - end - - def test_attributes_as_symbols - t = tag("<child v=john a=kelly>") - assert t.match(:attributes => { :v => /oh/ }) - assert t.match(:attributes => { :a => /ll/ }) - end - - def test_match_sibling - t = tag("<tag x:k='something'>") - tag("hello", t) - tag("<span a=b>", t) - tag("world", t) - m = tag("<span k=r>", t) - tag("<span m=l>", t) - - assert m.match(:sibling => {:tag => "span", :attributes => {:a => true}}) - assert m.match(:sibling => {:tag => "span", :attributes => {:m => true}}) - assert !m.match(:sibling => {:tag => "span", :attributes => {:k => true}}) - end - - def test_match_sibling_before - t = tag("<tag x:k='something'>") - tag("hello", t) - tag("<span a=b>", t) - tag("world", t) - m = tag("<span k=r>", t) - tag("<span m=l>", t) - - assert m.match(:before => {:tag => "span", :attributes => {:m => true}}) - assert !m.match(:before => {:tag => "span", :attributes => {:a => true}}) - assert !m.match(:before => {:tag => "span", :attributes => {:k => true}}) - end - - def test_match_sibling_after - t = tag("<tag x:k='something'>") - tag("hello", t) - tag("<span a=b>", t) - tag("world", t) - m = tag("<span k=r>", t) - tag("<span m=l>", t) - - assert m.match(:after => {:tag => "span", :attributes => {:a => true}}) - assert !m.match(:after => {:tag => "span", :attributes => {:m => true}}) - assert !m.match(:after => {:tag => "span", :attributes => {:k => true}}) - end - - def test_to_s - t = tag("<b x='foo'>") - tag("hello", t) - tag("<hr />", t) - assert_equal %(<b x="foo">hello<hr /></b>), t.to_s - end - - private - - def tag(content, parent=nil) - node = HTML::Node.parse(parent,0,0,content) - parent.children << node if parent - node - end -end diff --git a/actionpack/test/controller/html-scanner/text_node_test.rb b/actionpack/test/controller/html-scanner/text_node_test.rb deleted file mode 100644 index 1ab3f4454e..0000000000 --- a/actionpack/test/controller/html-scanner/text_node_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require 'abstract_unit' - -class TextNodeTest < Test::Unit::TestCase - def setup - @node = HTML::Text.new(nil, 0, 0, "hello, howdy, aloha, annyeong") - end - - def test_to_s - assert_equal "hello, howdy, aloha, annyeong", @node.to_s - end - - def test_find_string - assert_equal @node, @node.find("hello, howdy, aloha, annyeong") - assert_equal false, @node.find("bogus") - end - - def test_find_regexp - assert_equal @node, @node.find(/an+y/) - assert_nil @node.find(/b/) - end - - def test_find_hash - assert_equal @node, @node.find(:content => /howdy/) - assert_nil @node.find(:content => /^howdy$/) - assert_equal false, @node.find(:content => "howdy") - end - - def test_find_other - assert_nil @node.find(:hello) - end - - def test_match_string - assert @node.match("hello, howdy, aloha, annyeong") - assert_equal false, @node.match("bogus") - end - - def test_match_regexp - assert_not_nil @node, @node.match(/an+y/) - assert_nil @node.match(/b/) - end - - def test_match_hash - assert_not_nil @node, @node.match(:content => "howdy") - assert_nil @node.match(:content => /^howdy$/) - end - - def test_match_other - assert_nil @node.match(:hello) - end -end diff --git a/actionpack/test/controller/html-scanner/tokenizer_test.rb b/actionpack/test/controller/html-scanner/tokenizer_test.rb deleted file mode 100644 index a001bcbbad..0000000000 --- a/actionpack/test/controller/html-scanner/tokenizer_test.rb +++ /dev/null @@ -1,131 +0,0 @@ -require 'abstract_unit' - -class TokenizerTest < Test::Unit::TestCase - - def test_blank - tokenize "" - assert_end - end - - def test_space - tokenize " " - assert_next " " - assert_end - end - - def test_tag_simple_open - tokenize "<tag>" - assert_next "<tag>" - assert_end - end - - def test_tag_simple_self_closing - tokenize "<tag />" - assert_next "<tag />" - assert_end - end - - def test_tag_simple_closing - tokenize "</tag>" - assert_next "</tag>" - end - - def test_tag_with_single_quoted_attribute - tokenize %{<tag a='hello'>x} - assert_next %{<tag a='hello'>} - end - - def test_tag_with_single_quoted_attribute_with_escape - tokenize %{<tag a='hello\\''>x} - assert_next %{<tag a='hello\\''>} - end - - def test_tag_with_double_quoted_attribute - tokenize %{<tag a="hello">x} - assert_next %{<tag a="hello">} - end - - def test_tag_with_double_quoted_attribute_with_escape - tokenize %{<tag a="hello\\"">x} - assert_next %{<tag a="hello\\"">} - end - - def test_tag_with_unquoted_attribute - tokenize %{<tag a=hello>x} - assert_next %{<tag a=hello>} - end - - def test_tag_with_lt_char_in_attribute - tokenize %{<tag a="x < y">x} - assert_next %{<tag a="x < y">} - end - - def test_tag_with_gt_char_in_attribute - tokenize %{<tag a="x > y">x} - assert_next %{<tag a="x > y">} - end - - def test_doctype_tag - tokenize %{<!DOCTYPE "blah" "blah" "blah">\n <html>} - assert_next %{<!DOCTYPE "blah" "blah" "blah">} - assert_next %{\n } - assert_next %{<html>} - end - - def test_cdata_tag - tokenize %{<![CDATA[<br>]]>} - assert_next %{<![CDATA[<br>]]>} - assert_end - end - - def test_unterminated_cdata_tag - tokenize %{<content:encoded><![CDATA[ neverending...} - assert_next %{<content:encoded>} - assert_next %{<![CDATA[ neverending...} - assert_end - end - - def test_less_than_with_space - tokenize %{original < hello > world} - assert_next %{original } - assert_next %{< hello > world} - end - - def test_less_than_without_matching_greater_than - tokenize %{hello <span onmouseover="gotcha"\n<b>foo</b>\nbar</span>} - assert_next %{hello } - assert_next %{<span onmouseover="gotcha"\n} - assert_next %{<b>} - assert_next %{foo} - assert_next %{</b>} - assert_next %{\nbar} - assert_next %{</span>} - assert_end - end - - def test_unterminated_comment - tokenize %{hello <!-- neverending...} - assert_next %{hello } - assert_next %{<!-- neverending...} - assert_end - end - - private - - def tokenize(text) - @tokenizer = HTML::Tokenizer.new(text) - end - - def assert_next(expected, message=nil) - token = @tokenizer.next - assert_equal expected, token, message - end - - def assert_sequence(*expected) - assert_next expected.shift until expected.empty? - end - - def assert_end(message=nil) - assert_nil @tokenizer.next, message - end -end diff --git a/actionpack/test/html-scanner/cdata_node_test.rb b/actionpack/test/html-scanner/cdata_node_test.rb new file mode 100644 index 0000000000..1822cc565a --- /dev/null +++ b/actionpack/test/html-scanner/cdata_node_test.rb @@ -0,0 +1,15 @@ +require 'abstract_unit' + +class CDATANodeTest < Test::Unit::TestCase + def setup + @node = HTML::CDATA.new(nil, 0, 0, "<p>howdy</p>") + end + + def test_to_s + assert_equal "<![CDATA[<p>howdy</p>]]>", @node.to_s + end + + def test_content + assert_equal "<p>howdy</p>", @node.content + end +end diff --git a/actionpack/test/html-scanner/document_test.rb b/actionpack/test/html-scanner/document_test.rb new file mode 100644 index 0000000000..c68f04fa75 --- /dev/null +++ b/actionpack/test/html-scanner/document_test.rb @@ -0,0 +1,148 @@ +require 'abstract_unit' + +class DocumentTest < Test::Unit::TestCase + def test_handle_doctype + doc = nil + assert_nothing_raised do + doc = HTML::Document.new <<-HTML.strip + <!DOCTYPE "blah" "blah" "blah"> + <html> + </html> + HTML + end + assert_equal 3, doc.root.children.length + assert_equal %{<!DOCTYPE "blah" "blah" "blah">}, doc.root.children[0].content + assert_match %r{\s+}m, doc.root.children[1].content + assert_equal "html", doc.root.children[2].name + end + + def test_find_img + doc = HTML::Document.new <<-HTML.strip + <html> + <body> + <p><img src="hello.gif"></p> + </body> + </html> + HTML + assert doc.find(:tag=>"img", :attributes=>{"src"=>"hello.gif"}) + end + + def test_find_all + doc = HTML::Document.new <<-HTML.strip + <html> + <body> + <p class="test"><img src="hello.gif"></p> + <div class="foo"> + <p class="test">something</p> + <p>here is <em class="test">more</em></p> + </div> + </body> + </html> + HTML + all = doc.find_all :attributes => { :class => "test" } + assert_equal 3, all.length + assert_equal [ "p", "p", "em" ], all.map { |n| n.name } + end + + def test_find_with_text + doc = HTML::Document.new <<-HTML.strip + <html> + <body> + <p>Some text</p> + </body> + </html> + HTML + assert doc.find(:content => "Some text") + assert doc.find(:tag => "p", :child => { :content => "Some text" }) + assert doc.find(:tag => "p", :child => "Some text") + assert doc.find(:tag => "p", :content => "Some text") + end + + def test_parse_xml + assert_nothing_raised { HTML::Document.new("<tags><tag/></tags>", true, true) } + assert_nothing_raised { HTML::Document.new("<outer><link>something</link></outer>", true, true) } + end + + def test_parse_document + doc = HTML::Document.new(<<-HTML) + <div> + <h2>blah</h2> + <table> + </table> + </div> + HTML + assert_not_nil doc.find(:tag => "div", :children => { :count => 1, :only => { :tag => "table" } }) + end + + def test_tag_nesting_nothing_to_s + doc = HTML::Document.new("<tag></tag>") + assert_equal "<tag></tag>", doc.root.to_s + end + + def test_tag_nesting_space_to_s + doc = HTML::Document.new("<tag> </tag>") + assert_equal "<tag> </tag>", doc.root.to_s + end + + def test_tag_nesting_text_to_s + doc = HTML::Document.new("<tag>text</tag>") + assert_equal "<tag>text</tag>", doc.root.to_s + end + + def test_tag_nesting_tag_to_s + doc = HTML::Document.new("<tag><nested /></tag>") + assert_equal "<tag><nested /></tag>", doc.root.to_s + end + + def test_parse_cdata + doc = HTML::Document.new(<<-HTML) +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> + <head> + <title><![CDATA[<br>]]></title> + </head> + <body> + <p>this document has &lt;br&gt; for a title</p> + </body> +</html> +HTML + + assert_nil doc.find(:tag => "title", :descendant => { :tag => "br" }) + assert doc.find(:tag => "title", :child => "<br>") + end + + def test_find_empty_tag + doc = HTML::Document.new("<div id='map'></div>") + assert_nil doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /./) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /\A\Z/) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /^$/) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "") + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil) + end + + def test_parse_invalid_document + assert_nothing_raised do + doc = HTML::Document.new("<html> + <table> + <tr> + <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td> + </tr> + </table> + </html>") + end + end + + def test_invalid_document_raises_exception_when_strict + assert_raise RuntimeError do + doc = HTML::Document.new("<html> + <table> + <tr> + <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td> + </tr> + </table> + </html>", true) + end + end + +end diff --git a/actionpack/test/html-scanner/node_test.rb b/actionpack/test/html-scanner/node_test.rb new file mode 100644 index 0000000000..b0df36877e --- /dev/null +++ b/actionpack/test/html-scanner/node_test.rb @@ -0,0 +1,89 @@ +require 'abstract_unit' + +class NodeTest < Test::Unit::TestCase + + class MockNode + def initialize(matched, value) + @matched = matched + @value = value + end + + def find(conditions) + @matched && self + end + + def to_s + @value.to_s + end + end + + def setup + @node = HTML::Node.new("parent") + @node.children.concat [MockNode.new(false,1), MockNode.new(true,"two"), MockNode.new(false,:three)] + end + + def test_match + assert !@node.match("foo") + end + + def test_tag + assert !@node.tag? + end + + def test_to_s + assert_equal "1twothree", @node.to_s + end + + def test_find + assert_equal "two", @node.find('blah').to_s + end + + def test_parse_strict + s = "<b foo='hello'' bar='baz'>" + assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) } + end + + def test_parse_relaxed + s = "<b foo='hello'' bar='baz'>" + node = nil + assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } + assert node.attributes.has_key?("foo") + assert !node.attributes.has_key?("bar") + end + + def test_to_s_with_boolean_attrs + s = "<b foo bar>" + node = HTML::Node.parse(nil,0,0,s) + assert node.attributes.has_key?("foo") + assert node.attributes.has_key?("bar") + assert "<b foo bar>", node.to_s + end + + def test_parse_with_unclosed_tag + s = "<span onmouseover='bang'" + node = nil + assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } + assert node.attributes.has_key?("onmouseover") + end + + def test_parse_with_valid_cdata_section + s = "<![CDATA[<span>contents</span>]]>" + node = nil + assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } + assert_kind_of HTML::CDATA, node + assert_equal '<span>contents</span>', node.content + end + + def test_parse_strict_with_unterminated_cdata_section + s = "<![CDATA[neverending..." + assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) } + end + + def test_parse_relaxed_with_unterminated_cdata_section + s = "<![CDATA[neverending..." + node = nil + assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } + assert_kind_of HTML::CDATA, node + assert_equal 'neverending...', node.content + end +end diff --git a/actionpack/test/html-scanner/sanitizer_test.rb b/actionpack/test/html-scanner/sanitizer_test.rb new file mode 100644 index 0000000000..e85a5c7abf --- /dev/null +++ b/actionpack/test/html-scanner/sanitizer_test.rb @@ -0,0 +1,273 @@ +require 'abstract_unit' + +class SanitizerTest < ActionController::TestCase + def setup + @sanitizer = nil # used by assert_sanitizer + end + + def test_strip_tags + sanitizer = HTML::FullSanitizer.new + assert_equal("<<<bad html", sanitizer.sanitize("<<<bad html")) + assert_equal("<<", sanitizer.sanitize("<<<bad html>")) + assert_equal("Dont touch me", sanitizer.sanitize("Dont touch me")) + assert_equal("This is a test.", sanitizer.sanitize("<p>This <u>is<u> a <a href='test.html'><strong>test</strong></a>.</p>")) + assert_equal("Weirdos", sanitizer.sanitize("Wei<<a>a onclick='alert(document.cookie);'</a>/>rdos")) + assert_equal("This is a test.", sanitizer.sanitize("This is a test.")) + assert_equal( + %{This is a test.\n\n\nIt no longer contains any HTML.\n}, sanitizer.sanitize( + %{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n})) + assert_equal "This has a here.", sanitizer.sanitize("This has a <!-- comment --> here.") + assert_equal "This has a here.", sanitizer.sanitize("This has a <![CDATA[<section>]]> here.") + assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed <![CDATA[<section>]] here...") + [nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) } + end + + def test_strip_links + sanitizer = HTML::LinkSanitizer.new + assert_equal "Dont touch me", sanitizer.sanitize("Dont touch me") + assert_equal "on my mind\nall day long", sanitizer.sanitize("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>") + assert_equal "0wn3d", sanitizer.sanitize("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>") + assert_equal "Magic", sanitizer.sanitize("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic") + assert_equal "FrrFox", sanitizer.sanitize("<href onlclick='steal()'>FrrFox</a></href>") + assert_equal "My mind\nall <b>day</b> long", sanitizer.sanitize("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>") + assert_equal "all <b>day</b> long", sanitizer.sanitize("<<a>a href='hello'>all <b>day</b> long<</A>/a>") + + assert_equal "<a<a", sanitizer.sanitize("<a<a") + end + + def test_sanitize_form + assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", '' + end + + def test_sanitize_plaintext + raw = "<plaintext><span>foo</span></plaintext>" + assert_sanitized raw, "<span>foo</span>" + end + + def test_sanitize_script + assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f" + end + + # fucked + def test_sanitize_js_handlers + raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>} + assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>} + end + + def test_sanitize_javascript_href + raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>} + assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>} + end + + def test_sanitize_image_src + raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>} + assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>} + end + + HTML::WhiteListSanitizer.allowed_tags.each do |tag_name| + define_method "test_should_allow_#{tag_name}_tag" do + assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end) + end + end + + def test_should_allow_anchors + assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>) + end + + # RFC 3986, sec 4.2 + def test_allow_colons_in_path_component + assert_sanitized("<a href=\"./this:that\">foo</a>") + end + + %w(src width height alt).each do |img_attr| + define_method "test_should_allow_image_#{img_attr}_attribute" do + assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />) + end + end + + def test_should_handle_non_html + assert_sanitized 'abc' + end + + def test_should_handle_blank_text + assert_sanitized nil + assert_sanitized '' + end + + def test_should_allow_custom_tags + text = "<u>foo</u>" + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text, :tags => %w(u))) + end + + def test_should_allow_only_custom_tags + text = "<u>foo</u> with <i>bar</i>" + sanitizer = HTML::WhiteListSanitizer.new + assert_equal("<u>foo</u> with bar", sanitizer.sanitize(text, :tags => %w(u))) + end + + def test_should_allow_custom_tags_with_attributes + text = %(<blockquote cite="http://example.com/">foo</blockquote>) + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text)) + end + + def test_should_allow_custom_tags_with_custom_attributes + text = %(<blockquote foo="bar">Lorem ipsum</blockquote>) + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text, :attributes => ['foo'])) + end + + [%w(img src), %w(a href)].each do |(tag, attr)| + define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do + assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>) + end + end + + def test_should_flag_bad_protocols + sanitizer = HTML::WhiteListSanitizer.new + %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto| + assert sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://bad") + end + end + + def test_should_accept_good_protocols + sanitizer = HTML::WhiteListSanitizer.new + HTML::WhiteListSanitizer.allowed_protocols.each do |proto| + assert !sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://good") + end + end + + def test_should_reject_hex_codes_in_protocol + assert_sanitized %(<a href="&#37;6A&#37;61&#37;76&#37;61&#37;73&#37;63&#37;72&#37;69&#37;70&#37;74&#37;3A&#37;61&#37;6C&#37;65&#37;72&#37;74&#37;28&#37;22&#37;58&#37;53&#37;53&#37;22&#37;29">1</a>), "<a>1</a>" + assert @sanitizer.send(:contains_bad_protocols?, 'src', "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29") + end + + def test_should_block_script_tag + assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), "" + end + + [%(<IMG SRC="javascript:alert('XSS');">), + %(<IMG SRC=javascript:alert('XSS')>), + %(<IMG SRC=JaVaScRiPt:alert('XSS')>), + %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">), + %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>), + %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>), + %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>), + %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>), + %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>), + %(<IMG SRC="jav\tascript:alert('XSS');">), + %(<IMG SRC="jav&#x09;ascript:alert('XSS');">), + %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">), + %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">), + %(<IMG SRC=" &#14; javascript:alert('XSS');">), + %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i| + define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do + assert_sanitized img_hack, "<img>" + end + end + + def test_should_sanitize_tag_broken_up_by_null + assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "alert(\"XSS\")" + end + + def test_should_sanitize_invalid_script_tag + assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), "" + end + + def test_should_sanitize_script_tag_with_multiple_open_brackets + assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "&lt;" + assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), %(&lt;a) + end + + def test_should_sanitize_unclosed_script + assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>" + end + + def test_should_sanitize_half_open_scripts + assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>" + end + + def test_should_not_fall_for_ridiculous_hack + img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>) + assert_sanitized img_hack, "<img>" + end + + # fucked + def test_should_sanitize_attributes + assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>) + end + + def test_should_sanitize_illegal_style_properties + raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;) + expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;) + assert_equal expected, sanitize_css(raw) + end + + def test_should_sanitize_with_trailing_space + raw = "display:block; " + expected = "display: block;" + assert_equal expected, sanitize_css(raw) + end + + def test_should_sanitize_xul_style_attributes + raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_invalid_tag_names + assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f") + end + + def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags + assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>") + end + + def test_should_sanitize_invalid_tag_names_in_single_tags + assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />") + end + + def test_should_sanitize_img_dynsrc_lowsrc + assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />") + end + + def test_should_sanitize_div_background_image_unicode_encoded + raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_div_style_expression + raw = %(width: expression(alert('XSS'));) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_img_vbscript + assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />' + end + + def test_should_sanitize_cdata_section + assert_sanitized "<![CDATA[<span>section</span>]]>", "&lt;![CDATA[&lt;span>section&lt;/span>]]>" + end + + def test_should_sanitize_unterminated_cdata_section + assert_sanitized "<![CDATA[<span>neverending...", "&lt;![CDATA[&lt;span>neverending...]]>" + end + + def test_should_not_mangle_urls_with_ampersand + assert_sanitized %{<a href=\"http://www.domain.com?var1=1&amp;var2=2\">my link</a>} + end + +protected + def assert_sanitized(input, expected = nil) + @sanitizer ||= HTML::WhiteListSanitizer.new + if input + assert_dom_equal expected || input, @sanitizer.sanitize(input) + else + assert_nil @sanitizer.sanitize(input) + end + end + + def sanitize_css(input) + (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input) + end +end diff --git a/actionpack/test/html-scanner/tag_node_test.rb b/actionpack/test/html-scanner/tag_node_test.rb new file mode 100644 index 0000000000..d1d4667378 --- /dev/null +++ b/actionpack/test/html-scanner/tag_node_test.rb @@ -0,0 +1,238 @@ +require 'abstract_unit' + +class TagNodeTest < Test::Unit::TestCase + def test_open_without_attributes + node = tag("<tag>") + assert_equal "tag", node.name + assert_equal Hash.new, node.attributes + assert_nil node.closing + end + + def test_open_with_attributes + node = tag("<TAG1 foo=hey_ho x:bar=\"blah blah\" BAZ='blah blah blah' >") + assert_equal "tag1", node.name + assert_equal "hey_ho", node["foo"] + assert_equal "blah blah", node["x:bar"] + assert_equal "blah blah blah", node["baz"] + end + + def test_self_closing_without_attributes + node = tag("<tag/>") + assert_equal "tag", node.name + assert_equal Hash.new, node.attributes + assert_equal :self, node.closing + end + + def test_self_closing_with_attributes + node = tag("<tag a=b/>") + assert_equal "tag", node.name + assert_equal( { "a" => "b" }, node.attributes ) + assert_equal :self, node.closing + end + + def test_closing_without_attributes + node = tag("</tag>") + assert_equal "tag", node.name + assert_nil node.attributes + assert_equal :close, node.closing + end + + def test_bracket_op_when_no_attributes + node = tag("</tag>") + assert_nil node["foo"] + end + + def test_bracket_op_when_attributes + node = tag("<tag a=b/>") + assert_equal "b", node["a"] + end + + def test_attributes_with_escaped_quotes + node = tag("<tag a='b\\'c' b=\"bob \\\"float\\\"\">") + assert_equal "b\\'c", node["a"] + assert_equal "bob \\\"float\\\"", node["b"] + end + + def test_to_s + node = tag("<a b=c d='f' g=\"h 'i'\" />") + assert_equal %(<a b='c' d='f' g='h \\'i\\'' />), node.to_s + end + + def test_tag + assert tag("<tag>").tag? + end + + def test_match_tag_as_string + assert tag("<tag>").match(:tag => "tag") + assert !tag("<tag>").match(:tag => "b") + end + + def test_match_tag_as_regexp + assert tag("<tag>").match(:tag => /t.g/) + assert !tag("<tag>").match(:tag => /t[bqs]g/) + end + + def test_match_attributes_as_string + t = tag("<tag a=something b=else />") + assert t.match(:attributes => {"a" => "something"}) + assert t.match(:attributes => {"b" => "else"}) + end + + def test_match_attributes_as_regexp + t = tag("<tag a=something b=else />") + assert t.match(:attributes => {"a" => /^something$/}) + assert t.match(:attributes => {"b" => /e.*e/}) + assert t.match(:attributes => {"a" => /me..i/, "b" => /.ls.$/}) + end + + def test_match_attributes_as_number + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"a" => 15}) + assert t.match(:attributes => {"b" => 3.1415}) + assert t.match(:attributes => {"a" => 15, "b" => 3.1415}) + end + + def test_match_attributes_exist + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"a" => true}) + assert t.match(:attributes => {"b" => true}) + assert t.match(:attributes => {"a" => true, "b" => true}) + end + + def test_match_attributes_not_exist + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"c" => false}) + assert t.match(:attributes => {"c" => nil}) + assert t.match(:attributes => {"a" => true, "c" => false}) + end + + def test_match_parent_success + t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) + assert t.match(:parent => {:tag => "foo", :attributes => {"k" => /v.l/, "j" => false}}) + end + + def test_match_parent_fail + t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) + assert !t.match(:parent => {:tag => /kafka/}) + end + + def test_match_child_success + t = tag("<tag x:k='something'>") + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert t.match(:child => { :tag => "sib", :attributes => {"v" => /j/}}) + assert t.match(:child => { :attributes => {"a" => "kelly"}}) + end + + def test_match_child_fail + t = tag("<tag x:k='something'>") + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert !t.match(:child => { :tag => "sib", :attributes => {"v" => /r/}}) + assert !t.match(:child => { :attributes => {"v" => false}}) + end + + def test_match_ancestor_success + t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) + assert t.match(:ancestor => {:tag => "parent", :attributes => {"a" => /ll/}}) + assert t.match(:ancestor => {:attributes => {"m" => "vaughn"}}) + end + + def test_match_ancestor_fail + t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) + assert !t.match(:ancestor => {:tag => /^parent/, :attributes => {"v" => /m/}}) + assert !t.match(:ancestor => {:attributes => {"v" => false}}) + end + + def test_match_descendant_success + tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) + assert t.match(:descendant => {:tag => "child", :attributes => {"a" => /ll/}}) + assert t.match(:descendant => {:attributes => {"m" => "vaughn"}}) + end + + def test_match_descendant_fail + tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) + assert !t.match(:descendant => {:tag => /^child/, :attributes => {"v" => /m/}}) + assert !t.match(:descendant => {:attributes => {"v" => false}}) + end + + def test_match_child_count + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert t.match(:children => { :count => 2 }) + assert t.match(:children => { :count => 2..4 }) + assert t.match(:children => { :less_than => 4 }) + assert t.match(:children => { :greater_than => 1 }) + assert !t.match(:children => { :count => 3 }) + end + + def test_conditions_as_strings + t = tag("<tag x:k='something'>") + assert t.match("tag" => "tag") + assert t.match("attributes" => { "x:k" => "something" }) + assert !t.match("tag" => "gat") + assert !t.match("attributes" => { "x:j" => "something" }) + end + + def test_attributes_as_symbols + t = tag("<child v=john a=kelly>") + assert t.match(:attributes => { :v => /oh/ }) + assert t.match(:attributes => { :a => /ll/ }) + end + + def test_match_sibling + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:sibling => {:tag => "span", :attributes => {:a => true}}) + assert m.match(:sibling => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:sibling => {:tag => "span", :attributes => {:k => true}}) + end + + def test_match_sibling_before + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:before => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:before => {:tag => "span", :attributes => {:a => true}}) + assert !m.match(:before => {:tag => "span", :attributes => {:k => true}}) + end + + def test_match_sibling_after + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:after => {:tag => "span", :attributes => {:a => true}}) + assert !m.match(:after => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:after => {:tag => "span", :attributes => {:k => true}}) + end + + def test_to_s + t = tag("<b x='foo'>") + tag("hello", t) + tag("<hr />", t) + assert_equal %(<b x="foo">hello<hr /></b>), t.to_s + end + + private + + def tag(content, parent=nil) + node = HTML::Node.parse(parent,0,0,content) + parent.children << node if parent + node + end +end diff --git a/actionpack/test/html-scanner/text_node_test.rb b/actionpack/test/html-scanner/text_node_test.rb new file mode 100644 index 0000000000..1ab3f4454e --- /dev/null +++ b/actionpack/test/html-scanner/text_node_test.rb @@ -0,0 +1,50 @@ +require 'abstract_unit' + +class TextNodeTest < Test::Unit::TestCase + def setup + @node = HTML::Text.new(nil, 0, 0, "hello, howdy, aloha, annyeong") + end + + def test_to_s + assert_equal "hello, howdy, aloha, annyeong", @node.to_s + end + + def test_find_string + assert_equal @node, @node.find("hello, howdy, aloha, annyeong") + assert_equal false, @node.find("bogus") + end + + def test_find_regexp + assert_equal @node, @node.find(/an+y/) + assert_nil @node.find(/b/) + end + + def test_find_hash + assert_equal @node, @node.find(:content => /howdy/) + assert_nil @node.find(:content => /^howdy$/) + assert_equal false, @node.find(:content => "howdy") + end + + def test_find_other + assert_nil @node.find(:hello) + end + + def test_match_string + assert @node.match("hello, howdy, aloha, annyeong") + assert_equal false, @node.match("bogus") + end + + def test_match_regexp + assert_not_nil @node, @node.match(/an+y/) + assert_nil @node.match(/b/) + end + + def test_match_hash + assert_not_nil @node, @node.match(:content => "howdy") + assert_nil @node.match(:content => /^howdy$/) + end + + def test_match_other + assert_nil @node.match(:hello) + end +end diff --git a/actionpack/test/html-scanner/tokenizer_test.rb b/actionpack/test/html-scanner/tokenizer_test.rb new file mode 100644 index 0000000000..a001bcbbad --- /dev/null +++ b/actionpack/test/html-scanner/tokenizer_test.rb @@ -0,0 +1,131 @@ +require 'abstract_unit' + +class TokenizerTest < Test::Unit::TestCase + + def test_blank + tokenize "" + assert_end + end + + def test_space + tokenize " " + assert_next " " + assert_end + end + + def test_tag_simple_open + tokenize "<tag>" + assert_next "<tag>" + assert_end + end + + def test_tag_simple_self_closing + tokenize "<tag />" + assert_next "<tag />" + assert_end + end + + def test_tag_simple_closing + tokenize "</tag>" + assert_next "</tag>" + end + + def test_tag_with_single_quoted_attribute + tokenize %{<tag a='hello'>x} + assert_next %{<tag a='hello'>} + end + + def test_tag_with_single_quoted_attribute_with_escape + tokenize %{<tag a='hello\\''>x} + assert_next %{<tag a='hello\\''>} + end + + def test_tag_with_double_quoted_attribute + tokenize %{<tag a="hello">x} + assert_next %{<tag a="hello">} + end + + def test_tag_with_double_quoted_attribute_with_escape + tokenize %{<tag a="hello\\"">x} + assert_next %{<tag a="hello\\"">} + end + + def test_tag_with_unquoted_attribute + tokenize %{<tag a=hello>x} + assert_next %{<tag a=hello>} + end + + def test_tag_with_lt_char_in_attribute + tokenize %{<tag a="x < y">x} + assert_next %{<tag a="x < y">} + end + + def test_tag_with_gt_char_in_attribute + tokenize %{<tag a="x > y">x} + assert_next %{<tag a="x > y">} + end + + def test_doctype_tag + tokenize %{<!DOCTYPE "blah" "blah" "blah">\n <html>} + assert_next %{<!DOCTYPE "blah" "blah" "blah">} + assert_next %{\n } + assert_next %{<html>} + end + + def test_cdata_tag + tokenize %{<![CDATA[<br>]]>} + assert_next %{<![CDATA[<br>]]>} + assert_end + end + + def test_unterminated_cdata_tag + tokenize %{<content:encoded><![CDATA[ neverending...} + assert_next %{<content:encoded>} + assert_next %{<![CDATA[ neverending...} + assert_end + end + + def test_less_than_with_space + tokenize %{original < hello > world} + assert_next %{original } + assert_next %{< hello > world} + end + + def test_less_than_without_matching_greater_than + tokenize %{hello <span onmouseover="gotcha"\n<b>foo</b>\nbar</span>} + assert_next %{hello } + assert_next %{<span onmouseover="gotcha"\n} + assert_next %{<b>} + assert_next %{foo} + assert_next %{</b>} + assert_next %{\nbar} + assert_next %{</span>} + assert_end + end + + def test_unterminated_comment + tokenize %{hello <!-- neverending...} + assert_next %{hello } + assert_next %{<!-- neverending...} + assert_end + end + + private + + def tokenize(text) + @tokenizer = HTML::Tokenizer.new(text) + end + + def assert_next(expected, message=nil) + token = @tokenizer.next + assert_equal expected, token, message + end + + def assert_sequence(*expected) + assert_next expected.shift until expected.empty? + end + + def assert_end(message=nil) + assert_nil @tokenizer.next, message + end +end -- cgit v1.2.3 From fb64263c9181f247207919f1187934e29c4fe83c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Fri, 22 May 2009 17:22:30 -0700 Subject: Restore some missing test constants --- actionpack/test/new_base/abstract_unit.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/new_base/abstract_unit.rb b/actionpack/test/new_base/abstract_unit.rb index 5df2576916..e6690d41d9 100644 --- a/actionpack/test/new_base/abstract_unit.rb +++ b/actionpack/test/new_base/abstract_unit.rb @@ -35,6 +35,14 @@ end ActiveSupport::Dependencies.hook! +# Show backtraces for deprecated behavior for quicker cleanup. +ActiveSupport::Deprecation.debug = true + +# Register danish language for testing +I18n.backend.store_translations 'da', {} +I18n.backend.store_translations 'pt-BR', {} +ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort + FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), '../fixtures') module ActionController -- cgit v1.2.3 From 5097bd624110e190fee8033542db5d993a27696b Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> Date: Fri, 22 May 2009 17:25:55 -0700 Subject: Modify render_test's determine_layout to match RJS --- actionpack/test/controller/render_test.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index a750f018b8..9e42d1738a 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -625,9 +625,7 @@ class TestController < ActionController::Base "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" -- cgit v1.2.3 From 9286d422f8aff0aff8529edc93966fcab987c1af Mon Sep 17 00:00:00 2001 From: Pratik Naik <pratiknaik@gmail.com> Date: Sat, 23 May 2009 02:29:44 +0200 Subject: Add asset_host to Rails2Compatibility --- actionpack/lib/action_controller/new_base/compatibility.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 250e7f0dff..2bc76338b9 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -56,6 +56,12 @@ module ActionController 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" + @@asset_host = "" + cattr_accessor :asset_host end # For old tests -- cgit v1.2.3 From 3ac6d8f8b01fb04b8d6d35d75d802b41f4c256c9 Mon Sep 17 00:00:00 2001 From: Pratik Naik <pratiknaik@gmail.com> Date: Sat, 23 May 2009 02:35:34 +0200 Subject: Remove unnecessary asset_host initialization --- actionpack/lib/action_controller/base/base.rb | 1 - actionpack/lib/action_controller/new_base/compatibility.rb | 1 - 2 files changed, 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 2586037965..67369eb122 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -242,7 +242,6 @@ module ActionController #:nodoc: # 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. diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 2bc76338b9..b3190486e8 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -60,7 +60,6 @@ module ActionController # 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 end -- cgit v1.2.3 From e22a3d893ef8441fb52320315c5e348c6c208b69 Mon Sep 17 00:00:00 2001 From: Yehuda Katz <wycats@yehuda-katzs-macbookpro41.local> Date: Sat, 23 May 2009 00:39:32 -0700 Subject: Slightly modify things to get content type matching working without breaking other code --- actionpack/lib/action_controller/abstract/base.rb | 6 ++-- .../lib/action_controller/abstract/layouts.rb | 16 +++++------ actionpack/lib/action_dispatch/http/request.rb | 10 +++++-- actionpack/test/fixtures/test/greeting.erb | 1 - actionpack/test/fixtures/test/greeting.html.erb | 1 + actionpack/test/new_base/render_layout_test.rb | 32 ++++++++++++++++++++++ actionpack/test/new_base/test_helper.rb | 2 +- 7 files changed, 53 insertions(+), 15 deletions(-) delete mode 100644 actionpack/test/fixtures/test/greeting.erb create mode 100644 actionpack/test/fixtures/test/greeting.html.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 1f2f096dae..0e4803388a 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -68,11 +68,11 @@ module AbstractController 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) diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 8721e5f4dc..3d6810bda9 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -39,15 +39,15 @@ module AbstractController 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 @@ -60,7 +60,7 @@ module AbstractController private - def _layout() end # This will be overwritten + def _layout(details) end # This will be overwritten # :api: plugin # ==== @@ -79,13 +79,13 @@ module AbstractController end def _default_layout(require_layout = false, details = {:formats => formats}) - if require_layout && _action_has_layout? && !_layout + 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_for_name(_layout, details) if _action_has_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" diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 4831b89bde..259164d118 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -173,9 +173,15 @@ module ActionDispatch def formats if ActionController::Base.use_accept_header - Array(Mime[parameters[:format]] || accepts) + ret = Array(Mime[parameters[:format]] || accepts) + if defined?(ActionController::Http) + if all = ret.index(Mime::ALL) + ret.delete(Mime::ALL) && ret.insert(all, *Mime::SET) + end + end + ret else - [format, Mime[:all]] + [format] + Mime::SET end end diff --git a/actionpack/test/fixtures/test/greeting.erb b/actionpack/test/fixtures/test/greeting.erb deleted file mode 100644 index 62fb0293f0..0000000000 --- a/actionpack/test/fixtures/test/greeting.erb +++ /dev/null @@ -1 +0,0 @@ -<p>This is grand!</p> diff --git a/actionpack/test/fixtures/test/greeting.html.erb b/actionpack/test/fixtures/test/greeting.html.erb new file mode 100644 index 0000000000..62fb0293f0 --- /dev/null +++ b/actionpack/test/fixtures/test/greeting.html.erb @@ -0,0 +1 @@ +<p>This is grand!</p> diff --git a/actionpack/test/new_base/render_layout_test.rb b/actionpack/test/new_base/render_layout_test.rb index 76bd5175a3..f32c60d683 100644 --- a/actionpack/test/new_base/render_layout_test.rb +++ b/actionpack/test/new_base/render_layout_test.rb @@ -66,4 +66,36 @@ module ControllerLayouts assert_response "hai(layout_false.html.erb)" end end + + class MismatchFormatController < ::ApplicationController + self.view_paths = [ActionView::Template::FixturePath.new( + "layouts/application.html.erb" => "<html><%= yield %></html>", + "controller_layouts/mismatch_format/index.js.rjs" => "page[:test].omg", + "controller_layouts/mismatch_format/implicit.rjs" => "page[:test].omg" + )] + + def explicit + render :layout => "application" + end + end + + class MismatchFormatTest < SimpleRouteCase + testing ControllerLayouts::MismatchFormatController + + test "if JS is selected, an HTML template is not also selected" do + get :index + assert_response "$(\"test\").omg();" + end + + test "if JS is implicitly selected, an HTML template is not also selected" do + get :implicit + assert_response "$(\"test\").omg();" + end + + test "if an HTML template is explicitly provides for a JS template, an error is raised" do + assert_raises ActionView::MissingTemplate do + get :explicit, {}, "action_dispatch.show_exceptions" => false + end + end + end end \ No newline at end of file diff --git a/actionpack/test/new_base/test_helper.rb b/actionpack/test/new_base/test_helper.rb index 89c1290063..d92029df7f 100644 --- a/actionpack/test/new_base/test_helper.rb +++ b/actionpack/test/new_base/test_helper.rb @@ -67,7 +67,7 @@ class Rack::TestCase < ActionController::IntegrationTest def get(thing, *args) if thing.is_a?(Symbol) - super("#{self.class.testing}/#{thing}") + super("#{self.class.testing}/#{thing}", *args) else super end -- cgit v1.2.3 From e0ed4b7aa45cacba12ad5aeba23f71305579b395 Mon Sep 17 00:00:00 2001 From: Yehuda Katz <wycats@yehuda-katzs-macbookpro41.local> Date: Sat, 23 May 2009 01:30:25 -0700 Subject: Make a couple more tests pass. A large number of the remaining failing tests have to do with the semantics of filters that are Objects. The right solution is probably to just implement the filter/before/after semantics in NewCallbacks directly (the current semantics are based on the old AS::Callbacks specs) --- actionpack/lib/action_controller/abstract/callbacks.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 51b968c694..e4f9dd3112 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -36,6 +36,17 @@ module AbstractController 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 -- cgit v1.2.3 From 4e3fd23e311cd1773e62e7971f0f47af05d5000a Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Fri, 22 May 2009 17:59:28 -0700 Subject: test depends on html-scanner --- actionpack/test/controller/integration_test.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index eae6835714..197ba0c69c 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'action_controller/vendor/html-scanner' class SessionTest < Test::Unit::TestCase StubApp = lambda { |env| -- cgit v1.2.3 From a78b0a40c62600767d6ce75ba05bc86d401ad94c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Sat, 23 May 2009 19:00:06 -0700 Subject: runner class --- actionpack/examples/minimal.rb | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index 76668b375d..0fc527445e 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -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 @@ class BaseController < ActionController::Base end end -n = (ENV['N'] || 1000).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 }) + def call(env) + env['n'].to_i.times { @app.call(env) } + @app.call(env).tap { |response| report(env, response) } + end - puts status - puts headers.to_yaml - puts '---' - body.each do |part| - puts part + 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] -- cgit v1.2.3 From 6e039e863a5d71f2a516be2eef2605be23281290 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Sat, 23 May 2009 19:11:14 -0700 Subject: Speed up Request#formats --- actionpack/lib/action_dispatch/http/request.rb | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 259164d118..140feb9a68 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -3,7 +3,9 @@ require 'stringio' 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,15 +175,21 @@ module ActionDispatch def formats if ActionController::Base.use_accept_header - ret = Array(Mime[parameters[:format]] || accepts) - if defined?(ActionController::Http) - if all = ret.index(Mime::ALL) - ret.delete(Mime::ALL) && ret.insert(all, *Mime::SET) + 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 - ret else - [format] + Mime::SET + [format] + Mime::SET end end -- cgit v1.2.3 From bdb61c1dadd64ad4e146228ac8048fd0034fa8cc Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Sun, 24 May 2009 17:34:40 -0700 Subject: Compare Base with Http --- actionpack/examples/minimal.rb | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index 0fc527445e..e2d112648c 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -7,12 +7,6 @@ require 'action_controller' require 'action_controller/new_base' if ENV['NEW'] require 'benchmark' -class BaseController < ActionController::Base - def index - render :text => '' - end -end - class Runner def initialize(app) @app = app @@ -29,14 +23,31 @@ class Runner response[2].each { |part| out.puts part } out.puts '---' end + + def self.run(app, n) + env = { 'n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout } + t = Benchmark.realtime { new(app).call(env) } + puts "%d ms / %d req = %d usec/req" % [10**3 * t, n, 10**6 * t / n] + end +end + + +N = (ENV['N'] || 1000).to_i + +class BasePostController < ActionController::Base + def index + render :text => '' + end + + Runner.run(action(:index), N) end -n = (ENV['N'] || 1000).to_i -input = StringIO.new('') +if ActionController.const_defined?(:Http) + class HttpPostController < ActionController::Http + def index + self.response_body = '' + end -elapsed = Benchmark.realtime do - Runner.new(BaseController.action(:index)). - call('n' => n, 'rack.input' => input, 'rack.errors' => $stdout) + Runner.run(action(:index), N) + end end -puts "%dms elapsed, %d req/sec, %.2f msec/req" % - [1000 * elapsed, n / elapsed, 1000 * elapsed / n] -- cgit v1.2.3 From b1d4fb71bf890793133fab8e4226952865fd468b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Sun, 24 May 2009 17:35:49 -0700 Subject: Construct a single HeaderHash. Speed up assign_default_content_type_and_charset --- actionpack/lib/action_dispatch/http/response.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index edb522ff49..a01114b730 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -41,8 +41,7 @@ module ActionDispatch # :nodoc: delegate :default_charset, :to => 'ActionController::Base' def initialize - super - @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS) + super([], 200, DEFAULT_HEADERS) end # The response code of the request @@ -162,8 +161,15 @@ module ActionDispatch # :nodoc: end def assign_default_content_type_and_charset! - self.content_type ||= Mime::HTML - self.charset ||= default_charset unless sending_file? + if type = headers['Content-Type'] + unless type =~ /charset=/ || sending_file? + headers['Content-Type'] = "#{type}; charset=#{default_charset}" + end + else + type = Mime::HTML.to_s + type += "; charset=#{default_charset}" unless sending_file? + headers['Content-Type'] = type + end end def prepare! -- cgit v1.2.3 From 8097da93ccbfaec82e7785ded7b3e68c8248b32f Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Sun, 24 May 2009 19:25:53 -0700 Subject: Don't want Rack's Content-Type default header though --- actionpack/lib/action_dispatch/http/response.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index a01114b730..b9db7a4508 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -41,7 +41,8 @@ module ActionDispatch # :nodoc: delegate :default_charset, :to => 'ActionController::Base' def initialize - super([], 200, DEFAULT_HEADERS) + super + @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS) end # The response code of the request @@ -161,7 +162,7 @@ module ActionDispatch # :nodoc: end def assign_default_content_type_and_charset! - if type = headers['Content-Type'] + if type = headers['Content-Type'] || headers['type'] unless type =~ /charset=/ || sending_file? headers['Content-Type'] = "#{type}; charset=#{default_charset}" end -- cgit v1.2.3 From 9cda410d818353a5c27cbd5df754f1d1e290927d Mon Sep 17 00:00:00 2001 From: Pratik Naik <pratiknaik@gmail.com> Date: Mon, 25 May 2009 16:52:44 +0200 Subject: Make cookie store tests pass with the new base --- actionpack/test/dispatch/session/cookie_store_test.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 3090a70244..2db76818ac 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -5,6 +5,9 @@ class CookieStoreTest < ActionController::IntegrationTest SessionKey = '_myapp_session' SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33' + # Make sure Session middleware doesnt get included in the middleware stack + ActionController::Base.session_store = nil + DispatcherApp = ActionController::Dispatcher.new CookieStoreApp = ActionDispatch::Session::CookieStore.new(DispatcherApp, :key => SessionKey, :secret => SessionSecret) -- cgit v1.2.3 From 10085114ce7ec6bc967fa701c49ef218f666efb5 Mon Sep 17 00:00:00 2001 From: Pratik Naik <pratiknaik@gmail.com> Date: Mon, 25 May 2009 18:05:58 +0200 Subject: Make Filter#filter work with around filters --- .../lib/action_controller/caching/actions.rb | 24 +++-- .../action_controller/new_base/compatibility.rb | 2 +- .../lib/action_controller/new_base/testing.rb | 8 ++ actionpack/test/controller/filters_test.rb | 113 ++++++++++----------- 4 files changed, 76 insertions(+), 71 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 430db3932f..3646ff1af9 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -63,7 +63,7 @@ module ActionController #:nodoc: cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options) # TODO: Remove this once new base is swapped in. - if defined?(Http) + if defined?(ActionController::Http) around_filter cache_filter, filter_options else around_filter(filter_options) do |controller, action| @@ -92,16 +92,18 @@ module ActionController #:nodoc: 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) + if defined?(ActionController::Http) + def around_process_action(controller) + should_continue = before(controller) + yield if should_continue + after(controller) + end + else + def filter(controller, action) + should_continue = before(controller) + action.call if should_continue + after(controller) + end end def before(controller) diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index b3190486e8..4245ba982b 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -83,7 +83,7 @@ module ActionController @@cache_store = ActiveSupport::Cache.lookup_store(store_option) end end - + def initialize(*) super @template = _action_view diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index d8c3421587..78051a6252 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -1,5 +1,6 @@ module ActionController module Testing + extend ActiveSupport::DependencyModule # OMG MEGA HAX def process_with_new_base_test(request, response) @@ -26,5 +27,12 @@ module ActionController @_response ||= ActionDispatch::Response.new @_response.headers.replace(new_headers) end + + module ClassMethods + def before_filters + _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name} + end + end + end end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 22aa50adb2..bdcc24b371 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -8,8 +8,7 @@ class << ActionController::Base end end -class FilterTest < Test::Unit::TestCase - include ActionController::TestProcess +class FilterTest < ActionController::TestCase class TestController < ActionController::Base before_filter :ensure_login @@ -468,108 +467,108 @@ class FilterTest < Test::Unit::TestCase def test_running_filters test_process(PrependingController) - assert_equal %w( wonderful_life ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( wonderful_life ensure_login ), assigns["ran_filter"] end def test_running_filters_with_proc test_process(ProcController) - assert @controller.template.assigns["ran_proc_filter"] + assert assigns["ran_proc_filter"] end def test_running_filters_with_implicit_proc test_process(ImplicitProcController) - assert @controller.template.assigns["ran_proc_filter"] + assert assigns["ran_proc_filter"] end def test_running_filters_with_class test_process(AuditController) - assert @controller.template.assigns["was_audited"] + assert assigns["was_audited"] end def test_running_anomolous_yet_valid_condition_filters test_process(AnomolousYetValidConditionController) - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] - assert @controller.template.assigns["ran_class_filter"] - assert @controller.template.assigns["ran_proc_filter1"] - assert @controller.template.assigns["ran_proc_filter2"] + assert_equal %w( ensure_login ), assigns["ran_filter"] + assert assigns["ran_class_filter"] + assert assigns["ran_proc_filter1"] + assert assigns["ran_proc_filter2"] test_process(AnomolousYetValidConditionController, "show_without_filter") - assert_equal nil, @controller.template.assigns["ran_filter"] - assert !@controller.template.assigns["ran_class_filter"] - assert !@controller.template.assigns["ran_proc_filter1"] - assert !@controller.template.assigns["ran_proc_filter2"] + assert_equal nil, assigns["ran_filter"] + assert !assigns["ran_class_filter"] + assert !assigns["ran_proc_filter1"] + assert !assigns["ran_proc_filter2"] end def test_running_conditional_options test_process(ConditionalOptionsFilter) - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login ), assigns["ran_filter"] end def test_running_collection_condition_filters test_process(ConditionalCollectionFilterController) - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(ConditionalCollectionFilterController, "show_without_filter") - assert_equal nil, @controller.template.assigns["ran_filter"] + assert_equal nil, assigns["ran_filter"] test_process(ConditionalCollectionFilterController, "another_action") - assert_equal nil, @controller.template.assigns["ran_filter"] + assert_equal nil, assigns["ran_filter"] end def test_running_only_condition_filters test_process(OnlyConditionSymController) - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(OnlyConditionSymController, "show_without_filter") - assert_equal nil, @controller.template.assigns["ran_filter"] + assert_equal nil, assigns["ran_filter"] test_process(OnlyConditionProcController) - assert @controller.template.assigns["ran_proc_filter"] + assert assigns["ran_proc_filter"] test_process(OnlyConditionProcController, "show_without_filter") - assert !@controller.template.assigns["ran_proc_filter"] + assert !assigns["ran_proc_filter"] test_process(OnlyConditionClassController) - assert @controller.template.assigns["ran_class_filter"] + assert assigns["ran_class_filter"] test_process(OnlyConditionClassController, "show_without_filter") - assert !@controller.template.assigns["ran_class_filter"] + assert !assigns["ran_class_filter"] end def test_running_except_condition_filters test_process(ExceptConditionSymController) - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(ExceptConditionSymController, "show_without_filter") - assert_equal nil, @controller.template.assigns["ran_filter"] + assert_equal nil, assigns["ran_filter"] test_process(ExceptConditionProcController) - assert @controller.template.assigns["ran_proc_filter"] + assert assigns["ran_proc_filter"] test_process(ExceptConditionProcController, "show_without_filter") - assert !@controller.template.assigns["ran_proc_filter"] + assert !assigns["ran_proc_filter"] test_process(ExceptConditionClassController) - assert @controller.template.assigns["ran_class_filter"] + assert assigns["ran_class_filter"] test_process(ExceptConditionClassController, "show_without_filter") - assert !@controller.template.assigns["ran_class_filter"] + assert !assigns["ran_class_filter"] end def test_running_before_and_after_condition_filters test_process(BeforeAndAfterConditionController) - assert_equal %w( ensure_login clean_up_tmp), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"] test_process(BeforeAndAfterConditionController, "show_without_filter") - assert_equal nil, @controller.template.assigns["ran_filter"] + assert_equal nil, assigns["ran_filter"] end def test_around_filter test_process(AroundFilterController) - assert @controller.template.assigns["before_ran"] - assert @controller.template.assigns["after_ran"] + assert assigns["before_ran"] + assert assigns["after_ran"] end def test_before_after_class_filter test_process(BeforeAfterClassFilterController) - assert @controller.template.assigns["before_ran"] - assert @controller.template.assigns["after_ran"] + assert assigns["before_ran"] + assert assigns["after_ran"] end def test_having_properties_in_around_filter test_process(AroundFilterController) - assert_equal "before and after", @controller.template.assigns["execution_log"] + assert_equal "before and after", assigns["execution_log"] end def test_prepending_and_appending_around_filter @@ -582,7 +581,7 @@ class FilterTest < Test::Unit::TestCase def test_rendering_breaks_filtering_chain response = test_process(RenderingController) assert_equal "something else", response.body - assert !@controller.template.assigns["ran_action"] + assert !assigns["ran_action"] end def test_filters_with_mixed_specialization_run_in_order @@ -608,26 +607,26 @@ class FilterTest < Test::Unit::TestCase def test_running_prepended_before_and_after_filter test_process(PrependingBeforeAndAfterController) - assert_equal %w( before_all between_before_all_and_after_all after_all ), @controller.template.assigns["ran_filter"] + assert_equal %w( before_all between_before_all_and_after_all after_all ), assigns["ran_filter"] end def test_skipping_and_limiting_controller test_process(SkippingAndLimitedController, "index") - assert_equal %w( ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(SkippingAndLimitedController, "public") - assert_nil @controller.template.assigns["ran_filter"] + assert_nil assigns["ran_filter"] end def test_skipping_and_reordering_controller test_process(SkippingAndReorderingController, "index") - assert_equal %w( find_record ensure_login ), @controller.template.assigns["ran_filter"] + assert_equal %w( find_record ensure_login ), assigns["ran_filter"] end def test_conditional_skipping_of_filters test_process(ConditionalSkippingController, "login") - assert_nil @controller.template.assigns["ran_filter"] + assert_nil assigns["ran_filter"] test_process(ConditionalSkippingController, "change_password") - assert_equal %w( ensure_login find_user ), @controller.template.assigns["ran_filter"] + assert_equal %w( ensure_login find_user ), assigns["ran_filter"] test_process(ConditionalSkippingController, "login") assert_nil @controller.template.controller.instance_variable_get("@ran_after_filter") @@ -637,23 +636,23 @@ class FilterTest < Test::Unit::TestCase def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'] + assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'] test_process(ChildOfConditionalParentController, 'another_action') - assert_nil @controller.template.assigns['ran_filter'] + assert_nil assigns['ran_filter'] end def test_condition_skipping_of_filters_when_siblings_also_have_conditions test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'], "1" + assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'], "1" test_process(AnotherChildOfConditionalParentController) - assert_equal nil, @controller.template.assigns['ran_filter'] + assert_equal nil, assigns['ran_filter'] test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), @controller.template.assigns['ran_filter'] + assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'] end def test_changing_the_requirements test_process(ChangingTheRequirementsController, "go_wild") - assert_equal nil, @controller.template.assigns['ran_filter'] + assert_equal nil, assigns['ran_filter'] end def test_a_rescuing_around_filter @@ -806,9 +805,8 @@ class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters skip_filter :after end -class YieldingAroundFiltersTest < Test::Unit::TestCase +class YieldingAroundFiltersTest < ActionController::TestCase include PostsController::AroundExceptions - include ActionController::TestProcess def test_base controller = PostsController @@ -846,8 +844,8 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase def test_with_proc test_process(ControllerWithProcFilter,'no_raise') - assert @controller.template.assigns['before'] - assert @controller.template.assigns['after'] + assert assigns['before'] + assert assigns['after'] end def test_nested_filters @@ -868,12 +866,12 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase def test_filter_order_with_all_filter_types test_process(ControllerWithAllTypesOfFilters,'no_raise') - assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after', @controller.template.assigns['ran_filter'].join(' ') + assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after', assigns['ran_filter'].join(' ') end def test_filter_order_with_skip_filter_method test_process(ControllerWithTwoLessFilters,'no_raise') - assert_equal 'before around (before yield) around (after yield)', @controller.template.assigns['ran_filter'].join(' ') + assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ') end def test_first_filter_in_multiple_before_filter_chain_halts @@ -903,9 +901,6 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase protected def test_process(controller, action = "show") @controller = controller.is_a?(Class) ? controller.new : controller - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - process(action) end end -- cgit v1.2.3 From cd8fb1800df0b65b33b1efd5e5159e1810dfe504 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 11:47:42 -0700 Subject: Remove a no-op from view path tests and removed a Symbol#to_proc --- actionpack/test/controller/view_paths_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index 0ac10634b2..c732d1c910 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -22,7 +22,7 @@ class ViewLoadPathsTest < ActionController::TestCase end def setup - TestController.view_paths = nil + # TestController.view_paths = nil @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @@ -48,7 +48,7 @@ class ViewLoadPathsTest < ActionController::TestCase def assert_paths(*paths) controller = paths.first.is_a?(Class) ? paths.shift : @controller - assert_equal expand(paths), controller.view_paths.map(&:to_s) + assert_equal expand(paths), controller.view_paths.map { |p| p.to_s } end def test_template_load_path_was_set_correctly -- cgit v1.2.3 From cbb0724f0d0d51a8097ba707517dcf1d09b07a31 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 12:06:48 -0700 Subject: In new base Rails2Compatibility, move @template assignment to right before the first action is processed. --- actionpack/lib/action_controller/new_base/compatibility.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 4245ba982b..646e69843e 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -69,7 +69,12 @@ module ActionController # TODO: Remove this after we flip def template - _action_view + @template ||= _action_view + end + + def process_action(*) + template + super end module ClassMethods @@ -83,11 +88,6 @@ module ActionController @@cache_store = ActiveSupport::Cache.lookup_store(store_option) end end - - def initialize(*) - super - @template = _action_view - end def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) -- cgit v1.2.3 From 09907d1b933d202333280fb2efc079f8bf969e16 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 12:14:50 -0700 Subject: Get controller/view_paths_test.rb to pass on new base --- actionpack/Rakefile | 4 ++-- actionpack/lib/action_controller/abstract/renderer.rb | 4 ++++ actionpack/lib/action_controller/new_base/compatibility.rb | 13 +++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 9ce897aae8..d10e8b94a7 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -66,7 +66,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # * filters # * integration # * test - # * view_paths t.test_files = %w( action_pack_assertions addresses_render assert_select base benchmark caching capture content_type cookie dispatcher @@ -74,7 +73,8 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| 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 + resources routing selector send_file url_rewriter + verification view_paths webservice ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index d7c68549e1..7f7ec78054 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -86,6 +86,10 @@ module AbstractController self.view_paths << path end + def prepend_view_path(path) + self.view_paths.unshift(path) + end + def view_paths self._view_paths end diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 646e69843e..fddfadcbf2 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -116,5 +116,18 @@ module ActionController def performed? response_body end + + # ==== Request only view path switching ==== + def append_view_path(path) + view_paths.push(*path) + end + + def prepend_view_path(path) + view_paths.unshift(*path) + end + + def view_paths + _action_view.view_paths + end end end -- cgit v1.2.3 From 7dd094329eee01cf9d18e4141226357eb8f75c76 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 13:40:58 -0700 Subject: Add html-scanner to the new base set of autoloads --- actionpack/lib/action_controller/new_base.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 276be50614..e9e89769f1 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -40,5 +40,7 @@ module ActionController require 'action_controller/routing' end +autoload :HTML, 'action_controller/vendor/html-scanner' + require 'action_dispatch' require 'action_view' -- cgit v1.2.3 From a3ca5638d365113028610141f025839bb3ed738b Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 14:13:35 -0700 Subject: Get controller/test_test.rb to pass on new base --- actionpack/Rakefile | 3 +-- actionpack/lib/action_controller/testing/process2.rb | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index d10e8b94a7..41882e99f1 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -65,7 +65,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # ==== Not ported # * filters # * integration - # * test t.test_files = %w( action_pack_assertions addresses_render assert_select base benchmark caching capture content_type cookie dispatcher @@ -73,7 +72,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| 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 + resources routing selector send_file test url_rewriter verification view_paths webservice ).map { |name| "test/controller/#{name}_test.rb" } t.verbose = true diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 677dd41781..1c6fd2d80a 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -51,9 +51,10 @@ module ActionController @request.session = ActionController::TestSession.new(session) unless session.nil? @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash - build_request_uri(action, parameters) + @controller.request = @request @controller.params.merge!(parameters) + build_request_uri(action, parameters) # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest @controller.process_with_new_base_test(@request, @response) @response -- cgit v1.2.3 From 1358f77745c7a4afab0dab7796aa63072c9d323a Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 14:24:22 -0700 Subject: Add controller/integration_test.rb to the new base test runner --- actionpack/Rakefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 41882e99f1..a70d4834c0 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -64,12 +64,11 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # ==== Not ported # * filters - # * integration 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 + http_digest_authentication integration 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 test url_rewriter -- cgit v1.2.3 From a1f280e83d2b134e23897d4de457d76fb0095768 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 15:03:09 -0700 Subject: Got all the dispatch tests running on new base --- actionpack/Rakefile | 8 ++++---- actionpack/lib/action_controller/new_base/compatibility.rb | 3 +++ actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 11 ++++++----- actionpack/test/dispatch/show_exceptions_test.rb | 4 ++-- 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index a70d4834c0..c44c88f638 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -59,12 +59,13 @@ 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 + + t.verbose = true # ==== Not ported # * filters - t.test_files = %w( + + # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + + t.test_files = Dir.glob( "test/{dispatch}/**/*_test.rb" ).sort + %w( action_pack_assertions addresses_render assert_select base benchmark caching capture content_type cookie dispatcher filter_params flash helper http_basic_authentication @@ -74,7 +75,6 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| resources routing selector send_file test url_rewriter verification view_paths webservice ).map { |name| "test/controller/#{name}_test.rb" } - t.verbose = true end # Genereate the RDoc documentation diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index fddfadcbf2..c09e086b1b 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -61,6 +61,9 @@ module ActionController # 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 + + cattr_accessor :ip_spoofing_check + self.ip_spoofing_check = true end # For old tests diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 4d598669c7..1bd6a86bec 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -10,7 +10,8 @@ module ActionDispatch @@rescue_responses = Hash.new(:internal_server_error) @@rescue_responses.update({ 'ActionController::RoutingError' => :not_found, - 'ActionController::UnknownAction' => :not_found, + # TODO: Clean this up after the switch + ActionController::UnknownAction.name => :not_found, 'ActiveRecord::RecordNotFound' => :not_found, 'ActiveRecord::StaleObjectError' => :conflict, 'ActiveRecord::RecordInvalid' => :unprocessable_entity, @@ -23,10 +24,10 @@ module ActionDispatch 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' + 'ActionView::MissingTemplate' => 'missing_template', + 'ActionController::RoutingError' => 'routing_error', + ActionController::UnknownAction.name => 'unknown_action', + 'ActionView::TemplateError' => 'template_error' }) FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'}, diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 0c0c087340..ce1973853e 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -61,7 +61,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest get "/not_found" assert_response 404 - assert_match /ActionController::UnknownAction/, body + assert_match /#{ActionController::UnknownAction.name}/, body get "/method_not_allowed" assert_response 405 @@ -99,7 +99,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest get "/not_found" assert_response 404 - assert_match /ActionController::UnknownAction/, body + assert_match /#{ActionController::UnknownAction.name}/, body get "/method_not_allowed" assert_response 405 -- cgit v1.2.3 From 7211048b2b1d640c4f33587b57261bdfe9c77b93 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Tue, 26 May 2009 15:19:39 -0700 Subject: Get all template tests passing on new base --- actionpack/Rakefile | 3 +-- actionpack/lib/action_controller/new_base/base.rb | 2 +- actionpack/test/template/body_parts_test.rb | 5 ++++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index c44c88f638..5f5614e58f 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -64,8 +64,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t| # ==== Not ported # * filters - # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + - t.test_files = Dir.glob( "test/{dispatch}/**/*_test.rb" ).sort + %w( + t.test_files = Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + %w( action_pack_assertions addresses_render assert_select base benchmark caching capture content_type cookie dispatcher filter_params flash helper http_basic_authentication diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index ffe608ade4..3477fc0403 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -40,7 +40,7 @@ module ActionController module ImplicitRender def process_action(method_name) ret = super - default_render if response_body.nil? + default_render unless performed? ret end diff --git a/actionpack/test/template/body_parts_test.rb b/actionpack/test/template/body_parts_test.rb index e17092a452..4e7aa63f96 100644 --- a/actionpack/test/template/body_parts_test.rb +++ b/actionpack/test/template/body_parts_test.rb @@ -4,6 +4,9 @@ class BodyPartsTest < ActionController::TestCase RENDERINGS = [Object.new, Object.new, Object.new] class TestController < ActionController::Base + def performed? + defined?(ActionController::Http) ? true : super + end def index RENDERINGS.each do |rendering| @template.punctuate_body! rendering @@ -16,7 +19,7 @@ class BodyPartsTest < ActionController::TestCase def test_body_parts get :index - pending do + pending(:old_base) do # TestProcess buffers body_parts into body # TODO: Rewrite test w/o going through process assert_equal RENDERINGS, @response.body_parts -- cgit v1.2.3 From 311d686d031bbc7074bddd8d56ea42780a204b35 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Wed, 27 May 2009 01:00:02 -0500 Subject: add a metal to minimal examples for comparison --- actionpack/examples/minimal.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index e2d112648c..9eb92cd8e7 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -24,10 +24,12 @@ class Runner out.puts '---' end - def self.run(app, n) + def self.run(app, n, label = nil) + puts '=' * label.size, label, '=' * label.size if label env = { 'n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout } t = Benchmark.realtime { new(app).call(env) } - puts "%d ms / %d req = %d usec/req" % [10**3 * t, n, 10**6 * t / n] + puts "%d ms / %d req = %.1f usec/req" % [10**3 * t, n, 10**6 * t / n] + puts end end @@ -38,16 +40,19 @@ class BasePostController < ActionController::Base def index render :text => '' end - - Runner.run(action(:index), N) end +OK = [200, {}, []] +MetalPostController = lambda { OK } + if ActionController.const_defined?(:Http) class HttpPostController < ActionController::Http def index self.response_body = '' end - - Runner.run(action(:index), N) end end + +Runner.run(MetalPostController, N, 'metal') +Runner.run(HttpPostController.action(:index), N, 'http') if defined? HttpPostController +Runner.run(BasePostController.action(:index), N, 'base') -- cgit v1.2.3 From 6bbe965ccdcef2d7e713e65175722718d325b2bd Mon Sep 17 00:00:00 2001 From: Yehuda Katz <wycats@yehuda-katzs-macbookpro41.local> Date: Wed, 27 May 2009 10:40:43 +0200 Subject: Reduce the cost of using ActionController::Http significantly by: * Removing the dependency on AD::Request and AD::Response * Moving the logic for the request and response object into a new module that is included by default. * Changing Renderer and Redirector to use self.headers, self.content_type, and self.status, which have very basic default implementations on AC::Http. When RackConvenience is included (which it is by default on AC::Base), the full Request/Response logic is used instead of the simple logic. --- actionpack/lib/action_controller/new_base.rb | 1 + actionpack/lib/action_controller/new_base/base.rb | 1 + .../action_controller/new_base/conditional_get.rb | 3 ++ actionpack/lib/action_controller/new_base/http.rb | 42 +++++++++++++++------- .../action_controller/new_base/rack_convenience.rb | 34 ++++++++++++++++++ .../lib/action_controller/new_base/redirector.rb | 4 +-- .../action_controller/new_base/render_options.rb | 8 ++--- .../lib/action_controller/new_base/renderer.rb | 13 +++---- .../lib/action_controller/new_base/session.rb | 4 +++ .../lib/action_controller/new_base/testing.rb | 2 ++ .../lib/action_controller/new_base/url_for.rb | 4 +++ 11 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 actionpack/lib/action_controller/new_base/rack_convenience.rb (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index e9e89769f1..df256985ac 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -4,6 +4,7 @@ module ActionController autoload :HideActions, "action_controller/new_base/hide_actions" autoload :Http, "action_controller/new_base/http" autoload :Layouts, "action_controller/new_base/layouts" + autoload :RackConvenience, "action_controller/new_base/rack_convenience" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Redirector, "action_controller/new_base/redirector" autoload :Renderer, "action_controller/new_base/renderer" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 3477fc0403..6fe7793030 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -14,6 +14,7 @@ module ActionController include ActionController::Renderers::All include ActionController::Layouts include ActionController::ConditionalGet + include ActionController::RackConvenience # Legacy modules include SessionManagement diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index 116ce34494..7d41ee6371 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -1,5 +1,8 @@ module ActionController module ConditionalGet + extend ActiveSupport::DependencyModule + + depends_on RackConvenience # Sets the etag, last_modified, or both on the response and renders a # "304 Not Modified" response if the request is already fresh. diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 2525e221a6..7ff490bb9c 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -6,7 +6,7 @@ module ActionController abstract! # :api: public - attr_internal :request, :response, :params + attr_internal :params, :env # :api: public def self.controller_name @@ -36,32 +36,48 @@ module ActionController controller.call(env).to_rack end - delegate :headers, :to => "@_response" + # The details below can be overridden to support a specific + # Request and Response object. The default ActionController::Base + # implementation includes RackConvenience, which makes a request + # and response object available. You might wish to control the + # environment and response manually for performance reasons. - def params - @_params ||= @_request.parameters + attr_internal :status, :headers, :content_type + + def initialize(*) + @_headers = {} + super + end + + # Basic implements for content_type=, location=, and headers are + # provided to reduce the dependency on the RackConvenience module + # in Renderer and Redirector. + + def content_type=(type) + headers["Content-Type"] = type.to_s + end + + def location=(url) + headers["Location"] = url end # :api: private def call(name, env) - @_request = ActionDispatch::Request.new(env) - @_response = ActionDispatch::Response.new - @_response.request = request + @_env = env process(name) to_rack end + # :api: private + def to_rack + [status, headers, response_body] + end + def self.action(name) @actions ||= {} @actions[name.to_s] ||= proc do |env| new.call(name, env) end end - - # :api: private - def to_rack - @_response.prepare! - @_response.to_a - end end end diff --git a/actionpack/lib/action_controller/new_base/rack_convenience.rb b/actionpack/lib/action_controller/new_base/rack_convenience.rb new file mode 100644 index 0000000000..0422ab2f14 --- /dev/null +++ b/actionpack/lib/action_controller/new_base/rack_convenience.rb @@ -0,0 +1,34 @@ +module ActionController + module RackConvenience + extend ActiveSupport::DependencyModule + + included do + delegate :headers, :status=, :location=, + :status, :location, :content_type, :to => "@_response" + attr_internal :request, :response + end + + def call(name, env) + @_request = ActionDispatch::Request.new(env) + @_response = ActionDispatch::Response.new + @_response.request = request + super + end + + def params + @_params ||= @_request.parameters + end + + # :api: private + def to_rack + @_response.prepare! + @_response.to_a + end + + def response_body=(body) + response.body = body if response + super + end + + end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/redirector.rb b/actionpack/lib/action_controller/new_base/redirector.rb index ff7b74341c..b2da412edf 100644 --- a/actionpack/lib/action_controller/new_base/redirector.rb +++ b/actionpack/lib/action_controller/new_base/redirector.rb @@ -11,8 +11,8 @@ module ActionController def redirect_to(url, status) #:doc: raise AbstractController::DoubleRenderError if response_body logger.info("Redirected to #{url}") if logger && logger.info? - response.status = status - response.location = url.gsub(/[\r\n]/, '') + self.status = status + self.location = url.gsub(/[\r\n]/, '') self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>" end end diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 581a92cb7b..48575ec0bd 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -57,7 +57,7 @@ module ActionController 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.content_type ||= Mime::JSON self.response_body = json end end @@ -67,7 +67,7 @@ module ActionController register_renderer :js def _render_js(js, options) - response.content_type ||= Mime::JS + self.content_type ||= Mime::JS self.response_body = js end end @@ -77,7 +77,7 @@ module ActionController register_renderer :xml def _render_xml(xml, options) - response.content_type ||= Mime::XML + self.content_type ||= Mime::XML self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml end end @@ -88,7 +88,7 @@ module ActionController def _render_update(proc, options) generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(_action_view, &proc) - response.content_type = Mime::JS + self.content_type = Mime::JS self.response_body = generator.to_s end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 987751a601..fb6fe4aee6 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -8,16 +8,11 @@ module ActionController 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 + self.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 @@ -76,9 +71,9 @@ module ActionController def _process_options(options) 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 + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location end end end diff --git a/actionpack/lib/action_controller/new_base/session.rb b/actionpack/lib/action_controller/new_base/session.rb index a8715555fb..9ee3e9e136 100644 --- a/actionpack/lib/action_controller/new_base/session.rb +++ b/actionpack/lib/action_controller/new_base/session.rb @@ -1,5 +1,9 @@ module ActionController module Session + extend ActiveSupport::DependencyModule + + depends_on RackConvenience + def session @_request.session end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 78051a6252..596f613a13 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -2,6 +2,8 @@ module ActionController module Testing extend ActiveSupport::DependencyModule + depends_on RackConvenience + # OMG MEGA HAX def process_with_new_base_test(request, response) @_request = request diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index 94de9fab50..e6e5d3acce 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -1,5 +1,9 @@ module ActionController module UrlFor + extend ActiveSupport::DependencyModule + + depends_on RackConvenience + def process_action(*) initialize_current_url super -- cgit v1.2.3 From bb8e5843f32b13e759da51a4713a31b23ebcac6d Mon Sep 17 00:00:00 2001 From: Niels Ganser <niels@herimedia.com> Date: Wed, 27 May 2009 14:51:33 -0500 Subject: ActionController::Flash::FlashHash.use now returns either the value corresponding to the passed key or itself when no key is passed [#1792 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- actionpack/lib/action_controller/base/chained/flash.rb | 11 +++++------ actionpack/test/controller/flash_test.rb | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/chained/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb index 6bd482d85a..7a8dd2dcf9 100644 --- a/actionpack/lib/action_controller/base/chained/flash.rb +++ b/actionpack/lib/action_controller/base/chained/flash.rb @@ -135,12 +135,11 @@ module ActionController #:nodoc: # use('msg') # marks the "msg" entry as used # use(nil, false) # marks the entire flash as unused (keeps it around for one more action) # use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action) - def use(k=nil, v=true) - unless k.nil? - @used[k] = v - else - keys.each{ |key| use(key, v) } - end + # Returns the single value for the key you asked to be marked (un)used or the FlashHash itself + # if no key is passed. + def use(key = nil, used = true) + Array(key || keys).each { |k| @used[k] = used } + return key ? self[key] : self end end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 84e27d7779..ee215bb19e 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -140,4 +140,19 @@ class FlashTest < ActionController::TestCase get :std_action assert_nil assigns["flash_copy"]["foo"] end + + def test_keep_and_discard_return_values + flash = ActionController::Flash::FlashHash.new + flash.update(:foo => :foo_indeed, :bar => :bar_indeed) + + assert_equal(:foo_indeed, flash.discard(:foo)) # valid key passed + assert_nil flash.discard(:unknown) # non existant key passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard()) # nothing passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard(nil)) # nothing passed + + assert_equal(:foo_indeed, flash.keep(:foo)) # valid key passed + assert_nil flash.keep(:unknown) # non existant key passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep()) # nothing passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed + end end -- cgit v1.2.3 From 61c471eebb3718a3ef5741e1e4d0974be7483290 Mon Sep 17 00:00:00 2001 From: Eduard Bondarenko <edbond@gmail.com> Date: Wed, 27 May 2009 14:53:05 -0500 Subject: Add % to RESERVED_PCHAR [#2574 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- actionpack/lib/action_controller/routing/segments.rb | 2 +- actionpack/test/controller/routing_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 4f936d51d2..2603855476 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -1,7 +1,7 @@ module ActionController module Routing class Segment #:nodoc: - RESERVED_PCHAR = ':@&=+$,;' + RESERVED_PCHAR = ':@&=+$,;%' SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}" if RUBY_VERSION >= '1.9' UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 11bffdb42e..1694fc8f3e 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -90,6 +90,11 @@ class StaticSegmentTest < Test::Unit::TestCase assert_equal 'Hello World', s.interpolation_chunk end + def test_value_should_not_be_double_unescaped + s = ROUTING::StaticSegment.new('%D0%9A%D0%B0%D1%80%D1%82%D0%B0') # Карта + assert_equal '%D0%9A%D0%B0%D1%80%D1%82%D0%B0', s.interpolation_chunk + end + def test_regexp_chunk_should_escape_specials s = ROUTING::StaticSegment.new('Hello*World') assert_equal 'Hello\*World', s.regexp_chunk -- cgit v1.2.3 From 760cb633396a954b465ec0dd0344915185bddec1 Mon Sep 17 00:00:00 2001 From: "Hongli Lai (Phusion)" <hongli@phusion.nl> Date: Wed, 27 May 2009 15:01:03 -0500 Subject: Make the default 500 Internal Server Error page more friendly. Many people don't know they're supposed to look in the log files. [#2716 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 1bd6a86bec..bfff307669 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -31,7 +31,10 @@ module ActionDispatch }) FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'}, - ['<html><body><h1>500 Internal Server Error</h1></body></html>']] + ["<html><body><h1>500 Internal Server Error</h1>" << + "If you are the administrator of this website, then please read this web " << + "application's log file and/or the web server's log file to find out what " << + "went wrong.</body></html>"]] def initialize(app, consider_all_requests_local = false) @app = app -- cgit v1.2.3 From a5688fa9073dc8824d98071346e6cd9ae417eb72 Mon Sep 17 00:00:00 2001 From: Carl Lerche <carllerche@mac.com> Date: Wed, 27 May 2009 11:02:13 -0700 Subject: Add the ability to prepend filters to new callbacks --- actionpack/lib/action_controller/abstract/callbacks.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index e4f9dd3112..83dd06bf8b 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -37,6 +37,15 @@ module AbstractController end end + def prepend_#{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| + process_action_callback(:#{filter}, name, options.merge(:prepend => true)) + end + end + def skip_#{filter}_filter(*names, &blk) options = names.last.is_a?(Hash) ? names.pop : {} _normalize_callback_options(options) -- cgit v1.2.3 From e70bd6bdfae3615a013cf6252efdea3d94c5b64c Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> Date: Wed, 27 May 2009 15:59:14 -0700 Subject: Added hook point in new base #send_action which does the actual action method dispatching --- actionpack/lib/action_controller/abstract/base.rb | 4 +++- actionpack/lib/action_controller/new_base/base.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 0e4803388a..bbd42623d3 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -95,9 +95,11 @@ module AbstractController # overrides it to include the case where a template matching the # action_name is found. def process_action(method_name) - send(method_name) + send_action(method_name) end + alias send_action send + def _handle_action_missing action_missing(@_action_name) end diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 6fe7793030..f8aaf05387 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -39,7 +39,7 @@ module ActionController # TODO: Extract into its own module # This should be moved together with other normalizing behavior module ImplicitRender - def process_action(method_name) + def send_action(method_name) ret = super default_render unless performed? ret -- cgit v1.2.3 From bd7e3dc47d8ab4da1028c9c18c94474178f84bdd Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> Date: Wed, 27 May 2009 16:43:25 -0700 Subject: Added a compatibility layer to get legacy filter tests to pass on new base --- actionpack/test/controller/filters_test.rb | 32 +++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index bdcc24b371..b0b7274690 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -1,10 +1,32 @@ require 'abstract_unit' +require 'active_support/core_ext/symbol' -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) +class ActionController::Base + class << self + %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 + + if defined?(ActionController::Http) + def before_filters + filters = _process_action_callbacks.select { |c| c.kind == :before } + filters.map! { |c| c.instance_variable_get(:@raw_filter) } + end + end + end + + if defined?(ActionController::Http) + def assigns(key = nil) + assigns = {} + instance_variable_names.each do |ivar| + next if ActionController::Base.protected_instance_variables.include?(ivar) + assigns[ivar[1..-1]] = instance_variable_get(ivar) + end + + key.nil? ? assigns : assigns[key.to_s] + end end end -- cgit v1.2.3 From f2f58f535520bfa77ab2d0ad1fb598f18349dd2e Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> Date: Wed, 27 May 2009 17:31:48 -0700 Subject: Fix failing ActionCacheFilter tests due to around filter changes. --- actionpack/lib/action_controller/caching/actions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 3646ff1af9..54148b55d8 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -93,7 +93,7 @@ module ActionController #:nodoc: # TODO: Remove once New Base is merged if defined?(ActionController::Http) - def around_process_action(controller) + def filter(controller) should_continue = before(controller) yield if should_continue after(controller) -- cgit v1.2.3 From 0349278f3da9f7f532330cf295eed35ede3bae66 Mon Sep 17 00:00:00 2001 From: Olly Legg <olly@51degrees.net> Date: Thu, 28 May 2009 09:18:27 -0500 Subject: Memoize cookies so that updates to cookies are available in the current request. [#2733 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- actionpack/lib/action_controller/base/cookies.rb | 2 +- actionpack/test/controller/cookie_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/cookies.rb b/actionpack/lib/action_controller/base/cookies.rb index ca380e98d0..d4806623c3 100644 --- a/actionpack/lib/action_controller/base/cookies.rb +++ b/actionpack/lib/action_controller/base/cookies.rb @@ -51,7 +51,7 @@ module ActionController #:nodoc: protected # Returns the cookie container, which operates as described above. def cookies - CookieJar.new(self) + @cookies ||= CookieJar.new(self) end end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 39d0017dd8..7199da3441 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -123,6 +123,12 @@ class CookieTest < ActionController::TestCase assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT" end + def test_cookies_persist_throughout_request + get :authenticate + cookies = @controller.send(:cookies) + assert_equal 'david', cookies['user_name'] + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] -- cgit v1.2.3 From 72cb6f58be6590ac2590eea420a1b3ef175189b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20S=C3=B6rensen?= <johan@johansorensen.com> Date: Thu, 28 May 2009 09:30:49 -0500 Subject: The FlashHash and friends causes a lot of needless session storing, when we know for a fact that there's no content in the flash. By not storing the empty hash in the session we save a lot of communication with the various session backends, while still keeping the same interface to the flash. [#2703 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- .../lib/action_controller/base/chained/flash.rb | 70 ++++++++++++---------- actionpack/test/controller/flash_test.rb | 7 ++- 2 files changed, 43 insertions(+), 34 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base/chained/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb index 7a8dd2dcf9..2d084ba1ab 100644 --- a/actionpack/lib/action_controller/base/chained/flash.rb +++ b/actionpack/lib/action_controller/base/chained/flash.rb @@ -30,7 +30,7 @@ module ActionController #:nodoc: # 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) @@ -129,6 +129,11 @@ module ActionController #:nodoc: (@used.keys - keys).each{ |k| @used.delete(k) } end + def store(session, key = "flash") + return if self.empty? + session[key] = self + end + private # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods # use() # marks the entire flash as used @@ -145,48 +150,47 @@ module ActionController #:nodoc: module InstanceMethodsForBase #:nodoc: protected + def perform_action_with_flash + perform_action_without_flash + if defined? @_flash + @_flash.store(session) + remove_instance_variable(:@_flash) + end + end - 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 reset_session_with_flash + reset_session_without_flash + remove_instance_variable(:@_flash) if defined?(@_flash) + end end module InstanceMethodsForNewBase #:nodoc: protected + def process_action(method_name) + super + if defined? @_flash + @_flash.store(session) + remove_instance_variable(:@_flash) + end + end - 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 + def reset_session + super + 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: + if !defined?(@_flash) + @_flash = session["flash"] || FlashHash.new + @_flash.sweep + 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 + @_flash end - - @_flash - end end end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index ee215bb19e..c448f36cb3 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -122,7 +122,7 @@ class FlashTest < ActionController::TestCase 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", assigns["flashy_that"] @@ -130,6 +130,11 @@ class FlashTest < ActionController::TestCase assert_nil assigns["flashy_that_reset"] end + def test_does_not_set_the_session_if_the_flash_is_empty + get :std_action + assert_nil session["flash"] + end + def test_sweep_after_halted_filter_chain get :std_action assert_nil assigns["flash_copy"]["foo"] -- cgit v1.2.3 From dd98280e38d640f5724887cf8a715b79f0439d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20S=C3=B6rensen?= <johan@johansorensen.com> Date: Thu, 28 May 2009 09:35:17 -0500 Subject: Only save the session if we're actually writing to it [#2703 state:resolved] Signed-off-by: Joshua Peek <josh@joshpeek.com> --- .../middleware/session/abstract_store.rb | 11 ++++++++++- .../test/activerecord/active_record_store_test.rb | 22 ++++++++++++++++++++++ .../test/dispatch/session/mem_cache_store_test.rb | 8 ++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 03761b10bd..6d109f4624 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -15,6 +15,7 @@ module ActionDispatch @by = by @env = env @loaded = false + @updated = false end def session_id @@ -32,6 +33,7 @@ module ActionDispatch def []=(key, value) load! unless @loaded super(key.to_s, value) + @updated = true end def to_hash @@ -79,6 +81,10 @@ module ActionDispatch @loaded end + def updated? + @updated + end + def load! stale_session_check! do id, session = @by.send(:load_session, @env) @@ -147,7 +153,10 @@ module ActionDispatch options = env[ENV_SESSION_OPTIONS_KEY] if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after] - session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?) + if session_data.is_a?(AbstractStore::SessionHash) + session_data.send(:load!) if !session_data.send(:loaded?) + return response if !session_data.send(:updated?) + end sid = options[:id] || generate_sid diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 47f8496181..9ac33b3417 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -22,6 +22,11 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest render :text => "foo: #{session[:foo].inspect}" end + def set_cookie_and_get_session_value + cookies["kittens"] = { :value => "fluffy" } + render :text => "foo: #{session[:foo].inspect}" + end + def get_session_id session[:foo] render :text => "#{request.session_options[:id]}" @@ -78,6 +83,23 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end end + def test_getting_session_value_does_not_set_cookie + with_test_route_set do + get '/get_session_value' + assert_response :success + assert_equal "", headers["Set-Cookie"] + end + end + + def test_getting_session_value_and_setting_a_cookie_doesnt_delete_all_cookies + with_test_route_set do + get '/set_cookie_and_get_session_value' + assert_response :success + assert_equal 'foo: nil', response.body + assert_equal({"kittens" => "fluffy"}, response.cookies) + end + end + def test_setting_session_value_after_session_reset with_test_route_set do get '/set_session_value' diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 7561c93e4a..278f2c83ea 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -61,6 +61,14 @@ class MemCacheStoreTest < ActionController::IntegrationTest end end + def test_getting_session_value_does_not_set_cookie + with_test_route_set do + get '/get_session_value' + assert_response :success + assert_equal "", headers["Set-Cookie"] + end + end + def test_setting_session_value_after_session_reset with_test_route_set do get '/set_session_value' -- cgit v1.2.3 From de203245afd2bbf7f93f3241fcf3a71a88101d47 Mon Sep 17 00:00:00 2001 From: Joshua Peek <josh@joshpeek.com> Date: Thu, 28 May 2009 09:49:02 -0500 Subject: Revert "Revert "Whitespace!"" This reverts commit 0cac68d3bed3e6bf8ec2eb994858e4a179046941. --- actionpack/lib/action_controller/abstract.rb | 2 +- actionpack/lib/action_controller/abstract/base.rb | 34 ++++----- .../lib/action_controller/abstract/benchmarker.rb | 6 +- .../lib/action_controller/abstract/callbacks.rb | 8 +- .../lib/action_controller/abstract/exceptions.rb | 4 +- .../lib/action_controller/abstract/helpers.rb | 9 +-- .../lib/action_controller/abstract/layouts.rb | 25 ++++--- .../lib/action_controller/abstract/logger.rb | 12 +-- .../lib/action_controller/abstract/renderer.rb | 24 +++--- actionpack/lib/action_controller/new_base/base.rb | 18 ++--- .../action_controller/new_base/compatibility.rb | 34 +++++---- .../action_controller/new_base/conditional_get.rb | 29 ++++---- .../lib/action_controller/new_base/helpers.rb | 49 ++++++------- .../lib/action_controller/new_base/hide_actions.rb | 46 +++++++----- actionpack/lib/action_controller/new_base/http.rb | 38 ++++++---- .../lib/action_controller/new_base/layouts.rb | 38 +++++----- .../action_controller/new_base/rack_convenience.rb | 15 ++-- .../lib/action_controller/new_base/redirector.rb | 4 +- .../action_controller/new_base/render_options.rb | 16 ++-- .../lib/action_controller/new_base/renderer.rb | 85 +++++++++++----------- .../lib/action_controller/new_base/rescuable.rb | 29 ++++---- .../lib/action_controller/new_base/testing.rb | 3 +- .../lib/action_controller/new_base/url_for.rb | 6 +- 23 files changed, 270 insertions(+), 264 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index d6b7a44f5f..f46b91627f 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -11,4 +11,4 @@ module AbstractController autoload :Renderer, "action_controller/abstract/renderer" # === Exceptions autoload :ActionNotFound, "action_controller/abstract/exceptions" -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index bbd42623d3..87083a4d79 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -2,28 +2,27 @@ require 'active_support/core_ext/module/attr_internal' module AbstractController class Error < StandardError; end - + class DoubleRenderError < Error DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." def initialize(message = nil) super(message || DEFAULT_MESSAGE) end - end - + end + class Base - attr_internal :response_body attr_internal :response_obj attr_internal :action_name class << self - attr_reader :abstract - + attr_reader :abstract + def abstract! @abstract = true end - + alias_method :abstract?, :abstract def inherited(klass) @@ -34,13 +33,13 @@ module AbstractController def subclasses @subclasses ||= [] end - + def internal_methods controller = self controller = controller.superclass until controller.abstract? controller.public_instance_methods(true) end - + def process(action) new.process(action.to_s) end @@ -48,7 +47,7 @@ module AbstractController def hidden_actions [] end - + def action_methods @action_methods ||= # All public instance methods of this class, including ancestors @@ -61,13 +60,13 @@ module AbstractController hidden_actions end end - + abstract! - + def initialize self.response_obj = {} end - + def process(action) @_action_name = action_name = action.to_s @@ -78,17 +77,16 @@ module AbstractController process_action(action_name) self end - + private - def action_methods self.class.action_methods end - + def action_method?(action) action_methods.include?(action) end - + # It is possible for respond_to?(action_name) to be false and # respond_to?(:action_missing) to be false if respond_to_action? # is overridden in a subclass. For instance, ActionController::Base @@ -114,4 +112,4 @@ module AbstractController end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/benchmarker.rb b/actionpack/lib/action_controller/abstract/benchmarker.rb index 9f5889c704..9be06f48fb 100644 --- a/actionpack/lib/action_controller/abstract/benchmarker.rb +++ b/actionpack/lib/action_controller/abstract/benchmarker.rb @@ -1,9 +1,9 @@ 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 @@ -25,4 +25,4 @@ module AbstractController end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 83dd06bf8b..4314235ba9 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -13,7 +13,7 @@ module AbstractController super end end - + module ClassMethods def _normalize_callback_options(options) if only = options[:only] @@ -21,11 +21,11 @@ module AbstractController options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") + except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") options[:per_key] = {:unless => except} end end - + [:before, :after, :around].each do |filter| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{filter}_filter(*names, &blk) @@ -60,4 +60,4 @@ module AbstractController end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb index ec4680629b..2f6c55f068 100644 --- a/actionpack/lib/action_controller/abstract/exceptions.rb +++ b/actionpack/lib/action_controller/abstract/exceptions.rb @@ -1,3 +1,3 @@ module AbstractController - class ActionNotFound < StandardError ; end -end \ No newline at end of file + class ActionNotFound < StandardError; end +end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 41decfd0c7..7b1b197e1d 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -16,12 +16,12 @@ module AbstractController av end end - + module ClassMethods def inherited(klass) klass.master_helper_module = Module.new klass.master_helper_module.__send__ :include, master_helper_module - + super end @@ -57,7 +57,7 @@ module AbstractController ruby_eval end end - + def helper(*args, &block) args.flatten.each do |arg| case arg @@ -68,6 +68,5 @@ module AbstractController master_helper_module.module_eval(&block) if block_given? end end - end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 3d6810bda9..dd38485271 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -17,18 +17,18 @@ module AbstractController 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 end - + def _implied_layout_name name.underscore end - + # Takes the specified layout and creates a _layout method to be called # by _default_layout - # + # # If the specified layout is a: # String:: return the string # Symbol:: call the method specified by the symbol @@ -57,11 +57,12 @@ module AbstractController end end end - + private - - def _layout(details) end # This will be overwritten - + # This will be overwritten + def _layout(details) + end + # :api: plugin # ==== # Override this to mutate the inbound layout name @@ -69,7 +70,7 @@ module AbstractController 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, details, _layout_prefix(name)) end @@ -77,7 +78,7 @@ module AbstractController def _layout_prefix(name) "layouts" end - + def _default_layout(require_layout = false, details = {:formats => formats}) if require_layout && _action_has_layout? && !_layout(details) raise ArgumentError, @@ -87,7 +88,7 @@ module AbstractController begin _layout_for_name(_layout(details), details) if _action_has_layout? rescue NameError => e - raise NoMethodError, + raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end end @@ -103,4 +104,4 @@ module AbstractController end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 980ede0bed..ce73888763 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -9,7 +9,7 @@ module AbstractController def initialize(&blk) @blk = blk end - + def to_s @blk.call end @@ -19,10 +19,10 @@ module AbstractController included do cattr_accessor :logger end - + def process(action) ret = super - + if logger log = DelayedLog.new do "\n\nProcessing #{self.class.name}\##{action_name} " \ @@ -32,14 +32,14 @@ module AbstractController logger.info(log) end - + ret end - + def request_origin # this *needs* to be cached! # otherwise you'd get different results if calling it more than once @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}" - end + end end end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index 7f7ec78054..374ceb5b74 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -15,22 +15,22 @@ module AbstractController end def _action_view - @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) + @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - + def render(*args) if response_body raise AbstractController::DoubleRenderError, "OMG" end - + self.response_body = render_to_body(*args) end - + # Raw rendering of a template to a Rack-compatible body. # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_body(options = {}) # TODO: Refactor so we can just use the normal template logic for this @@ -46,7 +46,7 @@ module AbstractController # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_string(options = {}) AbstractController::Renderer.body_to_s(render_to_body(options)) @@ -55,8 +55,10 @@ module AbstractController def _render_template(options) _action_view._render_template_from_controller(options[:_template], options[:_layout], options, options[:_partial]) end - - def view_paths() _view_paths end + + def view_paths() + _view_paths + end # Return a string representation of a Rack-compatible response body. def self.body_to_s(body) @@ -71,7 +73,6 @@ module AbstractController end private - def _determine_template(options) name = (options[:_template_name] || action_name).to_s @@ -81,11 +82,10 @@ module AbstractController end module ClassMethods - def append_view_path(path) self.view_paths << path end - + def prepend_view_path(path) self.view_paths.unshift(path) end @@ -93,7 +93,7 @@ module AbstractController def view_paths self._view_paths end - + def view_paths=(paths) self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index f8aaf05387..d7b65d37fa 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,7 +1,7 @@ module ActionController class Base < Http abstract! - + include AbstractController::Benchmarker include AbstractController::Callbacks include AbstractController::Logger @@ -66,31 +66,31 @@ module ActionController ::ActionController::Base.subclasses << klass.to_s super end - + def self.subclasses @subclasses ||= [] end - + def self.app_loaded! @subclasses.each do |subclass| subclass.constantize._write_layout_method end end - + def _normalize_options(action = nil, options = {}, &blk) if action.is_a?(Hash) - options, action = action, nil + options, action = action, nil elsif action.is_a?(String) || action.is_a?(Symbol) key = case action = action.to_s when %r{^/} then :file when %r{/} then :template else :action - end + end options.merge! key => action elsif action options.merge! :partial => action end - + if options.key?(:action) && options[:action].to_s.index("/") options[:template] = options.delete(:action) end @@ -140,7 +140,7 @@ module ActionController # # When using <tt>redirect_to :back</tt>, if there is no referrer, # RedirectBackError will be raised. You may specify some fallback - # behavior for this case by rescuing RedirectBackError. + # behavior for this case by rescuing RedirectBackError. def redirect_to(options = {}, response_status = {}) #:doc: raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? @@ -166,7 +166,7 @@ module ActionController else url_for(options) end - + super(url, status) end end diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index c09e086b1b..1d0cb601e3 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -9,43 +9,43 @@ module ActionController included do ::ActionController::UnknownAction = ::AbstractController::ActionNotFound ::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError - + cattr_accessor :session_options self.session_options = {} - + cattr_accessor :allow_concurrency self.allow_concurrency = false - + cattr_accessor :param_parsers self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form, Mime::URL_ENCODED_FORM => :url_encoded_form, Mime::XML => :xml_simple, Mime::JSON => :json } - + cattr_accessor :relative_url_root self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] - + cattr_accessor :default_charset self.default_charset = "utf-8" - + # cattr_reader :protected_instance_variables cattr_accessor :protected_instance_variables self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params @_flash @_response) - + # Indicates whether or not optimise the generated named # route helper methods cattr_accessor :optimise_named_routes self.optimise_named_routes = true - + cattr_accessor :resources_path_names self.resources_path_names = { :new => 'new', :edit => 'edit' } - + # Controls the resource action separator cattr_accessor :resource_action_separator self.resource_action_separator = "/" - + cattr_accessor :use_accept_header self.use_accept_header = true @@ -65,7 +65,7 @@ module ActionController cattr_accessor :ip_spoofing_check self.ip_spoofing_check = true end - + # For old tests def initialize_template_class(*) end def assign_shortcuts(*) end @@ -81,7 +81,9 @@ module ActionController end module ClassMethods - def consider_all_requests_local() end + def consider_all_requests_local + end + def rescue_action(env) raise env["action_dispatch.rescue.exception"] end @@ -91,12 +93,12 @@ module ActionController @@cache_store = ActiveSupport::Cache.lookup_store(store_option) end end - + def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') end - + options[:text] = nil if options[:nothing] == true body = super @@ -110,8 +112,8 @@ module ActionController def method_for_action(action_name) super || (respond_to?(:method_missing) && "_handle_method_missing") - end - + end + def _layout_prefix(name) super unless name =~ /\blayouts/ end diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index 7d41ee6371..38f3d3cf68 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -3,13 +3,13 @@ module ActionController extend ActiveSupport::DependencyModule depends_on RackConvenience - + # Sets the etag, last_modified, or both on the response and renders a # "304 Not Modified" response if the request is already fresh. # # Parameters: # * <tt>:etag</tt> - # * <tt>:last_modified</tt> + # * <tt>:last_modified</tt> # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). # # Example: @@ -21,14 +21,14 @@ module ActionController # # This will render the show template if the request isn't sending a matching etag or # If-Modified-Since header and just a "304 Not Modified" response if there's a match. - # + # def fresh_when(options) options.assert_valid_keys(:etag, :last_modified, :public) response.etag = options[:etag] if options[:etag] response.last_modified = options[:last_modified] if options[:last_modified] - - if options[:public] + + if options[:public] cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } cache_control.delete("private") cache_control.delete("no-cache") @@ -39,8 +39,8 @@ module ActionController if request.fresh?(response) head :not_modified end - end - + end + # Return a response that has no content (merely headers). The options # argument is interpreted to be a hash of header names and values. # This allows you to easily return a response that consists only of @@ -67,8 +67,8 @@ module ActionController end render :nothing => true, :status => status - end - + end + # Sets the etag and/or last_modified on the response and checks it against # the client request. If the request doesn't match the options provided, the # request is considered stale and should be generated from scratch. Otherwise, @@ -76,7 +76,7 @@ module ActionController # # Parameters: # * <tt>:etag</tt> - # * <tt>:last_modified</tt> + # * <tt>:last_modified</tt> # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). # # Example: @@ -95,7 +95,7 @@ module ActionController fresh_when(options) !request.fresh?(response) end - + # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that # intermediate caches shouldn't cache the response. # @@ -117,10 +117,10 @@ module ActionController else cache_control << "private" end - + # This allows for additional headers to be passed through like 'max-stale' => 5.hours cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"} - + response.headers["Cache-Control"] = cache_control.join(', ') end @@ -129,6 +129,5 @@ module ActionController def expires_now #:doc: response.headers["Cache-Control"] = "no-cache" end - end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/helpers.rb b/actionpack/lib/action_controller/new_base/helpers.rb index e00c3c338b..1dece13114 100644 --- a/actionpack/lib/action_controller/new_base/helpers.rb +++ b/actionpack/lib/action_controller/new_base/helpers.rb @@ -24,10 +24,10 @@ module ActionController # # * <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 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 @@ -40,17 +40,17 @@ module ActionController # <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 + # 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" + # 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 } @@ -106,25 +106,24 @@ module ActionController 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 + 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 - 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 + # 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 end end diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index a29b09a893..10b8b582f5 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -7,27 +7,33 @@ module ActionController self.hidden_actions ||= Set.new end - def action_methods() self.class.action_names end - def action_names() action_methods end - - private - - def action_method?(action_name) - !hidden_actions.include?(action_name) && super + def action_methods + self.class.action_names end - - module ClassMethods - def hide_action(*args) - args.each do |arg| - self.hidden_actions << arg.to_s - end - end - - def action_methods - @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) - end - def self.action_names() action_methods end + def action_names + action_methods end + + private + def action_method?(action_name) + !hidden_actions.include?(action_name) && super + end + + module ClassMethods + def hide_action(*args) + args.each do |arg| + self.hidden_actions << arg.to_s + end + end + + def action_methods + @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) + end + + def self.action_names + action_methods + end + end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 7ff490bb9c..c96aaaa865 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -4,7 +4,7 @@ require 'active_support/core_ext/module/delegation' module ActionController class Http < AbstractController::Base abstract! - + # :api: public attr_internal :params, :env @@ -14,28 +14,36 @@ module ActionController end # :api: public - def controller_name() self.class.controller_name end + def controller_name + self.class.controller_name + end - # :api: public + # :api: public def self.controller_path @controller_path ||= self.name.sub(/Controller$/, '').underscore end - - # :api: public - def controller_path() self.class.controller_path end - - # :api: private - def self.action_names() action_methods end - + + # :api: public + def controller_path + self.class.controller_path + end + # :api: private - def action_names() action_methods end - + def self.action_names + action_methods + end + + # :api: private + def action_names + action_methods + end + # :api: plugin def self.call(env) controller = new controller.call(env).to_rack end - + # The details below can be overridden to support a specific # Request and Response object. The default ActionController::Base # implementation includes RackConvenience, which makes a request @@ -60,14 +68,14 @@ module ActionController def location=(url) headers["Location"] = url end - + # :api: private def call(name, env) @_env = env process(name) to_rack end - + # :api: private def to_rack [status, headers, response_body] diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index 35068db770..9b4057caaa 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -4,33 +4,31 @@ module ActionController depends_on ActionController::Renderer depends_on AbstractController::Layouts - + module ClassMethods def _implied_layout_name controller_path end 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) + 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 - end - - def _layout_for_option(name, details) - case name - 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, - "String, true, or false, expected for `layout'; you passed #{name.inspect}" + + def _layout_for_option(name, details) + case name + 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, + "String, true, or false, expected for `layout'; you passed #{name.inspect}" + end end - end - end end diff --git a/actionpack/lib/action_controller/new_base/rack_convenience.rb b/actionpack/lib/action_controller/new_base/rack_convenience.rb index 0422ab2f14..e465acca6e 100644 --- a/actionpack/lib/action_controller/new_base/rack_convenience.rb +++ b/actionpack/lib/action_controller/new_base/rack_convenience.rb @@ -1,34 +1,33 @@ module ActionController module RackConvenience extend ActiveSupport::DependencyModule - + included do - delegate :headers, :status=, :location=, + delegate :headers, :status=, :location=, :status, :location, :content_type, :to => "@_response" attr_internal :request, :response end - + def call(name, env) @_request = ActionDispatch::Request.new(env) @_response = ActionDispatch::Response.new @_response.request = request super end - + def params @_params ||= @_request.parameters end - + # :api: private def to_rack @_response.prepare! @_response.to_a end - + def response_body=(body) response.body = body if response super end - end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/redirector.rb b/actionpack/lib/action_controller/new_base/redirector.rb index b2da412edf..20060b001f 100644 --- a/actionpack/lib/action_controller/new_base/redirector.rb +++ b/actionpack/lib/action_controller/new_base/redirector.rb @@ -6,7 +6,7 @@ module ActionController super(message || DEFAULT_MESSAGE) end end - + module Redirector def redirect_to(url, status) #:doc: raise AbstractController::DoubleRenderError if response_body @@ -16,4 +16,4 @@ module ActionController self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>" end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 48575ec0bd..f12198a710 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -1,12 +1,12 @@ 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| @@ -17,25 +17,25 @@ module ActionController 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 @@ -53,13 +53,13 @@ module ActionController 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? self.content_type ||= Mime::JSON self.response_body = json - end + end end module Js diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index fb6fe4aee6..737a0d6fcf 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -3,7 +3,7 @@ module ActionController extend ActiveSupport::DependencyModule depends_on AbstractController::Renderer - + def process_action(*) self.formats = request.formats.map {|x| x.to_sym} super @@ -21,7 +21,7 @@ module ActionController def render_to_body(options) _process_options(options) - + if options.key?(:partial) _render_partial(options[:partial], options) end @@ -29,51 +29,50 @@ module ActionController super end - private + private + def _prefix + controller_path + end - def _prefix - controller_path - end + def _determine_template(options) + if options.key?(:text) + 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, {}) + options[:_template] = template + elsif options.key?(:template) + options[:_template_name] = options[:template] + elsif options.key?(:file) + options[:_template_name] = options[:file] + elsif !options.key?(:partial) + options[:_template_name] = (options[:action] || action_name).to_s + options[:_prefix] = _prefix + end - def _determine_template(options) - if options.key?(:text) - 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, {}) - options[:_template] = template - elsif options.key?(:template) - options[:_template_name] = options[:template] - elsif options.key?(:file) - options[:_template_name] = options[:file] - elsif !options.key?(:partial) - options[:_template_name] = (options[:action] || action_name).to_s - options[:_prefix] = _prefix + super end - - super - end - def _render_partial(partial, options) - case partial - when true - options[:_prefix] = _prefix - when String - options[:_prefix] = _prefix unless partial.index('/') - options[:_template_name] = partial - else - options[:_partial_object] = true - return + def _render_partial(partial, options) + case partial + when true + options[:_prefix] = _prefix + when String + options[:_prefix] = _prefix unless partial.index('/') + options[:_template_name] = partial + else + options[:_partial_object] = true + return + end + + options[:_partial] = options[:object] || true + end + + def _process_options(options) + status, content_type, location = options.values_at(:status, :content_type, :location) + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location end - - options[:_partial] = options[:object] || true - end - - def _process_options(options) - status, content_type, location = options.values_at(:status, :content_type, :location) - self.status = status if status - self.content_type = content_type if content_type - self.headers["Location"] = url_for(location) if location - end end end diff --git a/actionpack/lib/action_controller/new_base/rescuable.rb b/actionpack/lib/action_controller/new_base/rescuable.rb index 29ffe19d5f..4450a1131a 100644 --- a/actionpack/lib/action_controller/new_base/rescuable.rb +++ b/actionpack/lib/action_controller/new_base/rescuable.rb @@ -32,22 +32,21 @@ module ActionController #:nodoc: attr_internal :rescued_exception - private - - def method_for_action(action_name) - return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception") - super - end + private + def method_for_action(action_name) + return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception") + super + end - def _rescue_action - rescue_with_handler(rescued_exception) || raise(rescued_exception) - end + def _rescue_action + rescue_with_handler(rescued_exception) || raise(rescued_exception) + end - def process_action(*) - super - rescue Exception => exception - self.rescued_exception = exception - _rescue_action - end + def process_action(*) + super + rescue Exception => exception + self.rescued_exception = exception + _rescue_action + end end end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 596f613a13..97aadfe78f 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -15,7 +15,7 @@ module ActionController set_test_assigns ret end - + def set_test_assigns @assigns = {} (instance_variable_names - self.class.protected_instance_variables).each do |var| @@ -35,6 +35,5 @@ module ActionController _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name} end end - end end diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index e6e5d3acce..87bc689134 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -25,7 +25,7 @@ module ActionController # by this method. def default_url_options(options = nil) end - + def rewrite_options(options) #:nodoc: if defaults = default_url_options(options) defaults.merge(options) @@ -33,7 +33,7 @@ module ActionController options end end - + def url_for(options = {}) options ||= {} case options @@ -46,4 +46,4 @@ module ActionController end end end -end \ No newline at end of file +end -- cgit v1.2.3 From 4e50a35fa243f6cf7ad567774a9f7c1cb87a1653 Mon Sep 17 00:00:00 2001 From: Joshua Peek <josh@joshpeek.com> Date: Thu, 28 May 2009 11:35:36 -0500 Subject: Break up DependencyModule's dual function of providing a "depend_on" DSL and "included" block DSL into separate modules. But, unify both approaches under AS::Concern. --- .../lib/action_controller/abstract/benchmarker.rb | 2 +- .../lib/action_controller/abstract/callbacks.rb | 2 +- .../lib/action_controller/abstract/helpers.rb | 2 +- .../lib/action_controller/abstract/layouts.rb | 2 +- .../lib/action_controller/abstract/logger.rb | 2 +- .../lib/action_controller/abstract/renderer.rb | 2 +- .../lib/action_controller/base/chained/flash.rb | 2 +- .../base/filter_parameter_logging.rb | 2 +- actionpack/lib/action_controller/base/helpers.rb | 2 +- .../base/request_forgery_protection.rb | 2 +- actionpack/lib/action_controller/base/streaming.rb | 2 +- .../lib/action_controller/base/verification.rb | 2 +- actionpack/lib/action_controller/caching.rb | 2 +- .../action_controller/new_base/compatibility.rb | 2 +- .../action_controller/new_base/conditional_get.rb | 2 +- .../lib/action_controller/new_base/helpers.rb | 2 +- .../lib/action_controller/new_base/hide_actions.rb | 2 +- .../lib/action_controller/new_base/layouts.rb | 2 +- .../action_controller/new_base/rack_convenience.rb | 2 +- .../action_controller/new_base/render_options.rb | 36 ++++++++++------------ .../lib/action_controller/new_base/renderer.rb | 2 +- .../lib/action_controller/new_base/rescuable.rb | 2 +- .../lib/action_controller/new_base/session.rb | 2 +- .../lib/action_controller/new_base/testing.rb | 2 +- .../lib/action_controller/new_base/url_for.rb | 2 +- .../lib/action_controller/testing/integration.rb | 2 +- actionpack/lib/action_view/render/partials.rb | 2 +- 27 files changed, 42 insertions(+), 46 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/abstract/benchmarker.rb b/actionpack/lib/action_controller/abstract/benchmarker.rb index 9be06f48fb..6999329144 100644 --- a/actionpack/lib/action_controller/abstract/benchmarker.rb +++ b/actionpack/lib/action_controller/abstract/benchmarker.rb @@ -1,6 +1,6 @@ module AbstractController module Benchmarker - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on Logger diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index 4314235ba9..6c67315c58 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -1,6 +1,6 @@ module AbstractController module Callbacks - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on ActiveSupport::NewCallbacks diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 7b1b197e1d..43832f1e2d 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -1,6 +1,6 @@ module AbstractController module Helpers - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on Renderer diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index dd38485271..b3f21f7b22 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -1,6 +1,6 @@ module AbstractController module Layouts - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on Renderer diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index ce73888763..d6fa843485 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/logger' module AbstractController module Logger - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern class DelayedLog def initialize(&blk) diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index 374ceb5b74..cd3e87d861 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -2,7 +2,7 @@ require "action_controller/abstract/logger" module AbstractController module Renderer - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on AbstractController::Logger diff --git a/actionpack/lib/action_controller/base/chained/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb index 2d084ba1ab..04d27bf090 100644 --- a/actionpack/lib/action_controller/base/chained/flash.rb +++ b/actionpack/lib/action_controller/base/chained/flash.rb @@ -26,7 +26,7 @@ module ActionController #:nodoc: # # See docs on the FlashHash class for more details about the flash. module Flash - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base depends_on Session if defined?(ActionController::Http) diff --git a/actionpack/lib/action_controller/base/filter_parameter_logging.rb b/actionpack/lib/action_controller/base/filter_parameter_logging.rb index f5a678ca03..9df286ee24 100644 --- a/actionpack/lib/action_controller/base/filter_parameter_logging.rb +++ b/actionpack/lib/action_controller/base/filter_parameter_logging.rb @@ -1,6 +1,6 @@ module ActionController module FilterParameterLogging - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) diff --git a/actionpack/lib/action_controller/base/helpers.rb b/actionpack/lib/action_controller/base/helpers.rb index 96fa7896a9..f74158bc13 100644 --- a/actionpack/lib/action_controller/base/helpers.rb +++ b/actionpack/lib/action_controller/base/helpers.rb @@ -3,7 +3,7 @@ require 'active_support/dependencies' # FIXME: helper { ... } is broken on Ruby 1.9 module ActionController #:nodoc: module Helpers #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do # Initialize the base module to aggregate its helpers. diff --git a/actionpack/lib/action_controller/base/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb index 0a0e20e1f1..368c6e9de8 100644 --- a/actionpack/lib/action_controller/base/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb @@ -3,7 +3,7 @@ module ActionController #:nodoc: end module RequestForgeryProtection - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) diff --git a/actionpack/lib/action_controller/base/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb index 5872ba99a2..5f56c95483 100644 --- a/actionpack/lib/action_controller/base/streaming.rb +++ b/actionpack/lib/action_controller/base/streaming.rb @@ -2,7 +2,7 @@ module ActionController #:nodoc: # Methods for sending arbitrary data and for streaming files to the browser, # instead of rendering. module Streaming - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) diff --git a/actionpack/lib/action_controller/base/verification.rb b/actionpack/lib/action_controller/base/verification.rb index 3fa5a105b1..31654e36f3 100644 --- a/actionpack/lib/action_controller/base/verification.rb +++ b/actionpack/lib/action_controller/base/verification.rb @@ -1,6 +1,6 @@ module ActionController #:nodoc: module Verification #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 2f2eec10f6..38cf1da6a8 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -24,7 +24,7 @@ module ActionController #:nodoc: # ActionController::Base.cache_store = :mem_cache_store, "localhost" # ActionController::Base.cache_store = MyOwnStore.new("parameter") module Caching - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern autoload :Actions, 'action_controller/caching/actions' autoload :Fragments, 'action_controller/caching/fragments' diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 1d0cb601e3..f278c2da14 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -1,6 +1,6 @@ module ActionController module Rails2Compatibility - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern class ::ActionController::ActionControllerError < StandardError #:nodoc: end diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index 38f3d3cf68..8bd6db500b 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -1,6 +1,6 @@ module ActionController module ConditionalGet - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on RackConvenience diff --git a/actionpack/lib/action_controller/new_base/helpers.rb b/actionpack/lib/action_controller/new_base/helpers.rb index 1dece13114..c2ebd343e3 100644 --- a/actionpack/lib/action_controller/new_base/helpers.rb +++ b/actionpack/lib/action_controller/new_base/helpers.rb @@ -4,7 +4,7 @@ require 'active_support/dependencies' module ActionController module Helpers - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on AbstractController::Helpers diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index 10b8b582f5..b45e520bee 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -1,6 +1,6 @@ module ActionController module HideActions - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do extlib_inheritable_accessor :hidden_actions diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index 9b4057caaa..727358c394 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -1,6 +1,6 @@ module ActionController module Layouts - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on ActionController::Renderer depends_on AbstractController::Layouts diff --git a/actionpack/lib/action_controller/new_base/rack_convenience.rb b/actionpack/lib/action_controller/new_base/rack_convenience.rb index e465acca6e..5dfa7d12f3 100644 --- a/actionpack/lib/action_controller/new_base/rack_convenience.rb +++ b/actionpack/lib/action_controller/new_base/rack_convenience.rb @@ -1,6 +1,6 @@ module ActionController module RackConvenience - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do delegate :headers, :status=, :location=, diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index f12198a710..04b954134f 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -1,6 +1,6 @@ module ActionController module RenderOptions - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do extlib_inheritable_accessor :_renderers @@ -36,14 +36,12 @@ module ActionController end end - module RenderOption - extend ActiveSupport::DependencyModule + module RenderOption #:nodoc: + def self.extended(base) + base.extend ActiveSupport::Concern + base.depends_on ::ActionController::RenderOptions - included do - extend ActiveSupport::DependencyModule - depends_on ::ActionController::RenderOptions - - def self.register_renderer(name) + def base.register_renderer(name) included { _add_render_option(name) } end end @@ -51,7 +49,7 @@ module ActionController module Renderers module Json - include RenderOption + extend RenderOption register_renderer :json def _render_json(json, options) @@ -63,7 +61,7 @@ module ActionController end module Js - include RenderOption + extend RenderOption register_renderer :js def _render_js(js, options) @@ -73,7 +71,7 @@ module ActionController end module Xml - include RenderOption + extend RenderOption register_renderer :xml def _render_xml(xml, options) @@ -82,8 +80,8 @@ module ActionController end end - module Rjs - include RenderOption + module RJS + extend RenderOption register_renderer :update def _render_update(proc, options) @@ -94,14 +92,12 @@ module ActionController end module All - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - included do - include ::ActionController::Renderers::Json - include ::ActionController::Renderers::Js - include ::ActionController::Renderers::Xml - include ::ActionController::Renderers::Rjs - end + depends_on ActionController::Renderers::Json + depends_on ActionController::Renderers::Js + depends_on ActionController::Renderers::Xml + depends_on ActionController::Renderers::RJS end end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 737a0d6fcf..e132d4fdbb 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -1,6 +1,6 @@ module ActionController module Renderer - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on AbstractController::Renderer diff --git a/actionpack/lib/action_controller/new_base/rescuable.rb b/actionpack/lib/action_controller/new_base/rescuable.rb index 4450a1131a..029e643d93 100644 --- a/actionpack/lib/action_controller/new_base/rescuable.rb +++ b/actionpack/lib/action_controller/new_base/rescuable.rb @@ -15,7 +15,7 @@ module ActionController #:nodoc: # behavior is achieved by overriding the <tt>rescue_action_in_public</tt> # and <tt>rescue_action_locally</tt> methods. module Rescue - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do include ActiveSupport::Rescuable diff --git a/actionpack/lib/action_controller/new_base/session.rb b/actionpack/lib/action_controller/new_base/session.rb index 9ee3e9e136..a585630230 100644 --- a/actionpack/lib/action_controller/new_base/session.rb +++ b/actionpack/lib/action_controller/new_base/session.rb @@ -1,6 +1,6 @@ module ActionController module Session - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on RackConvenience diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 97aadfe78f..e8d210d149 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -1,6 +1,6 @@ module ActionController module Testing - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on RackConvenience diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index 87bc689134..902cac4d15 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -1,6 +1,6 @@ module ActionController module UrlFor - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern depends_on RackConvenience diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index cc157816e2..af4ccb7837 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -301,7 +301,7 @@ module ActionController # A module used to extend ActionController::Base, so that integration tests # can capture the controller used to satisfy a request. module ControllerCapture #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do alias_method_chain :initialize, :capture diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index f2429e8cef..eacf117bea 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -171,7 +171,7 @@ module ActionView # <% end %> module Partials extend ActiveSupport::Memoizable - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do attr_accessor :_partial -- cgit v1.2.3 From d120f9de7e150ea6a5f21c834c1f1d0a9ea25d1a Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Thu, 28 May 2009 16:55:05 -0500 Subject: Reinstate pending output buffer tests --- actionpack/test/template/output_buffer_test.rb | 64 +++++++++++++++----------- 1 file changed, 36 insertions(+), 28 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index 171cfb63e1..f1df1c7a60 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -9,33 +9,41 @@ class OutputBufferTest < ActionController::TestCase tests TestController - def test_flush_output_buffer - pending - # TODO: This tests needs to be rewritten due - # The @response is not the same response object assigned - # to the @controller.template - - # Start with the default body parts - # --- - # get :index - # assert_equal ['foo'], @response.body_parts - # assert_nil @controller.template.output_buffer - # - # # Nil output buffer is skipped - # @controller.template.flush_output_buffer - # assert_nil @controller.template.output_buffer - # assert_equal ['foo'], @response.body_parts - # - # # Empty output buffer is skipped - # @controller.template.output_buffer = '' - # @controller.template.flush_output_buffer - # assert_equal '', @controller.template.output_buffer - # assert_equal ['foo'], @response.body_parts - # - # # Flushing appends the output buffer to the body parts - # @controller.template.output_buffer = 'bar' - # @controller.template.flush_output_buffer - # assert_equal '', @controller.template.output_buffer - # assert_equal ['foo', 'bar'], @response.body_parts + def setup + get :index + assert_equal ['foo'], body_parts end + + test 'output buffer is nil after rendering' do + assert_nil output_buffer + end + + test 'flushing ignores nil output buffer' do + @controller.template.flush_output_buffer + assert_nil output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing ignores empty output buffer' do + @controller.template.output_buffer = '' + @controller.template.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing appends the output buffer to the body parts' do + @controller.template.output_buffer = 'bar' + @controller.template.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo', 'bar'], body_parts + end + + protected + def output_buffer + @controller.template.output_buffer + end + + def body_parts + @controller.template.response.body_parts + end end -- cgit v1.2.3 From e23554d79e2db2324144f3ab58f82a895b93fbf5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Thu, 28 May 2009 16:56:09 -0500 Subject: Ruby 1.9: flushing the output buffer preserves its encoding --- actionpack/lib/action_view/helpers/capture_helper.rb | 13 ++++++++++--- actionpack/test/template/output_buffer_test.rb | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 9e39536653..b4197479a0 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -124,7 +124,11 @@ module ActionView # Use an alternate output buffer for the duration of the block. # Defaults to a new empty string. - def with_output_buffer(buf = '') #:nodoc: + def with_output_buffer(buf = nil) #:nodoc: + unless buf + buf = '' + buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding) + end self.output_buffer, old_buffer = buf, output_buffer yield output_buffer @@ -134,9 +138,12 @@ module ActionView # Add the output buffer to the response body and start a new one. def flush_output_buffer #:nodoc: - if output_buffer && output_buffer != '' + if output_buffer && !output_buffer.empty? response.body_parts << output_buffer - self.output_buffer = '' + new = '' + new.force_encoding(output_buffer.encoding) if new.respond_to?(:force_encoding) + self.output_buffer = new + nil end end end diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index f1df1c7a60..36bbaf9099 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -38,6 +38,17 @@ class OutputBufferTest < ActionController::TestCase assert_equal ['foo', 'bar'], body_parts end + if '1.9'.respond_to?(:force_encoding) + test 'flushing preserves output buffer encoding' do + original_buffer = ' '.force_encoding(Encoding::EUC_JP) + @controller.template.output_buffer = original_buffer + @controller.template.flush_output_buffer + assert_equal ['foo', original_buffer], body_parts + assert_not_equal original_buffer, output_buffer + assert_equal Encoding::EUC_JP, output_buffer.encoding + end + end + protected def output_buffer @controller.template.output_buffer -- cgit v1.2.3 From 5ec2c7dc29b36d85b2658465b8a979deb0529d7e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper <jeremy@bitsweat.net> Date: Thu, 28 May 2009 17:12:28 -0500 Subject: Ruby 1.9: ERB template encoding using a magic comment at the top of the file --- actionpack/CHANGELOG | 3 +++ actionpack/lib/action_view/template/handlers/erb.rb | 6 +----- actionpack/lib/action_view/template/template.rb | 16 +++++++++++++--- actionpack/test/fixtures/test/utf8.html.erb | 5 ++++- actionpack/test/template/render_test.rb | 2 +- 5 files changed, 22 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index e3ad19558e..e758983d7a 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,8 @@ *Edge* +* Ruby 1.9: ERB template encoding using a magic comment at the top of the file. [Jeremy Kemper] + <%# encoding: utf-8 %> + * Change integration test helpers to accept Rack environment instead of just HTTP Headers [Pratik Naik] Before : get '/path', {}, 'Accept' => 'text/javascript' diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 95f11d6490..d773df7d29 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -16,11 +16,7 @@ module ActionView self.default_format = Mime::HTML def compile(template) - src = ::ERB.new("<% __in_erb_template=true %>#{template.source}", nil, erb_trim_mode, '@output_buffer').src - - # Ruby 1.9 prepends an encoding to the source. However this is - # useless because you can only set an encoding on the first line - RUBY_VERSION >= '1.9' ? src.sub(/\A#coding:.*\n/, '') : src + ::ERB.new("<% __in_erb_template=true %>#{template.source}", nil, erb_trim_mode, '@output_buffer').src end end end diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index f61dd591a5..a9897258d2 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -52,16 +52,26 @@ module ActionView locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + code = @handler.call(self) + encoding_comment = $1 if code.sub!(/\A(#.*coding.*)\n/, '') + source = <<-end_src def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)} + old_output_buffer = output_buffer;#{locals_code};#{code} ensure self.output_buffer = old_output_buffer end end_src + if encoding_comment + source = "#{encoding_comment}\n#{source}" + line = -1 + else + line = 0 + end + begin - ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0) + ActionView::Base::CompiledTemplates.module_eval(source, identifier, line) method_name rescue Exception => e # errors from template code if logger = (view && view.logger) @@ -79,4 +89,4 @@ module ActionView "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end end -end \ No newline at end of file +end diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionpack/test/fixtures/test/utf8.html.erb index 0b4d19aa0e..58cd03b439 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionpack/test/fixtures/test/utf8.html.erb @@ -1,2 +1,5 @@ +<%# encoding: utf-8 -%> Русский текст -日本語のテキスト \ No newline at end of file +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 71291f009c..a56d7aee75 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -249,7 +249,7 @@ module RenderTestCases if '1.9'.respond_to?(:force_encoding) def test_render_utf8_template result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\n日本語のテキスト", result + assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result assert_equal Encoding::UTF_8, result.encoding end end -- cgit v1.2.3