actionpack 5.2.8.1 → 6.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +270 -347
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller/base.rb +4 -3
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/callbacks.rb +12 -0
  9. data/lib/abstract_controller/collector.rb +1 -2
  10. data/lib/abstract_controller/helpers.rb +7 -6
  11. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  12. data/lib/abstract_controller/translation.rb +4 -4
  13. data/lib/action_controller/api.rb +2 -1
  14. data/lib/action_controller/base.rb +2 -7
  15. data/lib/action_controller/caching.rb +1 -2
  16. data/lib/action_controller/log_subscriber.rb +8 -5
  17. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  18. data/lib/action_controller/metal/conditional_get.rb +9 -3
  19. data/lib/action_controller/metal/content_security_policy.rb +0 -1
  20. data/lib/action_controller/metal/data_streaming.rb +5 -6
  21. data/lib/action_controller/metal/default_headers.rb +17 -0
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  23. data/lib/action_controller/metal/exceptions.rb +23 -2
  24. data/lib/action_controller/metal/flash.rb +5 -5
  25. data/lib/action_controller/metal/force_ssl.rb +15 -56
  26. data/lib/action_controller/metal/head.rb +1 -1
  27. data/lib/action_controller/metal/helpers.rb +3 -4
  28. data/lib/action_controller/metal/http_authentication.rb +20 -21
  29. data/lib/action_controller/metal/implicit_render.rb +4 -14
  30. data/lib/action_controller/metal/instrumentation.rb +3 -6
  31. data/lib/action_controller/metal/live.rb +29 -31
  32. data/lib/action_controller/metal/mime_responds.rb +13 -2
  33. data/lib/action_controller/metal/params_wrapper.rb +18 -14
  34. data/lib/action_controller/metal/redirecting.rb +5 -5
  35. data/lib/action_controller/metal/renderers.rb +4 -4
  36. data/lib/action_controller/metal/rendering.rb +2 -3
  37. data/lib/action_controller/metal/request_forgery_protection.rb +25 -48
  38. data/lib/action_controller/metal/streaming.rb +0 -1
  39. data/lib/action_controller/metal/strong_parameters.rb +65 -44
  40. data/lib/action_controller/metal/url_for.rb +1 -1
  41. data/lib/action_controller/metal.rb +8 -6
  42. data/lib/action_controller/railties/helpers.rb +1 -1
  43. data/lib/action_controller/renderer.rb +17 -3
  44. data/lib/action_controller/template_assertions.rb +1 -1
  45. data/lib/action_controller/test_case.rb +7 -8
  46. data/lib/action_controller.rb +5 -1
  47. data/lib/action_dispatch/http/cache.rb +14 -11
  48. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  49. data/lib/action_dispatch/http/content_security_policy.rb +28 -17
  50. data/lib/action_dispatch/http/filter_parameters.rb +8 -7
  51. data/lib/action_dispatch/http/filter_redirect.rb +1 -2
  52. data/lib/action_dispatch/http/headers.rb +1 -2
  53. data/lib/action_dispatch/http/mime_negotiation.rb +13 -6
  54. data/lib/action_dispatch/http/mime_type.rb +14 -8
  55. data/lib/action_dispatch/http/parameter_filter.rb +5 -79
  56. data/lib/action_dispatch/http/parameters.rb +15 -6
  57. data/lib/action_dispatch/http/request.rb +21 -14
  58. data/lib/action_dispatch/http/response.rb +40 -21
  59. data/lib/action_dispatch/http/upload.rb +9 -1
  60. data/lib/action_dispatch/http/url.rb +81 -82
  61. data/lib/action_dispatch/journey/formatter.rb +2 -3
  62. data/lib/action_dispatch/journey/gtg/builder.rb +0 -1
  63. data/lib/action_dispatch/journey/gtg/transition_table.rb +0 -1
  64. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
  65. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -1
  66. data/lib/action_dispatch/journey/nodes/node.rb +9 -8
  67. data/lib/action_dispatch/journey/path/pattern.rb +6 -3
  68. data/lib/action_dispatch/journey/route.rb +5 -4
  69. data/lib/action_dispatch/journey/router/utils.rb +10 -10
  70. data/lib/action_dispatch/journey/router.rb +0 -4
  71. data/lib/action_dispatch/journey/routes.rb +0 -2
  72. data/lib/action_dispatch/journey/scanner.rb +10 -4
  73. data/lib/action_dispatch/journey/visitors.rb +1 -4
  74. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  76. data/lib/action_dispatch/middleware/cookies.rb +62 -78
  77. data/lib/action_dispatch/middleware/debug_exceptions.rb +45 -61
  78. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  79. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  80. data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -16
  81. data/lib/action_dispatch/middleware/flash.rb +1 -1
  82. data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  84. data/lib/action_dispatch/middleware/remote_ip.rb +9 -12
  85. data/lib/action_dispatch/middleware/request_id.rb +2 -2
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -1
  87. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -7
  88. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -2
  89. data/lib/action_dispatch/middleware/ssl.rb +8 -8
  90. data/lib/action_dispatch/middleware/stack.rb +38 -2
  91. data/lib/action_dispatch/middleware/static.rb +6 -7
  92. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  95. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  96. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  97. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  98. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
  101. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  102. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
  103. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +5 -2
  104. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  106. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  107. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  108. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  109. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  110. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
  111. data/lib/action_dispatch/railtie.rb +7 -2
  112. data/lib/action_dispatch/request/session.rb +9 -2
  113. data/lib/action_dispatch/routing/inspector.rb +97 -50
  114. data/lib/action_dispatch/routing/mapper.rb +63 -42
  115. data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -6
  116. data/lib/action_dispatch/routing/route_set.rb +25 -31
  117. data/lib/action_dispatch/routing/url_for.rb +2 -2
  118. data/lib/action_dispatch/routing.rb +21 -20
  119. data/lib/action_dispatch/system_test_case.rb +44 -6
  120. data/lib/action_dispatch/system_testing/browser.rb +38 -7
  121. data/lib/action_dispatch/system_testing/driver.rb +11 -2
  122. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
  123. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
  124. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  125. data/lib/action_dispatch/testing/assertions/response.rb +2 -3
  126. data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
  127. data/lib/action_dispatch/testing/assertions.rb +1 -1
  128. data/lib/action_dispatch/testing/integration.rb +33 -12
  129. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  130. data/lib/action_dispatch/testing/test_process.rb +2 -2
  131. data/lib/action_dispatch/testing/test_response.rb +4 -32
  132. data/lib/action_dispatch.rb +7 -2
  133. data/lib/action_pack/gem_version.rb +4 -4
  134. data/lib/action_pack.rb +1 -1
  135. metadata +29 -15
  136. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_dispatch/http/parameter_filter"
3
+ require "active_support/parameter_filter"
4
4
 
5
5
  module ActionDispatch
6
6
  module Http
@@ -9,8 +9,8 @@ module ActionDispatch
9
9
  # sub-hashes of the params hash to filter. Filtering only certain sub-keys
10
10
  # from a hash is possible by using the dot notation: 'credit_card.number'.
11
11
  # If a block is given, each key and value of the params hash and all
12
- # sub-hashes is passed to it, where the value or the key can be replaced using
13
- # String#replace or similar method.
12
+ # sub-hashes are passed to it, where the value or the key can be replaced using
13
+ # String#replace or similar methods.
14
14
  #
15
15
  # env["action_dispatch.parameter_filter"] = [:password]
16
16
  # => replaces the value to all keys matching /password/i with "[FILTERED]"
@@ -28,8 +28,8 @@ module ActionDispatch
28
28
  # => reverses the value to all keys matching /secret/i
29
29
  module FilterParameters
30
30
  ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
31
- NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
32
- NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
31
+ NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
32
+ NULL_ENV_FILTER = ActiveSupport::ParameterFilter.new ENV_MATCH # :nodoc:
33
33
 
34
34
  def initialize
35
35
  super
@@ -41,6 +41,8 @@ module ActionDispatch
41
41
  # Returns a hash of parameters with all sensitive data replaced.
42
42
  def filtered_parameters
43
43
  @filtered_parameters ||= parameter_filter.filter(parameters)
44
+ rescue ActionDispatch::Http::Parameters::ParseError
45
+ @filtered_parameters = {}
44
46
  end
45
47
 
46
48
  # Returns a hash of request.env with all sensitive data replaced.
@@ -54,7 +56,6 @@ module ActionDispatch
54
56
  end
55
57
 
56
58
  private
57
-
58
59
  def parameter_filter # :doc:
59
60
  parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
60
61
  return NULL_PARAM_FILTER
@@ -69,7 +70,7 @@ module ActionDispatch
69
70
  end
70
71
 
71
72
  def parameter_filter_for(filters) # :doc:
72
- ParameterFilter.new(filters)
73
+ ActiveSupport::ParameterFilter.new(filters)
73
74
  end
74
75
 
75
76
  KV_RE = "[^&;=]+"
@@ -3,7 +3,7 @@
3
3
  module ActionDispatch
4
4
  module Http
5
5
  module FilterRedirect
6
- FILTERED = "[FILTERED]".freeze # :nodoc:
6
+ FILTERED = "[FILTERED]" # :nodoc:
7
7
 
8
8
  def filtered_location # :nodoc:
9
9
  if location_filter_match?
@@ -14,7 +14,6 @@ module ActionDispatch
14
14
  end
15
15
 
16
16
  private
17
-
18
17
  def location_filters
19
18
  if request
20
19
  request.get_header("action_dispatch.redirect_filter") || []
@@ -116,12 +116,11 @@ module ActionDispatch
116
116
  def env; @req.env.dup; end
117
117
 
118
118
  private
119
-
120
119
  # Converts an HTTP header name to an environment variable name if it is
121
120
  # not contained within the headers hash.
122
121
  def env_name(key)
123
122
  key = key.to_s
124
- if key =~ HTTP_HEADER
123
+ if HTTP_HEADER.match?(key)
125
124
  key = key.upcase.tr("-", "_")
126
125
  key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
127
126
  end
@@ -7,6 +7,13 @@ module ActionDispatch
7
7
  module MimeNegotiation
8
8
  extend ActiveSupport::Concern
9
9
 
10
+ class InvalidType < ::Mime::Type::InvalidMimeType; end
11
+
12
+ RESCUABLE_MIME_FORMAT_ERRORS = [
13
+ ActionController::BadRequest,
14
+ ActionDispatch::Http::Parameters::ParseError,
15
+ ]
16
+
10
17
  included do
11
18
  mattr_accessor :ignore_accept_header, default: false
12
19
  end
@@ -20,6 +27,8 @@ module ActionDispatch
20
27
  nil
21
28
  end
22
29
  set_header k, v
30
+ rescue ::Mime::Type::InvalidMimeType => e
31
+ raise InvalidType, e.message
23
32
  end
24
33
  end
25
34
 
@@ -42,6 +51,8 @@ module ActionDispatch
42
51
  Mime::Type.parse(header)
43
52
  end
44
53
  set_header k, v
54
+ rescue ::Mime::Type::InvalidMimeType => e
55
+ raise InvalidType, e.message
45
56
  end
46
57
  end
47
58
 
@@ -59,7 +70,7 @@ module ActionDispatch
59
70
  fetch_header("action_dispatch.request.formats") do |k|
60
71
  params_readable = begin
61
72
  parameters[:format]
62
- rescue ActionController::BadRequest
73
+ rescue *RESCUABLE_MIME_FORMAT_ERRORS
63
74
  false
64
75
  end
65
76
 
@@ -90,10 +101,7 @@ module ActionDispatch
90
101
  if variant.all? { |v| v.is_a?(Symbol) }
91
102
  @variant = ActiveSupport::ArrayInquirer.new(variant)
92
103
  else
93
- raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \
94
- "For security reasons, never directly set the variant to a user-provided value, " \
95
- "like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
96
- "then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
104
+ raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
97
105
  end
98
106
  end
99
107
 
@@ -152,7 +160,6 @@ module ActionDispatch
152
160
  end
153
161
 
154
162
  private
155
-
156
163
  BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
157
164
 
158
165
  def valid_accept_header # :doc:
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # -*- frozen-string-literal: true -*-
4
-
5
3
  require "singleton"
6
4
  require "active_support/core_ext/string/starts_ends_with"
7
5
 
@@ -74,7 +72,7 @@ module Mime
74
72
  def initialize(index, name, q = nil)
75
73
  @index = index
76
74
  @name = name
77
- q ||= 0.0 if @name == "*/*".freeze # Default wildcard match to end of list.
75
+ q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
78
76
  @q = ((q || 1.0).to_f * 100).to_i
79
77
  end
80
78
 
@@ -172,6 +170,7 @@ module Mime
172
170
  def parse(accept_header)
173
171
  if !accept_header.include?(",")
174
172
  accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first
173
+ return [] unless accept_header
175
174
  parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact
176
175
  else
177
176
  list, index = [], 0
@@ -223,7 +222,18 @@ module Mime
223
222
 
224
223
  attr_reader :hash
225
224
 
225
+ MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
226
+ MIME_PARAMETER_KEY = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
227
+ MIME_PARAMETER_VALUE = "#{Regexp.escape('"')}?[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}#{Regexp.escape('"')}?"
228
+ MIME_PARAMETER = "\s*\;\s*#{MIME_PARAMETER_KEY}(?:\=#{MIME_PARAMETER_VALUE})?"
229
+ MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>\s*#{MIME_PARAMETER}\s*)*)\z/
230
+
231
+ class InvalidMimeType < StandardError; end
232
+
226
233
  def initialize(string, symbol = nil, synonyms = [])
234
+ unless MIME_REGEXP.match?(string)
235
+ raise InvalidMimeType, "#{string.inspect} is not a valid MIME type"
236
+ end
227
237
  @symbol, @synonyms = symbol, synonyms
228
238
  @string = string
229
239
  @hash = [@string, @synonyms, @symbol].hash
@@ -279,14 +289,10 @@ module Mime
279
289
 
280
290
  def all?; false; end
281
291
 
282
- # TODO Change this to private once we've dropped Ruby 2.2 support.
283
- # Workaround for Ruby 2.2 "private attribute?" warning.
284
292
  protected
285
-
286
293
  attr_reader :string, :synonyms
287
294
 
288
295
  private
289
-
290
296
  def to_ary; end
291
297
  def to_a; end
292
298
 
@@ -307,7 +313,7 @@ module Mime
307
313
  include Singleton
308
314
 
309
315
  def initialize
310
- super "*/*", :all
316
+ super "*/*", nil
311
317
  end
312
318
 
313
319
  def all?; true; end
@@ -1,86 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/duplicable"
3
+ require "active_support/deprecation/constant_accessor"
4
+ require "active_support/parameter_filter"
4
5
 
5
6
  module ActionDispatch
6
7
  module Http
7
- class ParameterFilter
8
- FILTERED = "[FILTERED]".freeze # :nodoc:
9
-
10
- def initialize(filters = [])
11
- @filters = filters
12
- end
13
-
14
- def filter(params)
15
- compiled_filter.call(params)
16
- end
17
-
18
- private
19
-
20
- def compiled_filter
21
- @compiled_filter ||= CompiledFilter.compile(@filters)
22
- end
23
-
24
- class CompiledFilter # :nodoc:
25
- def self.compile(filters)
26
- return lambda { |params| params.dup } if filters.empty?
27
-
28
- strings, regexps, blocks = [], [], []
29
-
30
- filters.each do |item|
31
- case item
32
- when Proc
33
- blocks << item
34
- when Regexp
35
- regexps << item
36
- else
37
- strings << Regexp.escape(item.to_s)
38
- end
39
- end
40
-
41
- deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
42
- deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
43
-
44
- regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
45
- deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
46
-
47
- new regexps, deep_regexps, blocks
48
- end
49
-
50
- attr_reader :regexps, :deep_regexps, :blocks
51
-
52
- def initialize(regexps, deep_regexps, blocks)
53
- @regexps = regexps
54
- @deep_regexps = deep_regexps.any? ? deep_regexps : nil
55
- @blocks = blocks
56
- end
57
-
58
- def call(original_params, parents = [])
59
- filtered_params = original_params.class.new
60
-
61
- original_params.each do |key, value|
62
- parents.push(key) if deep_regexps
63
- if regexps.any? { |r| key =~ r }
64
- value = FILTERED
65
- elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
66
- value = FILTERED
67
- elsif value.is_a?(Hash)
68
- value = call(value, parents)
69
- elsif value.is_a?(Array)
70
- value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
71
- elsif blocks.any?
72
- key = key.dup if key.duplicable?
73
- value = value.dup if value.duplicable?
74
- blocks.each { |b| b.call(key, value) }
75
- end
76
- parents.pop if deep_regexps
77
-
78
- filtered_params[key] = value
79
- end
80
-
81
- filtered_params
82
- end
83
- end
84
- end
8
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
9
+ deprecate_constant "ParameterFilter", "ActiveSupport::ParameterFilter",
10
+ message: "ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead."
85
11
  end
86
12
  end
@@ -85,12 +85,11 @@ module ActionDispatch
85
85
  end
86
86
 
87
87
  private
88
-
89
88
  def set_binary_encoding(params, controller, action)
90
89
  return params unless controller && controller.valid_encoding?
91
90
 
92
91
  if binary_params_for?(controller, action)
93
- ActionDispatch::Request::Utils.each_param_value(params) do |param|
92
+ ActionDispatch::Request::Utils.each_param_value(params.except(:controller, :action)) do |param|
94
93
  param.force_encoding ::Encoding::ASCII_8BIT
95
94
  end
96
95
  end
@@ -99,7 +98,7 @@ module ActionDispatch
99
98
 
100
99
  def binary_params_for?(controller, action)
101
100
  controller_class_for(controller).binary_params_for?(action)
102
- rescue NameError
101
+ rescue MissingController
103
102
  false
104
103
  end
105
104
 
@@ -111,13 +110,23 @@ module ActionDispatch
111
110
  begin
112
111
  strategy.call(raw_post)
113
112
  rescue # JSON or Ruby code block errors.
114
- my_logger = logger || ActiveSupport::Logger.new($stderr)
115
- my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
116
-
113
+ log_parse_error_once
117
114
  raise ParseError
118
115
  end
119
116
  end
120
117
 
118
+ def log_parse_error_once
119
+ @parse_error_logged ||= begin
120
+ parse_logger = logger || ActiveSupport::Logger.new($stderr)
121
+ parse_logger.debug <<~MSG.chomp
122
+ Error occurred while parsing request parameters.
123
+ Contents:
124
+
125
+ #{raw_post}
126
+ MSG
127
+ end
128
+ end
129
+
121
130
  def params_parsers
122
131
  ActionDispatch::Request.parameter_parsers
123
132
  end
@@ -85,7 +85,15 @@ module ActionDispatch
85
85
  if name
86
86
  controller_param = name.underscore
87
87
  const_name = "#{controller_param.camelize}Controller"
88
- ActiveSupport::Dependencies.constantize(const_name)
88
+ begin
89
+ ActiveSupport::Dependencies.constantize(const_name)
90
+ rescue NameError => error
91
+ if error.missing_name == const_name || const_name.start_with?("#{error.missing_name}::")
92
+ raise MissingController.new(error.message, error.name)
93
+ else
94
+ raise
95
+ end
96
+ end
89
97
  else
90
98
  PASS_NOT_FOUND
91
99
  end
@@ -125,6 +133,8 @@ module ActionDispatch
125
133
  HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
126
134
  }
127
135
 
136
+ alias raw_request_method request_method # :nodoc:
137
+
128
138
  # Returns the HTTP \method that the application should see.
129
139
  # In the case where the \method was overridden by a middleware
130
140
  # (for instance, if a HEAD request was converted to a GET,
@@ -136,11 +146,11 @@ module ActionDispatch
136
146
  end
137
147
 
138
148
  def routes # :nodoc:
139
- get_header("action_dispatch.routes".freeze)
149
+ get_header("action_dispatch.routes")
140
150
  end
141
151
 
142
152
  def routes=(routes) # :nodoc:
143
- set_header("action_dispatch.routes".freeze, routes)
153
+ set_header("action_dispatch.routes", routes)
144
154
  end
145
155
 
146
156
  def engine_script_name(_routes) # :nodoc:
@@ -158,11 +168,11 @@ module ActionDispatch
158
168
  end
159
169
 
160
170
  def controller_instance # :nodoc:
161
- get_header("action_controller.instance".freeze)
171
+ get_header("action_controller.instance")
162
172
  end
163
173
 
164
174
  def controller_instance=(controller) # :nodoc:
165
- set_header("action_controller.instance".freeze, controller)
175
+ set_header("action_controller.instance", controller)
166
176
  end
167
177
 
168
178
  def http_auth_salt
@@ -173,7 +183,7 @@ module ActionDispatch
173
183
  # We're treating `nil` as "unset", and we want the default setting to be
174
184
  # `true`. This logic should be extracted to `env_config` and calculated
175
185
  # once.
176
- !(get_header("action_dispatch.show_exceptions".freeze) == false)
186
+ !(get_header("action_dispatch.show_exceptions") == false)
177
187
  end
178
188
 
179
189
  # Returns a symbol form of the #request_method.
@@ -280,10 +290,10 @@ module ActionDispatch
280
290
  end
281
291
 
282
292
  def remote_ip=(remote_ip)
283
- set_header "action_dispatch.remote_ip".freeze, remote_ip
293
+ set_header "action_dispatch.remote_ip", remote_ip
284
294
  end
285
295
 
286
- ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
296
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
287
297
 
288
298
  # Returns the unique request id, which is based on either the X-Request-Id header that can
289
299
  # be generated by a firewall, load balancer, or web server or by the RequestId middleware
@@ -383,9 +393,6 @@ module ActionDispatch
383
393
  end
384
394
  self.request_parameters = Request::Utils.normalize_encode_params(pr)
385
395
  end
386
- rescue Http::Parameters::ParseError # one of the parse strategies blew up
387
- self.request_parameters = Request::Utils.normalize_encode_params(super || {})
388
- raise
389
396
  rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
390
397
  raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
391
398
  end
@@ -407,18 +414,18 @@ module ActionDispatch
407
414
 
408
415
  def request_parameters=(params)
409
416
  raise if params.nil?
410
- set_header("action_dispatch.request.request_parameters".freeze, params)
417
+ set_header("action_dispatch.request.request_parameters", params)
411
418
  end
412
419
 
413
420
  def logger
414
- get_header("action_dispatch.logger".freeze)
421
+ get_header("action_dispatch.logger")
415
422
  end
416
423
 
417
424
  def commit_flash
418
425
  end
419
426
 
420
427
  def ssl?
421
- super || scheme == "wss".freeze
428
+ super || scheme == "wss"
422
429
  end
423
430
 
424
431
  private
@@ -78,13 +78,14 @@ module ActionDispatch # :nodoc:
78
78
  x
79
79
  end
80
80
 
81
- CONTENT_TYPE = "Content-Type".freeze
82
- SET_COOKIE = "Set-Cookie".freeze
83
- LOCATION = "Location".freeze
81
+ CONTENT_TYPE = "Content-Type"
82
+ SET_COOKIE = "Set-Cookie"
83
+ LOCATION = "Location"
84
84
  NO_CONTENT_CODES = [100, 101, 102, 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
 
89
90
  include Rack::Response::Helpers
90
91
  # Aliasing these off because AD::Http::Cache::Response defines them.
@@ -105,7 +106,7 @@ module ActionDispatch # :nodoc:
105
106
 
106
107
  def body
107
108
  @str_body ||= begin
108
- buf = "".dup
109
+ buf = +""
109
110
  each { |chunk| buf << chunk }
110
111
  buf
111
112
  end
@@ -142,7 +143,6 @@ module ActionDispatch # :nodoc:
142
143
  end
143
144
 
144
145
  private
145
-
146
146
  def each_chunk(&block)
147
147
  @buf.each(&block)
148
148
  end
@@ -224,16 +224,6 @@ module ActionDispatch # :nodoc:
224
224
  @status = Rack::Utils.status_code(status)
225
225
  end
226
226
 
227
- # Sets the HTTP content type.
228
- def content_type=(content_type)
229
- return unless content_type
230
- new_header_info = parse_content_type(content_type.to_s)
231
- prev_header_info = parsed_content_type_header
232
- charset = new_header_info.charset || prev_header_info.charset
233
- charset ||= self.class.default_charset unless prev_header_info.mime_type
234
- set_content_type new_header_info.mime_type, charset
235
- end
236
-
237
227
  # Sets the HTTP response's content MIME type. For example, in the controller
238
228
  # you could write this:
239
229
  #
@@ -242,8 +232,32 @@ module ActionDispatch # :nodoc:
242
232
  # If a character set has been defined for this response (see charset=) then
243
233
  # the character set information will also be included in the content type
244
234
  # information.
235
+ def content_type=(content_type)
236
+ return unless content_type
237
+ new_header_info = parse_content_type(content_type.to_s)
238
+ prev_header_info = parsed_content_type_header
239
+ charset = new_header_info.charset || prev_header_info.charset
240
+ charset ||= self.class.default_charset unless prev_header_info.mime_type
241
+ set_content_type new_header_info.mime_type, charset
242
+ end
245
243
 
244
+ # Content type of response.
246
245
  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
+ end
258
+
259
+ # Media type of response.
260
+ def media_type
247
261
  parsed_content_type_header.mime_type
248
262
  end
249
263
 
@@ -404,15 +418,18 @@ module ActionDispatch # :nodoc:
404
418
  end
405
419
 
406
420
  private
407
-
408
421
  ContentTypeHeader = Struct.new :mime_type, :charset
409
422
  NullContentTypeHeader = ContentTypeHeader.new nil, nil
410
423
 
424
+ CONTENT_TYPE_PARSER = /
425
+ \A
426
+ (?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
427
+ (?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
428
+ /x # :nodoc:
429
+
411
430
  def parse_content_type(content_type)
412
- if content_type
413
- type, charset = content_type.split(/;\s*charset=/)
414
- type = nil if type && type.empty?
415
- ContentTypeHeader.new(type, charset)
431
+ if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
432
+ ContentTypeHeader.new(match[:mime_type], match[:charset])
416
433
  else
417
434
  NullContentTypeHeader
418
435
  end
@@ -459,7 +476,7 @@ module ActionDispatch # :nodoc:
459
476
  end
460
477
 
461
478
  def assign_default_content_type_and_charset!
462
- return if content_type
479
+ return if media_type
463
480
 
464
481
  ct = parsed_content_type_header
465
482
  set_content_type(ct.mime_type || Mime[:html].to_s,
@@ -517,4 +534,6 @@ module ActionDispatch # :nodoc:
517
534
  end
518
535
  end
519
536
  end
537
+
538
+ ActiveSupport.run_load_hooks(:action_dispatch_response, Response)
520
539
  end
@@ -20,7 +20,6 @@ module ActionDispatch
20
20
  # A +Tempfile+ object with the actual uploaded file. Note that some of
21
21
  # its interface is available directly.
22
22
  attr_accessor :tempfile
23
- alias :to_io :tempfile
24
23
 
25
24
  # A string with the headers of the multipart request.
26
25
  attr_accessor :headers
@@ -65,6 +64,11 @@ module ActionDispatch
65
64
  @tempfile.path
66
65
  end
67
66
 
67
+ # Shortcut for +tempfile.to_path+.
68
+ def to_path
69
+ @tempfile.to_path
70
+ end
71
+
68
72
  # Shortcut for +tempfile.rewind+.
69
73
  def rewind
70
74
  @tempfile.rewind
@@ -79,6 +83,10 @@ module ActionDispatch
79
83
  def eof?
80
84
  @tempfile.eof?
81
85
  end
86
+
87
+ def to_io
88
+ @tempfile.to_io
89
+ end
82
90
  end
83
91
  end
84
92
  end