actionpack 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +149 -7
- data/MIT-LICENSE +1 -1
- data/README +1 -1
- data/Rakefile +5 -6
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions/model_assertions.rb +2 -1
- data/lib/action_controller/assertions/response_assertions.rb +4 -2
- data/lib/action_controller/assertions/routing_assertions.rb +3 -3
- data/lib/action_controller/assertions/selector_assertions.rb +30 -27
- data/lib/action_controller/assertions/tag_assertions.rb +3 -3
- data/lib/action_controller/base.rb +103 -129
- data/lib/action_controller/benchmarking.rb +3 -3
- data/lib/action_controller/caching.rb +41 -652
- data/lib/action_controller/caching/actions.rb +144 -0
- data/lib/action_controller/caching/fragments.rb +138 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sql_cache.rb +18 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/cgi_ext/cookie.rb +27 -23
- data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
- data/lib/action_controller/cgi_process.rb +6 -4
- data/lib/action_controller/components.rb +7 -6
- data/lib/action_controller/cookies.rb +31 -19
- data/lib/action_controller/dispatcher.rb +51 -84
- data/lib/action_controller/filters.rb +295 -421
- data/lib/action_controller/flash.rb +1 -6
- data/lib/action_controller/headers.rb +31 -0
- data/lib/action_controller/helpers.rb +26 -9
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +65 -13
- data/lib/action_controller/layout.rb +24 -39
- data/lib/action_controller/mime_responds.rb +7 -3
- data/lib/action_controller/mime_type.rb +25 -9
- data/lib/action_controller/mime_types.rb +1 -1
- data/lib/action_controller/polymorphic_routes.rb +32 -17
- data/lib/action_controller/record_identifier.rb +10 -4
- data/lib/action_controller/request.rb +46 -30
- data/lib/action_controller/request_forgery_protection.rb +10 -9
- data/lib/action_controller/request_profiler.rb +29 -8
- data/lib/action_controller/rescue.rb +24 -24
- data/lib/action_controller/resources.rb +66 -23
- data/lib/action_controller/response.rb +2 -2
- data/lib/action_controller/routing.rb +113 -1229
- data/lib/action_controller/routing/builder.rb +204 -0
- data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
- data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
- data/lib/action_controller/routing/route.rb +240 -0
- data/lib/action_controller/routing/route_set.rb +435 -0
- data/lib/action_controller/routing/routing_ext.rb +46 -0
- data/lib/action_controller/routing/segments.rb +283 -0
- data/lib/action_controller/session/active_record_store.rb +13 -8
- data/lib/action_controller/session/cookie_store.rb +20 -17
- data/lib/action_controller/session_management.rb +10 -3
- data/lib/action_controller/streaming.rb +45 -31
- data/lib/action_controller/test_case.rb +33 -23
- data/lib/action_controller/test_process.rb +39 -35
- data/lib/action_controller/url_rewriter.rb +18 -12
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +11 -3
- data/lib/action_view/base.rb +73 -390
- data/lib/action_view/helpers/active_record_helper.rb +83 -62
- data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
- data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
- data/lib/action_view/helpers/benchmark_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +3 -2
- data/lib/action_view/helpers/capture_helper.rb +1 -2
- data/lib/action_view/helpers/date_helper.rb +104 -82
- data/lib/action_view/helpers/form_helper.rb +148 -75
- data/lib/action_view/helpers/form_options_helper.rb +44 -23
- data/lib/action_view/helpers/form_tag_helper.rb +22 -13
- data/lib/action_view/helpers/javascripts/controls.js +1 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
- data/lib/action_view/helpers/javascripts/effects.js +1 -1
- data/lib/action_view/helpers/number_helper.rb +10 -3
- data/lib/action_view/helpers/prototype_helper.rb +61 -29
- data/lib/action_view/helpers/record_tag_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +23 -17
- data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
- data/lib/action_view/helpers/text_helper.rb +153 -125
- data/lib/action_view/helpers/url_helper.rb +83 -28
- data/lib/action_view/inline_template.rb +20 -0
- data/lib/action_view/partial_template.rb +70 -0
- data/lib/action_view/partials.rb +31 -73
- data/lib/action_view/template.rb +127 -0
- data/lib/action_view/template_error.rb +8 -7
- data/lib/action_view/template_finder.rb +177 -0
- data/lib/action_view/template_handler.rb +18 -1
- data/lib/action_view/template_handlers/builder.rb +10 -2
- data/lib/action_view/template_handlers/compilable.rb +128 -0
- data/lib/action_view/template_handlers/erb.rb +37 -2
- data/lib/action_view/template_handlers/rjs.rb +14 -1
- data/lib/action_view/test_case.rb +58 -0
- data/test/abstract_unit.rb +1 -1
- data/test/active_record_unit.rb +3 -6
- data/test/activerecord/active_record_store_test.rb +1 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
- data/test/adv_attr_test.rb +20 -0
- data/test/controller/action_pack_assertions_test.rb +16 -19
- data/test/controller/addresses_render_test.rb +1 -1
- data/test/controller/assert_select_test.rb +13 -6
- data/test/controller/base_test.rb +48 -2
- data/test/controller/benchmark_test.rb +1 -2
- data/test/controller/caching_test.rb +282 -21
- data/test/controller/capture_test.rb +1 -1
- data/test/controller/cgi_test.rb +1 -1
- data/test/controller/components_test.rb +1 -1
- data/test/controller/content_type_test.rb +2 -2
- data/test/controller/cookie_test.rb +13 -2
- data/test/controller/custom_handler_test.rb +14 -10
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
- data/test/controller/dispatcher_test.rb +31 -49
- data/test/controller/fake_controllers.rb +17 -0
- data/test/controller/fake_models.rb +6 -0
- data/test/controller/filter_params_test.rb +14 -8
- data/test/controller/filters_test.rb +44 -16
- data/test/controller/flash_test.rb +2 -2
- data/test/controller/header_test.rb +14 -0
- data/test/controller/helper_test.rb +19 -15
- data/test/controller/html-scanner/document_test.rb +1 -2
- data/test/controller/html-scanner/node_test.rb +1 -2
- data/test/controller/html-scanner/sanitizer_test.rb +8 -5
- data/test/controller/html-scanner/tag_node_test.rb +1 -2
- data/test/controller/html-scanner/text_node_test.rb +2 -3
- data/test/controller/html-scanner/tokenizer_test.rb +8 -2
- data/test/controller/http_authentication_test.rb +1 -1
- data/test/controller/integration_test.rb +14 -16
- data/test/controller/integration_upload_test.rb +43 -0
- data/test/controller/layout_test.rb +26 -6
- data/test/controller/mime_responds_test.rb +39 -7
- data/test/controller/mime_type_test.rb +29 -5
- data/test/controller/new_render_test.rb +105 -34
- data/test/controller/polymorphic_routes_test.rb +32 -20
- data/test/controller/record_identifier_test.rb +38 -2
- data/test/controller/redirect_test.rb +21 -1
- data/test/controller/render_test.rb +59 -15
- data/test/controller/request_forgery_protection_test.rb +92 -5
- data/test/controller/request_test.rb +64 -6
- data/test/controller/rescue_test.rb +22 -6
- data/test/controller/resources_test.rb +102 -14
- data/test/controller/routing_test.rb +231 -19
- data/test/controller/selector_test.rb +2 -2
- data/test/controller/send_file_test.rb +14 -3
- data/test/controller/session/cookie_store_test.rb +16 -4
- data/test/controller/session/mem_cache_store_test.rb +3 -4
- data/test/controller/session_fixation_test.rb +1 -1
- data/test/controller/session_management_test.rb +23 -1
- data/test/controller/test_test.rb +39 -18
- data/test/controller/url_rewriter_test.rb +35 -1
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -12
- data/test/controller/webservice_test.rb +48 -3
- data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
- data/test/fixtures/company.rb +1 -0
- data/test/fixtures/customers/_customer.html.erb +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/functional_caching/_partial.erb +3 -0
- data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
- data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
- data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
- data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
- data/test/fixtures/mascot.rb +3 -0
- data/test/fixtures/mascots.yml +4 -0
- data/test/fixtures/mascots/_mascot.html.erb +1 -0
- data/test/fixtures/multipart/boundary_problem_file +10 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/public/javascripts/controls.js +1 -0
- data/test/fixtures/public/javascripts/dragdrop.js +1 -0
- data/test/fixtures/public/javascripts/effects.js +1 -0
- data/test/fixtures/public/javascripts/prototype.js +1 -0
- data/test/fixtures/public/javascripts/version.1.0.js +1 -0
- data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
- data/test/fixtures/reply.rb +1 -0
- data/test/fixtures/shared.html.erb +1 -0
- data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
- data/test/fixtures/test/_customer_counter.erb +1 -0
- data/test/fixtures/test/_form.erb +1 -0
- data/test/fixtures/test/_labelling_form.erb +1 -0
- data/test/fixtures/test/_raise.html.erb +1 -0
- data/test/fixtures/test/greeting.js.rjs +1 -0
- data/test/fixtures/topics/_topic.html.erb +1 -0
- data/test/template/active_record_helper_test.rb +25 -8
- data/test/template/asset_tag_helper_test.rb +100 -17
- data/test/template/atom_feed_helper_test.rb +29 -1
- data/test/template/benchmark_helper_test.rb +10 -22
- data/test/template/date_helper_test.rb +455 -153
- data/test/template/erb_util_test.rb +10 -42
- data/test/template/form_helper_test.rb +192 -66
- data/test/template/form_options_helper_test.rb +19 -8
- data/test/template/form_tag_helper_test.rb +11 -8
- data/test/template/javascript_helper_test.rb +3 -9
- data/test/template/number_helper_test.rb +6 -3
- data/test/template/prototype_helper_test.rb +27 -40
- data/test/template/record_tag_helper_test.rb +54 -0
- data/test/template/sanitize_helper_test.rb +5 -6
- data/test/template/scriptaculous_helper_test.rb +7 -13
- data/test/template/tag_helper_test.rb +3 -6
- data/test/template/template_finder_test.rb +73 -0
- data/test/template/template_object_test.rb +95 -0
- data/test/template/test_test.rb +56 -0
- data/test/template/text_helper_test.rb +46 -33
- data/test/template/url_helper_test.rb +8 -10
- metadata +65 -12
- data/lib/action_view/compiled_templates.rb +0 -69
- data/test/action_view_test.rb +0 -44
- data/test/activerecord/fixtures_test.rb +0 -24
- data/test/controller/fragment_store_setting_test.rb +0 -47
- data/test/template/compiled_templates_test.rb +0 -197
- data/test/template/deprecate_ivars_test.rb +0 -51
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module ActionController #:nodoc:
|
|
2
|
+
module Caching
|
|
3
|
+
# Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
|
|
4
|
+
# They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
|
|
5
|
+
#
|
|
6
|
+
# class ListSweeper < ActionController::Caching::Sweeper
|
|
7
|
+
# observe List, Item
|
|
8
|
+
#
|
|
9
|
+
# def after_save(record)
|
|
10
|
+
# list = record.is_a?(List) ? record : record.list
|
|
11
|
+
# expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
|
|
12
|
+
# expire_action(:controller => "lists", :action => "all")
|
|
13
|
+
# list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# The sweeper is assigned in the controllers that wish to have its job performed using the <tt>cache_sweeper</tt> class method:
|
|
18
|
+
#
|
|
19
|
+
# class ListsController < ApplicationController
|
|
20
|
+
# caches_action :index, :show, :public, :feed
|
|
21
|
+
# cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# In the example above, four actions are cached and three actions are responsible for expiring those caches.
|
|
25
|
+
#
|
|
26
|
+
# You can also name an explicit class in the declaration of a sweeper, which is needed if the sweeper is in a module:
|
|
27
|
+
#
|
|
28
|
+
# class ListsController < ApplicationController
|
|
29
|
+
# caches_action :index, :show, :public, :feed
|
|
30
|
+
# cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
|
|
31
|
+
# end
|
|
32
|
+
module Sweeping
|
|
33
|
+
def self.included(base) #:nodoc:
|
|
34
|
+
base.extend(ClassMethods)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module ClassMethods #:nodoc:
|
|
38
|
+
def cache_sweeper(*sweepers)
|
|
39
|
+
configuration = sweepers.extract_options!
|
|
40
|
+
|
|
41
|
+
sweepers.each do |sweeper|
|
|
42
|
+
ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
|
|
43
|
+
sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(sweeper.to_s.classify) : sweeper).instance
|
|
44
|
+
|
|
45
|
+
if sweeper_instance.is_a?(Sweeper)
|
|
46
|
+
around_filter(sweeper_instance, :only => configuration[:only])
|
|
47
|
+
else
|
|
48
|
+
after_filter(sweeper_instance, :only => configuration[:only])
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
|
|
56
|
+
class Sweeper < ActiveRecord::Observer #:nodoc:
|
|
57
|
+
attr_accessor :controller
|
|
58
|
+
|
|
59
|
+
def before(controller)
|
|
60
|
+
self.controller = controller
|
|
61
|
+
callback(:before) if controller.perform_caching
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def after(controller)
|
|
65
|
+
callback(:after) if controller.perform_caching
|
|
66
|
+
# Clean up, so that the controller can be collected after this request
|
|
67
|
+
self.controller = nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
protected
|
|
71
|
+
# gets the action cache path for the given options.
|
|
72
|
+
def action_path_for(options)
|
|
73
|
+
ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Retrieve instance variables set in the controller.
|
|
77
|
+
def assigns(key)
|
|
78
|
+
controller.instance_variable_get("@#{key}")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
def callback(timing)
|
|
83
|
+
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
|
|
84
|
+
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
|
|
85
|
+
|
|
86
|
+
send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
|
|
87
|
+
send!(action_callback_method_name) if respond_to?(action_callback_method_name, true)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def method_missing(method, *arguments)
|
|
91
|
+
return if @controller.nil?
|
|
92
|
+
@controller.send!(method, *arguments)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -6,25 +6,24 @@ class CGI #:nodoc:
|
|
|
6
6
|
attr_accessor :name, :value, :path, :domain, :expires
|
|
7
7
|
attr_reader :secure, :http_only
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Creates a new CGI::Cookie object.
|
|
10
10
|
#
|
|
11
11
|
# The contents of the cookie can be specified as a +name+ and one
|
|
12
12
|
# or more +value+ arguments. Alternatively, the contents can
|
|
13
13
|
# be specified as a single hash argument. The possible keywords of
|
|
14
14
|
# this hash are as follows:
|
|
15
15
|
#
|
|
16
|
-
# name
|
|
17
|
-
# value
|
|
18
|
-
# path
|
|
19
|
-
#
|
|
20
|
-
# domain
|
|
21
|
-
# expires
|
|
22
|
-
# secure
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# Defaults to false.
|
|
16
|
+
# * <tt>:name</tt> - The name of the cookie. Required.
|
|
17
|
+
# * <tt>:value</tt> - The cookie's value or list of values.
|
|
18
|
+
# * <tt>:path</tt> - The path for which this cookie applies. Defaults to the
|
|
19
|
+
# base directory of the CGI script.
|
|
20
|
+
# * <tt>:domain</tt> - The domain for which this cookie applies.
|
|
21
|
+
# * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
|
|
22
|
+
# * <tt>:secure</tt> - Whether this cookie is a secure cookie or not (defaults to
|
|
23
|
+
# +false+). Secure cookies are only transmitted to HTTPS servers.
|
|
24
|
+
# * <tt>:http_only</tt> - Whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP.
|
|
25
|
+
# More details in http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx. Defaults to +false+.
|
|
26
|
+
#
|
|
28
27
|
# These keywords correspond to attributes of the cookie object.
|
|
29
28
|
def initialize(name = '', *value)
|
|
30
29
|
if name.kind_of?(String)
|
|
@@ -37,7 +36,7 @@ class CGI #:nodoc:
|
|
|
37
36
|
@path = nil
|
|
38
37
|
else
|
|
39
38
|
@name = name['name']
|
|
40
|
-
@value = Array(name['value'])
|
|
39
|
+
@value = (name['value'].kind_of?(String) ? [name['value']] : Array(name['value'])).delete_if(&:blank?)
|
|
41
40
|
@domain = name['domain']
|
|
42
41
|
@expires = name['expires']
|
|
43
42
|
@secure = name['secure'] || false
|
|
@@ -56,17 +55,17 @@ class CGI #:nodoc:
|
|
|
56
55
|
super(@value)
|
|
57
56
|
end
|
|
58
57
|
|
|
59
|
-
#
|
|
58
|
+
# Sets whether the Cookie is a secure cookie or not.
|
|
60
59
|
def secure=(val)
|
|
61
60
|
@secure = val == true
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
#
|
|
63
|
+
# Sets whether the Cookie is an HTTP only cookie or not.
|
|
65
64
|
def http_only=(val)
|
|
66
65
|
@http_only = val == true
|
|
67
66
|
end
|
|
68
67
|
|
|
69
|
-
#
|
|
68
|
+
# Converts the Cookie to its string representation.
|
|
70
69
|
def to_s
|
|
71
70
|
buf = ''
|
|
72
71
|
buf << @name << '='
|
|
@@ -79,23 +78,28 @@ class CGI #:nodoc:
|
|
|
79
78
|
buf
|
|
80
79
|
end
|
|
81
80
|
|
|
82
|
-
#
|
|
81
|
+
# FIXME: work around broken 1.8.7 DelegateClass#respond_to?
|
|
82
|
+
def respond_to?(method, include_private = false)
|
|
83
|
+
return true if super(method)
|
|
84
|
+
return __getobj__.respond_to?(method, include_private)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Parses a raw cookie string into a hash of <tt>cookie-name => cookie-object</tt>
|
|
83
88
|
# pairs.
|
|
84
89
|
#
|
|
85
90
|
# cookies = CGI::Cookie::parse("raw_cookie_string")
|
|
86
|
-
# # { "name1" => cookie1, "name2" => cookie2, ... }
|
|
91
|
+
# # => { "name1" => cookie1, "name2" => cookie2, ... }
|
|
87
92
|
#
|
|
88
93
|
def self.parse(raw_cookie)
|
|
89
94
|
cookies = Hash.new([])
|
|
90
95
|
|
|
91
96
|
if raw_cookie
|
|
92
97
|
raw_cookie.split(/;\s?/).each do |pairs|
|
|
93
|
-
name,
|
|
94
|
-
next unless name and
|
|
98
|
+
name, value = pairs.split('=',2)
|
|
99
|
+
next unless name and value
|
|
95
100
|
name = CGI::unescape(name)
|
|
96
|
-
values = values.split('&').collect!{|v| CGI::unescape(v) }
|
|
97
101
|
unless cookies.has_key?(name)
|
|
98
|
-
cookies[name] = new(name,
|
|
102
|
+
cookies[name] = new(name, CGI::unescape(value))
|
|
99
103
|
end
|
|
100
104
|
end
|
|
101
105
|
end
|
|
@@ -3,7 +3,7 @@ require 'action_controller/session/cookie_store'
|
|
|
3
3
|
|
|
4
4
|
module ActionController #:nodoc:
|
|
5
5
|
class Base
|
|
6
|
-
# Process a request extracted from
|
|
6
|
+
# Process a request extracted from a CGI object and return a response. Pass false as <tt>session_options</tt> to disable
|
|
7
7
|
# sessions (large performance increase if sessions are not needed). The <tt>session_options</tt> are the same as for CGI::Session:
|
|
8
8
|
#
|
|
9
9
|
# * <tt>:database_manager</tt> - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore
|
|
@@ -15,9 +15,9 @@ module ActionController #:nodoc:
|
|
|
15
15
|
# * <tt>:new_session</tt> - if true, force creation of a new session. If not set, a new session is only created if none currently
|
|
16
16
|
# exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set,
|
|
17
17
|
# an ArgumentError is raised.
|
|
18
|
-
# * <tt>:session_expires</tt> - the time the current session expires, as a
|
|
18
|
+
# * <tt>:session_expires</tt> - the time the current session expires, as a Time object. If not set, the session will continue
|
|
19
19
|
# indefinitely.
|
|
20
|
-
# * <tt>:session_domain</tt> -
|
|
20
|
+
# * <tt>:session_domain</tt> - the hostname domain for which this session is valid. If not set, defaults to the hostname of the
|
|
21
21
|
# server.
|
|
22
22
|
# * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS.
|
|
23
23
|
# * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script.
|
|
@@ -34,7 +34,8 @@ module ActionController #:nodoc:
|
|
|
34
34
|
|
|
35
35
|
class CgiRequest < AbstractRequest #:nodoc:
|
|
36
36
|
attr_accessor :cgi, :session_options
|
|
37
|
-
class SessionFixationAttempt < StandardError
|
|
37
|
+
class SessionFixationAttempt < StandardError #:nodoc:
|
|
38
|
+
end
|
|
38
39
|
|
|
39
40
|
DEFAULT_SESSION_OPTIONS = {
|
|
40
41
|
:database_manager => CGI::Session::CookieStore, # store data in cookie
|
|
@@ -64,6 +65,7 @@ module ActionController #:nodoc:
|
|
|
64
65
|
# variable is already set, wrap it in a StringIO.
|
|
65
66
|
def body
|
|
66
67
|
if raw_post = env['RAW_POST_DATA']
|
|
68
|
+
raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
|
|
67
69
|
StringIO.new(raw_post)
|
|
68
70
|
else
|
|
69
71
|
@cgi.stdinput
|
|
@@ -39,12 +39,7 @@ module ActionController #:nodoc:
|
|
|
39
39
|
base.class_eval do
|
|
40
40
|
include InstanceMethods
|
|
41
41
|
extend ClassMethods
|
|
42
|
-
|
|
43
|
-
helper do
|
|
44
|
-
def render_component(options)
|
|
45
|
-
@controller.send!(:render_component_as_string, options)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
42
|
+
helper HelperMethods
|
|
48
43
|
|
|
49
44
|
# If this controller was instantiated to process a component request,
|
|
50
45
|
# +parent_controller+ points to the instantiator of this controller.
|
|
@@ -67,6 +62,12 @@ module ActionController #:nodoc:
|
|
|
67
62
|
end
|
|
68
63
|
end
|
|
69
64
|
|
|
65
|
+
module HelperMethods
|
|
66
|
+
def render_component(options)
|
|
67
|
+
@controller.send!(:render_component_as_string, options)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
70
71
|
module InstanceMethods
|
|
71
72
|
# Extracts the action_name from the request parameters and performs that action.
|
|
72
73
|
def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc:
|
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
module ActionController #:nodoc:
|
|
2
|
-
# Cookies are read and written through ActionController#cookies.
|
|
3
|
-
# the cookies being written are what will be sent out with the response. Cookies are read by value (so you won't get the cookie object
|
|
4
|
-
# itself back -- just the value it holds). Examples for writing:
|
|
2
|
+
# Cookies are read and written through ActionController#cookies.
|
|
5
3
|
#
|
|
6
|
-
#
|
|
4
|
+
# The cookies being read are the ones received along with the request, the cookies
|
|
5
|
+
# being written will be sent out with the response. Reading a cookie does not get
|
|
6
|
+
# the cookie object itself back, just the value it holds.
|
|
7
|
+
#
|
|
8
|
+
# Examples for writing:
|
|
9
|
+
#
|
|
10
|
+
# # Sets a simple session cookie.
|
|
11
|
+
# cookies[:user_name] = "david"
|
|
12
|
+
#
|
|
13
|
+
# # Sets a cookie that expires in 1 hour.
|
|
7
14
|
# cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
|
|
8
|
-
# # => Will set a cookie that expires in 1 hour
|
|
9
15
|
#
|
|
10
16
|
# Examples for reading:
|
|
11
17
|
#
|
|
12
18
|
# cookies[:user_name] # => "david"
|
|
13
|
-
# cookies.size
|
|
19
|
+
# cookies.size # => 2
|
|
14
20
|
#
|
|
15
21
|
# Example for deleting:
|
|
16
22
|
#
|
|
17
23
|
# cookies.delete :user_name
|
|
18
24
|
#
|
|
19
|
-
#
|
|
25
|
+
# The option symbols for setting cookies are:
|
|
20
26
|
#
|
|
21
|
-
# * <tt
|
|
22
|
-
# * <tt
|
|
23
|
-
#
|
|
24
|
-
# * <tt
|
|
25
|
-
# * <tt
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
27
|
+
# * <tt>:value</tt> - The cookie's value or list of values (as an array).
|
|
28
|
+
# * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
|
|
29
|
+
# of the application.
|
|
30
|
+
# * <tt>:domain</tt> - The domain for which this cookie applies.
|
|
31
|
+
# * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
|
|
32
|
+
# * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
|
|
33
|
+
# Default is +false+.
|
|
34
|
+
# * <tt>:http_only</tt> - Whether this cookie is accessible via scripting or
|
|
35
|
+
# only HTTP. Defaults to +false+.
|
|
29
36
|
module Cookies
|
|
30
37
|
def self.included(base)
|
|
31
38
|
base.helper_method :cookies
|
|
@@ -45,8 +52,7 @@ module ActionController #:nodoc:
|
|
|
45
52
|
update(@cookies)
|
|
46
53
|
end
|
|
47
54
|
|
|
48
|
-
# Returns the value of the cookie by +name
|
|
49
|
-
# (for simple name/value cookies without options).
|
|
55
|
+
# Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
|
|
50
56
|
def [](name)
|
|
51
57
|
cookie = @cookies[name.to_s]
|
|
52
58
|
if cookie && cookie.respond_to?(:value)
|
|
@@ -54,6 +60,8 @@ module ActionController #:nodoc:
|
|
|
54
60
|
end
|
|
55
61
|
end
|
|
56
62
|
|
|
63
|
+
# Sets the cookie named +name+. The second argument may be the very cookie
|
|
64
|
+
# value, or a hash of options as documented above.
|
|
57
65
|
def []=(name, options)
|
|
58
66
|
if options.is_a?(Hash)
|
|
59
67
|
options = options.inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options }
|
|
@@ -66,14 +74,18 @@ module ActionController #:nodoc:
|
|
|
66
74
|
end
|
|
67
75
|
|
|
68
76
|
# Removes the cookie on the client machine by setting the value to an empty string
|
|
69
|
-
# and setting its expiration date into the past.
|
|
70
|
-
# hash to delete cookies with extra data such as a
|
|
77
|
+
# and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
|
|
78
|
+
# an options hash to delete cookies with extra data such as a <tt>:path</tt>.
|
|
71
79
|
def delete(name, options = {})
|
|
72
80
|
options.stringify_keys!
|
|
73
81
|
set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0)))
|
|
74
82
|
end
|
|
75
83
|
|
|
76
84
|
private
|
|
85
|
+
# Builds a CGI::Cookie object and adds the cookie to the response headers.
|
|
86
|
+
#
|
|
87
|
+
# The path of the cookie defaults to "/" if there's none in +options+, and
|
|
88
|
+
# everything is passed to the CGI::Cookie constructor.
|
|
77
89
|
def set_cookie(options) #:doc:
|
|
78
90
|
options["path"] = "/" unless options["path"]
|
|
79
91
|
cookie = CGI::Cookie.new(options)
|
|
@@ -2,27 +2,39 @@ module ActionController
|
|
|
2
2
|
# Dispatches requests to the appropriate controller and takes care of
|
|
3
3
|
# reloading the app after each request when Dependencies.load? is true.
|
|
4
4
|
class Dispatcher
|
|
5
|
+
@@guard = Mutex.new
|
|
6
|
+
|
|
5
7
|
class << self
|
|
8
|
+
def define_dispatcher_callbacks(cache_classes)
|
|
9
|
+
unless cache_classes
|
|
10
|
+
# Development mode callbacks
|
|
11
|
+
before_dispatch :reload_application
|
|
12
|
+
after_dispatch :cleanup_application
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Common callbacks
|
|
16
|
+
to_prepare :load_application_controller do
|
|
17
|
+
begin
|
|
18
|
+
require_dependency 'application' unless defined?(::ApplicationController)
|
|
19
|
+
rescue LoadError => error
|
|
20
|
+
raise unless error.message =~ /application\.rb/
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if defined?(ActiveRecord)
|
|
25
|
+
before_dispatch { ActiveRecord::Base.verify_active_connections! }
|
|
26
|
+
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
after_dispatch :flush_logger if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)
|
|
30
|
+
end
|
|
31
|
+
|
|
6
32
|
# Backward-compatible class method takes CGI-specific args. Deprecated
|
|
7
33
|
# in favor of Dispatcher.new(output, request, response).dispatch.
|
|
8
34
|
def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
|
|
9
35
|
new(output).dispatch_cgi(cgi, session_options)
|
|
10
36
|
end
|
|
11
37
|
|
|
12
|
-
# Declare a block to be called before each dispatch.
|
|
13
|
-
# Run in the order declared.
|
|
14
|
-
def before_dispatch(*method_names, &block)
|
|
15
|
-
callbacks[:before].concat method_names
|
|
16
|
-
callbacks[:before] << block if block_given?
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Declare a block to be called after each dispatch.
|
|
20
|
-
# Run in reverse of the order declared.
|
|
21
|
-
def after_dispatch(*method_names, &block)
|
|
22
|
-
callbacks[:after].concat method_names
|
|
23
|
-
callbacks[:after] << block if block_given?
|
|
24
|
-
end
|
|
25
|
-
|
|
26
38
|
# Add a preparation callback. Preparation callbacks are run before every
|
|
27
39
|
# request in development mode, and before the first request in production
|
|
28
40
|
# mode.
|
|
@@ -32,16 +44,9 @@ module ActionController
|
|
|
32
44
|
# existing callback. Passing an identifier is a suggested practice if the
|
|
33
45
|
# code adding a preparation block may be reloaded.
|
|
34
46
|
def to_prepare(identifier = nil, &block)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
callback[1] = block
|
|
39
|
-
else
|
|
40
|
-
callbacks[:prepare] << [identifier, block]
|
|
41
|
-
end
|
|
42
|
-
else
|
|
43
|
-
callbacks[:prepare] << block
|
|
44
|
-
end
|
|
47
|
+
@prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
|
|
48
|
+
callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
|
|
49
|
+
@prepare_dispatch_callbacks | callback
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
# If the block raises, send status code as a last-ditch response.
|
|
@@ -86,37 +91,26 @@ module ActionController
|
|
|
86
91
|
end
|
|
87
92
|
|
|
88
93
|
cattr_accessor :error_file_path
|
|
89
|
-
self.error_file_path =
|
|
90
|
-
|
|
91
|
-
cattr_accessor :callbacks
|
|
92
|
-
self.callbacks = Hash.new { |h, k| h[k] = [] }
|
|
93
|
-
|
|
94
|
-
cattr_accessor :unprepared
|
|
95
|
-
self.unprepared = true
|
|
96
|
-
|
|
94
|
+
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
before_dispatch :
|
|
100
|
-
after_dispatch :flush_logger
|
|
101
|
-
after_dispatch :cleanup_application
|
|
102
|
-
|
|
103
|
-
if defined? ActiveRecord
|
|
104
|
-
to_prepare :activerecord_instantiate_observers do
|
|
105
|
-
ActiveRecord::Base.instantiate_observers
|
|
106
|
-
end
|
|
107
|
-
end
|
|
96
|
+
include ActiveSupport::Callbacks
|
|
97
|
+
define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch
|
|
108
98
|
|
|
109
99
|
def initialize(output, request = nil, response = nil)
|
|
110
100
|
@output, @request, @response = output, request, response
|
|
111
101
|
end
|
|
112
102
|
|
|
113
103
|
def dispatch
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
104
|
+
@@guard.synchronize do
|
|
105
|
+
begin
|
|
106
|
+
run_callbacks :before_dispatch
|
|
107
|
+
handle_request
|
|
108
|
+
rescue Exception => exception
|
|
109
|
+
failsafe_rescue exception
|
|
110
|
+
ensure
|
|
111
|
+
run_callbacks :after_dispatch, :enumerator => :reverse_each
|
|
112
|
+
end
|
|
113
|
+
end
|
|
120
114
|
end
|
|
121
115
|
|
|
122
116
|
def dispatch_cgi(cgi, session_options)
|
|
@@ -130,39 +124,23 @@ module ActionController
|
|
|
130
124
|
end
|
|
131
125
|
|
|
132
126
|
def reload_application
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
self.unprepared = true
|
|
136
|
-
end
|
|
137
|
-
end
|
|
127
|
+
# Run prepare callbacks before every request in development mode
|
|
128
|
+
run_callbacks :prepare_dispatch
|
|
138
129
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
require_dependency 'application' unless defined?(::ApplicationController)
|
|
142
|
-
rescue LoadError => error
|
|
143
|
-
raise unless error.message =~ /application\.rb/
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
|
|
147
|
-
|
|
148
|
-
if unprepared || force
|
|
149
|
-
run_callbacks :prepare
|
|
150
|
-
self.unprepared = false
|
|
151
|
-
end
|
|
130
|
+
Routing::Routes.reload
|
|
131
|
+
ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading
|
|
152
132
|
end
|
|
153
133
|
|
|
154
134
|
# Cleanup the application by clearing out loaded classes so they can
|
|
155
135
|
# be reloaded on the next request without restarting the server.
|
|
156
|
-
def cleanup_application
|
|
157
|
-
if
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
|
161
|
-
end
|
|
136
|
+
def cleanup_application
|
|
137
|
+
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
|
138
|
+
Dependencies.clear
|
|
139
|
+
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
|
162
140
|
end
|
|
163
141
|
|
|
164
142
|
def flush_logger
|
|
165
|
-
RAILS_DEFAULT_LOGGER.flush
|
|
143
|
+
RAILS_DEFAULT_LOGGER.flush
|
|
166
144
|
end
|
|
167
145
|
|
|
168
146
|
protected
|
|
@@ -171,17 +149,6 @@ module ActionController
|
|
|
171
149
|
@controller.process(@request, @response).out(@output)
|
|
172
150
|
end
|
|
173
151
|
|
|
174
|
-
def run_callbacks(kind, enumerator = :each)
|
|
175
|
-
callbacks[kind].send!(enumerator) do |callback|
|
|
176
|
-
case callback
|
|
177
|
-
when Proc; callback.call(self)
|
|
178
|
-
when String, Symbol; send!(callback)
|
|
179
|
-
when Array; callback[1].call(self)
|
|
180
|
-
else raise ArgumentError, "Unrecognized callback #{callback.inspect}"
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
152
|
def failsafe_rescue(exception)
|
|
186
153
|
self.class.failsafe_response(@output, '500 Internal Server Error', exception) do
|
|
187
154
|
if @controller ||= defined?(::ApplicationController) ? ::ApplicationController : Base
|