actionpack 5.2.4.4 → 6.1.1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -322
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller.rb +1 -0
  6. data/lib/abstract_controller/base.rb +38 -4
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/caching/fragments.rb +6 -22
  9. data/lib/abstract_controller/callbacks.rb +14 -2
  10. data/lib/abstract_controller/collector.rb +1 -2
  11. data/lib/abstract_controller/helpers.rb +106 -90
  12. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  13. data/lib/abstract_controller/rendering.rb +9 -9
  14. data/lib/abstract_controller/translation.rb +11 -5
  15. data/lib/action_controller.rb +7 -4
  16. data/lib/action_controller/api.rb +4 -3
  17. data/lib/action_controller/base.rb +6 -9
  18. data/lib/action_controller/caching.rb +1 -3
  19. data/lib/action_controller/log_subscriber.rb +10 -7
  20. data/lib/action_controller/metal.rb +10 -8
  21. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  22. data/lib/action_controller/metal/conditional_get.rb +19 -5
  23. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  24. data/lib/action_controller/metal/cookies.rb +3 -1
  25. data/lib/action_controller/metal/data_streaming.rb +6 -7
  26. data/lib/action_controller/metal/default_headers.rb +17 -0
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
  28. data/lib/action_controller/metal/exceptions.rb +56 -2
  29. data/lib/action_controller/metal/flash.rb +5 -5
  30. data/lib/action_controller/metal/head.rb +7 -4
  31. data/lib/action_controller/metal/helpers.rb +14 -5
  32. data/lib/action_controller/metal/http_authentication.rb +24 -23
  33. data/lib/action_controller/metal/implicit_render.rb +5 -15
  34. data/lib/action_controller/metal/instrumentation.rb +13 -14
  35. data/lib/action_controller/metal/live.rb +30 -32
  36. data/lib/action_controller/metal/logging.rb +20 -0
  37. data/lib/action_controller/metal/mime_responds.rb +19 -4
  38. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  39. data/lib/action_controller/metal/params_wrapper.rb +31 -22
  40. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  41. data/lib/action_controller/metal/redirecting.rb +6 -6
  42. data/lib/action_controller/metal/renderers.rb +4 -4
  43. data/lib/action_controller/metal/rendering.rb +8 -3
  44. data/lib/action_controller/metal/request_forgery_protection.rb +62 -34
  45. data/lib/action_controller/metal/rescue.rb +1 -1
  46. data/lib/action_controller/metal/streaming.rb +0 -1
  47. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  48. data/lib/action_controller/metal/url_for.rb +1 -1
  49. data/lib/action_controller/railties/helpers.rb +1 -1
  50. data/lib/action_controller/renderer.rb +37 -13
  51. data/lib/action_controller/template_assertions.rb +1 -1
  52. data/lib/action_controller/test_case.rb +70 -65
  53. data/lib/action_dispatch.rb +9 -3
  54. data/lib/action_dispatch/http/cache.rb +26 -21
  55. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  56. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  57. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  59. data/lib/action_dispatch/http/headers.rb +4 -4
  60. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  61. data/lib/action_dispatch/http/mime_type.rb +42 -23
  62. data/lib/action_dispatch/http/parameters.rb +14 -23
  63. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  64. data/lib/action_dispatch/http/request.rb +45 -22
  65. data/lib/action_dispatch/http/response.rb +45 -25
  66. data/lib/action_dispatch/http/upload.rb +9 -1
  67. data/lib/action_dispatch/http/url.rb +82 -82
  68. data/lib/action_dispatch/journey.rb +0 -2
  69. data/lib/action_dispatch/journey/formatter.rb +54 -30
  70. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  71. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  72. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  73. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  74. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  75. data/lib/action_dispatch/journey/parser.rb +13 -13
  76. data/lib/action_dispatch/journey/parser.y +1 -1
  77. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  78. data/lib/action_dispatch/journey/route.rb +10 -20
  79. data/lib/action_dispatch/journey/router.rb +26 -34
  80. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  81. data/lib/action_dispatch/journey/routes.rb +0 -2
  82. data/lib/action_dispatch/journey/scanner.rb +10 -4
  83. data/lib/action_dispatch/journey/visitors.rb +1 -4
  84. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  85. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  86. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  87. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  88. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  89. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  90. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  91. data/lib/action_dispatch/middleware/flash.rb +1 -1
  92. data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
  93. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  94. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  95. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  96. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  97. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  98. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  99. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  100. data/lib/action_dispatch/middleware/stack.rb +56 -2
  101. data/lib/action_dispatch/middleware/static.rb +153 -93
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  108. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  114. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  123. data/lib/action_dispatch/railtie.rb +8 -2
  124. data/lib/action_dispatch/request/session.rb +10 -9
  125. data/lib/action_dispatch/request/utils.rb +26 -2
  126. data/lib/action_dispatch/routing.rb +21 -20
  127. data/lib/action_dispatch/routing/inspector.rb +100 -52
  128. data/lib/action_dispatch/routing/mapper.rb +155 -103
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  130. data/lib/action_dispatch/routing/redirection.rb +3 -3
  131. data/lib/action_dispatch/routing/route_set.rb +71 -69
  132. data/lib/action_dispatch/routing/url_for.rb +2 -2
  133. data/lib/action_dispatch/system_test_case.rb +54 -11
  134. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  135. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  136. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  137. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  138. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  139. data/lib/action_dispatch/testing/assertions.rb +1 -1
  140. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  141. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  142. data/lib/action_dispatch/testing/integration.rb +61 -28
  143. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  144. data/lib/action_dispatch/testing/test_process.rb +29 -4
  145. data/lib/action_dispatch/testing/test_request.rb +3 -3
  146. data/lib/action_dispatch/testing/test_response.rb +4 -32
  147. data/lib/action_pack.rb +1 -1
  148. data/lib/action_pack/gem_version.rb +4 -4
  149. metadata +38 -26
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/keys"
4
-
5
3
  module ActionController
6
4
  # ActionController::Renderer allows you to render arbitrary templates
7
5
  # without requirement of being in controller actions.
@@ -67,10 +65,29 @@ module ActionController
67
65
  def initialize(controller, env, defaults)
68
66
  @controller = controller
69
67
  @defaults = defaults
70
- @env = normalize_keys defaults.merge(env)
68
+ @env = normalize_keys defaults, env
71
69
  end
72
70
 
73
71
  # Render templates with any options from ActionController::Base#render_to_string.
72
+ #
73
+ # The primary options are:
74
+ # * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt> for details.
75
+ # * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
76
+ # It shouldn’t be used directly with unsanitized user input due to lack of validation.
77
+ # * <tt>:inline</tt> - Renders an ERB template string.
78
+ # * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
79
+ # * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
80
+ # performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
81
+ # * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
82
+ # need to call <tt>.to_json</tt> on the object you want to render.
83
+ # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
+ #
85
+ # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
86
+ #
87
+ # If an object responding to `render_in` is passed, `render_in` is called on the object,
88
+ # passing in the current view context.
89
+ #
90
+ # Otherwise, a partial is rendered using the second parameter as the locals hash.
74
91
  def render(*args)
75
92
  raise "missing controller" unless controller
76
93
 
@@ -82,11 +99,18 @@ module ActionController
82
99
  instance.set_response! controller.make_response!(request)
83
100
  instance.render_to_string(*args)
84
101
  end
102
+ alias_method :render_to_string, :render # :nodoc:
85
103
 
86
104
  private
87
- def normalize_keys(env)
105
+ def normalize_keys(defaults, env)
88
106
  new_env = {}
89
107
  env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
108
+
109
+ defaults.each_pair do |k, v|
110
+ key = rack_key_for(k)
111
+ new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
112
+ end
113
+
90
114
  new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
91
115
  new_env
92
116
  end
@@ -99,19 +123,19 @@ module ActionController
99
123
  input: "rack.input"
100
124
  }
101
125
 
102
- IDENTITY = ->(_) { _ }
103
-
104
- RACK_VALUE_TRANSLATION = {
105
- https: ->(v) { v ? "on" : "off" },
106
- method: ->(v) { v.upcase },
107
- }
108
-
109
126
  def rack_key_for(key)
110
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
127
+ RACK_KEY_TRANSLATION[key] || key.to_s
111
128
  end
112
129
 
113
130
  def rack_value_for(key, value)
114
- RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
131
+ case key
132
+ when :https
133
+ value ? "on" : "off"
134
+ when :method
135
+ -value.upcase
136
+ else
137
+ value
138
+ end
115
139
  end
116
140
  end
117
141
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
- module TemplateAssertions
4
+ module TemplateAssertions # :nodoc:
5
5
  def assert_template(options = {}, message = nil)
6
6
  raise NoMethodError,
7
7
  "assert_template has been extracted to a gem. To continue using it,
@@ -26,7 +26,7 @@ module ActionController
26
26
  end
27
27
  end
28
28
 
29
- # ActionController::TestCase will be deprecated and moved to a gem in Rails 5.1.
29
+ # ActionController::TestCase will be deprecated and moved to a gem in the future.
30
30
  # Please use ActionDispatch::IntegrationTest going forward.
31
31
  class TestRequest < ActionDispatch::TestRequest #:nodoc:
32
32
  DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
@@ -84,7 +84,7 @@ module ActionController
84
84
  value = value.to_param
85
85
  end
86
86
 
87
- path_parameters[key] = value
87
+ path_parameters[key.to_sym] = value
88
88
  end
89
89
  end
90
90
 
@@ -158,7 +158,6 @@ module ActionController
158
158
  end.new
159
159
 
160
160
  private
161
-
162
161
  def params_parsers
163
162
  super.merge @custom_param_parsers
164
163
  end
@@ -177,12 +176,12 @@ module ActionController
177
176
 
178
177
  # Methods #destroy and #load! are overridden to avoid calling methods on the
179
178
  # @store object, which does not exist for the TestSession class.
180
- class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
179
+ class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash #:nodoc:
181
180
  DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
182
181
 
183
182
  def initialize(session = {})
184
183
  super(nil, nil)
185
- @id = SecureRandom.hex(16)
184
+ @id = Rack::Session::SessionId.new(SecureRandom.hex(16))
186
185
  @data = stringify_keys(session)
187
186
  @loaded = true
188
187
  end
@@ -203,12 +202,16 @@ module ActionController
203
202
  clear
204
203
  end
205
204
 
205
+ def dig(*keys)
206
+ keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
207
+ @data.dig(*keys)
208
+ end
209
+
206
210
  def fetch(key, *args, &block)
207
211
  @data.fetch(key.to_s, *args, &block)
208
212
  end
209
213
 
210
214
  private
211
-
212
215
  def load!
213
216
  @id
214
217
  end
@@ -276,9 +279,6 @@ module ActionController
276
279
  # after calling +post+. If the various assert methods are not sufficient, then you
277
280
  # may use this object to inspect the HTTP response in detail.
278
281
  #
279
- # (Earlier versions of \Rails required each functional test to subclass
280
- # Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
281
- #
282
282
  # == Controller is automatically inferred
283
283
  #
284
284
  # ActionController::TestCase will automatically infer the controller under test
@@ -460,7 +460,7 @@ module ActionController
460
460
  def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
461
461
  check_required_ivars
462
462
 
463
- action = action.to_s.dup
463
+ action = +action.to_s
464
464
  http_method = method.to_s.upcase
465
465
 
466
466
  @html_document = nil
@@ -492,57 +492,8 @@ module ActionController
492
492
  parameters[:format] = format
493
493
  end
494
494
 
495
- generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
496
- generated_path = generated_path(generated_extras)
497
- query_string_keys = query_parameter_names(generated_extras)
498
-
499
- @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
500
-
501
- @request.session.update(session) if session
502
- @request.flash.update(flash || {})
503
-
504
- if xhr
505
- @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
506
- @request.fetch_header("HTTP_ACCEPT") do |k|
507
- @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
508
- end
509
- end
510
-
511
- @request.fetch_header("SCRIPT_NAME") do |k|
512
- @request.set_header k, @controller.config.relative_url_root
513
- end
514
-
515
- begin
516
- @controller.recycle!
517
- @controller.dispatch(action, @request, @response)
518
- ensure
519
- @request = @controller.request
520
- @response = @controller.response
521
-
522
- if @request.have_cookie_jar?
523
- unless @request.cookie_jar.committed?
524
- @request.cookie_jar.write(@response)
525
- cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
526
- end
527
- end
528
- @response.prepare!
529
-
530
- if flash_value = @request.flash.to_session_value
531
- @request.session["flash"] = flash_value
532
- else
533
- @request.session.delete("flash")
534
- end
535
-
536
- if xhr
537
- @request.delete_header "HTTP_X_REQUESTED_WITH"
538
- @request.delete_header "HTTP_ACCEPT"
539
- end
540
- @request.query_string = ""
541
-
542
- @response.sent!
543
- end
544
-
545
- @response
495
+ setup_request(controller_class_name, action, parameters, session, flash, xhr)
496
+ process_controller_response(action, cookies, xhr)
546
497
  end
547
498
 
548
499
  def controller_class_name
@@ -598,12 +549,66 @@ module ActionController
598
549
  end
599
550
 
600
551
  private
552
+ def setup_request(controller_class_name, action, parameters, session, flash, xhr)
553
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
554
+ generated_path = generated_path(generated_extras)
555
+ query_string_keys = query_parameter_names(generated_extras)
556
+
557
+ @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
558
+
559
+ @request.session.update(session) if session
560
+ @request.flash.update(flash || {})
561
+
562
+ if xhr
563
+ @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
564
+ @request.fetch_header("HTTP_ACCEPT") do |k|
565
+ @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
566
+ end
567
+ end
568
+
569
+ @request.fetch_header("SCRIPT_NAME") do |k|
570
+ @request.set_header k, @controller.config.relative_url_root
571
+ end
572
+ end
573
+
574
+ def process_controller_response(action, cookies, xhr)
575
+ begin
576
+ @controller.recycle!
577
+ @controller.dispatch(action, @request, @response)
578
+ ensure
579
+ @request = @controller.request
580
+ @response = @controller.response
581
+
582
+ if @request.have_cookie_jar?
583
+ unless @request.cookie_jar.committed?
584
+ @request.cookie_jar.write(@response)
585
+ cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
586
+ end
587
+ end
588
+ @response.prepare!
589
+
590
+ if flash_value = @request.flash.to_session_value
591
+ @request.session["flash"] = flash_value
592
+ else
593
+ @request.session.delete("flash")
594
+ end
595
+
596
+ if xhr
597
+ @request.delete_header "HTTP_X_REQUESTED_WITH"
598
+ @request.delete_header "HTTP_ACCEPT"
599
+ end
600
+ @request.query_string = ""
601
+
602
+ @response.sent!
603
+ end
604
+
605
+ @response
606
+ end
601
607
 
602
608
  def scrub_env!(env)
603
- env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
604
- env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
605
- env.delete "action_dispatch.request.query_parameters"
606
- env.delete "action_dispatch.request.request_parameters"
609
+ env.delete_if do |k, _|
610
+ k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
611
+ end
607
612
  env["rack.input"] = StringIO.new
608
613
  env.delete "CONTENT_LENGTH"
609
614
  env.delete "RAW_POST_DATA"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2018 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -40,20 +40,27 @@ module ActionDispatch
40
40
  class IllegalStateError < StandardError
41
41
  end
42
42
 
43
+ class MissingController < NameError
44
+ end
45
+
43
46
  eager_autoload do
44
47
  autoload_under "http" do
45
48
  autoload :ContentSecurityPolicy
49
+ autoload :PermissionsPolicy
46
50
  autoload :Request
47
51
  autoload :Response
48
52
  end
49
53
  end
50
54
 
51
55
  autoload_under "middleware" do
56
+ autoload :HostAuthorization
52
57
  autoload :RequestId
53
58
  autoload :Callbacks
54
59
  autoload :Cookies
60
+ autoload :ActionableExceptions
55
61
  autoload :DebugExceptions
56
62
  autoload :DebugLocks
63
+ autoload :DebugView
57
64
  autoload :ExceptionWrapper
58
65
  autoload :Executor
59
66
  autoload :Flash
@@ -76,8 +83,6 @@ module ActionDispatch
76
83
  autoload :Headers
77
84
  autoload :MimeNegotiation
78
85
  autoload :Parameters
79
- autoload :ParameterFilter
80
- autoload :Upload
81
86
  autoload :UploadedFile, "action_dispatch/http/upload"
82
87
  autoload :URL
83
88
  end
@@ -110,4 +115,5 @@ autoload :Mime, "action_dispatch/http/mime_type"
110
115
  ActiveSupport.on_load(:action_view) do
111
116
  ActionView::Base.default_formats ||= Mime::SET.symbols
112
117
  ActionView::Template::Types.delegate_to Mime
118
+ ActionView::LookupContext::DetailsKey.clear
113
119
  end
@@ -4,8 +4,8 @@ module ActionDispatch
4
4
  module Http
5
5
  module Cache
6
6
  module Request
7
- HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
8
- HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
7
+ HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
8
+ HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
9
9
 
10
10
  def if_modified_since
11
11
  if since = get_header(HTTP_IF_MODIFIED_SINCE)
@@ -114,7 +114,7 @@ module ActionDispatch
114
114
 
115
115
  # True if an ETag is set and it's a weak validator (preceded with W/)
116
116
  def weak_etag?
117
- etag? && etag.starts_with?('W/"')
117
+ etag? && etag.start_with?('W/"')
118
118
  end
119
119
 
120
120
  # True if an ETag is set and it isn't a weak validator (not preceded with W/)
@@ -123,10 +123,9 @@ module ActionDispatch
123
123
  end
124
124
 
125
125
  private
126
-
127
- DATE = "Date".freeze
128
- LAST_MODIFIED = "Last-Modified".freeze
129
- SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
126
+ DATE = "Date"
127
+ LAST_MODIFIED = "Last-Modified"
128
+ SPECIAL_KEYS = Set.new(%w[extras no-store no-cache max-age public private must-revalidate])
130
129
 
131
130
  def generate_weak_etag(validators)
132
131
  "W/#{generate_strong_etag(validators)}"
@@ -151,8 +150,8 @@ module ActionDispatch
151
150
  directive, argument = segment.split("=", 2)
152
151
 
153
152
  if SPECIAL_KEYS.include? directive
154
- key = directive.tr("-", "_")
155
- cache_control[key.to_sym] = argument || true
153
+ directive.tr!("-", "_")
154
+ cache_control[directive.to_sym] = argument || true
156
155
  else
157
156
  cache_control[:extras] ||= []
158
157
  cache_control[:extras] << segment
@@ -166,11 +165,12 @@ module ActionDispatch
166
165
  @cache_control = cache_control_headers
167
166
  end
168
167
 
169
- DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze
170
- NO_CACHE = "no-cache".freeze
171
- PUBLIC = "public".freeze
172
- PRIVATE = "private".freeze
173
- MUST_REVALIDATE = "must-revalidate".freeze
168
+ DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
169
+ NO_STORE = "no-store"
170
+ NO_CACHE = "no-cache"
171
+ PUBLIC = "public"
172
+ PRIVATE = "private"
173
+ MUST_REVALIDATE = "must-revalidate"
174
174
 
175
175
  def handle_conditional_get!
176
176
  # Normally default cache control setting is handled by ETag
@@ -183,19 +183,20 @@ module ActionDispatch
183
183
  end
184
184
 
185
185
  def merge_and_normalize_cache_control!(cache_control)
186
- control = {}
187
- cc_headers = cache_control_headers
188
- if extras = cc_headers.delete(:extras)
186
+ control = cache_control_headers
187
+
188
+ return if control.empty? && cache_control.empty? # Let middleware handle default behavior
189
+
190
+ if extras = control.delete(:extras)
189
191
  cache_control[:extras] ||= []
190
192
  cache_control[:extras] += extras
191
193
  cache_control[:extras].uniq!
192
194
  end
193
195
 
194
- control.merge! cc_headers
195
196
  control.merge! cache_control
196
197
 
197
- if control.empty?
198
- # Let middleware handle default behavior
198
+ if control[:no_store]
199
+ self._cache_control = NO_STORE
199
200
  elsif control[:no_cache]
200
201
  options = []
201
202
  options << PUBLIC if control[:public]
@@ -204,13 +205,17 @@ module ActionDispatch
204
205
 
205
206
  self._cache_control = options.join(", ")
206
207
  else
207
- extras = control[:extras]
208
+ extras = control[:extras]
208
209
  max_age = control[:max_age]
210
+ stale_while_revalidate = control[:stale_while_revalidate]
211
+ stale_if_error = control[:stale_if_error]
209
212
 
210
213
  options = []
211
214
  options << "max-age=#{max_age.to_i}" if max_age
212
215
  options << (control[:public] ? PUBLIC : PRIVATE)
213
216
  options << MUST_REVALIDATE if control[:must_revalidate]
217
+ options << "stale-while-revalidate=#{stale_while_revalidate.to_i}" if stale_while_revalidate
218
+ options << "stale-if-error=#{stale_if_error.to_i}" if stale_if_error
214
219
  options.concat(extras) if extras
215
220
 
216
221
  self._cache_control = options.join(", ")