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
@@ -68,13 +68,7 @@ module ActionDispatch
68
68
 
69
69
  def formats
70
70
  fetch_header("action_dispatch.request.formats") do |k|
71
- params_readable = begin
72
- parameters[:format]
73
- rescue *RESCUABLE_MIME_FORMAT_ERRORS
74
- false
75
- end
76
-
77
- v = if params_readable
71
+ v = if params_readable?
78
72
  Array(Mime[parameters[:format]])
79
73
  elsif use_accept_header && valid_accept_header
80
74
  accepts
@@ -159,12 +153,24 @@ module ActionDispatch
159
153
  order.include?(Mime::ALL) ? format : nil
160
154
  end
161
155
 
156
+ def should_apply_vary_header?
157
+ !params_readable? && use_accept_header && valid_accept_header
158
+ end
159
+
162
160
  private
161
+ # We use normal content negotiation unless you include */* in your list,
162
+ # in which case we assume you're a browser and send HTML.
163
163
  BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
164
164
 
165
+ def params_readable? # :doc:
166
+ parameters[:format]
167
+ rescue *RESCUABLE_MIME_FORMAT_ERRORS
168
+ false
169
+ end
170
+
165
171
  def valid_accept_header # :doc:
166
172
  (xhr? && (accept.present? || content_mime_type)) ||
167
- (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
173
+ (accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
168
174
  end
169
175
 
170
176
  def use_accept_header # :doc:
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "singleton"
4
- require "active_support/core_ext/string/starts_ends_with"
4
+ require "active_support/core_ext/symbol/starts_ends_with"
5
5
 
6
6
  module Mime
7
7
  class Mimes
8
+ attr_reader :symbols
9
+
8
10
  include Enumerable
9
11
 
10
12
  def initialize
11
13
  @mimes = []
12
- @symbols = nil
14
+ @symbols = []
13
15
  end
14
16
 
15
17
  def each
@@ -18,15 +20,16 @@ module Mime
18
20
 
19
21
  def <<(type)
20
22
  @mimes << type
21
- @symbols = nil
23
+ @symbols << type.to_sym
22
24
  end
23
25
 
24
26
  def delete_if
25
- @mimes.delete_if { |x| yield x }.tap { @symbols = nil }
26
- end
27
-
28
- def symbols
29
- @symbols ||= map(&:to_sym)
27
+ @mimes.delete_if do |x|
28
+ if yield x
29
+ @symbols.delete(x.to_sym)
30
+ true
31
+ end
32
+ end
30
33
  end
31
34
  end
32
35
 
@@ -114,7 +117,7 @@ module Mime
114
117
  type = list[idx]
115
118
  break if type.q < app_xml.q
116
119
 
117
- if type.name.ends_with? "+xml"
120
+ if type.name.end_with? "+xml"
118
121
  list[app_xml_idx], list[idx] = list[idx], app_xml
119
122
  app_xml_idx = idx
120
123
  end
@@ -202,7 +205,7 @@ module Mime
202
205
  # For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
203
206
  # Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
204
207
  def parse_data_with_trailing_star(type)
205
- Mime::SET.select { |m| m =~ type }
208
+ Mime::SET.select { |m| m.match?(type) }
206
209
  end
207
210
 
208
211
  # This method is opposite of register method.
@@ -283,8 +286,14 @@ module Mime
283
286
  @synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
284
287
  end
285
288
 
289
+ def match?(mime_type)
290
+ return false unless mime_type
291
+ regexp = Regexp.new(Regexp.quote(mime_type.to_s))
292
+ @synonyms.any? { |synonym| synonym.to_s.match?(regexp) } || @string.match?(regexp)
293
+ end
294
+
286
295
  def html?
287
- symbol == :html || @string =~ /html/
296
+ (symbol == :html) || /html/.match?(@string)
288
297
  end
289
298
 
290
299
  def all?; false; end
@@ -297,7 +306,7 @@ module Mime
297
306
  def to_a; end
298
307
 
299
308
  def method_missing(method, *args)
300
- if method.to_s.ends_with? "?"
309
+ if method.end_with?("?")
301
310
  method[0..-2].downcase.to_sym == to_sym
302
311
  else
303
312
  super
@@ -305,7 +314,7 @@ module Mime
305
314
  end
306
315
 
307
316
  def respond_to_missing?(method, include_private = false)
308
- (method.to_s.ends_with? "?") || super
317
+ method.end_with?("?") || super
309
318
  end
310
319
  end
311
320
 
@@ -321,7 +330,7 @@ module Mime
321
330
  end
322
331
 
323
332
  # ALL isn't a real MIME type, so we don't register it for lookup with the
324
- # other concrete types. It's a wildcard match that we use for `respond_to`
333
+ # other concrete types. It's a wildcard match that we use for +respond_to+
325
334
  # negotiation internals.
326
335
  ALL = AllType.instance
327
336
 
@@ -332,15 +341,19 @@ module Mime
332
341
  true
333
342
  end
334
343
 
344
+ def to_s
345
+ ""
346
+ end
347
+
335
348
  def ref; end
336
349
 
337
350
  private
338
351
  def respond_to_missing?(method, _)
339
- method.to_s.ends_with? "?"
352
+ method.end_with?("?")
340
353
  end
341
354
 
342
355
  def method_missing(method, *args)
343
- false if method.to_s.ends_with? "?"
356
+ false if method.end_with?("?")
344
357
  end
345
358
  end
346
359
  end
@@ -57,7 +57,6 @@ module ActionDispatch
57
57
  query_parameters.dup
58
58
  end
59
59
  params.merge!(path_parameters)
60
- params = set_binary_encoding(params, params[:controller], params[:action])
61
60
  set_header("action_dispatch.request.parameters", params)
62
61
  params
63
62
  end
@@ -66,7 +65,7 @@ module ActionDispatch
66
65
  def path_parameters=(parameters) #:nodoc:
67
66
  delete_header("action_dispatch.request.parameters")
68
67
 
69
- parameters = set_binary_encoding(parameters, parameters[:controller], parameters[:action])
68
+ parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
70
69
  # If any of the path parameters has an invalid encoding then
71
70
  # raise since it's likely to trigger errors further on.
72
71
  Request::Utils.check_param_encoding(parameters)
@@ -85,23 +84,6 @@ module ActionDispatch
85
84
  end
86
85
 
87
86
  private
88
- def set_binary_encoding(params, controller, action)
89
- return params unless controller && controller.valid_encoding?
90
-
91
- if binary_params_for?(controller, action)
92
- ActionDispatch::Request::Utils.each_param_value(params.except(:controller, :action)) do |param|
93
- param.force_encoding ::Encoding::ASCII_8BIT
94
- end
95
- end
96
- params
97
- end
98
-
99
- def binary_params_for?(controller, action)
100
- controller_class_for(controller).binary_params_for?(action)
101
- rescue MissingController
102
- false
103
- end
104
-
105
87
  def parse_formatted_parameters(parsers)
106
88
  return yield if content_length.zero? || content_mime_type.nil?
107
89
 
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/deep_dup"
4
+
5
+ module ActionDispatch #:nodoc:
6
+ class PermissionsPolicy
7
+ class Middleware
8
+ CONTENT_TYPE = "Content-Type"
9
+ # The Feature-Policy header has been renamed to Permissions-Policy.
10
+ # The Permissions-Policy requires a different implementation and isn't
11
+ # yet supported by all browsers. To avoid having to rename this
12
+ # middleware in the future we use the new name for the middleware but
13
+ # keep the old header name and implementation for now.
14
+ POLICY = "Feature-Policy"
15
+
16
+ def initialize(app)
17
+ @app = app
18
+ end
19
+
20
+ def call(env)
21
+ request = ActionDispatch::Request.new(env)
22
+ _, headers, _ = response = @app.call(env)
23
+
24
+ return response unless html_response?(headers)
25
+ return response if policy_present?(headers)
26
+
27
+ if policy = request.permissions_policy
28
+ headers[POLICY] = policy.build(request.controller_instance)
29
+ end
30
+
31
+ if policy_empty?(policy)
32
+ headers.delete(POLICY)
33
+ end
34
+
35
+ response
36
+ end
37
+
38
+ private
39
+ def html_response?(headers)
40
+ if content_type = headers[CONTENT_TYPE]
41
+ /html/.match?(content_type)
42
+ end
43
+ end
44
+
45
+ def policy_present?(headers)
46
+ headers[POLICY]
47
+ end
48
+
49
+ def policy_empty?(policy)
50
+ policy&.directives&.empty?
51
+ end
52
+ end
53
+
54
+ module Request
55
+ POLICY = "action_dispatch.permissions_policy"
56
+
57
+ def permissions_policy
58
+ get_header(POLICY)
59
+ end
60
+
61
+ def permissions_policy=(policy)
62
+ set_header(POLICY, policy)
63
+ end
64
+ end
65
+
66
+ MAPPINGS = {
67
+ self: "'self'",
68
+ none: "'none'",
69
+ }.freeze
70
+
71
+ # List of available permissions can be found at
72
+ # https://github.com/w3c/webappsec-permissions-policy/blob/master/features.md#policy-controlled-features
73
+ DIRECTIVES = {
74
+ accelerometer: "accelerometer",
75
+ ambient_light_sensor: "ambient-light-sensor",
76
+ autoplay: "autoplay",
77
+ camera: "camera",
78
+ encrypted_media: "encrypted-media",
79
+ fullscreen: "fullscreen",
80
+ geolocation: "geolocation",
81
+ gyroscope: "gyroscope",
82
+ magnetometer: "magnetometer",
83
+ microphone: "microphone",
84
+ midi: "midi",
85
+ payment: "payment",
86
+ picture_in_picture: "picture-in-picture",
87
+ speaker: "speaker",
88
+ usb: "usb",
89
+ vibrate: "vibrate",
90
+ vr: "vr",
91
+ }.freeze
92
+
93
+ private_constant :MAPPINGS, :DIRECTIVES
94
+
95
+ attr_reader :directives
96
+
97
+ def initialize
98
+ @directives = {}
99
+ yield self if block_given?
100
+ end
101
+
102
+ def initialize_copy(other)
103
+ @directives = other.directives.deep_dup
104
+ end
105
+
106
+ DIRECTIVES.each do |name, directive|
107
+ define_method(name) do |*sources|
108
+ if sources.first
109
+ @directives[directive] = apply_mappings(sources)
110
+ else
111
+ @directives.delete(directive)
112
+ end
113
+ end
114
+ end
115
+
116
+ def build(context = nil)
117
+ build_directives(context).compact.join("; ")
118
+ end
119
+
120
+ private
121
+ def apply_mappings(sources)
122
+ sources.map do |source|
123
+ case source
124
+ when Symbol
125
+ apply_mapping(source)
126
+ when String, Proc
127
+ source
128
+ else
129
+ raise ArgumentError, "Invalid HTTP permissions policy source: #{source.inspect}"
130
+ end
131
+ end
132
+ end
133
+
134
+ def apply_mapping(source)
135
+ MAPPINGS.fetch(source) do
136
+ raise ArgumentError, "Unknown HTTP permissions policy source mapping: #{source.inspect}"
137
+ end
138
+ end
139
+
140
+ def build_directives(context)
141
+ @directives.map do |directive, sources|
142
+ if sources.is_a?(Array)
143
+ "#{directive} #{build_directive(sources, context).join(' ')}"
144
+ elsif sources
145
+ directive
146
+ else
147
+ nil
148
+ end
149
+ end
150
+ end
151
+
152
+ def build_directive(sources, context)
153
+ sources.map { |source| resolve_source(source, context) }
154
+ end
155
+
156
+ def resolve_source(source, context)
157
+ case source
158
+ when String
159
+ source
160
+ when Symbol
161
+ source.to_s
162
+ when Proc
163
+ if context.nil?
164
+ raise RuntimeError, "Missing context for the dynamic permissions policy source: #{source.inspect}"
165
+ else
166
+ context.instance_exec(&source)
167
+ end
168
+ else
169
+ raise RuntimeError, "Unexpected permissions policy source: #{source.inspect}"
170
+ end
171
+ end
172
+ end
173
+ end
@@ -23,6 +23,7 @@ module ActionDispatch
23
23
  include ActionDispatch::Http::FilterParameters
24
24
  include ActionDispatch::Http::URL
25
25
  include ActionDispatch::ContentSecurityPolicy::Request
26
+ include ActionDispatch::PermissionsPolicy::Request
26
27
  include Rack::Request::Env
27
28
 
28
29
  autoload :Session, "action_dispatch/request/session"
@@ -44,11 +45,14 @@ module ActionDispatch
44
45
  SERVER_ADDR
45
46
  ].freeze
46
47
 
48
+ # TODO: Remove SERVER_ADDR when we remove support to Rack 2.1.
49
+ # See https://github.com/rack/rack/commit/c173b188d81ee437b588c1e046a1c9f031dea550
47
50
  ENV_METHODS.each do |env|
48
51
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
49
- def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset
50
- get_header "#{env}".freeze # get_header "HTTP_ACCEPT_CHARSET".freeze
51
- end # end
52
+ # frozen_string_literal: true
53
+ def #{env.delete_prefix("HTTP_").downcase} # def accept_charset
54
+ get_header "#{env}" # get_header "HTTP_ACCEPT_CHARSET"
55
+ end # end
52
56
  METHOD
53
57
  end
54
58
 
@@ -72,7 +76,7 @@ module ActionDispatch
72
76
  PASS_NOT_FOUND = Class.new { # :nodoc:
73
77
  def self.action(_); self; end
74
78
  def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
75
- def self.binary_params_for?(action); false; end
79
+ def self.action_encoding_template(action); false; end
76
80
  }
77
81
 
78
82
  def controller_class
@@ -84,7 +88,7 @@ module ActionDispatch
84
88
  def controller_class_for(name)
85
89
  if name
86
90
  controller_param = name.underscore
87
- const_name = "#{controller_param.camelize}Controller"
91
+ const_name = controller_param.camelize << "Controller"
88
92
  begin
89
93
  ActiveSupport::Dependencies.constantize(const_name)
90
94
  rescue NameError => error
@@ -274,7 +278,7 @@ module ActionDispatch
274
278
  # (case-insensitive), which may need to be manually added depending on the
275
279
  # choice of JavaScript libraries and frameworks.
276
280
  def xml_http_request?
277
- get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i
281
+ /XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
278
282
  end
279
283
  alias :xhr? :xml_http_request?
280
284
 
@@ -290,6 +294,7 @@ module ActionDispatch
290
294
  end
291
295
 
292
296
  def remote_ip=(remote_ip)
297
+ @remote_ip = nil
293
298
  set_header "action_dispatch.remote_ip", remote_ip
294
299
  end
295
300
 
@@ -331,7 +336,7 @@ module ActionDispatch
331
336
  # variable is already set, wrap it in a StringIO.
332
337
  def body
333
338
  if raw_post = get_header("RAW_POST_DATA")
334
- raw_post = raw_post.dup.force_encoding(Encoding::BINARY)
339
+ raw_post = (+raw_post).force_encoding(Encoding::BINARY)
335
340
  StringIO.new(raw_post)
336
341
  else
337
342
  body_stream
@@ -376,6 +381,9 @@ module ActionDispatch
376
381
  def GET
377
382
  fetch_header("action_dispatch.request.query_parameters") do |k|
378
383
  rack_query_params = super || {}
384
+ controller = path_parameters[:controller]
385
+ action = path_parameters[:action]
386
+ rack_query_params = Request::Utils.set_binary_encoding(self, rack_query_params, controller, action)
379
387
  # Check for non UTF-8 parameter values, which would cause errors later
380
388
  Request::Utils.check_param_encoding(rack_query_params)
381
389
  set_header k, Request::Utils.normalize_encode_params(rack_query_params)
@@ -391,6 +399,8 @@ module ActionDispatch
391
399
  pr = parse_formatted_parameters(params_parsers) do |params|
392
400
  super || {}
393
401
  end
402
+ pr = Request::Utils.set_binary_encoding(self, pr, path_parameters[:controller], path_parameters[:action])
403
+ Request::Utils.check_param_encoding(pr)
394
404
  self.request_parameters = Request::Utils.normalize_encode_params(pr)
395
405
  end
396
406
  rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
@@ -409,7 +419,7 @@ module ActionDispatch
409
419
 
410
420
  # True if the request came from localhost, 127.0.0.1, or ::1.
411
421
  def local?
412
- LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
422
+ LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
413
423
  end
414
424
 
415
425
  def request_parameters=(params)
@@ -428,6 +438,10 @@ module ActionDispatch
428
438
  super || scheme == "wss"
429
439
  end
430
440
 
441
+ def inspect # :nodoc:
442
+ "#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
443
+ end
444
+
431
445
  private
432
446
  def check_method(name)
433
447
  HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
@@ -435,3 +449,5 @@ module ActionDispatch
435
449
  end
436
450
  end
437
451
  end
452
+
453
+ ActiveSupport.run_load_hooks :action_dispatch_request, ActionDispatch::Request
@@ -81,11 +81,22 @@ module ActionDispatch # :nodoc:
81
81
  CONTENT_TYPE = "Content-Type"
82
82
  SET_COOKIE = "Set-Cookie"
83
83
  LOCATION = "Location"
84
- NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
84
+ NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]
85
85
 
86
86
  cattr_accessor :default_charset, default: "utf-8"
87
87
  cattr_accessor :default_headers
88
- cattr_accessor :return_only_media_type_on_content_type, default: false
88
+
89
+ def self.return_only_media_type_on_content_type=(*)
90
+ ActiveSupport::Deprecation.warn(
91
+ ".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in 7.0."
92
+ )
93
+ end
94
+
95
+ def self.return_only_media_type_on_content_type
96
+ ActiveSupport::Deprecation.warn(
97
+ ".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in 7.0."
98
+ )
99
+ end
89
100
 
90
101
  include Rack::Response::Helpers
91
102
  # Aliasing these off because AD::Http::Cache::Response defines them.
@@ -243,17 +254,7 @@ module ActionDispatch # :nodoc:
243
254
 
244
255
  # Content type of response.
245
256
  def content_type
246
- if self.class.return_only_media_type_on_content_type
247
- ActiveSupport::Deprecation.warn(
248
- "Rails 6.1 will return Content-Type header without modification." \
249
- " If you want just the MIME type, please use `#media_type` instead."
250
- )
251
-
252
- content_type = super
253
- content_type ? content_type.split(/;\s*charset=/)[0].presence : content_type
254
- else
255
- super.presence
256
- end
257
+ super.presence
257
258
  end
258
259
 
259
260
  # Media type of response.
@@ -442,8 +443,8 @@ module ActionDispatch # :nodoc:
442
443
  end
443
444
 
444
445
  def set_content_type(content_type, charset)
445
- type = (content_type || "").dup
446
- type << "; charset=#{charset.to_s.downcase}" if charset
446
+ type = content_type || ""
447
+ type = "#{type}; charset=#{charset.to_s.downcase}" if charset
447
448
  set_header CONTENT_TYPE, type
448
449
  end
449
450
 
@@ -503,7 +504,7 @@ module ActionDispatch # :nodoc:
503
504
  end
504
505
 
505
506
  def respond_to?(method, include_private = false)
506
- if method.to_s == "to_path"
507
+ if method.to_sym == :to_path
507
508
  @response.stream.respond_to?(method)
508
509
  else
509
510
  super
@@ -9,6 +9,7 @@ module ActionDispatch
9
9
  HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
10
10
  PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
11
11
 
12
+ mattr_accessor :secure_protocol, default: false
12
13
  mattr_accessor :tld_length, default: 1
13
14
 
14
15
  class << self
@@ -133,13 +134,13 @@ module ActionDispatch
133
134
  end
134
135
 
135
136
  def named_host?(host)
136
- IP_HOST_REGEXP !~ host
137
+ !IP_HOST_REGEXP.match?(host)
137
138
  end
138
139
 
139
140
  def normalize_protocol(protocol)
140
141
  case protocol
141
142
  when nil
142
- "http://"
143
+ secure_protocol ? "https://" : "http://"
143
144
  when false, "//"
144
145
  "//"
145
146
  when PROTOCOL_REGEXP