actionpack 3.0.0.beta4 → 3.0.0.rc
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +36 -0
- data/{README → README.rdoc} +79 -137
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +3 -12
- data/lib/abstract_controller/rendering.rb +2 -2
- data/lib/abstract_controller/view_paths.rb +2 -1
- data/lib/action_controller.rb +1 -2
- data/lib/action_controller/base.rb +3 -9
- data/lib/action_controller/log_subscriber.rb +56 -0
- data/lib/action_controller/metal.rb +10 -3
- data/lib/action_controller/metal/helpers.rb +5 -4
- data/lib/action_controller/metal/hide_actions.rb +3 -3
- data/lib/action_controller/metal/instrumentation.rb +2 -1
- data/lib/action_controller/metal/mime_responds.rb +13 -10
- data/lib/action_controller/metal/rack_delegation.rb +0 -4
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
- data/lib/action_controller/metal/rescue.rb +9 -0
- data/lib/action_controller/metal/responder.rb +13 -5
- data/lib/action_controller/metal/streaming.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +5 -5
- data/lib/action_controller/railtie.rb +14 -23
- data/lib/action_controller/record_identifier.rb +6 -25
- data/lib/action_controller/test_case.rb +18 -6
- data/lib/action_controller/vendor/html-scanner/html/node.rb +1 -0
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -0
- data/lib/action_dispatch.rb +6 -0
- data/lib/action_dispatch/http/cache.rb +2 -2
- data/lib/action_dispatch/http/filter_parameters.rb +10 -66
- data/lib/action_dispatch/http/mime_type.rb +1 -1
- data/lib/action_dispatch/http/parameter_filter.rb +72 -0
- data/lib/action_dispatch/http/parameters.rb +31 -2
- data/lib/action_dispatch/http/request.rb +4 -1
- data/lib/action_dispatch/http/upload.rb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +4 -4
- data/lib/action_dispatch/middleware/cookies.rb +39 -6
- data/lib/action_dispatch/middleware/flash.rb +9 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +121 -36
- data/lib/action_dispatch/middleware/session/cookie_store.rb +26 -19
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/stack.rb +12 -5
- data/lib/action_dispatch/railtie.rb +1 -1
- data/lib/action_dispatch/routing.rb +11 -13
- data/lib/action_dispatch/routing/deprecated_mapper.rb +6 -388
- data/lib/action_dispatch/routing/mapper.rb +364 -234
- data/lib/action_dispatch/routing/polymorphic_routes.rb +186 -0
- data/lib/action_dispatch/routing/route.rb +11 -2
- data/lib/action_dispatch/routing/route_set.rb +62 -28
- data/lib/action_dispatch/routing/url_for.rb +2 -1
- data/lib/action_dispatch/testing/assertions.rb +0 -2
- data/lib/action_dispatch/testing/assertions/routing.rb +0 -1
- data/lib/action_dispatch/testing/assertions/selector.rb +20 -24
- data/lib/action_dispatch/testing/integration.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +2 -2
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view.rb +1 -0
- data/lib/action_view/base.rb +20 -21
- data/lib/action_view/context.rb +9 -12
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/helpers/active_model_helper.rb +17 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +15 -33
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +4 -2
- data/lib/action_view/helpers/capture_helper.rb +4 -4
- data/lib/action_view/helpers/csrf_helper.rb +3 -1
- data/lib/action_view/helpers/date_helper.rb +10 -5
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +36 -30
- data/lib/action_view/helpers/form_options_helper.rb +7 -6
- data/lib/action_view/helpers/form_tag_helper.rb +17 -6
- data/lib/action_view/helpers/javascript_helper.rb +1 -0
- data/lib/action_view/helpers/number_helper.rb +16 -45
- data/lib/action_view/helpers/prototype_helper.rb +14 -16
- data/lib/action_view/helpers/raw_output_helper.rb +9 -0
- data/lib/action_view/helpers/record_tag_helper.rb +5 -0
- data/lib/action_view/helpers/sanitize_helper.rb +26 -20
- data/lib/action_view/helpers/scriptaculous_helper.rb +6 -5
- data/lib/action_view/helpers/tag_helper.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +24 -111
- data/lib/action_view/helpers/translation_helper.rb +17 -10
- data/lib/action_view/helpers/url_helper.rb +26 -33
- data/lib/action_view/log_subscriber.rb +28 -0
- data/lib/action_view/lookup_context.rb +2 -0
- data/lib/action_view/paths.rb +1 -0
- data/lib/action_view/railtie.rb +15 -3
- data/lib/action_view/render/layouts.rb +2 -1
- data/lib/action_view/render/partials.rb +3 -1
- data/lib/action_view/render/rendering.rb +2 -1
- data/lib/action_view/template.rb +12 -8
- data/lib/action_view/template/error.rb +1 -0
- data/lib/action_view/template/handlers.rb +1 -0
- data/lib/action_view/template/resolver.rb +2 -1
- data/lib/action_view/template/text.rb +1 -0
- data/lib/action_view/test_case.rb +42 -20
- metadata +44 -23
- data/lib/action_controller/polymorphic_routes.rb +0 -182
- data/lib/action_controller/railties/log_subscriber.rb +0 -56
- data/lib/action_controller/railties/url_helpers.rb +0 -14
- data/lib/action_dispatch/testing/assertions/model.rb +0 -19
- data/lib/action_view/helpers/record_identification_helper.rb +0 -20
- data/lib/action_view/railties/log_subscriber.rb +0 -24
@@ -40,7 +40,7 @@ module ActionController
|
|
40
40
|
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
|
41
41
|
end
|
42
42
|
|
43
|
-
# Asserts that the request was rendered with the appropriate template file or partials
|
43
|
+
# Asserts that the request was rendered with the appropriate template file or partials.
|
44
44
|
#
|
45
45
|
# ==== Examples
|
46
46
|
#
|
@@ -53,6 +53,12 @@ module ActionController
|
|
53
53
|
# # assert that no partials were rendered
|
54
54
|
# assert_template :partial => false
|
55
55
|
#
|
56
|
+
# In a view test case, you can also assert that specific locals are passed
|
57
|
+
# to partials:
|
58
|
+
#
|
59
|
+
# # assert that the "_customer" partial was rendered with a specific object
|
60
|
+
# assert_template :partial => '_customer', :locals => { :customer => @customer }
|
61
|
+
#
|
56
62
|
def assert_template(options = {}, message = nil)
|
57
63
|
validate_request!
|
58
64
|
|
@@ -72,9 +78,13 @@ module ActionController
|
|
72
78
|
end
|
73
79
|
when Hash
|
74
80
|
if expected_partial = options[:partial]
|
75
|
-
if
|
81
|
+
if expected_locals = options[:locals]
|
82
|
+
actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
|
83
|
+
expected_locals.each_pair do |k,v|
|
84
|
+
assert_equal(v, actual_locals[k])
|
85
|
+
end
|
86
|
+
elsif expected_count = options[:count]
|
76
87
|
actual_count = @partials[expected_partial]
|
77
|
-
# actual_count = found.nil? ? 0 : found[1]
|
78
88
|
msg = build_message(message,
|
79
89
|
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
|
80
90
|
expected_partial, expected_count, actual_count)
|
@@ -183,12 +193,14 @@ module ActionController
|
|
183
193
|
replace(session.stringify_keys)
|
184
194
|
@loaded = true
|
185
195
|
end
|
196
|
+
|
197
|
+
def exists?; true; end
|
186
198
|
end
|
187
199
|
|
188
200
|
# Superclass for ActionController functional tests. Functional tests allow you to
|
189
201
|
# test a single controller action per test method. This should not be confused with
|
190
202
|
# integration tests (see ActionController::IntegrationTest), which are more like
|
191
|
-
# "stories" that can involve multiple controllers and
|
203
|
+
# "stories" that can involve multiple controllers and multiple actions (i.e. multiple
|
192
204
|
# different HTTP requests).
|
193
205
|
#
|
194
206
|
# == Basic example
|
@@ -353,7 +365,7 @@ module ActionController
|
|
353
365
|
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
|
354
366
|
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
355
367
|
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
356
|
-
|
368
|
+
__send__(request_method, action, parameters, session, flash).tap do
|
357
369
|
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
358
370
|
@request.env.delete 'HTTP_ACCEPT'
|
359
371
|
end
|
@@ -442,7 +454,7 @@ module ActionController
|
|
442
454
|
end
|
443
455
|
|
444
456
|
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
|
445
|
-
# (
|
457
|
+
# (skipping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
|
446
458
|
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
|
447
459
|
# than 0.0.0.0.
|
448
460
|
#
|
data/lib/action_dispatch.rb
CHANGED
@@ -24,9 +24,14 @@
|
|
24
24
|
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
25
25
|
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
26
26
|
|
27
|
+
activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
|
28
|
+
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
|
29
|
+
|
27
30
|
require 'active_support'
|
28
31
|
require 'active_support/dependencies/autoload'
|
29
32
|
|
33
|
+
require 'action_pack'
|
34
|
+
require 'active_model'
|
30
35
|
require 'rack'
|
31
36
|
|
32
37
|
module Rack
|
@@ -63,6 +68,7 @@ module ActionDispatch
|
|
63
68
|
autoload :Headers
|
64
69
|
autoload :MimeNegotiation
|
65
70
|
autoload :Parameters
|
71
|
+
autoload :ParameterFilter
|
66
72
|
autoload :FilterParameters
|
67
73
|
autoload :Upload
|
68
74
|
autoload :UploadedFile, 'action_dispatch/http/upload'
|
@@ -89,7 +89,7 @@ module ActionDispatch
|
|
89
89
|
if etag? || last_modified? || !@cache_control.empty?
|
90
90
|
set_conditional_cache_control!
|
91
91
|
elsif nonempty_ok_response?
|
92
|
-
self.etag =
|
92
|
+
self.etag = body
|
93
93
|
|
94
94
|
if request && request.etag_matches?(etag)
|
95
95
|
self.status = 304
|
@@ -137,4 +137,4 @@ module ActionDispatch
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
140
|
-
end
|
140
|
+
end
|
@@ -26,88 +26,32 @@ module ActionDispatch
|
|
26
26
|
module FilterParameters
|
27
27
|
extend ActiveSupport::Concern
|
28
28
|
|
29
|
-
@@
|
29
|
+
@@parameter_filter_for = {}
|
30
30
|
|
31
31
|
# Return a hash of parameters with all sensitive data replaced.
|
32
32
|
def filtered_parameters
|
33
|
-
@filtered_parameters ||=
|
34
|
-
process_parameter_filter(parameters)
|
35
|
-
else
|
36
|
-
parameters.dup
|
37
|
-
end
|
33
|
+
@filtered_parameters ||= parameter_filter.filter(parameters)
|
38
34
|
end
|
39
|
-
alias :fitered_params :filtered_parameters
|
40
35
|
|
41
36
|
# Return a hash of request.env with all sensitive data replaced.
|
42
37
|
def filtered_env
|
43
|
-
filtered_env
|
44
|
-
filtered_env.each do |key, value|
|
45
|
-
if (key =~ /RAW_POST_DATA/i)
|
46
|
-
filtered_env[key] = '[FILTERED]'
|
47
|
-
elsif value.is_a?(Hash)
|
48
|
-
filtered_env[key] = process_parameter_filter(value)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
filtered_env
|
38
|
+
@filtered_env ||= env_filter.filter(@env)
|
52
39
|
end
|
53
40
|
|
54
41
|
protected
|
55
42
|
|
56
|
-
def
|
57
|
-
@env["action_dispatch.parameter_filter"]
|
43
|
+
def parameter_filter
|
44
|
+
parameter_filter_for(@env["action_dispatch.parameter_filter"])
|
58
45
|
end
|
59
46
|
|
60
|
-
def
|
61
|
-
|
47
|
+
def env_filter
|
48
|
+
parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/)
|
62
49
|
end
|
63
50
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
filters.each do |item|
|
68
|
-
case item
|
69
|
-
when NilClass
|
70
|
-
when Proc
|
71
|
-
blocks << item
|
72
|
-
when Regexp
|
73
|
-
regexps << item
|
74
|
-
else
|
75
|
-
strings << item.to_s
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
|
80
|
-
[regexps, blocks]
|
81
|
-
end
|
82
|
-
|
83
|
-
def compiled_parameter_filter_for(filters) #:nodoc:
|
84
|
-
@@compiled_parameter_filter_for[filters] ||= begin
|
85
|
-
regexps, blocks = compile_parameter_filter(filters)
|
86
|
-
|
87
|
-
lambda do |original_params|
|
88
|
-
filtered_params = {}
|
89
|
-
|
90
|
-
original_params.each do |key, value|
|
91
|
-
if regexps.find { |r| key =~ r }
|
92
|
-
value = '[FILTERED]'
|
93
|
-
elsif value.is_a?(Hash)
|
94
|
-
value = process_parameter_filter(value)
|
95
|
-
elsif value.is_a?(Array)
|
96
|
-
value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
|
97
|
-
elsif blocks.present?
|
98
|
-
key = key.dup
|
99
|
-
value = value.dup if value.duplicable?
|
100
|
-
blocks.each { |b| b.call(key, value) }
|
101
|
-
end
|
102
|
-
|
103
|
-
filtered_params[key] = value
|
104
|
-
end
|
105
|
-
|
106
|
-
filtered_params
|
107
|
-
end
|
108
|
-
end
|
51
|
+
def parameter_filter_for(filters)
|
52
|
+
@@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
|
109
53
|
end
|
110
54
|
|
111
55
|
end
|
112
56
|
end
|
113
|
-
end
|
57
|
+
end
|
@@ -60,7 +60,7 @@ module Mime
|
|
60
60
|
def initialize(order, name, q=nil)
|
61
61
|
@order = order
|
62
62
|
@name = name.strip
|
63
|
-
q ||= 0.0 if @name == Mime::ALL # default
|
63
|
+
q ||= 0.0 if @name == Mime::ALL # default wildcard match to end of list
|
64
64
|
@q = ((q || 1.0).to_f * 100).to_i
|
65
65
|
end
|
66
66
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ActionDispatch
|
2
|
+
module Http
|
3
|
+
class ParameterFilter
|
4
|
+
|
5
|
+
def initialize(filters)
|
6
|
+
@filters = filters
|
7
|
+
end
|
8
|
+
|
9
|
+
def filter(params)
|
10
|
+
if enabled?
|
11
|
+
compiled_filter.call(params)
|
12
|
+
else
|
13
|
+
params.dup
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def enabled?
|
20
|
+
@filters.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def compiled_filter
|
24
|
+
@compiled_filter ||= begin
|
25
|
+
regexps, blocks = compile_filter
|
26
|
+
|
27
|
+
lambda do |original_params|
|
28
|
+
filtered_params = {}
|
29
|
+
|
30
|
+
original_params.each do |key, value|
|
31
|
+
if regexps.find { |r| key =~ r }
|
32
|
+
value = '[FILTERED]'
|
33
|
+
elsif value.is_a?(Hash)
|
34
|
+
value = filter(value)
|
35
|
+
elsif value.is_a?(Array)
|
36
|
+
value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
|
37
|
+
elsif blocks.present?
|
38
|
+
key = key.dup
|
39
|
+
value = value.dup if value.duplicable?
|
40
|
+
blocks.each { |b| b.call(key, value) }
|
41
|
+
end
|
42
|
+
|
43
|
+
filtered_params[key] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
filtered_params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def compile_filter
|
52
|
+
strings, regexps, blocks = [], [], []
|
53
|
+
|
54
|
+
@filters.each do |item|
|
55
|
+
case item
|
56
|
+
when NilClass
|
57
|
+
when Proc
|
58
|
+
blocks << item
|
59
|
+
when Regexp
|
60
|
+
regexps << item
|
61
|
+
else
|
62
|
+
strings << item.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
|
67
|
+
[regexps, blocks]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -6,7 +6,11 @@ module ActionDispatch
|
|
6
6
|
module Parameters
|
7
7
|
# Returns both GET and POST \parameters in a single hash.
|
8
8
|
def parameters
|
9
|
-
@env["action_dispatch.request.parameters"] ||=
|
9
|
+
@env["action_dispatch.request.parameters"] ||= begin
|
10
|
+
params = request_parameters.merge(query_parameters)
|
11
|
+
params.merge!(path_parameters)
|
12
|
+
encode_params(params).with_indifferent_access
|
13
|
+
end
|
10
14
|
end
|
11
15
|
alias :params :parameters
|
12
16
|
|
@@ -32,7 +36,32 @@ module ActionDispatch
|
|
32
36
|
end
|
33
37
|
|
34
38
|
private
|
35
|
-
|
39
|
+
|
40
|
+
# TODO: Validate that the characters are UTF-8. If they aren't,
|
41
|
+
# you'll get a weird error down the road, but our form handling
|
42
|
+
# should really prevent that from happening
|
43
|
+
def encode_params(params)
|
44
|
+
return params unless "ruby".encoding_aware?
|
45
|
+
|
46
|
+
if params.is_a?(String)
|
47
|
+
return params.force_encoding("UTF-8").encode!
|
48
|
+
elsif !params.is_a?(Hash)
|
49
|
+
return params
|
50
|
+
end
|
51
|
+
|
52
|
+
params.each do |k, v|
|
53
|
+
case v
|
54
|
+
when Hash
|
55
|
+
encode_params(v)
|
56
|
+
when Array
|
57
|
+
v.map! {|el| encode_params(el) }
|
58
|
+
else
|
59
|
+
encode_params(v)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Convert nested Hash to HashWithIndifferentAccess
|
36
65
|
def normalize_parameters(value)
|
37
66
|
case value
|
38
67
|
when Hash
|
@@ -194,9 +194,12 @@ module ActionDispatch
|
|
194
194
|
@env['rack.input']
|
195
195
|
end
|
196
196
|
|
197
|
+
# TODO This should be broken apart into AD::Request::Session and probably
|
198
|
+
# be included by the session middleware.
|
197
199
|
def reset_session
|
198
|
-
|
200
|
+
session.destroy if session
|
199
201
|
self.session = {}
|
202
|
+
@env['action_dispatch.request.flash_hash'] = nil
|
200
203
|
end
|
201
204
|
|
202
205
|
def session=(session) #:nodoc:
|
@@ -31,8 +31,8 @@ module ActionDispatch
|
|
31
31
|
end
|
32
32
|
|
33
33
|
module Upload
|
34
|
-
# Convert nested
|
35
|
-
# file upload
|
34
|
+
# Convert nested Hash to HashWithIndifferentAccess and replace
|
35
|
+
# file upload hash with UploadedFile objects
|
36
36
|
def normalize_parameters(value)
|
37
37
|
if Hash === value && value.has_key?(:tempfile)
|
38
38
|
upload = value[:tempfile]
|
@@ -8,7 +8,7 @@ module ActionDispatch
|
|
8
8
|
class Callbacks
|
9
9
|
include ActiveSupport::Callbacks
|
10
10
|
|
11
|
-
define_callbacks :call, :
|
11
|
+
define_callbacks :call, :rescuable => true
|
12
12
|
define_callbacks :prepare, :scope => :name
|
13
13
|
|
14
14
|
# Add a preparation callback. Preparation callbacks are run before every
|
@@ -37,12 +37,12 @@ module ActionDispatch
|
|
37
37
|
|
38
38
|
def initialize(app, prepare_each_request = false)
|
39
39
|
@app, @prepare_each_request = app, prepare_each_request
|
40
|
-
|
40
|
+
_run_prepare_callbacks
|
41
41
|
end
|
42
42
|
|
43
43
|
def call(env)
|
44
|
-
|
45
|
-
|
44
|
+
_run_call_callbacks do
|
45
|
+
_run_prepare_callbacks if @prepare_each_request
|
46
46
|
@app.call(env)
|
47
47
|
end
|
48
48
|
end
|
@@ -45,7 +45,16 @@ module ActionDispatch
|
|
45
45
|
# * <tt>:value</tt> - The cookie's value or list of values (as an array).
|
46
46
|
# * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
|
47
47
|
# of the application.
|
48
|
-
# * <tt>:domain</tt> - The domain for which this cookie applies
|
48
|
+
# * <tt>:domain</tt> - The domain for which this cookie applies so you can
|
49
|
+
# restrict to the domain level. If you use a schema like www.example.com
|
50
|
+
# and want to share session with user.example.com set <tt>:domain</tt>
|
51
|
+
# to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
|
52
|
+
# <tt>:all</tt> again when deleting keys.
|
53
|
+
#
|
54
|
+
# :domain => nil # Does not sets cookie domain. (default)
|
55
|
+
# :domain => :all # Allow the cookie for the top most level
|
56
|
+
# domain and subdomains.
|
57
|
+
#
|
49
58
|
# * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
|
50
59
|
# * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
|
51
60
|
# Default is +false+.
|
@@ -59,17 +68,29 @@ module ActionDispatch
|
|
59
68
|
class CookieOverflow < StandardError; end
|
60
69
|
|
61
70
|
class CookieJar < Hash #:nodoc:
|
71
|
+
|
72
|
+
# This regular expression is used to split the levels of a domain
|
73
|
+
# So www.example.co.uk gives:
|
74
|
+
# $1 => www.
|
75
|
+
# $2 => example
|
76
|
+
# $3 => co.uk
|
77
|
+
DOMAIN_REGEXP = /^(.*\.)*(.*)\.(...|...\...|....|..\...|..)$/
|
78
|
+
|
62
79
|
def self.build(request)
|
63
80
|
secret = request.env[TOKEN_KEY]
|
64
|
-
|
81
|
+
host = request.env["HTTP_HOST"]
|
82
|
+
|
83
|
+
new(secret, host).tap do |hash|
|
65
84
|
hash.update(request.cookies)
|
66
85
|
end
|
67
86
|
end
|
68
87
|
|
69
|
-
def initialize(secret=nil)
|
88
|
+
def initialize(secret = nil, host = nil)
|
70
89
|
@secret = secret
|
71
90
|
@set_cookies = {}
|
72
91
|
@delete_cookies = {}
|
92
|
+
@host = host
|
93
|
+
|
73
94
|
super()
|
74
95
|
end
|
75
96
|
|
@@ -78,6 +99,15 @@ module ActionDispatch
|
|
78
99
|
super(name.to_s)
|
79
100
|
end
|
80
101
|
|
102
|
+
def handle_options(options) #:nodoc:
|
103
|
+
options[:path] ||= "/"
|
104
|
+
|
105
|
+
if options[:domain] == :all
|
106
|
+
@host =~ DOMAIN_REGEXP
|
107
|
+
options[:domain] = ".#{$2}.#{$3}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
81
111
|
# Sets the cookie named +name+. The second argument may be the very cookie
|
82
112
|
# value, or a hash of options as documented above.
|
83
113
|
def []=(key, options)
|
@@ -91,7 +121,8 @@ module ActionDispatch
|
|
91
121
|
|
92
122
|
value = super(key.to_s, value)
|
93
123
|
|
94
|
-
options
|
124
|
+
handle_options(options)
|
125
|
+
|
95
126
|
@set_cookies[key] = options
|
96
127
|
@delete_cookies.delete(key)
|
97
128
|
value
|
@@ -102,7 +133,9 @@ module ActionDispatch
|
|
102
133
|
# an options hash to delete cookies with extra data such as a <tt>:path</tt>.
|
103
134
|
def delete(key, options = {})
|
104
135
|
options.symbolize_keys!
|
105
|
-
|
136
|
+
|
137
|
+
handle_options(options)
|
138
|
+
|
106
139
|
value = super(key.to_s)
|
107
140
|
@delete_cookies[key] = options
|
108
141
|
value
|
@@ -118,7 +151,7 @@ module ActionDispatch
|
|
118
151
|
# This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples:
|
119
152
|
#
|
120
153
|
# cookies.permanent.signed[:remember_me] = current_user.id
|
121
|
-
# # => Set-Cookie:
|
154
|
+
# # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
122
155
|
def permanent
|
123
156
|
@permanent ||= PermanentCookieJar.new(self, @secret)
|
124
157
|
end
|