actionpack 6.0.6.1 → 6.1.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +416 -255
  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 +21 -2
  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 +18 -17
  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 +89 -46
  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 +18 -19
  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
@@ -18,7 +18,7 @@ module ActionDispatch
18
18
  end
19
19
 
20
20
  def if_none_match_etags
21
- if_none_match ? if_none_match.split(/\s*,\s*/) : []
21
+ if_none_match ? if_none_match.split(",").each(&:strip!) : []
22
22
  end
23
23
 
24
24
  def not_modified?(modified_at)
@@ -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