actionpack 7.0.4.2 → 7.0.5

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.

Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -1
  3. data/lib/abstract_controller/helpers.rb +8 -7
  4. data/lib/abstract_controller/rendering.rb +9 -11
  5. data/lib/action_controller/api.rb +1 -1
  6. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  7. data/lib/action_controller/metal/conditional_get.rb +121 -123
  8. data/lib/action_controller/metal/content_security_policy.rb +4 -4
  9. data/lib/action_controller/metal/data_streaming.rb +18 -18
  10. data/lib/action_controller/metal/etag_with_flash.rb +1 -1
  11. data/lib/action_controller/metal/head.rb +1 -1
  12. data/lib/action_controller/metal/live.rb +1 -1
  13. data/lib/action_controller/metal/permissions_policy.rb +1 -1
  14. data/lib/action_controller/metal/redirecting.rb +1 -1
  15. data/lib/action_controller/metal/rendering.rb +114 -2
  16. data/lib/action_controller/metal/request_forgery_protection.rb +5 -3
  17. data/lib/action_controller/metal/streaming.rb +1 -1
  18. data/lib/action_controller/metal/url_for.rb +2 -4
  19. data/lib/action_controller/railtie.rb +2 -1
  20. data/lib/action_controller/renderer.rb +1 -20
  21. data/lib/action_dispatch/http/cache.rb +7 -7
  22. data/lib/action_dispatch/http/content_security_policy.rb +5 -1
  23. data/lib/action_dispatch/http/filter_parameters.rb +4 -24
  24. data/lib/action_dispatch/http/headers.rb +1 -1
  25. data/lib/action_dispatch/http/request.rb +15 -16
  26. data/lib/action_dispatch/http/response.rb +0 -4
  27. data/lib/action_dispatch/http/upload.rb +13 -2
  28. data/lib/action_dispatch/middleware/cookies.rb +6 -6
  29. data/lib/action_dispatch/middleware/remote_ip.rb +4 -4
  30. data/lib/action_dispatch/middleware/request_id.rb +2 -2
  31. data/lib/action_dispatch/middleware/static.rb +3 -3
  32. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +17 -8
  33. data/lib/action_dispatch/routing/mapper.rb +23 -0
  34. data/lib/action_dispatch/routing/url_for.rb +21 -21
  35. data/lib/action_dispatch/system_testing/driver.rb +1 -1
  36. data/lib/action_dispatch/testing/assertions/response.rb +1 -1
  37. data/lib/action_pack/gem_version.rb +2 -2
  38. metadata +17 -17
@@ -12,7 +12,7 @@ module ActionController
12
12
  include ActionController::ConditionalGet
13
13
 
14
14
  included do
15
- etag { flash unless flash.empty? }
15
+ etag { flash if request.respond_to?(:flash) && !flash.empty? }
16
16
  end
17
17
  end
18
18
  end
@@ -17,7 +17,7 @@ module ActionController
17
17
  # return head(:bad_request) unless valid_request?
18
18
  # render
19
19
  #
20
- # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list of valid +status+ symbols.
20
+ # See +Rack::Utils::SYMBOL_TO_STATUS_CODE+ for a full list of valid +status+ symbols.
21
21
  def head(status, options = {})
22
22
  if status.is_a?(Hash)
23
23
  raise ArgumentError, "#{status.inspect} is not a valid value for `status`."
@@ -321,7 +321,7 @@ module ActionController
321
321
  def send_stream(filename:, disposition: "attachment", type: nil)
322
322
  response.headers["Content-Type"] =
323
323
  (type.is_a?(Symbol) ? Mime[type].to_s : type) ||
324
- Mime::Type.lookup_by_extension(File.extname(filename).downcase.delete(".")) ||
324
+ Mime::Type.lookup_by_extension(File.extname(filename).downcase.delete("."))&.to_s ||
325
325
  "application/octet-stream"
326
326
 
327
327
  response.headers["Content-Disposition"] =
@@ -5,7 +5,7 @@ module ActionController # :nodoc:
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- # Overrides parts of the globally configured Feature-Policy
8
+ # Overrides parts of the globally configured +Feature-Policy+
9
9
  # header:
10
10
  #
11
11
  # class PagesController < ApplicationController
@@ -200,7 +200,7 @@ module ActionController
200
200
  return true if host == request.host
201
201
  return false unless host.nil?
202
202
  return false unless url.to_s.start_with?("/")
203
- return !url.to_s.start_with?("//")
203
+ !url.to_s.start_with?("//")
204
204
  rescue ArgumentError, URI::Error
205
205
  false
206
206
  end
@@ -24,12 +24,124 @@ module ActionController
24
24
  end
25
25
  end
26
26
 
27
+ # Renders a template and assigns the result to +self.response_body+.
28
+ #
29
+ # If no rendering mode option is specified, the template will be derived
30
+ # from the first argument.
31
+ #
32
+ # render "posts/show"
33
+ # # => renders app/views/posts/show.html.erb
34
+ #
35
+ # # In a PostsController action...
36
+ # render :show
37
+ # # => renders app/views/posts/show.html.erb
38
+ #
39
+ # If the first argument responds to +render_in+, the template will be
40
+ # rendered by calling +render_in+ with the current view context.
41
+ #
42
+ # ==== \Rendering Mode
43
+ #
44
+ # [+:partial+]
45
+ # See ActionView::PartialRenderer for details.
46
+ #
47
+ # render partial: "posts/form", locals: { post: Post.new }
48
+ # # => renders app/views/posts/_form.html.erb
49
+ #
50
+ # [+:file+]
51
+ # Renders the contents of a file. This option should <b>not</b> be used
52
+ # with unsanitized user input.
53
+ #
54
+ # render file: "/path/to/some/file"
55
+ # # => renders /path/to/some/file
56
+ #
57
+ # [+:inline+]
58
+ # Renders an ERB template string.
59
+ #
60
+ # @name = "World"
61
+ # render inline: "<h1>Hello, <%= @name %>!</h1>"
62
+ # # => renders "<h1>Hello, World!</h1>"
63
+ #
64
+ # [+:body+]
65
+ # Renders the provided text, and sets the content type as +text/plain+.
66
+ #
67
+ # render body: "Hello, World!"
68
+ # # => renders "Hello, World!"
69
+ #
70
+ # [+:plain+]
71
+ # Renders the provided text, and sets the content type as +text/plain+.
72
+ #
73
+ # render plain: "Hello, World!"
74
+ # # => renders "Hello, World!"
75
+ #
76
+ # [+:html+]
77
+ # Renders the provided HTML string, and sets the content type as +text/html+.
78
+ # If the string is not +html_safe?+, performs HTML escaping on the string
79
+ # before rendering.
80
+ #
81
+ # render html: "<h1>Hello, World!</h1>".html_safe
82
+ # # => renders "<h1>Hello, World!</h1>"
83
+ #
84
+ # render html: "<h1>Hello, World!</h1>"
85
+ # # => renders "&lt;h1&gt;Hello, World!&lt;/h1&gt;"
86
+ #
87
+ # [+:json+]
88
+ # Renders the provided object as JSON, and sets the content type as
89
+ # +application/json+. If the object is not a string, it will be converted
90
+ # to JSON by calling +to_json+.
91
+ #
92
+ # render json: { hello: "world" }
93
+ # # => renders "{\"hello\":\"world\"}"
94
+ #
95
+ # By default, when a rendering mode is specified, no layout template is
96
+ # rendered.
97
+ #
98
+ # ==== Options
99
+ #
100
+ # [+:assigns+]
101
+ # Hash of instance variable assignments for the template.
102
+ #
103
+ # render inline: "<h1>Hello, <%= @name %>!</h1>", assigns: { name: "World" }
104
+ # # => renders "<h1>Hello, World!</h1>"
105
+ #
106
+ # [+:locals+]
107
+ # Hash of local variable assignments for the template.
108
+ #
109
+ # render inline: "<h1>Hello, <%= name %>!</h1>", locals: { name: "World" }
110
+ # # => renders "<h1>Hello, World!</h1>"
111
+ #
112
+ # [+:layout+]
113
+ # The layout template to render. Can also be +false+ or +true+ to disable
114
+ # or (re)enable the default layout template.
115
+ #
116
+ # render "posts/show", layout: "holiday"
117
+ # # => renders app/views/posts/show.html.erb with the app/views/layouts/holiday.html.erb layout
118
+ #
119
+ # render "posts/show", layout: false
120
+ # # => renders app/views/posts/show.html.erb with no layout
121
+ #
122
+ # render inline: "<h1>Hello, World!</h1>", layout: true
123
+ # # => renders "<h1>Hello, World!</h1>" with the default layout
124
+ #
125
+ # [+:status+]
126
+ # The HTTP status code to send with the response. Can be specified as a
127
+ # number or as the status name in Symbol form. Defaults to 200.
128
+ #
129
+ # render "posts/new", status: 422
130
+ # # => renders app/views/posts/new.html.erb with HTTP status code 422
131
+ #
132
+ # render "posts/new", status: :unprocessable_entity
133
+ # # => renders app/views/posts/new.html.erb with HTTP status code 422
134
+ #
135
+ #--
27
136
  # Check for double render errors and set the content_type after rendering.
28
- def render(*args) # :nodoc:
137
+ def render(*args)
29
138
  raise ::AbstractController::DoubleRenderError if response_body
30
139
  super
31
140
  end
32
141
 
142
+ # Similar to #render, but only returns the rendered template as a string,
143
+ # instead of setting +self.response_body+.
144
+ #--
33
145
  # Override render_to_string because body can now be set to a Rack body.
34
146
  def render_to_string(*)
35
147
  result = super
@@ -42,7 +154,7 @@ module ActionController
42
154
  end
43
155
  end
44
156
 
45
- def render_to_body(options = {})
157
+ def render_to_body(options = {}) # :nodoc:
46
158
  super || _render_in_priorities(options) || " "
47
159
  end
48
160
 
@@ -118,9 +118,11 @@ module ActionController # :nodoc:
118
118
  # protect_from_forgery except: :index
119
119
  # end
120
120
  #
121
- # You can disable forgery protection on controller by skipping the verification before_action:
121
+ # You can disable forgery protection on a controller using skip_forgery_protection:
122
122
  #
123
- # skip_before_action :verify_authenticity_token
123
+ # class BarController < ApplicationController
124
+ # skip_forgery_protection
125
+ # end
124
126
  #
125
127
  # Valid Options:
126
128
  #
@@ -334,7 +336,7 @@ module ActionController # :nodoc:
334
336
  #
335
337
  # * Is it a GET or HEAD request? GETs should be safe and idempotent
336
338
  # * Does the form_authenticity_token match the given token value from the params?
337
- # * Does the X-CSRF-Token header match the form_authenticity_token?
339
+ # * Does the +X-CSRF-Token+ header match the form_authenticity_token?
338
340
  def verified_request? # :doc:
339
341
  !protect_against_forgery? || request.get? || request.head? ||
340
342
  (valid_request_origin? && any_authenticity_token_valid?)
@@ -147,7 +147,7 @@ module ActionController # :nodoc:
147
147
  # needs to inject contents in the HTML body.
148
148
  #
149
149
  # Also <tt>Rack::Cache</tt> won't work with streaming as it does not support
150
- # streaming bodies yet. Whenever streaming Cache-Control is automatically
150
+ # streaming bodies yet. Whenever streaming +Cache-Control+ is automatically
151
151
  # set to "no-cache".
152
152
  #
153
153
  # == Errors
@@ -6,10 +6,8 @@ module ActionController
6
6
  #
7
7
  # In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
8
8
  # URL options like the +host+. In order to do so, this module requires the host class
9
- # to implement +env+ which needs to be Rack-compatible and +request+
10
- # which is either an instance of ActionDispatch::Request or an object
11
- # that responds to the +host+, +optional_port+, +protocol+, and
12
- # +symbolized_path_parameter+ methods.
9
+ # to implement +env+ which needs to be Rack-compatible, and +request+ which
10
+ # returns an ActionDispatch::Request instance.
13
11
  #
14
12
  # class RootUrl
15
13
  # include ActionController::UrlFor
@@ -111,7 +111,8 @@ module ActionController
111
111
  app.config.action_controller.log_query_tags_around_actions
112
112
 
113
113
  if query_logs_tags_enabled
114
- app.config.active_record.query_log_tags += [:controller, :action]
114
+ app.config.active_record.query_log_tags |= [:controller] unless app.config.active_record.query_log_tags.include?(:namespaced_controller)
115
+ app.config.active_record.query_log_tags |= [:action]
115
116
 
116
117
  ActiveSupport.on_load(:active_record) do
117
118
  ActiveRecord::QueryLogs.taggings.merge!(
@@ -68,26 +68,7 @@ module ActionController
68
68
  @env = normalize_keys defaults, env
69
69
  end
70
70
 
71
- # Render templates with any options from ActionController::Base#render_to_string.
72
- #
73
- # The primary options are:
74
- # * <tt>:partial</tt> - See ActionView::PartialRenderer for details.
75
- # * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
76
- # It shouldn’t be used directly with unsanitized user input due to lack of validation.
77
- # * <tt>:inline</tt> - Renders an ERB template string.
78
- # * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
79
- # * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
80
- # performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
81
- # * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
82
- # need to call <tt>.to_json</tt> on the object you want to render.
83
- # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
- #
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.
71
+ # Renders a template to a string, just like ActionController::Rendering#render_to_string.
91
72
  def render(*args)
92
73
  raise "missing controller" unless controller
93
74
 
@@ -32,8 +32,8 @@ module ActionDispatch
32
32
  end
33
33
  end
34
34
 
35
- # Check response freshness (Last-Modified and ETag) against request
36
- # If-Modified-Since and If-None-Match conditions. If both headers are
35
+ # Check response freshness (+Last-Modified+ and ETag) against request
36
+ # +If-Modified-Since+ and +If-None-Match+ conditions. If both headers are
37
37
  # supplied, both must match, or the request is not considered fresh.
38
38
  def fresh?(response)
39
39
  last_modified = if_modified_since
@@ -81,8 +81,8 @@ module ActionDispatch
81
81
 
82
82
  # This method sets a weak ETag validator on the response so browsers
83
83
  # and proxies may cache the response, keyed on the ETag. On subsequent
84
- # requests, the If-None-Match header is set to the cached ETag. If it
85
- # matches the current ETag, we can return a 304 Not Modified response
84
+ # requests, the +If-None-Match+ header is set to the cached ETag. If it
85
+ # matches the current ETag, we can return a <tt>304 Not Modified</tt> response
86
86
  # with no body, letting the browser or proxy know that their cache is
87
87
  # current. Big savings in request time and network bandwidth.
88
88
  #
@@ -92,7 +92,7 @@ module ActionDispatch
92
92
  # is viewing.
93
93
  #
94
94
  # Strong ETags are considered byte-for-byte identical. They allow a
95
- # browser or proxy cache to support Range requests, useful for paging
95
+ # browser or proxy cache to support +Range+ requests, useful for paging
96
96
  # through a PDF file or scrubbing through a video. Some CDNs only
97
97
  # support strong ETags and will ignore weak ETags entirely.
98
98
  #
@@ -112,12 +112,12 @@ module ActionDispatch
112
112
 
113
113
  def etag?; etag; end
114
114
 
115
- # True if an ETag is set and it's a weak validator (preceded with W/)
115
+ # True if an ETag is set, and it's a weak validator (preceded with <tt>W/</tt>).
116
116
  def weak_etag?
117
117
  etag? && etag.start_with?('W/"')
118
118
  end
119
119
 
120
- # True if an ETag is set and it isn't a weak validator (not preceded with W/)
120
+ # True if an ETag is set, and it isn't a weak validator (not preceded with <tt>W/</tt>).
121
121
  def strong_etag?
122
122
  etag? && !weak_etag?
123
123
  end
@@ -33,7 +33,11 @@ module ActionDispatch # :nodoc:
33
33
 
34
34
  def call(env)
35
35
  request = ActionDispatch::Request.new env
36
- _, headers, _ = response = @app.call(env)
36
+ status, headers, _ = response = @app.call(env)
37
+
38
+ # Returning CSP headers with a 304 Not Modified is harmful, since nonces in the new
39
+ # CSP headers might not match nonces in the cached HTML.
40
+ return response if status == 304
37
41
 
38
42
  return response if policy_present?(headers)
39
43
 
@@ -4,33 +4,13 @@ require "active_support/parameter_filter"
4
4
 
5
5
  module ActionDispatch
6
6
  module Http
7
- # Allows you to specify sensitive parameters which will be replaced from
8
- # the request log by looking in the query string of the request and all
9
- # sub-hashes of the params hash to filter. Filtering only certain sub-keys
10
- # from a hash is possible by using the dot notation: 'credit_card.number'.
11
- # If a block is given, each key and value of the params hash and all
12
- # sub-hashes are passed to it, where the value or the key can be replaced using
13
- # String#replace or similar methods.
14
- #
15
- # env["action_dispatch.parameter_filter"] = [:password]
16
- # => replaces the value to all keys matching /password/i with "[FILTERED]"
7
+ # Allows you to specify sensitive query string and POST parameters to filter
8
+ # from the request log.
17
9
  #
10
+ # # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
18
11
  # env["action_dispatch.parameter_filter"] = [:foo, "bar"]
19
- # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
20
- #
21
- # env["action_dispatch.parameter_filter"] = [ /\Apin\z/i, /\Apin_/i ]
22
- # => replaces the value for the exact (case-insensitive) key 'pin' and all
23
- # (case-insensitive) keys beginning with 'pin_', with "[FILTERED]"
24
- # Does not match keys with 'pin' as a substring, such as 'shipping_id'.
25
- #
26
- # env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
27
- # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
28
- # change { file: { code: "xxxx"} }
29
12
  #
30
- # env["action_dispatch.parameter_filter"] = -> (k, v) do
31
- # v.reverse! if k.match?(/secret/i)
32
- # end
33
- # => reverses the value to all keys matching /secret/i
13
+ # For more information about filter behavior, see ActiveSupport::ParameterFilter.
34
14
  module FilterParameters
35
15
  ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
36
16
  NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
@@ -65,7 +65,7 @@ module ActionDispatch
65
65
  @req.set_header env_name(key), value
66
66
  end
67
67
 
68
- # Add a value to a multivalued header like Vary or Accept-Encoding.
68
+ # Add a value to a multivalued header like +Vary+ or +Accept-Encoding+.
69
69
  def add(key, value)
70
70
  @req.add_header env_name(key), value
71
71
  end
@@ -107,22 +107,21 @@ module ActionDispatch
107
107
  has_header? key
108
108
  end
109
109
 
110
- # List of HTTP request methods from the following RFCs:
111
- # Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt)
112
- # HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt)
113
- # Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt)
114
- # Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt)
115
- # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt)
116
- # Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt)
117
- # Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt)
118
- # PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt)
110
+ # HTTP methods from {RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1}[https://www.ietf.org/rfc/rfc2616.txt]
119
111
  RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
112
+ # HTTP methods from {RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV}[https://www.ietf.org/rfc/rfc2518.txt]
120
113
  RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
114
+ # HTTP methods from {RFC 3253: Versioning Extensions to WebDAV}[https://www.ietf.org/rfc/rfc3253.txt]
121
115
  RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
116
+ # HTTP methods from {RFC 3648: WebDAV Ordered Collections Protocol}[https://www.ietf.org/rfc/rfc3648.txt]
122
117
  RFC3648 = %w(ORDERPATCH)
118
+ # HTTP methods from {RFC 3744: WebDAV Access Control Protocol}[https://www.ietf.org/rfc/rfc3744.txt]
123
119
  RFC3744 = %w(ACL)
120
+ # HTTP methods from {RFC 5323: WebDAV SEARCH}[https://www.ietf.org/rfc/rfc5323.txt]
124
121
  RFC5323 = %w(SEARCH)
122
+ # HTTP methods from {RFC 4791: Calendaring Extensions to WebDAV}[https://www.ietf.org/rfc/rfc4791.txt]
125
123
  RFC4791 = %w(MKCALENDAR)
124
+ # HTTP methods from {RFC 5789: PATCH Method for HTTP}[https://www.ietf.org/rfc/rfc5789.txt]
126
125
  RFC5789 = %w(PATCH)
127
126
 
128
127
  HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
@@ -271,7 +270,7 @@ module ActionDispatch
271
270
  super.to_i
272
271
  end
273
272
 
274
- # Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
273
+ # Returns true if the +X-Requested-With+ header contains "XMLHttpRequest"
275
274
  # (case-insensitive), which may need to be manually added depending on the
276
275
  # choice of JavaScript libraries and frameworks.
277
276
  def xml_http_request?
@@ -297,7 +296,7 @@ module ActionDispatch
297
296
 
298
297
  ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
299
298
 
300
- # Returns the unique request id, which is based on either the X-Request-Id header that can
299
+ # Returns the unique request id, which is based on either the +X-Request-Id+ header that can
301
300
  # be generated by a firewall, load balancer, or web server, or by the RequestId middleware
302
301
  # (which sets the +action_dispatch.request_id+ environment variable).
303
302
  #
@@ -341,13 +340,13 @@ module ActionDispatch
341
340
  end
342
341
 
343
342
  # Determine whether the request body contains form-data by checking
344
- # the request Content-Type for one of the media-types:
345
- # "application/x-www-form-urlencoded" or "multipart/form-data". The
343
+ # the request +Content-Type+ for one of the media-types:
344
+ # +application/x-www-form-urlencoded+ or +multipart/form-data+. The
346
345
  # list of form-data media types can be modified through the
347
346
  # +FORM_DATA_MEDIA_TYPES+ array.
348
347
  #
349
348
  # A request body is not assumed to contain form-data when no
350
- # Content-Type header is provided and the request_method is POST.
349
+ # +Content-Type+ header is provided and the request_method is POST.
351
350
  def form_data?
352
351
  FORM_DATA_MEDIA_TYPES.include?(media_type)
353
352
  end
@@ -379,7 +378,7 @@ module ActionDispatch
379
378
  Request::Utils.check_param_encoding(rack_query_params)
380
379
  set_header k, Request::Utils.normalize_encode_params(rack_query_params)
381
380
  end
382
- rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
381
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError => e
383
382
  raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
384
383
  end
385
384
  alias :query_parameters :GET
@@ -394,7 +393,7 @@ module ActionDispatch
394
393
  Request::Utils.check_param_encoding(pr)
395
394
  self.request_parameters = Request::Utils.normalize_encode_params(pr)
396
395
  end
397
- rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
396
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError, EOFError => e
398
397
  raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
399
398
  end
400
399
  alias :request_parameters :POST
@@ -501,10 +501,6 @@ module ActionDispatch # :nodoc:
501
501
  def to_path
502
502
  @response.stream.to_path
503
503
  end
504
-
505
- def to_ary
506
- nil
507
- end
508
504
  end
509
505
 
510
506
  def handle_no_content!
@@ -28,6 +28,8 @@ module ActionDispatch
28
28
  @tempfile = hash[:tempfile]
29
29
  raise(ArgumentError, ":tempfile is required") unless @tempfile
30
30
 
31
+ @content_type = hash[:type]
32
+
31
33
  if hash[:filename]
32
34
  @original_filename = hash[:filename].dup
33
35
 
@@ -40,8 +42,17 @@ module ActionDispatch
40
42
  @original_filename = nil
41
43
  end
42
44
 
43
- @content_type = hash[:type]
44
- @headers = hash[:head]
45
+ if hash[:head]
46
+ @headers = hash[:head].dup
47
+
48
+ begin
49
+ @headers.encode!(Encoding::UTF_8)
50
+ rescue EncodingError
51
+ @headers.force_encoding(Encoding::UTF_8)
52
+ end
53
+ else
54
+ @headers = nil
55
+ end
45
56
  end
46
57
 
47
58
  # Shortcut for +tempfile.read+.
@@ -95,7 +95,7 @@ module ActionDispatch
95
95
  # Read and write data to cookies through ActionController::Base#cookies.
96
96
  #
97
97
  # When reading cookie data, the data is read from the HTTP request header, Cookie.
98
- # When writing cookie data, the data is sent out in the HTTP response header, Set-Cookie.
98
+ # When writing cookie data, the data is sent out in the HTTP response header, +Set-Cookie+.
99
99
  #
100
100
  # Examples of writing:
101
101
  #
@@ -443,7 +443,7 @@ module ActionDispatch
443
443
 
444
444
  if options[:domain] == :all || options[:domain] == "all"
445
445
  cookie_domain = ""
446
- dot_splitted_host = request.host.split('.', -1)
446
+ dot_splitted_host = request.host.split(".", -1)
447
447
 
448
448
  # Case where request.host is not an IP address or it's an invalid domain
449
449
  # (ip confirms to the domain structure we expect so we explicitly check for ip)
@@ -453,10 +453,10 @@ module ActionDispatch
453
453
  end
454
454
 
455
455
  # If there is a provided tld length then we use it otherwise default domain.
456
- if options[:tld_length].present?
456
+ if options[:tld_length].present?
457
457
  # Case where the tld_length provided is valid
458
458
  if dot_splitted_host.length >= options[:tld_length]
459
- cookie_domain = dot_splitted_host.last(options[:tld_length]).join('.')
459
+ cookie_domain = dot_splitted_host.last(options[:tld_length]).join(".")
460
460
  end
461
461
  # Case where tld_length is not provided
462
462
  else
@@ -465,7 +465,7 @@ module ActionDispatch
465
465
  cookie_domain = dot_splitted_host.last(2).join(".")
466
466
  # **.**, ***.** style TLDs like co.uk and com.au
467
467
  else
468
- cookie_domain = dot_splitted_host.last(3).join('.')
468
+ cookie_domain = dot_splitted_host.last(3).join(".")
469
469
  end
470
470
  end
471
471
 
@@ -683,7 +683,7 @@ module ActionDispatch
683
683
  deserialize(name) do |rotate|
684
684
  @encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate, purpose: purpose)
685
685
  end
686
- rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
686
+ rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature, JSON::ParserError
687
687
  nil
688
688
  end
689
689
 
@@ -22,7 +22,7 @@ module ActionDispatch
22
22
  # This middleware assumes that there is at least one proxy sitting around
23
23
  # and setting headers with the client's remote IP address. If you don't use
24
24
  # a proxy, because you are hosted on e.g. Heroku without SSL, any client can
25
- # claim to have any IP address by setting the X-Forwarded-For header. If you
25
+ # claim to have any IP address by setting the +X-Forwarded-For+ header. If you
26
26
  # care about that, then you need to explicitly drop or ignore those headers
27
27
  # sometime before this middleware runs.
28
28
  class RemoteIp
@@ -53,7 +53,7 @@ module ActionDispatch
53
53
  #
54
54
  # The +custom_proxies+ argument can take an enumerable which will be used
55
55
  # instead of +TRUSTED_PROXIES+. Any proxy setup will put the value you
56
- # want in the middle (or at the beginning) of the X-Forwarded-For list,
56
+ # want in the middle (or at the beginning) of the +X-Forwarded-For+ list,
57
57
  # with your proxy servers after it. If your proxies aren't removed, pass
58
58
  # them in via the +custom_proxies+ parameter. That way, the middleware will
59
59
  # ignore those IP addresses, and return the one that you want.
@@ -110,9 +110,9 @@ module ActionDispatch
110
110
  # REMOTE_ADDR will be correct if the request is made directly against the
111
111
  # Ruby process, on e.g. Heroku. When the request is proxied by another
112
112
  # server like HAProxy or NGINX, the IP address that made the original
113
- # request will be put in an X-Forwarded-For header. If there are multiple
113
+ # request will be put in an +X-Forwarded-For+ header. If there are multiple
114
114
  # proxies, that header may contain a list of IPs. Other proxy services
115
- # set the Client-Ip header instead, so we check that too.
115
+ # set the +Client-Ip+ header instead, so we check that too.
116
116
  #
117
117
  # As discussed in {this post about Rails IP Spoofing}[https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/],
118
118
  # while the first IP in the list is likely to be the "originating" IP,
@@ -6,9 +6,9 @@ require "active_support/core_ext/string/access"
6
6
  module ActionDispatch
7
7
  # Makes a unique request id available to the +action_dispatch.request_id+ env variable (which is then accessible
8
8
  # through ActionDispatch::Request#request_id or the alias ActionDispatch::Request#uuid) and sends
9
- # the same id to the client via the X-Request-Id header.
9
+ # the same id to the client via the +X-Request-Id+ header.
10
10
  #
11
- # The unique request id is either based on the X-Request-Id header in the request, which would typically be generated
11
+ # The unique request id is either based on the +X-Request-Id+ header in the request, which would typically be generated
12
12
  # by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the
13
13
  # header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.
14
14
  #
@@ -24,7 +24,7 @@ module ActionDispatch
24
24
  end
25
25
  end
26
26
 
27
- # This endpoint serves static files from disk using Rack::File.
27
+ # This endpoint serves static files from disk using +Rack::File+.
28
28
  #
29
29
  # URL paths are matched with static files according to expected
30
30
  # conventions: +path+, +path+.html, +path+/index.html.
@@ -33,13 +33,13 @@ module ActionDispatch
33
33
  # and gzip (.gz) files are supported. If +path+.br exists, this
34
34
  # endpoint returns that file with a <tt>Content-Encoding: br</tt> header.
35
35
  #
36
- # If no matching file is found, this endpoint responds 404 Not Found.
36
+ # If no matching file is found, this endpoint responds <tt>404 Not Found</tt>.
37
37
  #
38
38
  # Pass the +root+ directory to search for matching files, an optional
39
39
  # <tt>index: "index"</tt> to change the default +path+/index.html, and optional
40
40
  # additional response headers.
41
41
  class FileHandler
42
- # Accept-Encoding value -> file extension
42
+ # +Accept-Encoding+ value -> file extension
43
43
  PRECOMPRESSED = {
44
44
  "br" => ".br",
45
45
  "gzip" => ".gz",