actionpack 7.1.6 → 7.2.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +117 -607
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +93 -100
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +75 -72
- data/lib/action_controller/base.rb +198 -126
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +187 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +69 -62
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +116 -108
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +112 -85
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +104 -76
- data/lib/action_controller/metal/request_forgery_protection.rb +165 -134
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +483 -481
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +148 -129
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +40 -38
- data/lib/action_dispatch/http/filter_parameters.rb +9 -5
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +35 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +19 -36
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +72 -72
- data/lib/action_dispatch/http/response.rb +88 -62
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +77 -75
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +14 -12
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -6
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +9 -14
- data/lib/action_dispatch/middleware/executor.rb +7 -2
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +13 -7
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +76 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -3
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -3
- data/lib/action_dispatch/routing/mapper.rb +622 -623
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +59 -45
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +4 -2
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +222 -222
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -28
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +34 -11
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/object/deep_dup"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch # :nodoc:
|
|
6
|
-
#
|
|
8
|
+
# # Action Dispatch PermissionsPolicy
|
|
7
9
|
#
|
|
8
10
|
# Configures the HTTP
|
|
9
|
-
#
|
|
10
|
-
# response header to specify which browser features the current
|
|
11
|
-
# its iframes can use.
|
|
11
|
+
# [Feature-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy)
|
|
12
|
+
# response header to specify which browser features the current
|
|
13
|
+
# document and its iframes can use.
|
|
12
14
|
#
|
|
13
15
|
# Example global policy:
|
|
14
16
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
17
|
+
# Rails.application.config.permissions_policy do |policy|
|
|
18
|
+
# policy.camera :none
|
|
19
|
+
# policy.gyroscope :none
|
|
20
|
+
# policy.microphone :none
|
|
21
|
+
# policy.usb :none
|
|
22
|
+
# policy.fullscreen :self
|
|
23
|
+
# policy.payment :self, "https://secure.example.com"
|
|
24
|
+
# end
|
|
23
25
|
#
|
|
24
|
-
# The Feature-Policy header has been renamed to Permissions-Policy.
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# The Feature-Policy header has been renamed to Permissions-Policy. The
|
|
27
|
+
# Permissions-Policy requires a different implementation and isn't yet supported
|
|
28
|
+
# by all browsers. To avoid having to rename this middleware in the future we
|
|
29
|
+
# use the new name for the middleware but keep the old header name and
|
|
30
|
+
# implementation for now.
|
|
29
31
|
class PermissionsPolicy
|
|
30
32
|
class Middleware
|
|
31
33
|
def initialize(app)
|
|
@@ -125,25 +127,6 @@ module ActionDispatch # :nodoc:
|
|
|
125
127
|
end
|
|
126
128
|
end
|
|
127
129
|
|
|
128
|
-
%w[speaker vibrate vr].each do |directive|
|
|
129
|
-
define_method(directive) do |*sources|
|
|
130
|
-
ActionDispatch.deprecator.warn(<<~MSG)
|
|
131
|
-
The `#{directive}` permissions policy directive is deprecated
|
|
132
|
-
and will be removed in Rails 7.2.
|
|
133
|
-
|
|
134
|
-
There is no browser support for this directive, and no plan
|
|
135
|
-
for browser support in the future. You can just remove this
|
|
136
|
-
directive from your application.
|
|
137
|
-
MSG
|
|
138
|
-
|
|
139
|
-
if sources.first
|
|
140
|
-
@directives[directive] = apply_mappings(sources)
|
|
141
|
-
else
|
|
142
|
-
@directives.delete(directive)
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
130
|
def build(context = nil)
|
|
148
131
|
build_directives(context).compact.join("; ")
|
|
149
132
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "stringio"
|
|
4
6
|
|
|
5
7
|
require "active_support/inflector"
|
|
@@ -102,26 +104,26 @@ module ActionDispatch
|
|
|
102
104
|
|
|
103
105
|
# Returns true if the request has a header matching the given key parameter.
|
|
104
106
|
#
|
|
105
|
-
#
|
|
107
|
+
# request.key? :ip_spoofing_check # => true
|
|
106
108
|
def key?(key)
|
|
107
109
|
has_header? key
|
|
108
110
|
end
|
|
109
111
|
|
|
110
|
-
# HTTP methods from
|
|
112
|
+
# HTTP methods from [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1](https://www.ietf.org/rfc/rfc2616.txt)
|
|
111
113
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
|
112
|
-
# HTTP methods from
|
|
114
|
+
# HTTP methods from [RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV](https://www.ietf.org/rfc/rfc2518.txt)
|
|
113
115
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
|
114
|
-
# HTTP methods from
|
|
116
|
+
# HTTP methods from [RFC 3253: Versioning Extensions to WebDAV](https://www.ietf.org/rfc/rfc3253.txt)
|
|
115
117
|
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
|
116
|
-
# HTTP methods from
|
|
118
|
+
# HTTP methods from [RFC 3648: WebDAV Ordered Collections Protocol](https://www.ietf.org/rfc/rfc3648.txt)
|
|
117
119
|
RFC3648 = %w(ORDERPATCH)
|
|
118
|
-
# HTTP methods from
|
|
120
|
+
# HTTP methods from [RFC 3744: WebDAV Access Control Protocol](https://www.ietf.org/rfc/rfc3744.txt)
|
|
119
121
|
RFC3744 = %w(ACL)
|
|
120
|
-
# HTTP methods from
|
|
122
|
+
# HTTP methods from [RFC 5323: WebDAV SEARCH](https://www.ietf.org/rfc/rfc5323.txt)
|
|
121
123
|
RFC5323 = %w(SEARCH)
|
|
122
|
-
# HTTP methods from
|
|
124
|
+
# HTTP methods from [RFC 4791: Calendaring Extensions to WebDAV](https://www.ietf.org/rfc/rfc4791.txt)
|
|
123
125
|
RFC4791 = %w(MKCALENDAR)
|
|
124
|
-
# HTTP methods from
|
|
126
|
+
# HTTP methods from [RFC 5789: PATCH Method for HTTP](https://www.ietf.org/rfc/rfc5789.txt)
|
|
125
127
|
RFC5789 = %w(PATCH)
|
|
126
128
|
|
|
127
129
|
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
|
|
@@ -130,25 +132,24 @@ module ActionDispatch
|
|
|
130
132
|
|
|
131
133
|
# Populate the HTTP method lookup cache.
|
|
132
134
|
HTTP_METHODS.each { |method|
|
|
133
|
-
HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
|
|
135
|
+
HTTP_METHOD_LOOKUP[method] = method.downcase.underscore.to_sym
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
alias raw_request_method request_method # :nodoc:
|
|
137
139
|
|
|
138
|
-
# Returns the HTTP
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# value, not the original.
|
|
140
|
+
# Returns the HTTP method that the application should see. In the case where the
|
|
141
|
+
# method was overridden by a middleware (for instance, if a HEAD request was
|
|
142
|
+
# converted to a GET, or if a _method parameter was used to determine the method
|
|
143
|
+
# the application should use), this method returns the overridden value, not the
|
|
144
|
+
# original.
|
|
144
145
|
def request_method
|
|
145
146
|
@request_method ||= check_method(super)
|
|
146
147
|
end
|
|
147
148
|
|
|
148
|
-
# Returns the URI pattern of the matched route for the request,
|
|
149
|
-
#
|
|
149
|
+
# Returns the URI pattern of the matched route for the request, using the same
|
|
150
|
+
# format as `bin/rails routes`:
|
|
150
151
|
#
|
|
151
|
-
#
|
|
152
|
+
# request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
|
|
152
153
|
def route_uri_pattern
|
|
153
154
|
get_header("action_dispatch.route_uri_pattern")
|
|
154
155
|
end
|
|
@@ -196,12 +197,11 @@ module ActionDispatch
|
|
|
196
197
|
HTTP_METHOD_LOOKUP[request_method]
|
|
197
198
|
end
|
|
198
199
|
|
|
199
|
-
# Returns the original value of the environment's REQUEST_METHOD,
|
|
200
|
-
#
|
|
201
|
-
# more information.
|
|
200
|
+
# Returns the original value of the environment's REQUEST_METHOD, even if it was
|
|
201
|
+
# overridden by middleware. See #request_method for more information.
|
|
202
202
|
#
|
|
203
|
-
# For debugging purposes, when called with arguments this method will
|
|
204
|
-
#
|
|
203
|
+
# For debugging purposes, when called with arguments this method will fall back
|
|
204
|
+
# to Object#method
|
|
205
205
|
def method(*args)
|
|
206
206
|
if args.empty?
|
|
207
207
|
@method ||= check_method(
|
|
@@ -221,63 +221,62 @@ module ActionDispatch
|
|
|
221
221
|
|
|
222
222
|
# Provides access to the request's HTTP headers, for example:
|
|
223
223
|
#
|
|
224
|
-
#
|
|
224
|
+
# request.headers["Content-Type"] # => "text/plain"
|
|
225
225
|
def headers
|
|
226
226
|
@headers ||= Http::Headers.new(self)
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
# Early Hints is an HTTP/2 status code that indicates hints to help a client
|
|
230
|
-
# making preparations for processing the final response.
|
|
229
|
+
# Early Hints is an HTTP/2 status code that indicates hints to help a client
|
|
230
|
+
# start making preparations for processing the final response.
|
|
231
231
|
#
|
|
232
|
-
# If the env contains
|
|
232
|
+
# If the env contains `rack.early_hints` then the server accepts HTTP2 push for
|
|
233
233
|
# link headers.
|
|
234
234
|
#
|
|
235
|
-
# The
|
|
235
|
+
# The `send_early_hints` method accepts a hash of links as follows:
|
|
236
236
|
#
|
|
237
|
-
#
|
|
237
|
+
# send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")
|
|
238
238
|
#
|
|
239
|
-
# If you are using
|
|
240
|
-
#
|
|
239
|
+
# If you are using {javascript_include_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#javascript_include_tag]
|
|
240
|
+
# or {stylesheet_link_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#stylesheet_link_tag]
|
|
241
|
+
# the Early Hints headers are included by default if supported.
|
|
241
242
|
def send_early_hints(links)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
env["rack.early_hints"].call(links)
|
|
243
|
+
env["rack.early_hints"]&.call(links)
|
|
245
244
|
end
|
|
246
245
|
|
|
247
|
-
# Returns a
|
|
246
|
+
# Returns a `String` with the last requested path including their params.
|
|
248
247
|
#
|
|
249
|
-
#
|
|
250
|
-
#
|
|
248
|
+
# # get '/foo'
|
|
249
|
+
# request.original_fullpath # => '/foo'
|
|
251
250
|
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
251
|
+
# # get '/foo?bar'
|
|
252
|
+
# request.original_fullpath # => '/foo?bar'
|
|
254
253
|
def original_fullpath
|
|
255
254
|
@original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
|
|
256
255
|
end
|
|
257
256
|
|
|
258
|
-
# Returns the
|
|
257
|
+
# Returns the `String` full path including params of the last URL requested.
|
|
259
258
|
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
259
|
+
# # get "/articles"
|
|
260
|
+
# request.fullpath # => "/articles"
|
|
262
261
|
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
262
|
+
# # get "/articles?page=2"
|
|
263
|
+
# request.fullpath # => "/articles?page=2"
|
|
265
264
|
def fullpath
|
|
266
265
|
@fullpath ||= super
|
|
267
266
|
end
|
|
268
267
|
|
|
269
|
-
# Returns the original request URL as a
|
|
268
|
+
# Returns the original request URL as a `String`.
|
|
270
269
|
#
|
|
271
|
-
#
|
|
272
|
-
#
|
|
270
|
+
# # get "/articles?page=2"
|
|
271
|
+
# request.original_url # => "http://www.example.com/articles?page=2"
|
|
273
272
|
def original_url
|
|
274
273
|
base_url + original_fullpath
|
|
275
274
|
end
|
|
276
275
|
|
|
277
|
-
# The
|
|
276
|
+
# The `String` MIME type of the request.
|
|
278
277
|
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
278
|
+
# # get "/articles"
|
|
279
|
+
# request.media_type # => "application/x-www-form-urlencoded"
|
|
281
280
|
def media_type
|
|
282
281
|
content_mime_type&.to_s
|
|
283
282
|
end
|
|
@@ -288,7 +287,7 @@ module ActionDispatch
|
|
|
288
287
|
super.to_i
|
|
289
288
|
end
|
|
290
289
|
|
|
291
|
-
# Returns true if the
|
|
290
|
+
# Returns true if the `X-Requested-With` header contains "XMLHttpRequest"
|
|
292
291
|
# (case-insensitive), which may need to be manually added depending on the
|
|
293
292
|
# choice of JavaScript libraries and frameworks.
|
|
294
293
|
def xml_http_request?
|
|
@@ -296,13 +295,13 @@ module ActionDispatch
|
|
|
296
295
|
end
|
|
297
296
|
alias :xhr? :xml_http_request?
|
|
298
297
|
|
|
299
|
-
# Returns the IP address of client as a
|
|
298
|
+
# Returns the IP address of client as a `String`.
|
|
300
299
|
def ip
|
|
301
300
|
@ip ||= super
|
|
302
301
|
end
|
|
303
302
|
|
|
304
|
-
# Returns the IP address of client as a
|
|
305
|
-
#
|
|
303
|
+
# Returns the IP address of client as a `String`, usually set by the RemoteIp
|
|
304
|
+
# middleware.
|
|
306
305
|
def remote_ip
|
|
307
306
|
@remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
|
|
308
307
|
end
|
|
@@ -314,12 +313,14 @@ module ActionDispatch
|
|
|
314
313
|
|
|
315
314
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
|
316
315
|
|
|
317
|
-
# Returns the unique request id, which is based on either the
|
|
318
|
-
# be generated by a firewall, load balancer, or web server, or
|
|
319
|
-
# (which sets the
|
|
316
|
+
# Returns the unique request id, which is based on either the `X-Request-Id`
|
|
317
|
+
# header that can be generated by a firewall, load balancer, or web server, or
|
|
318
|
+
# by the RequestId middleware (which sets the `action_dispatch.request_id`
|
|
319
|
+
# environment variable).
|
|
320
320
|
#
|
|
321
|
-
# This unique ID is useful for tracing a request from end-to-end as part of
|
|
322
|
-
# This relies on the Rack variable set by the
|
|
321
|
+
# This unique ID is useful for tracing a request from end-to-end as part of
|
|
322
|
+
# logging or debugging. This relies on the Rack variable set by the
|
|
323
|
+
# ActionDispatch::RequestId middleware.
|
|
323
324
|
def request_id
|
|
324
325
|
get_header ACTION_DISPATCH_REQUEST_ID
|
|
325
326
|
end
|
|
@@ -335,8 +336,8 @@ module ActionDispatch
|
|
|
335
336
|
(get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
|
|
336
337
|
end
|
|
337
338
|
|
|
338
|
-
# Read the request
|
|
339
|
-
#
|
|
339
|
+
# Read the request body. This is useful for web services that need to work with
|
|
340
|
+
# raw requests directly.
|
|
340
341
|
def raw_post
|
|
341
342
|
unless has_header? "RAW_POST_DATA"
|
|
342
343
|
set_header("RAW_POST_DATA", read_body_stream)
|
|
@@ -355,14 +356,13 @@ module ActionDispatch
|
|
|
355
356
|
end
|
|
356
357
|
end
|
|
357
358
|
|
|
358
|
-
# Determine whether the request body contains form-data by checking
|
|
359
|
-
#
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
# +FORM_DATA_MEDIA_TYPES+ array.
|
|
359
|
+
# Determine whether the request body contains form-data by checking the request
|
|
360
|
+
# `Content-Type` for one of the media-types: `application/x-www-form-urlencoded`
|
|
361
|
+
# or `multipart/form-data`. The list of form-data media types can be modified
|
|
362
|
+
# through the `FORM_DATA_MEDIA_TYPES` array.
|
|
363
363
|
#
|
|
364
|
-
# A request body is not assumed to contain form-data when no
|
|
365
|
-
#
|
|
364
|
+
# A request body is not assumed to contain form-data when no `Content-Type`
|
|
365
|
+
# header is provided and the request_method is POST.
|
|
366
366
|
def form_data?
|
|
367
367
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
|
368
368
|
end
|
|
@@ -415,8 +415,8 @@ module ActionDispatch
|
|
|
415
415
|
end
|
|
416
416
|
alias :request_parameters :POST
|
|
417
417
|
|
|
418
|
-
# Returns the authorization header regardless of whether it was specified
|
|
419
|
-
# proxy alternatives.
|
|
418
|
+
# Returns the authorization header regardless of whether it was specified
|
|
419
|
+
# directly or through one of the proxy alternatives.
|
|
420
420
|
def authorization
|
|
421
421
|
get_header("HTTP_AUTHORIZATION") ||
|
|
422
422
|
get_header("X-HTTP_AUTHORIZATION") ||
|
|
@@ -456,7 +456,7 @@ module ActionDispatch
|
|
|
456
456
|
private
|
|
457
457
|
def check_method(name)
|
|
458
458
|
if name
|
|
459
|
-
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS
|
|
459
|
+
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(locale: false)}")
|
|
460
460
|
end
|
|
461
461
|
|
|
462
462
|
name
|
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
6
|
require "action_dispatch/http/filter_redirect"
|
|
5
7
|
require "action_dispatch/http/cache"
|
|
6
8
|
require "monitor"
|
|
7
9
|
|
|
8
10
|
module ActionDispatch # :nodoc:
|
|
9
|
-
#
|
|
11
|
+
# # Action Dispatch Response
|
|
10
12
|
#
|
|
11
13
|
# Represents an HTTP response generated by a controller action. Use it to
|
|
12
14
|
# retrieve the current state of the response, or customize the response. It can
|
|
13
|
-
# either represent a real HTTP response (i.e. one that is meant to be sent
|
|
14
|
-
#
|
|
15
|
-
#
|
|
15
|
+
# either represent a real HTTP response (i.e. one that is meant to be sent back
|
|
16
|
+
# to the web browser) or a TestResponse (i.e. one that is generated from
|
|
17
|
+
# integration tests).
|
|
16
18
|
#
|
|
17
|
-
# The
|
|
18
|
-
# ActionController::Metal#response. ActionController::Metal also provides a
|
|
19
|
-
#
|
|
19
|
+
# The Response object for the current request is exposed on controllers as
|
|
20
|
+
# ActionController::Metal#response. ActionController::Metal also provides a few
|
|
21
|
+
# additional methods that delegate to attributes of the Response such as
|
|
20
22
|
# ActionController::Metal#headers.
|
|
21
23
|
#
|
|
22
|
-
# Integration tests will likely also want to inspect responses in
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
24
|
+
# Integration tests will likely also want to inspect responses in more detail.
|
|
25
|
+
# Methods such as Integration::RequestHelpers#get and
|
|
26
|
+
# Integration::RequestHelpers#post return instances of TestResponse (which
|
|
27
|
+
# inherits from Response) for this purpose.
|
|
26
28
|
#
|
|
27
29
|
# For example, the following demo integration test prints the body of the
|
|
28
30
|
# controller response to the console:
|
|
29
31
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
32
|
+
# class DemoControllerTest < ActionDispatch::IntegrationTest
|
|
33
|
+
# def test_print_root_path_to_console
|
|
34
|
+
# get('/')
|
|
35
|
+
# puts response.body
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
36
38
|
class Response
|
|
37
39
|
begin
|
|
38
40
|
# For `Rack::Headers` (Rack 3+):
|
|
@@ -44,6 +46,20 @@ module ActionDispatch # :nodoc:
|
|
|
44
46
|
Headers = ::Rack::Utils::HeaderHash
|
|
45
47
|
end
|
|
46
48
|
|
|
49
|
+
class << self
|
|
50
|
+
if ActionDispatch::Constants::UNPROCESSABLE_CONTENT == :unprocessable_content
|
|
51
|
+
def rack_status_code(status) # :nodoc:
|
|
52
|
+
status = :unprocessable_content if status == :unprocessable_entity
|
|
53
|
+
Rack::Utils.status_code(status)
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
def rack_status_code(status) # :nodoc:
|
|
57
|
+
status = :unprocessable_entity if status == :unprocessable_content
|
|
58
|
+
Rack::Utils.status_code(status)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
47
63
|
# To be deprecated:
|
|
48
64
|
Header = Headers
|
|
49
65
|
|
|
@@ -55,17 +71,17 @@ module ActionDispatch # :nodoc:
|
|
|
55
71
|
|
|
56
72
|
# The headers for the response.
|
|
57
73
|
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
74
|
+
# header["Content-Type"] # => "text/plain"
|
|
75
|
+
# header["Content-Type"] = "application/json"
|
|
76
|
+
# header["Content-Type"] # => "application/json"
|
|
61
77
|
#
|
|
62
|
-
# Also aliased as
|
|
78
|
+
# Also aliased as `headers`.
|
|
63
79
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
80
|
+
# headers["Content-Type"] # => "text/plain"
|
|
81
|
+
# headers["Content-Type"] = "application/json"
|
|
82
|
+
# headers["Content-Type"] # => "application/json"
|
|
67
83
|
#
|
|
68
|
-
# Also aliased as
|
|
84
|
+
# Also aliased as `header` for compatibility.
|
|
69
85
|
attr_reader :headers
|
|
70
86
|
|
|
71
87
|
alias_method :header, :headers
|
|
@@ -229,18 +245,30 @@ module ActionDispatch # :nodoc:
|
|
|
229
245
|
def committed?; synchronize { @committed }; end
|
|
230
246
|
def sent?; synchronize { @sent }; end
|
|
231
247
|
|
|
248
|
+
##
|
|
249
|
+
# :method: location
|
|
250
|
+
#
|
|
251
|
+
# Location of the response.
|
|
252
|
+
|
|
253
|
+
##
|
|
254
|
+
# :method: location=
|
|
255
|
+
#
|
|
256
|
+
# :call-seq: location=(location)
|
|
257
|
+
#
|
|
258
|
+
# Sets the location of the response
|
|
259
|
+
|
|
232
260
|
# Sets the HTTP status code.
|
|
233
261
|
def status=(status)
|
|
234
|
-
@status =
|
|
262
|
+
@status = Response.rack_status_code(status)
|
|
235
263
|
end
|
|
236
264
|
|
|
237
|
-
# Sets the HTTP response's content MIME type. For example, in the controller
|
|
238
|
-
#
|
|
265
|
+
# Sets the HTTP response's content MIME type. For example, in the controller you
|
|
266
|
+
# could write this:
|
|
239
267
|
#
|
|
240
|
-
#
|
|
268
|
+
# response.content_type = "text/plain"
|
|
241
269
|
#
|
|
242
|
-
# If a character set has been defined for this response (see charset=) then
|
|
243
|
-
#
|
|
270
|
+
# If a character set has been defined for this response (see #charset=) then the
|
|
271
|
+
# character set information will also be included in the content type
|
|
244
272
|
# information.
|
|
245
273
|
def content_type=(content_type)
|
|
246
274
|
return unless content_type
|
|
@@ -267,11 +295,11 @@ module ActionDispatch # :nodoc:
|
|
|
267
295
|
end
|
|
268
296
|
end
|
|
269
297
|
|
|
270
|
-
# Sets the HTTP character set. In case of
|
|
271
|
-
#
|
|
298
|
+
# Sets the HTTP character set. In case of `nil` parameter it sets the charset to
|
|
299
|
+
# `default_charset`.
|
|
272
300
|
#
|
|
273
|
-
#
|
|
274
|
-
#
|
|
301
|
+
# response.charset = 'utf-16' # => 'utf-16'
|
|
302
|
+
# response.charset = nil # => 'utf-8'
|
|
275
303
|
def charset=(charset)
|
|
276
304
|
content_type = parsed_content_type_header.mime_type
|
|
277
305
|
if false == charset
|
|
@@ -281,8 +309,8 @@ module ActionDispatch # :nodoc:
|
|
|
281
309
|
end
|
|
282
310
|
end
|
|
283
311
|
|
|
284
|
-
# The charset of the response. HTML wants to know the encoding of the
|
|
285
|
-
#
|
|
312
|
+
# The charset of the response. HTML wants to know the encoding of the content
|
|
313
|
+
# you're giving them, so we need to send that along.
|
|
286
314
|
def charset
|
|
287
315
|
header_info = parsed_content_type_header
|
|
288
316
|
header_info.charset || self.class.default_charset
|
|
@@ -293,26 +321,26 @@ module ActionDispatch # :nodoc:
|
|
|
293
321
|
@status
|
|
294
322
|
end
|
|
295
323
|
|
|
296
|
-
# Returns a string to ensure compatibility with
|
|
324
|
+
# Returns a string to ensure compatibility with `Net::HTTPResponse`.
|
|
297
325
|
def code
|
|
298
326
|
@status.to_s
|
|
299
327
|
end
|
|
300
328
|
|
|
301
329
|
# Returns the corresponding message for the current HTTP status code:
|
|
302
330
|
#
|
|
303
|
-
#
|
|
304
|
-
#
|
|
331
|
+
# response.status = 200
|
|
332
|
+
# response.message # => "OK"
|
|
305
333
|
#
|
|
306
|
-
#
|
|
307
|
-
#
|
|
334
|
+
# response.status = 404
|
|
335
|
+
# response.message # => "Not Found"
|
|
308
336
|
#
|
|
309
337
|
def message
|
|
310
338
|
Rack::Utils::HTTP_STATUS_CODES[@status]
|
|
311
339
|
end
|
|
312
340
|
alias_method :status_message, :message
|
|
313
341
|
|
|
314
|
-
# Returns the content of the response as a string. This contains the contents
|
|
315
|
-
#
|
|
342
|
+
# Returns the content of the response as a string. This contains the contents of
|
|
343
|
+
# any calls to `render`.
|
|
316
344
|
def body
|
|
317
345
|
@stream.body
|
|
318
346
|
end
|
|
@@ -332,9 +360,9 @@ module ActionDispatch # :nodoc:
|
|
|
332
360
|
end
|
|
333
361
|
end
|
|
334
362
|
|
|
335
|
-
# Avoid having to pass an open file handle as the response body.
|
|
336
|
-
#
|
|
337
|
-
#
|
|
363
|
+
# Avoid having to pass an open file handle as the response body. Rack::Sendfile
|
|
364
|
+
# will usually intercept the response and uses the path directly, so there is no
|
|
365
|
+
# reason to open the file.
|
|
338
366
|
class FileBody # :nodoc:
|
|
339
367
|
attr_reader :to_path
|
|
340
368
|
|
|
@@ -356,7 +384,7 @@ module ActionDispatch # :nodoc:
|
|
|
356
384
|
end
|
|
357
385
|
end
|
|
358
386
|
|
|
359
|
-
# Send the file stored at
|
|
387
|
+
# Send the file stored at `path` as the response body.
|
|
360
388
|
def send_file(path)
|
|
361
389
|
commit!
|
|
362
390
|
@stream = FileBody.new(path)
|
|
@@ -383,17 +411,16 @@ module ActionDispatch # :nodoc:
|
|
|
383
411
|
if stream.respond_to?(:abort)
|
|
384
412
|
stream.abort
|
|
385
413
|
elsif stream.respond_to?(:close)
|
|
386
|
-
# `stream.close` should really be reserved for a close from the
|
|
387
|
-
#
|
|
388
|
-
# compatibility.
|
|
414
|
+
# `stream.close` should really be reserved for a close from the other direction,
|
|
415
|
+
# but we must fall back to it for compatibility.
|
|
389
416
|
stream.close
|
|
390
417
|
end
|
|
391
418
|
end
|
|
392
419
|
|
|
393
|
-
# Turns the Response into a Rack-compatible array of the status, headers,
|
|
394
|
-
#
|
|
420
|
+
# Turns the Response into a Rack-compatible array of the status, headers, and
|
|
421
|
+
# body. Allows explicit splatting:
|
|
395
422
|
#
|
|
396
|
-
#
|
|
423
|
+
# status, headers, body = *response
|
|
397
424
|
def to_a
|
|
398
425
|
commit!
|
|
399
426
|
rack_response @status, @headers.to_hash
|
|
@@ -402,7 +429,7 @@ module ActionDispatch # :nodoc:
|
|
|
402
429
|
|
|
403
430
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
|
404
431
|
#
|
|
405
|
-
#
|
|
432
|
+
# assert_equal 'AuthorOfNewPage', r.cookies['author']
|
|
406
433
|
def cookies
|
|
407
434
|
cookies = {}
|
|
408
435
|
if header = get_header(SET_COOKIE)
|
|
@@ -456,11 +483,10 @@ module ActionDispatch # :nodoc:
|
|
|
456
483
|
end
|
|
457
484
|
|
|
458
485
|
def before_sending
|
|
459
|
-
# Normally we've already committed by now, but it's possible
|
|
460
|
-
#
|
|
461
|
-
#
|
|
462
|
-
#
|
|
463
|
-
# our last chance.
|
|
486
|
+
# Normally we've already committed by now, but it's possible (e.g., if the
|
|
487
|
+
# controller action tries to read back its own response) to get here before
|
|
488
|
+
# that. In that case, we must force an "early" commit: we're about to freeze the
|
|
489
|
+
# headers, so this is our last chance.
|
|
464
490
|
commit! unless committed?
|
|
465
491
|
|
|
466
492
|
@request.commit_cookie_jar! unless committed?
|
|
@@ -488,8 +514,8 @@ module ActionDispatch # :nodoc:
|
|
|
488
514
|
end
|
|
489
515
|
|
|
490
516
|
def close
|
|
491
|
-
# Rack "close" maps to Response#abort, and
|
|
492
|
-
#
|
|
517
|
+
# Rack "close" maps to Response#abort, and **not** Response#close (which is used
|
|
518
|
+
# when the controller's finished writing)
|
|
493
519
|
@response.abort
|
|
494
520
|
end
|
|
495
521
|
|