actionpack 4.2.11.3 → 5.0.0.beta1

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.

Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +379 -462
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/abstract_controller.rb +0 -2
  6. data/lib/abstract_controller/base.rb +17 -32
  7. data/lib/abstract_controller/callbacks.rb +52 -19
  8. data/lib/abstract_controller/collector.rb +4 -9
  9. data/lib/abstract_controller/helpers.rb +2 -2
  10. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  11. data/lib/abstract_controller/rendering.rb +27 -22
  12. data/lib/abstract_controller/translation.rb +8 -7
  13. data/lib/action_controller.rb +4 -3
  14. data/lib/action_controller/api.rb +146 -0
  15. data/lib/action_controller/base.rb +6 -10
  16. data/lib/action_controller/caching.rb +1 -3
  17. data/lib/action_controller/caching/fragments.rb +48 -3
  18. data/lib/action_controller/form_builder.rb +48 -0
  19. data/lib/action_controller/log_subscriber.rb +1 -10
  20. data/lib/action_controller/metal.rb +89 -62
  21. data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
  22. data/lib/action_controller/metal/conditional_get.rb +65 -24
  23. data/lib/action_controller/metal/cookies.rb +0 -2
  24. data/lib/action_controller/metal/data_streaming.rb +2 -22
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  26. data/lib/action_controller/metal/exceptions.rb +11 -6
  27. data/lib/action_controller/metal/force_ssl.rb +6 -6
  28. data/lib/action_controller/metal/head.rb +14 -7
  29. data/lib/action_controller/metal/helpers.rb +9 -5
  30. data/lib/action_controller/metal/http_authentication.rb +37 -38
  31. data/lib/action_controller/metal/implicit_render.rb +23 -6
  32. data/lib/action_controller/metal/instrumentation.rb +0 -1
  33. data/lib/action_controller/metal/live.rb +17 -55
  34. data/lib/action_controller/metal/mime_responds.rb +17 -37
  35. data/lib/action_controller/metal/params_wrapper.rb +8 -8
  36. data/lib/action_controller/metal/redirecting.rb +32 -9
  37. data/lib/action_controller/metal/renderers.rb +10 -8
  38. data/lib/action_controller/metal/rendering.rb +38 -6
  39. data/lib/action_controller/metal/request_forgery_protection.rb +67 -35
  40. data/lib/action_controller/metal/rescue.rb +2 -4
  41. data/lib/action_controller/metal/streaming.rb +4 -4
  42. data/lib/action_controller/metal/strong_parameters.rb +231 -78
  43. data/lib/action_controller/metal/testing.rb +1 -12
  44. data/lib/action_controller/metal/url_for.rb +12 -5
  45. data/lib/action_controller/renderer.rb +111 -0
  46. data/lib/action_controller/template_assertions.rb +9 -0
  47. data/lib/action_controller/test_case.rb +267 -363
  48. data/lib/action_dispatch.rb +2 -1
  49. data/lib/action_dispatch/http/cache.rb +23 -26
  50. data/lib/action_dispatch/http/filter_parameters.rb +6 -8
  51. data/lib/action_dispatch/http/filter_redirect.rb +7 -8
  52. data/lib/action_dispatch/http/headers.rb +28 -11
  53. data/lib/action_dispatch/http/mime_negotiation.rb +40 -26
  54. data/lib/action_dispatch/http/mime_type.rb +92 -61
  55. data/lib/action_dispatch/http/mime_types.rb +1 -4
  56. data/lib/action_dispatch/http/parameter_filter.rb +18 -8
  57. data/lib/action_dispatch/http/parameters.rb +45 -41
  58. data/lib/action_dispatch/http/request.rb +146 -82
  59. data/lib/action_dispatch/http/response.rb +180 -99
  60. data/lib/action_dispatch/http/url.rb +117 -8
  61. data/lib/action_dispatch/journey/formatter.rb +34 -28
  62. data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
  64. data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
  65. data/lib/action_dispatch/journey/nodes/node.rb +14 -4
  66. data/lib/action_dispatch/journey/parser_extras.rb +4 -0
  67. data/lib/action_dispatch/journey/path/pattern.rb +37 -41
  68. data/lib/action_dispatch/journey/route.rb +71 -17
  69. data/lib/action_dispatch/journey/router.rb +5 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +5 -5
  71. data/lib/action_dispatch/journey/routes.rb +14 -15
  72. data/lib/action_dispatch/journey/visitors.rb +86 -43
  73. data/lib/action_dispatch/middleware/cookies.rb +184 -135
  74. data/lib/action_dispatch/middleware/debug_exceptions.rb +115 -45
  75. data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -20
  76. data/lib/action_dispatch/middleware/flash.rb +61 -45
  77. data/lib/action_dispatch/middleware/load_interlock.rb +21 -0
  78. data/lib/action_dispatch/middleware/params_parser.rb +30 -46
  79. data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
  80. data/lib/action_dispatch/middleware/reloader.rb +2 -4
  81. data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
  82. data/lib/action_dispatch/middleware/request_id.rb +11 -6
  83. data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
  84. data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
  85. data/lib/action_dispatch/middleware/session/cookie_store.rb +29 -23
  86. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
  87. data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
  88. data/lib/action_dispatch/middleware/ssl.rb +93 -36
  89. data/lib/action_dispatch/middleware/stack.rb +43 -48
  90. data/lib/action_dispatch/middleware/static.rb +52 -40
  91. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  92. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  95. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  96. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  97. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
  98. data/lib/action_dispatch/railtie.rb +0 -2
  99. data/lib/action_dispatch/request/session.rb +66 -34
  100. data/lib/action_dispatch/request/utils.rb +51 -19
  101. data/lib/action_dispatch/routing.rb +3 -8
  102. data/lib/action_dispatch/routing/inspector.rb +6 -30
  103. data/lib/action_dispatch/routing/mapper.rb +447 -322
  104. data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
  105. data/lib/action_dispatch/routing/redirection.rb +3 -3
  106. data/lib/action_dispatch/routing/route_set.rb +124 -227
  107. data/lib/action_dispatch/routing/url_for.rb +27 -10
  108. data/lib/action_dispatch/testing/assertions.rb +1 -1
  109. data/lib/action_dispatch/testing/assertions/response.rb +27 -9
  110. data/lib/action_dispatch/testing/assertions/routing.rb +9 -9
  111. data/lib/action_dispatch/testing/integration.rb +237 -76
  112. data/lib/action_dispatch/testing/test_process.rb +5 -5
  113. data/lib/action_dispatch/testing/test_request.rb +12 -21
  114. data/lib/action_dispatch/testing/test_response.rb +1 -4
  115. data/lib/action_pack.rb +1 -1
  116. data/lib/action_pack/gem_version.rb +4 -4
  117. metadata +26 -25
  118. data/lib/action_controller/metal/hide_actions.rb +0 -40
  119. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  120. data/lib/action_controller/middleware.rb +0 -39
  121. data/lib/action_controller/model_naming.rb +0 -12
  122. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  123. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  124. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  125. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,15 +1,63 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
- require 'active_support/core_ext/module/attribute_accessors'
3
- require 'active_support/core_ext/object/blank'
4
2
  require 'active_support/key_generator'
5
3
  require 'active_support/message_verifier'
6
4
  require 'active_support/json'
7
5
 
8
6
  module ActionDispatch
9
- class Request < Rack::Request
7
+ class Request
10
8
  def cookie_jar
11
- env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self)
9
+ fetch_header('action_dispatch.cookies'.freeze) do
10
+ self.cookie_jar = Cookies::CookieJar.build(self, cookies)
11
+ end
12
+ end
13
+
14
+ # :stopdoc:
15
+ prepend Module.new {
16
+ def commit_cookie_jar!
17
+ cookie_jar.commit!
18
+ end
19
+ }
20
+
21
+ def have_cookie_jar?
22
+ has_header? 'action_dispatch.cookies'.freeze
23
+ end
24
+
25
+ def cookie_jar=(jar)
26
+ set_header 'action_dispatch.cookies'.freeze, jar
27
+ end
28
+
29
+ def key_generator
30
+ get_header Cookies::GENERATOR_KEY
31
+ end
32
+
33
+ def signed_cookie_salt
34
+ get_header Cookies::SIGNED_COOKIE_SALT
35
+ end
36
+
37
+ def encrypted_cookie_salt
38
+ get_header Cookies::ENCRYPTED_COOKIE_SALT
39
+ end
40
+
41
+ def encrypted_signed_cookie_salt
42
+ get_header Cookies::ENCRYPTED_SIGNED_COOKIE_SALT
12
43
  end
44
+
45
+ def secret_token
46
+ get_header Cookies::SECRET_TOKEN
47
+ end
48
+
49
+ def secret_key_base
50
+ get_header Cookies::SECRET_KEY_BASE
51
+ end
52
+
53
+ def cookies_serializer
54
+ get_header Cookies::COOKIES_SERIALIZER
55
+ end
56
+
57
+ def cookies_digest
58
+ get_header Cookies::COOKIES_DIGEST
59
+ end
60
+ # :startdoc:
13
61
  end
14
62
 
15
63
  # \Cookies are read and written through ActionController#cookies.
@@ -35,6 +83,12 @@ module ActionDispatch
35
83
  # # It can be read using the signed method `cookies.signed[:name]`
36
84
  # cookies.signed[:user_id] = current_user.id
37
85
  #
86
+ # # Sets an encrypted cookie value before sending it to the client which
87
+ # # prevent users from reading and tampering with its value.
88
+ # # The cookie is signed by your app's `secrets.secret_key_base` value.
89
+ # # It can be read using the encrypted method `cookies.encrypted[:name]`
90
+ # cookies.encrypted[:discount] = 45
91
+ #
38
92
  # # Sets a "permanent" cookie (which expires in 20 years from now).
39
93
  # cookies.permanent[:login] = "XJ-122"
40
94
  #
@@ -47,6 +101,7 @@ module ActionDispatch
47
101
  # cookies.size # => 2
48
102
  # JSON.parse(cookies[:lat_lon]) # => [47.68, -122.37]
49
103
  # cookies.signed[:login] # => "XJ-122"
104
+ # cookies.encrypted[:discount] # => 45
50
105
  #
51
106
  # Example for deleting:
52
107
  #
@@ -73,12 +128,15 @@ module ActionDispatch
73
128
  # to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
74
129
  # <tt>:all</tt> or <tt>Array</tt> again when deleting cookies.
75
130
  #
76
- # domain: nil # Does not sets cookie domain. (default)
131
+ # domain: nil # Does not set cookie domain. (default)
77
132
  # domain: :all # Allow the cookie for the top most level
78
133
  # # domain and subdomains.
79
134
  # domain: %w(.example.com .example.org) # Allow the cookie
80
135
  # # for concrete domain names.
81
136
  #
137
+ # * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
138
+ # set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
139
+ # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 1.
82
140
  # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
83
141
  # * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
84
142
  # Default is +false+.
@@ -115,7 +173,7 @@ module ActionDispatch
115
173
  # cookies.permanent.signed[:remember_me] = current_user.id
116
174
  # # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
117
175
  def permanent
118
- @permanent ||= PermanentCookieJar.new(self, @key_generator, @options)
176
+ @permanent ||= PermanentCookieJar.new(self)
119
177
  end
120
178
 
121
179
  # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
@@ -135,10 +193,10 @@ module ActionDispatch
135
193
  # cookies.signed[:discount] # => 45
136
194
  def signed
137
195
  @signed ||=
138
- if @options[:upgrade_legacy_signed_cookies]
139
- UpgradeLegacySignedCookieJar.new(self, @key_generator, @options)
196
+ if upgrade_legacy_signed_cookies?
197
+ UpgradeLegacySignedCookieJar.new(self)
140
198
  else
141
- SignedCookieJar.new(self, @key_generator, @options)
199
+ SignedCookieJar.new(self)
142
200
  end
143
201
  end
144
202
 
@@ -158,10 +216,10 @@ module ActionDispatch
158
216
  # cookies.encrypted[:discount] # => 45
159
217
  def encrypted
160
218
  @encrypted ||=
161
- if @options[:upgrade_legacy_signed_cookies]
162
- UpgradeLegacyEncryptedCookieJar.new(self, @key_generator, @options)
219
+ if upgrade_legacy_signed_cookies?
220
+ UpgradeLegacyEncryptedCookieJar.new(self)
163
221
  else
164
- EncryptedCookieJar.new(self, @key_generator, @options)
222
+ EncryptedCookieJar.new(self)
165
223
  end
166
224
  end
167
225
 
@@ -169,12 +227,18 @@ module ActionDispatch
169
227
  # Used by ActionDispatch::Session::CookieStore to avoid the need to introduce new cookie stores.
170
228
  def signed_or_encrypted
171
229
  @signed_or_encrypted ||=
172
- if @options[:secret_key_base].present?
230
+ if request.secret_key_base.present?
173
231
  encrypted
174
232
  else
175
233
  signed
176
234
  end
177
235
  end
236
+
237
+ private
238
+
239
+ def upgrade_legacy_signed_cookies?
240
+ request.secret_token.present? && request.secret_key_base.present?
241
+ end
178
242
  end
179
243
 
180
244
  # Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream
@@ -184,7 +248,7 @@ module ActionDispatch
184
248
  module VerifyAndUpgradeLegacySignedMessage # :nodoc:
185
249
  def initialize(*args)
186
250
  super
187
- @legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: ActiveSupport::MessageEncryptor::NullSerializer)
251
+ @legacy_verifier = ActiveSupport::MessageVerifier.new(request.secret_token, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
188
252
  end
189
253
 
190
254
  def verify_and_upgrade_legacy_signed_message(name, signed_message)
@@ -194,6 +258,11 @@ module ActionDispatch
194
258
  rescue ActiveSupport::MessageVerifier::InvalidSignature
195
259
  nil
196
260
  end
261
+
262
+ private
263
+ def parse(name, signed_message)
264
+ super || verify_and_upgrade_legacy_signed_message(name, signed_message)
265
+ end
197
266
  end
198
267
 
199
268
  class CookieJar #:nodoc:
@@ -213,38 +282,18 @@ module ActionDispatch
213
282
  # $& => example.local
214
283
  DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
215
284
 
216
- def self.options_for_env(env) #:nodoc:
217
- { signed_cookie_salt: env[SIGNED_COOKIE_SALT] || '',
218
- encrypted_cookie_salt: env[ENCRYPTED_COOKIE_SALT] || '',
219
- encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] || '',
220
- secret_token: env[SECRET_TOKEN],
221
- secret_key_base: env[SECRET_KEY_BASE],
222
- upgrade_legacy_signed_cookies: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present?,
223
- serializer: env[COOKIES_SERIALIZER],
224
- digest: env[COOKIES_DIGEST]
225
- }
226
- end
227
-
228
- def self.build(request)
229
- env = request.env
230
- key_generator = env[GENERATOR_KEY]
231
- options = options_for_env env
232
-
233
- host = request.host
234
- secure = request.ssl?
235
-
236
- new(key_generator, host, secure, options).tap do |hash|
237
- hash.update(request.cookies)
285
+ def self.build(req, cookies)
286
+ new(req).tap do |hash|
287
+ hash.update(cookies)
238
288
  end
239
289
  end
240
290
 
241
- def initialize(key_generator, host = nil, secure = false, options = {})
242
- @key_generator = key_generator
291
+ attr_reader :request
292
+
293
+ def initialize(request)
243
294
  @set_cookies = {}
244
295
  @delete_cookies = {}
245
- @host = host
246
- @secure = secure
247
- @options = options
296
+ @request = request
248
297
  @cookies = {}
249
298
  @committed = false
250
299
  end
@@ -280,21 +329,32 @@ module ActionDispatch
280
329
  self
281
330
  end
282
331
 
332
+ def update_cookies_from_jar
333
+ request_jar = @request.cookie_jar.instance_variable_get(:@cookies)
334
+ set_cookies = request_jar.reject { |k,_| @delete_cookies.key?(k) }
335
+
336
+ @cookies.update set_cookies if set_cookies
337
+ end
338
+
339
+ def to_header
340
+ @cookies.map { |k,v| "#{k}=#{v}" }.join ';'
341
+ end
342
+
283
343
  def handle_options(options) #:nodoc:
284
344
  options[:path] ||= "/"
285
345
 
286
- if options[:domain] == :all
346
+ if options[:domain] == :all || options[:domain] == 'all'
287
347
  # if there is a provided tld length then we use it otherwise default domain regexp
288
348
  domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
289
349
 
290
350
  # if host is not ip and matches domain regexp
291
351
  # (ip confirms to domain regexp so we explicitly check for ip)
292
- options[:domain] = if (@host !~ /^[\d.]+$/) && (@host =~ domain_regexp)
352
+ options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp)
293
353
  ".#{$&}"
294
354
  end
295
355
  elsif options[:domain].is_a? Array
296
356
  # if host matches one of the supplied domains without a dot in front of it
297
- options[:domain] = options[:domain].find {|domain| @host.include? domain.sub(/^\./, '') }
357
+ options[:domain] = options[:domain].find {|domain| request.host.include? domain.sub(/^\./, '') }
298
358
  end
299
359
  end
300
360
 
@@ -311,7 +371,7 @@ module ActionDispatch
311
371
 
312
372
  handle_options(options)
313
373
 
314
- if @cookies[name.to_s] != value || options[:expires]
374
+ if @cookies[name.to_s] != value or options[:expires]
315
375
  @cookies[name.to_s] = value
316
376
  @set_cookies[name.to_s] = options
317
377
  @delete_cookies.delete(name.to_s)
@@ -349,47 +409,71 @@ module ActionDispatch
349
409
  end
350
410
 
351
411
  def write(headers)
352
- @set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) if write_cookie?(v) }
353
- @delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
354
- end
355
-
356
- def recycle! #:nodoc:
357
- @set_cookies = {}
358
- @delete_cookies = {}
412
+ if header = make_set_cookie_header(headers[HTTP_HEADER])
413
+ headers[HTTP_HEADER] = header
414
+ end
359
415
  end
360
416
 
361
417
  mattr_accessor :always_write_cookie
362
418
  self.always_write_cookie = false
363
419
 
364
420
  private
365
- def write_cookie?(cookie)
366
- @secure || !cookie[:secure] || always_write_cookie
367
- end
421
+
422
+ def make_set_cookie_header(header)
423
+ header = @set_cookies.inject(header) { |m, (k, v)|
424
+ if write_cookie?(v)
425
+ ::Rack::Utils.add_cookie_to_header(m, k, v)
426
+ else
427
+ m
428
+ end
429
+ }
430
+ @delete_cookies.inject(header) { |m, (k, v)|
431
+ ::Rack::Utils.add_remove_cookie_to_header(m, k, v)
432
+ }
433
+ end
434
+
435
+ def write_cookie?(cookie)
436
+ request.ssl? || !cookie[:secure] || always_write_cookie
437
+ end
368
438
  end
369
439
 
370
- class PermanentCookieJar #:nodoc:
440
+ class AbstractCookieJar # :nodoc:
371
441
  include ChainedCookieJars
372
442
 
373
- def initialize(parent_jar, key_generator, options = {})
443
+ def initialize(parent_jar)
374
444
  @parent_jar = parent_jar
375
- @key_generator = key_generator
376
- @options = options
377
445
  end
378
446
 
379
447
  def [](name)
380
- @parent_jar[name.to_s]
448
+ if data = @parent_jar[name.to_s]
449
+ parse name, data
450
+ end
381
451
  end
382
452
 
383
453
  def []=(name, options)
384
454
  if options.is_a?(Hash)
385
455
  options.symbolize_keys!
386
456
  else
387
- options = { :value => options }
457
+ options = { value: options }
388
458
  end
389
459
 
390
- options[:expires] = 20.years.from_now
460
+ commit(options)
391
461
  @parent_jar[name] = options
392
462
  end
463
+
464
+ protected
465
+ def request; @parent_jar.request; end
466
+
467
+ private
468
+ def parse(name, data); data; end
469
+ def commit(options); end
470
+ end
471
+
472
+ class PermanentCookieJar < AbstractCookieJar # :nodoc:
473
+ private
474
+ def commit(options)
475
+ options[:expires] = 20.years.from_now
476
+ end
393
477
  end
394
478
 
395
479
  class JsonSerializer # :nodoc:
@@ -407,10 +491,10 @@ module ActionDispatch
407
491
 
408
492
  protected
409
493
  def needs_migration?(value)
410
- @options[:serializer] == :hybrid && value.start_with?(MARSHAL_SIGNATURE)
494
+ request.cookies_serializer == :hybrid && value.start_with?(MARSHAL_SIGNATURE)
411
495
  end
412
496
 
413
- def serialize(name, value)
497
+ def serialize(value)
414
498
  serializer.dump(value)
415
499
  end
416
500
 
@@ -427,7 +511,7 @@ module ActionDispatch
427
511
  end
428
512
 
429
513
  def serializer
430
- serializer = @options[:serializer] || :marshal
514
+ serializer = request.cookies_serializer || :marshal
431
515
  case serializer
432
516
  when :marshal
433
517
  Marshal
@@ -439,103 +523,71 @@ module ActionDispatch
439
523
  end
440
524
 
441
525
  def digest
442
- @options[:digest] || 'SHA1'
526
+ request.cookies_digest || 'SHA1'
527
+ end
528
+
529
+ def key_generator
530
+ request.key_generator
443
531
  end
444
532
  end
445
533
 
446
- class SignedCookieJar #:nodoc:
447
- include ChainedCookieJars
534
+ class SignedCookieJar < AbstractCookieJar # :nodoc:
448
535
  include SerializedCookieJars
449
536
 
450
- def initialize(parent_jar, key_generator, options = {})
451
- @parent_jar = parent_jar
452
- @options = options
453
- secret = key_generator.generate_key(@options[:signed_cookie_salt])
537
+ def initialize(parent_jar)
538
+ super
539
+ secret = key_generator.generate_key(request.signed_cookie_salt)
454
540
  @verifier = ActiveSupport::MessageVerifier.new(secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
455
541
  end
456
542
 
457
- def [](name)
458
- if signed_message = @parent_jar[name]
459
- deserialize name, verify(signed_message)
460
- end
461
- end
462
-
463
- def []=(name, options)
464
- if options.is_a?(Hash)
465
- options.symbolize_keys!
466
- options[:value] = @verifier.generate(serialize(name, options[:value]))
467
- else
468
- options = { :value => @verifier.generate(serialize(name, options)) }
543
+ private
544
+ def parse(name, signed_message)
545
+ deserialize name, @verifier.verified(signed_message)
469
546
  end
470
547
 
471
- raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
472
- @parent_jar[name] = options
473
- end
548
+ def commit(options)
549
+ options[:value] = @verifier.generate(serialize(options[:value]))
474
550
 
475
- private
476
- def verify(signed_message)
477
- @verifier.verify(signed_message)
478
- rescue ActiveSupport::MessageVerifier::InvalidSignature
479
- nil
551
+ raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
480
552
  end
481
553
  end
482
554
 
483
555
  # UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
484
556
  # secrets.secret_token and secrets.secret_key_base are both set. It reads
485
- # legacy cookies signed with the old dummy key generator and re-saves
486
- # them using the new key generator to provide a smooth upgrade path.
557
+ # legacy cookies signed with the old dummy key generator and signs and
558
+ # re-saves them using the new key generator to provide a smooth upgrade path.
487
559
  class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
488
560
  include VerifyAndUpgradeLegacySignedMessage
489
-
490
- def [](name)
491
- if signed_message = @parent_jar[name]
492
- deserialize(name, verify(signed_message)) || verify_and_upgrade_legacy_signed_message(name, signed_message)
493
- end
494
- end
495
561
  end
496
562
 
497
- class EncryptedCookieJar #:nodoc:
498
- include ChainedCookieJars
563
+ class EncryptedCookieJar < AbstractCookieJar # :nodoc:
499
564
  include SerializedCookieJars
500
565
 
501
- def initialize(parent_jar, key_generator, options = {})
566
+ def initialize(parent_jar)
567
+ super
568
+
502
569
  if ActiveSupport::LegacyKeyGenerator === key_generator
503
570
  raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " +
504
571
  "Read the upgrade documentation to learn more about this new config option."
505
572
  end
506
573
 
507
- @parent_jar = parent_jar
508
- @options = options
509
- secret = key_generator.generate_key(@options[:encrypted_cookie_salt])[0, ActiveSupport::MessageEncryptor.key_len]
510
- sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
574
+ secret = key_generator.generate_key(request.encrypted_cookie_salt || '')
575
+ sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || '')
511
576
  @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
512
577
  end
513
578
 
514
- def [](name)
515
- if encrypted_message = @parent_jar[name]
516
- deserialize name, decrypt_and_verify(encrypted_message)
517
- end
518
- end
519
-
520
- def []=(name, options)
521
- if options.is_a?(Hash)
522
- options.symbolize_keys!
523
- else
524
- options = { :value => options }
525
- end
526
-
527
- options[:value] = @encryptor.encrypt_and_sign(serialize(name, options[:value]))
528
-
529
- raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
530
- @parent_jar[name] = options
531
- end
532
-
533
579
  private
534
- def decrypt_and_verify(encrypted_message)
535
- @encryptor.decrypt_and_verify(encrypted_message)
580
+ def parse(name, encrypted_message)
581
+ deserialize name, @encryptor.decrypt_and_verify(encrypted_message)
536
582
  rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
537
583
  nil
538
584
  end
585
+
586
+ def commit(options)
587
+ options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]))
588
+
589
+ raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
590
+ end
539
591
  end
540
592
 
541
593
  # UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
@@ -544,12 +596,6 @@ module ActionDispatch
544
596
  # encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
545
597
  class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
546
598
  include VerifyAndUpgradeLegacySignedMessage
547
-
548
- def [](name)
549
- if encrypted_or_signed_message = @parent_jar[name]
550
- deserialize(name, decrypt_and_verify(encrypted_or_signed_message)) || verify_and_upgrade_legacy_signed_message(name, encrypted_or_signed_message)
551
- end
552
- end
553
599
  end
554
600
 
555
601
  def initialize(app)
@@ -557,9 +603,12 @@ module ActionDispatch
557
603
  end
558
604
 
559
605
  def call(env)
606
+ request = ActionDispatch::Request.new env
607
+
560
608
  status, headers, body = @app.call(env)
561
609
 
562
- if cookie_jar = env['action_dispatch.cookies']
610
+ if request.have_cookie_jar?
611
+ cookie_jar = request.cookie_jar
563
612
  unless cookie_jar.committed?
564
613
  cookie_jar.write(headers)
565
614
  if headers[HTTP_HEADER].respond_to?(:join)