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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +416 -255
- 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 +21 -2
- 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 +3 -3
- 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
|