actionpack 6.0.5.1 → 6.1.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +393 -253
- data/MIT-LICENSE +1 -2
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/collector.rb +4 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal/conditional_get.rb +11 -3
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +5 -2
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +10 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +14 -8
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +104 -16
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/renderer.rb +23 -13
- data/lib/action_controller/test_case.rb +65 -56
- data/lib/action_controller.rb +2 -3
- data/lib/action_dispatch/http/cache.rb +18 -17
- data/lib/action_dispatch/http/content_security_policy.rb +6 -1
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +14 -8
- data/lib/action_dispatch/http/mime_type.rb +29 -16
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +24 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey/formatter.rb +55 -30
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +89 -46
- data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -15
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +28 -16
- data/lib/action_dispatch/middleware/host_authorization.rb +63 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -0
- data/lib/action_dispatch/middleware/ssl.rb +12 -7
- data/lib/action_dispatch/middleware/stack.rb +19 -1
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +100 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +21 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
- data/lib/action_dispatch/routing/redirection.rb +4 -4
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/system_test_case.rb +35 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +40 -29
- data/lib/action_dispatch/testing/test_process.rb +32 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_pack/gem_version.rb +2 -2
- data/lib/action_pack.rb +1 -1
- metadata +18 -19
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- 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
|
-
"
|
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
|
817
|
-
@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.
|
868
|
-
|
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
|
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.
|
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.
|
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
|
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,
|
86
|
-
#
|
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
|
127
|
+
RACK_KEY_TRANSLATION[key] || key.to_s
|
125
128
|
end
|
126
129
|
|
127
130
|
def rack_value_for(key, value)
|
128
|
-
|
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
|
-
|
496
|
-
|
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
|
603
|
-
|
604
|
-
|
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"
|
data/lib/action_controller.rb
CHANGED
@@ -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(
|
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.
|
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
|
-
|
154
|
-
cache_control[
|
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
|
-
|
187
|
-
if
|
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
|
-
|
197
|
-
|
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
|
-
|
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
|
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
|
@@ -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
|
125
|
-
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
|