actionpack 6.0.5.1 → 6.1.7

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +382 -253
  3. data/MIT-LICENSE +1 -2
  4. data/lib/abstract_controller/base.rb +35 -2
  5. data/lib/abstract_controller/callbacks.rb +2 -2
  6. data/lib/abstract_controller/collector.rb +4 -2
  7. data/lib/abstract_controller/helpers.rb +105 -90
  8. data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
  9. data/lib/abstract_controller/rendering.rb +9 -9
  10. data/lib/abstract_controller/translation.rb +8 -2
  11. data/lib/abstract_controller.rb +1 -0
  12. data/lib/action_controller/api.rb +2 -2
  13. data/lib/action_controller/base.rb +4 -2
  14. data/lib/action_controller/caching.rb +0 -1
  15. data/lib/action_controller/log_subscriber.rb +3 -3
  16. data/lib/action_controller/metal/conditional_get.rb +11 -3
  17. data/lib/action_controller/metal/content_security_policy.rb +1 -1
  18. data/lib/action_controller/metal/cookies.rb +3 -1
  19. data/lib/action_controller/metal/data_streaming.rb +1 -1
  20. data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
  21. data/lib/action_controller/metal/exceptions.rb +33 -0
  22. data/lib/action_controller/metal/head.rb +7 -4
  23. data/lib/action_controller/metal/helpers.rb +11 -1
  24. data/lib/action_controller/metal/http_authentication.rb +5 -2
  25. data/lib/action_controller/metal/implicit_render.rb +1 -1
  26. data/lib/action_controller/metal/instrumentation.rb +11 -9
  27. data/lib/action_controller/metal/live.rb +10 -1
  28. data/lib/action_controller/metal/logging.rb +20 -0
  29. data/lib/action_controller/metal/mime_responds.rb +6 -2
  30. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  31. data/lib/action_controller/metal/params_wrapper.rb +14 -8
  32. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  33. data/lib/action_controller/metal/redirecting.rb +1 -1
  34. data/lib/action_controller/metal/rendering.rb +6 -0
  35. data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
  36. data/lib/action_controller/metal/rescue.rb +1 -1
  37. data/lib/action_controller/metal/strong_parameters.rb +104 -16
  38. data/lib/action_controller/metal.rb +2 -2
  39. data/lib/action_controller/renderer.rb +23 -13
  40. data/lib/action_controller/test_case.rb +65 -56
  41. data/lib/action_controller.rb +2 -3
  42. data/lib/action_dispatch/http/cache.rb +17 -16
  43. data/lib/action_dispatch/http/content_security_policy.rb +6 -1
  44. data/lib/action_dispatch/http/filter_parameters.rb +1 -1
  45. data/lib/action_dispatch/http/filter_redirect.rb +1 -1
  46. data/lib/action_dispatch/http/headers.rb +3 -2
  47. data/lib/action_dispatch/http/mime_negotiation.rb +14 -8
  48. data/lib/action_dispatch/http/mime_type.rb +29 -16
  49. data/lib/action_dispatch/http/parameters.rb +1 -19
  50. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  51. data/lib/action_dispatch/http/request.rb +24 -8
  52. data/lib/action_dispatch/http/response.rb +17 -16
  53. data/lib/action_dispatch/http/url.rb +3 -2
  54. data/lib/action_dispatch/journey/formatter.rb +55 -30
  55. data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
  56. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  57. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
  58. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  59. data/lib/action_dispatch/journey/nodes/node.rb +4 -3
  60. data/lib/action_dispatch/journey/parser.rb +13 -13
  61. data/lib/action_dispatch/journey/parser.y +1 -1
  62. data/lib/action_dispatch/journey/path/pattern.rb +13 -18
  63. data/lib/action_dispatch/journey/route.rb +7 -18
  64. data/lib/action_dispatch/journey/router/utils.rb +6 -4
  65. data/lib/action_dispatch/journey/router.rb +26 -30
  66. data/lib/action_dispatch/journey/visitors.rb +1 -1
  67. data/lib/action_dispatch/journey.rb +0 -2
  68. data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
  69. data/lib/action_dispatch/middleware/cookies.rb +67 -32
  70. data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -15
  71. data/lib/action_dispatch/middleware/debug_view.rb +1 -1
  72. data/lib/action_dispatch/middleware/exception_wrapper.rb +28 -16
  73. data/lib/action_dispatch/middleware/host_authorization.rb +63 -14
  74. data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
  75. data/lib/action_dispatch/middleware/request_id.rb +4 -5
  76. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
  77. data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
  78. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -0
  79. data/lib/action_dispatch/middleware/ssl.rb +12 -7
  80. data/lib/action_dispatch/middleware/stack.rb +19 -1
  81. data/lib/action_dispatch/middleware/static.rb +154 -93
  82. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  83. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
  84. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
  85. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
  86. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +100 -8
  87. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  88. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +21 -1
  89. data/lib/action_dispatch/railtie.rb +3 -2
  90. data/lib/action_dispatch/request/session.rb +2 -8
  91. data/lib/action_dispatch/request/utils.rb +26 -2
  92. data/lib/action_dispatch/routing/inspector.rb +8 -7
  93. data/lib/action_dispatch/routing/mapper.rb +102 -71
  94. data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
  95. data/lib/action_dispatch/routing/redirection.rb +4 -4
  96. data/lib/action_dispatch/routing/route_set.rb +49 -41
  97. data/lib/action_dispatch/system_test_case.rb +35 -24
  98. data/lib/action_dispatch/system_testing/browser.rb +33 -27
  99. data/lib/action_dispatch/system_testing/driver.rb +6 -7
  100. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
  101. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
  102. data/lib/action_dispatch/testing/assertions/response.rb +2 -4
  103. data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
  104. data/lib/action_dispatch/testing/assertions.rb +1 -1
  105. data/lib/action_dispatch/testing/integration.rb +40 -29
  106. data/lib/action_dispatch/testing/test_process.rb +32 -4
  107. data/lib/action_dispatch/testing/test_request.rb +3 -3
  108. data/lib/action_dispatch.rb +3 -2
  109. data/lib/action_pack/gem_version.rb +3 -3
  110. data/lib/action_pack.rb +1 -1
  111. metadata +17 -18
  112. data/lib/action_controller/metal/force_ssl.rb +0 -58
  113. data/lib/action_dispatch/http/parameter_filter.rb +0 -12
  114. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  115. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  116. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -19,12 +19,36 @@ module ActionController
19
19
  # params.require(:a)
20
20
  # # => ActionController::ParameterMissing: param is missing or the value is empty: a
21
21
  class ParameterMissing < KeyError
22
- attr_reader :param # :nodoc:
22
+ attr_reader :param, :keys # :nodoc:
23
23
 
24
- def initialize(param) # :nodoc:
24
+ def initialize(param, keys = nil) # :nodoc:
25
25
  @param = param
26
+ @keys = keys
26
27
  super("param is missing or the value is empty: #{param}")
27
28
  end
29
+
30
+ class Correction
31
+ def initialize(error)
32
+ @error = error
33
+ end
34
+
35
+ def corrections
36
+ if @error.param && @error.keys
37
+ maybe_these = @error.keys
38
+
39
+ maybe_these.sort_by { |n|
40
+ DidYouMean::Jaro.distance(@error.param.to_s, n)
41
+ }.reverse.first(4)
42
+ else
43
+ []
44
+ end
45
+ end
46
+ end
47
+
48
+ # We may not have DYM, and DYM might not let us register error handlers
49
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
50
+ DidYouMean.correct_error(self, Correction)
51
+ end
28
52
  end
29
53
 
30
54
  # Raised when a supplied parameter is not expected and
@@ -180,6 +204,14 @@ module ActionController
180
204
  #
181
205
  # Returns true if the given key is present in the parameters.
182
206
 
207
+ ##
208
+ # :method: member?
209
+ #
210
+ # :call-seq:
211
+ # member?(key)
212
+ #
213
+ # Returns true if the given key is present in the parameters.
214
+
183
215
  ##
184
216
  # :method: keys
185
217
  #
@@ -211,7 +243,7 @@ module ActionController
211
243
  # values()
212
244
  #
213
245
  # Returns a new array of the values of the parameters.
214
- delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
246
+ delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
215
247
  :as_json, :to_s, :each_key, to: :@parameters
216
248
 
217
249
  # By default, never raise an UnpermittedParameters exception if these
@@ -220,9 +252,15 @@ module ActionController
220
252
  # to change these is to specify `always_permitted_parameters` in your
221
253
  # config. For instance:
222
254
  #
223
- # config.always_permitted_parameters = %w( controller action format )
255
+ # config.action_controller.always_permitted_parameters = %w( controller action format )
224
256
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
225
257
 
258
+ class << self
259
+ def nested_attribute?(key, value) # :nodoc:
260
+ /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
261
+ end
262
+ end
263
+
226
264
  # Returns a new instance of <tt>ActionController::Parameters</tt>.
227
265
  # Also, sets the +permitted+ attribute to the default value of
228
266
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
@@ -253,6 +291,11 @@ module ActionController
253
291
  @parameters == other
254
292
  end
255
293
  end
294
+ alias eql? ==
295
+
296
+ def hash
297
+ [@parameters.hash, @permitted].hash
298
+ end
256
299
 
257
300
  # Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
258
301
  # representation of the parameters with all unpermitted keys removed.
@@ -341,6 +384,7 @@ module ActionController
341
384
  # Convert all hashes in values into parameters, then yield each pair in
342
385
  # the same way as <tt>Hash#each_pair</tt>.
343
386
  def each_pair(&block)
387
+ return to_enum(__callee__) unless block_given?
344
388
  @parameters.each_pair do |key, value|
345
389
  yield [key, convert_hashes_to_parameters(key, value)]
346
390
  end
@@ -352,6 +396,7 @@ module ActionController
352
396
  # Convert all hashes in values into parameters, then yield each value in
353
397
  # the same way as <tt>Hash#each_value</tt>.
354
398
  def each_value(&block)
399
+ return to_enum(:each_value) unless block_given?
355
400
  @parameters.each_pair do |key, value|
356
401
  yield convert_hashes_to_parameters(key, value)
357
402
  end
@@ -459,7 +504,7 @@ module ActionController
459
504
  if value.present? || value == false
460
505
  value
461
506
  else
462
- raise ParameterMissing.new(key)
507
+ raise ParameterMissing.new(key, @parameters.keys)
463
508
  end
464
509
  end
465
510
 
@@ -596,7 +641,7 @@ module ActionController
596
641
  if block_given?
597
642
  yield
598
643
  else
599
- args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
644
+ args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
600
645
  end
601
646
  }
602
647
  )
@@ -691,6 +736,23 @@ module ActionController
691
736
  self
692
737
  end
693
738
 
739
+ # Returns a new <tt>ActionController::Parameters</tt> instance with the
740
+ # results of running +block+ once for every key. This includes the keys
741
+ # from the root hash and from all nested hashes and arrays. The values are unchanged.
742
+ def deep_transform_keys(&block)
743
+ new_instance_with_inherited_permitted_status(
744
+ @parameters.deep_transform_keys(&block)
745
+ )
746
+ end
747
+
748
+ # Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
749
+ # This includes the keys from the root hash and from all nested hashes and arrays.
750
+ # The values are unchanged.
751
+ def deep_transform_keys!(&block)
752
+ @parameters.deep_transform_keys!(&block)
753
+ self
754
+ end
755
+
694
756
  # Deletes a key-value pair from +Parameters+ and returns the value. If
695
757
  # +key+ is not found, returns +nil+ (or, with optional code block, yields
696
758
  # +key+ and returns the result). Cf. +#extract!+, which returns the
@@ -725,6 +787,28 @@ module ActionController
725
787
  end
726
788
  alias_method :delete_if, :reject!
727
789
 
790
+ # Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
791
+ def compact
792
+ new_instance_with_inherited_permitted_status(@parameters.compact)
793
+ end
794
+
795
+ # Removes all +nil+ values in place and returns +self+, or +nil+ if no changes were made.
796
+ def compact!
797
+ self if @parameters.compact!
798
+ end
799
+
800
+ # Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
801
+ # Uses Object#blank? for determining if a value is blank.
802
+ def compact_blank
803
+ reject { |_k, v| v.blank? }
804
+ end
805
+
806
+ # Removes all blank values in place and returns self.
807
+ # Uses Object#blank? for determining if a value is blank.
808
+ def compact_blank!
809
+ reject! { |_k, v| v.blank? }
810
+ end
811
+
728
812
  # Returns values that were assigned to the given +keys+. Note that all the
729
813
  # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
730
814
  def values_at(*keys)
@@ -771,7 +855,7 @@ module ActionController
771
855
  end
772
856
 
773
857
  def inspect
774
- "<#{self.class} #{@parameters} permitted: #{@permitted}>"
858
+ "#<#{self.class} #{@parameters} permitted: #{@permitted}>"
775
859
  end
776
860
 
777
861
  def self.hook_into_yaml_loading # :nodoc:
@@ -813,8 +897,14 @@ module ActionController
813
897
 
814
898
  attr_writer :permitted
815
899
 
816
- def fields_for_style?
817
- @parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
900
+ def nested_attributes?
901
+ @parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
902
+ end
903
+
904
+ def each_nested_attribute
905
+ hash = self.class.new
906
+ self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
907
+ hash
818
908
  end
819
909
 
820
910
  private
@@ -850,7 +940,7 @@ module ActionController
850
940
  when Array
851
941
  return value if converted_arrays.member?(value)
852
942
  converted = value.map { |_| convert_value_to_parameters(_) }
853
- converted_arrays << converted
943
+ converted_arrays << converted.dup
854
944
  converted
855
945
  when Hash
856
946
  self.class.new(value)
@@ -859,15 +949,13 @@ module ActionController
859
949
  end
860
950
  end
861
951
 
862
- def each_element(object)
952
+ def each_element(object, &block)
863
953
  case object
864
954
  when Array
865
955
  object.grep(Parameters).map { |el| yield el }.compact
866
956
  when Parameters
867
- if object.fields_for_style?
868
- hash = object.class.new
869
- object.each { |k, v| hash[k] = yield v }
870
- hash
957
+ if object.nested_attributes?
958
+ object.each_nested_attribute(&block)
871
959
  else
872
960
  yield object
873
961
  end
@@ -895,7 +983,7 @@ module ActionController
895
983
  # --- Filtering ----------------------------------------------------------
896
984
  #
897
985
 
898
- # This is a white list of permitted scalar types that includes the ones
986
+ # This is a list of permitted scalar types that includes the ones
899
987
  # supported in XML and JSON requests.
900
988
  #
901
989
  # This list is in particular used to filter ordinary requests, String goes
@@ -126,7 +126,7 @@ module ActionController
126
126
  # ==== Returns
127
127
  # * <tt>string</tt>
128
128
  def self.controller_name
129
- @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore
129
+ @controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
130
130
  end
131
131
 
132
132
  def self.make_response!(request)
@@ -135,7 +135,7 @@ module ActionController
135
135
  end
136
136
  end
137
137
 
138
- def self.binary_params_for?(action) # :nodoc:
138
+ def self.action_encoding_template(action) # :nodoc:
139
139
  false
140
140
  end
141
141
 
@@ -65,7 +65,7 @@ module ActionController
65
65
  def initialize(controller, env, defaults)
66
66
  @controller = controller
67
67
  @defaults = defaults
68
- @env = normalize_keys defaults.merge(env)
68
+ @env = normalize_keys defaults, env
69
69
  end
70
70
 
71
71
  # Render templates with any options from ActionController::Base#render_to_string.
@@ -82,8 +82,12 @@ module ActionController
82
82
  # need to call <tt>.to_json</tt> on the object you want to render.
83
83
  # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
84
  #
85
- # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, the default is
86
- # to render a partial and use the second parameter as the locals hash.
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.
87
91
  def render(*args)
88
92
  raise "missing controller" unless controller
89
93
 
@@ -98,9 +102,15 @@ module ActionController
98
102
  alias_method :render_to_string, :render # :nodoc:
99
103
 
100
104
  private
101
- def normalize_keys(env)
105
+ def normalize_keys(defaults, env)
102
106
  new_env = {}
103
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
+
104
114
  new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
105
115
  new_env
106
116
  end
@@ -113,19 +123,19 @@ module ActionController
113
123
  input: "rack.input"
114
124
  }
115
125
 
116
- IDENTITY = ->(_) { _ }
117
-
118
- RACK_VALUE_TRANSLATION = {
119
- https: ->(v) { v ? "on" : "off" },
120
- method: ->(v) { -v.upcase },
121
- }
122
-
123
126
  def rack_key_for(key)
124
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
127
+ RACK_KEY_TRANSLATION[key] || key.to_s
125
128
  end
126
129
 
127
130
  def rack_value_for(key, value)
128
- 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
129
139
  end
130
140
  end
131
141
  end
@@ -24,6 +24,9 @@ module ActionController
24
24
  def new_controller_thread # :nodoc:
25
25
  yield
26
26
  end
27
+
28
+ # Avoid a deadlock from the queue filling up
29
+ Buffer.queue_size = nil
27
30
  end
28
31
 
29
32
  # ActionController::TestCase will be deprecated and moved to a gem in the future.
@@ -84,7 +87,7 @@ module ActionController
84
87
  value = value.to_param
85
88
  end
86
89
 
87
- path_parameters[key] = value
90
+ path_parameters[key.to_sym] = value
88
91
  end
89
92
  end
90
93
 
@@ -492,57 +495,8 @@ module ActionController
492
495
  parameters[:format] = format
493
496
  end
494
497
 
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
498
+ setup_request(controller_class_name, action, parameters, session, flash, xhr)
499
+ process_controller_response(action, cookies, xhr)
546
500
  end
547
501
 
548
502
  def controller_class_name
@@ -598,11 +552,66 @@ module ActionController
598
552
  end
599
553
 
600
554
  private
555
+ def setup_request(controller_class_name, action, parameters, session, flash, xhr)
556
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
557
+ generated_path = generated_path(generated_extras)
558
+ query_string_keys = query_parameter_names(generated_extras)
559
+
560
+ @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
561
+
562
+ @request.session.update(session) if session
563
+ @request.flash.update(flash || {})
564
+
565
+ if xhr
566
+ @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
567
+ @request.fetch_header("HTTP_ACCEPT") do |k|
568
+ @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
569
+ end
570
+ end
571
+
572
+ @request.fetch_header("SCRIPT_NAME") do |k|
573
+ @request.set_header k, @controller.config.relative_url_root
574
+ end
575
+ end
576
+
577
+ def process_controller_response(action, cookies, xhr)
578
+ begin
579
+ @controller.recycle!
580
+ @controller.dispatch(action, @request, @response)
581
+ ensure
582
+ @request = @controller.request
583
+ @response = @controller.response
584
+
585
+ if @request.have_cookie_jar?
586
+ unless @request.cookie_jar.committed?
587
+ @request.cookie_jar.write(@response)
588
+ cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
589
+ end
590
+ end
591
+ @response.prepare!
592
+
593
+ if flash_value = @request.flash.to_session_value
594
+ @request.session["flash"] = flash_value
595
+ else
596
+ @request.session.delete("flash")
597
+ end
598
+
599
+ if xhr
600
+ @request.delete_header "HTTP_X_REQUESTED_WITH"
601
+ @request.delete_header "HTTP_ACCEPT"
602
+ end
603
+ @request.query_string = ""
604
+
605
+ @response.sent!
606
+ end
607
+
608
+ @response
609
+ end
610
+
601
611
  def scrub_env!(env)
602
- env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
603
- env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
604
- env.delete "action_dispatch.request.query_parameters"
605
- env.delete "action_dispatch.request.request_parameters"
612
+ env.delete_if do |k, _|
613
+ k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
614
+ end
606
615
  env["rack.input"] = StringIO.new
607
616
  env.delete "CONTENT_LENGTH"
608
617
  env.delete "RAW_POST_DATA"
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/rails"
4
3
  require "abstract_controller"
5
4
  require "action_dispatch"
6
5
  require "action_controller/metal/strong_parameters"
@@ -11,7 +10,6 @@ module ActionController
11
10
  autoload :API
12
11
  autoload :Base
13
12
  autoload :Metal
14
- autoload :Middleware
15
13
  autoload :Renderer
16
14
  autoload :FormBuilder
17
15
 
@@ -31,14 +29,15 @@ module ActionController
31
29
  autoload :DefaultHeaders
32
30
  autoload :EtagWithTemplateDigest
33
31
  autoload :EtagWithFlash
32
+ autoload :PermissionsPolicy
34
33
  autoload :Flash
35
- autoload :ForceSSL
36
34
  autoload :Head
37
35
  autoload :Helpers
38
36
  autoload :HttpAuthentication
39
37
  autoload :BasicImplicitRender
40
38
  autoload :ImplicitRender
41
39
  autoload :Instrumentation
40
+ autoload :Logging
42
41
  autoload :MimeResponds
43
42
  autoload :ParamsWrapper
44
43
  autoload :Redirecting
@@ -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/)
@@ -125,7 +125,7 @@ module ActionDispatch
125
125
  private
126
126
  DATE = "Date"
127
127
  LAST_MODIFIED = "Last-Modified"
128
- SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
128
+ SPECIAL_KEYS = Set.new(%w[extras no-store no-cache max-age public private must-revalidate])
129
129
 
130
130
  def generate_weak_etag(validators)
131
131
  "W/#{generate_strong_etag(validators)}"
@@ -150,8 +150,8 @@ module ActionDispatch
150
150
  directive, argument = segment.split("=", 2)
151
151
 
152
152
  if SPECIAL_KEYS.include? directive
153
- key = directive.tr("-", "_")
154
- cache_control[key.to_sym] = argument || true
153
+ directive.tr!("-", "_")
154
+ cache_control[directive.to_sym] = argument || true
155
155
  else
156
156
  cache_control[:extras] ||= []
157
157
  cache_control[:extras] << segment
@@ -166,6 +166,7 @@ module ActionDispatch
166
166
  end
167
167
 
168
168
  DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
169
+ NO_STORE = "no-store"
169
170
  NO_CACHE = "no-cache"
170
171
  PUBLIC = "public"
171
172
  PRIVATE = "private"
@@ -182,42 +183,42 @@ module ActionDispatch
182
183
  end
183
184
 
184
185
  def merge_and_normalize_cache_control!(cache_control)
185
- control = {}
186
- cc_headers = cache_control_headers
187
- 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)
188
191
  cache_control[:extras] ||= []
189
192
  cache_control[:extras] += extras
190
193
  cache_control[:extras].uniq!
191
194
  end
192
195
 
193
- control.merge! cc_headers
194
196
  control.merge! cache_control
195
197
 
196
- if control.empty?
197
- # Let middleware handle default behavior
198
+ options = []
199
+
200
+ if control[:no_store]
201
+ options << PRIVATE if control[:private]
202
+ options << NO_STORE
198
203
  elsif control[:no_cache]
199
- options = []
200
204
  options << PUBLIC if control[:public]
201
205
  options << NO_CACHE
202
206
  options.concat(control[:extras]) if control[:extras]
203
-
204
- self._cache_control = options.join(", ")
205
207
  else
206
208
  extras = control[:extras]
207
209
  max_age = control[:max_age]
208
210
  stale_while_revalidate = control[:stale_while_revalidate]
209
211
  stale_if_error = control[:stale_if_error]
210
212
 
211
- options = []
212
213
  options << "max-age=#{max_age.to_i}" if max_age
213
214
  options << (control[:public] ? PUBLIC : PRIVATE)
214
215
  options << MUST_REVALIDATE if control[:must_revalidate]
215
216
  options << "stale-while-revalidate=#{stale_while_revalidate.to_i}" if stale_while_revalidate
216
217
  options << "stale-if-error=#{stale_if_error.to_i}" if stale_if_error
217
218
  options.concat(extras) if extras
218
-
219
- self._cache_control = options.join(", ")
220
219
  end
220
+
221
+ self._cache_control = options.join(", ")
221
222
  end
222
223
  end
223
224
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/object/deep_dup"
4
+ require "active_support/core_ext/array/wrap"
4
5
 
5
6
  module ActionDispatch #:nodoc:
6
7
  class ContentSecurityPolicy
@@ -130,7 +131,11 @@ module ActionDispatch #:nodoc:
130
131
  object_src: "object-src",
131
132
  prefetch_src: "prefetch-src",
132
133
  script_src: "script-src",
134
+ script_src_attr: "script-src-attr",
135
+ script_src_elem: "script-src-elem",
133
136
  style_src: "style-src",
137
+ style_src_attr: "style-src-attr",
138
+ style_src_elem: "style-src-elem",
134
139
  worker_src: "worker-src"
135
140
  }.freeze
136
141
 
@@ -261,7 +266,7 @@ module ActionDispatch #:nodoc:
261
266
  raise RuntimeError, "Missing context for the dynamic content security policy source: #{source.inspect}"
262
267
  else
263
268
  resolved = context.instance_exec(&source)
264
- resolved.is_a?(Symbol) ? apply_mapping(resolved) : resolved
269
+ apply_mappings(Array.wrap(resolved))
265
270
  end
266
271
  else
267
272
  raise RuntimeError, "Unexpected content security policy source: #{source.inspect}"
@@ -23,7 +23,7 @@ module ActionDispatch
23
23
  # change { file: { code: "xxxx"} }
24
24
  #
25
25
  # env["action_dispatch.parameter_filter"] = -> (k, v) do
26
- # v.reverse! if k =~ /secret/i
26
+ # v.reverse! if k.match?(/secret/i)
27
27
  # end
28
28
  # => reverses the value to all keys matching /secret/i
29
29
  module FilterParameters
@@ -27,7 +27,7 @@ module ActionDispatch
27
27
  if String === filter
28
28
  location.include?(filter)
29
29
  elsif Regexp === filter
30
- location =~ filter
30
+ location.match?(filter)
31
31
  end
32
32
  end
33
33
  end
@@ -121,8 +121,9 @@ module ActionDispatch
121
121
  def env_name(key)
122
122
  key = key.to_s
123
123
  if HTTP_HEADER.match?(key)
124
- key = key.upcase.tr("-", "_")
125
- key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
124
+ key = key.upcase
125
+ key.tr!("-", "_")
126
+ key.prepend("HTTP_") unless CGI_VARIABLES.include?(key)
126
127
  end
127
128
  key
128
129
  end