actionpack 7.1.5.1 → 8.1.2
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 +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- 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 +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- 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 +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- 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 +72 -63
- 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 +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- 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 +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- 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 +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- 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 +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- 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 +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- 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 +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- 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 +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- 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 +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- 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 +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- 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 +30 -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 +53 -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/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- 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 +34 -23
- 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 +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- 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 +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -31
|
@@ -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)
|
|
@@ -84,12 +86,14 @@ module ActionDispatch # :nodoc:
|
|
|
84
86
|
ambient_light_sensor: "ambient-light-sensor",
|
|
85
87
|
autoplay: "autoplay",
|
|
86
88
|
camera: "camera",
|
|
89
|
+
display_capture: "display-capture",
|
|
87
90
|
encrypted_media: "encrypted-media",
|
|
88
91
|
fullscreen: "fullscreen",
|
|
89
92
|
geolocation: "geolocation",
|
|
90
93
|
gyroscope: "gyroscope",
|
|
91
94
|
hid: "hid",
|
|
92
95
|
idle_detection: "idle-detection",
|
|
96
|
+
keyboard_map: "keyboard-map",
|
|
93
97
|
magnetometer: "magnetometer",
|
|
94
98
|
microphone: "microphone",
|
|
95
99
|
midi: "midi",
|
|
@@ -125,25 +129,6 @@ module ActionDispatch # :nodoc:
|
|
|
125
129
|
end
|
|
126
130
|
end
|
|
127
131
|
|
|
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
132
|
def build(context = nil)
|
|
148
133
|
build_directives(context).compact.join("; ")
|
|
149
134
|
end
|
|
@@ -201,4 +186,8 @@ module ActionDispatch # :nodoc:
|
|
|
201
186
|
end
|
|
202
187
|
end
|
|
203
188
|
end
|
|
189
|
+
|
|
190
|
+
ActiveSupport.on_load(:action_dispatch_request) do
|
|
191
|
+
include ActionDispatch::PermissionsPolicy::Request
|
|
192
|
+
end
|
|
204
193
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require "rack"
|
|
5
|
+
|
|
6
|
+
module ActionDispatch
|
|
7
|
+
class QueryParser
|
|
8
|
+
DEFAULT_SEP = /& */n
|
|
9
|
+
COMMON_SEP = { ";" => /; */n, ";," => /[;,] */n, "&" => /& */n, "&;" => /[&;] */n }
|
|
10
|
+
|
|
11
|
+
def self.strict_query_string_separator
|
|
12
|
+
ActionDispatch.deprecator.warn <<~MSG
|
|
13
|
+
The `strict_query_string_separator` configuration is deprecated have no effect and will be removed in Rails 8.2.
|
|
14
|
+
MSG
|
|
15
|
+
@strict_query_string_separator
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.strict_query_string_separator=(value)
|
|
19
|
+
ActionDispatch.deprecator.warn <<~MSG
|
|
20
|
+
The `strict_query_string_separator` configuration is deprecated have no effect and will be removed in Rails 8.2.
|
|
21
|
+
MSG
|
|
22
|
+
@strict_query_string_separator = value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#--
|
|
26
|
+
# Note this departs from WHATWG's specified parsing algorithm by
|
|
27
|
+
# giving a nil value for keys that do not use '='. Callers that need
|
|
28
|
+
# the standard's interpretation can use `v.to_s`.
|
|
29
|
+
def self.each_pair(s, separator = nil)
|
|
30
|
+
return enum_for(:each_pair, s, separator) unless block_given?
|
|
31
|
+
|
|
32
|
+
s ||= ""
|
|
33
|
+
|
|
34
|
+
splitter =
|
|
35
|
+
if separator
|
|
36
|
+
COMMON_SEP[separator] || /[#{separator}] */n
|
|
37
|
+
else
|
|
38
|
+
DEFAULT_SEP
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
s.split(splitter).each do |part|
|
|
42
|
+
next if part.empty?
|
|
43
|
+
|
|
44
|
+
k, v = part.split("=", 2)
|
|
45
|
+
|
|
46
|
+
k = URI.decode_www_form_component(k)
|
|
47
|
+
v &&= URI.decode_www_form_component(v)
|
|
48
|
+
|
|
49
|
+
yield k, v
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
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"
|
|
@@ -23,7 +25,6 @@ module ActionDispatch
|
|
|
23
25
|
include ActionDispatch::Http::FilterParameters
|
|
24
26
|
include ActionDispatch::Http::URL
|
|
25
27
|
include ActionDispatch::ContentSecurityPolicy::Request
|
|
26
|
-
include ActionDispatch::PermissionsPolicy::Request
|
|
27
28
|
include Rack::Request::Env
|
|
28
29
|
|
|
29
30
|
autoload :Session, "action_dispatch/request/session"
|
|
@@ -53,12 +54,17 @@ module ActionDispatch
|
|
|
53
54
|
METHOD
|
|
54
55
|
end
|
|
55
56
|
|
|
57
|
+
TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING" # :nodoc:
|
|
58
|
+
|
|
56
59
|
def self.empty
|
|
57
60
|
new({})
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
def initialize(env)
|
|
61
64
|
super
|
|
65
|
+
|
|
66
|
+
@rack_request = Rack::Request.new(env)
|
|
67
|
+
|
|
62
68
|
@method = nil
|
|
63
69
|
@request_method = nil
|
|
64
70
|
@remote_ip = nil
|
|
@@ -67,6 +73,8 @@ module ActionDispatch
|
|
|
67
73
|
@ip = nil
|
|
68
74
|
end
|
|
69
75
|
|
|
76
|
+
attr_reader :rack_request
|
|
77
|
+
|
|
70
78
|
def commit_cookie_jar! # :nodoc:
|
|
71
79
|
end
|
|
72
80
|
|
|
@@ -102,26 +110,26 @@ module ActionDispatch
|
|
|
102
110
|
|
|
103
111
|
# Returns true if the request has a header matching the given key parameter.
|
|
104
112
|
#
|
|
105
|
-
#
|
|
113
|
+
# request.key? :ip_spoofing_check # => true
|
|
106
114
|
def key?(key)
|
|
107
115
|
has_header? key
|
|
108
116
|
end
|
|
109
117
|
|
|
110
|
-
# HTTP methods from
|
|
118
|
+
# HTTP methods from [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1](https://www.ietf.org/rfc/rfc2616.txt)
|
|
111
119
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
|
112
|
-
# HTTP methods from
|
|
120
|
+
# HTTP methods from [RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV](https://www.ietf.org/rfc/rfc2518.txt)
|
|
113
121
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
|
114
|
-
# HTTP methods from
|
|
122
|
+
# HTTP methods from [RFC 3253: Versioning Extensions to WebDAV](https://www.ietf.org/rfc/rfc3253.txt)
|
|
115
123
|
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
|
116
|
-
# HTTP methods from
|
|
124
|
+
# HTTP methods from [RFC 3648: WebDAV Ordered Collections Protocol](https://www.ietf.org/rfc/rfc3648.txt)
|
|
117
125
|
RFC3648 = %w(ORDERPATCH)
|
|
118
|
-
# HTTP methods from
|
|
126
|
+
# HTTP methods from [RFC 3744: WebDAV Access Control Protocol](https://www.ietf.org/rfc/rfc3744.txt)
|
|
119
127
|
RFC3744 = %w(ACL)
|
|
120
|
-
# HTTP methods from
|
|
128
|
+
# HTTP methods from [RFC 5323: WebDAV SEARCH](https://www.ietf.org/rfc/rfc5323.txt)
|
|
121
129
|
RFC5323 = %w(SEARCH)
|
|
122
|
-
# HTTP methods from
|
|
130
|
+
# HTTP methods from [RFC 4791: Calendaring Extensions to WebDAV](https://www.ietf.org/rfc/rfc4791.txt)
|
|
123
131
|
RFC4791 = %w(MKCALENDAR)
|
|
124
|
-
# HTTP methods from
|
|
132
|
+
# HTTP methods from [RFC 5789: PATCH Method for HTTP](https://www.ietf.org/rfc/rfc5789.txt)
|
|
125
133
|
RFC5789 = %w(PATCH)
|
|
126
134
|
|
|
127
135
|
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
|
|
@@ -130,31 +138,36 @@ module ActionDispatch
|
|
|
130
138
|
|
|
131
139
|
# Populate the HTTP method lookup cache.
|
|
132
140
|
HTTP_METHODS.each { |method|
|
|
133
|
-
HTTP_METHOD_LOOKUP[method] = method.
|
|
141
|
+
HTTP_METHOD_LOOKUP[method] = method.downcase.tap { |m| m.tr!("-", "_") }.to_sym
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
alias raw_request_method request_method # :nodoc:
|
|
137
145
|
|
|
138
|
-
# Returns the HTTP
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# value, not the original.
|
|
146
|
+
# Returns the HTTP method that the application should see. In the case where the
|
|
147
|
+
# method was overridden by a middleware (for instance, if a HEAD request was
|
|
148
|
+
# converted to a GET, or if a _method parameter was used to determine the method
|
|
149
|
+
# the application should use), this method returns the overridden value, not the
|
|
150
|
+
# original.
|
|
144
151
|
def request_method
|
|
145
152
|
@request_method ||= check_method(super)
|
|
146
153
|
end
|
|
147
154
|
|
|
148
|
-
# Returns the URI pattern of the matched route for the request,
|
|
149
|
-
#
|
|
155
|
+
# Returns the URI pattern of the matched route for the request, using the same
|
|
156
|
+
# format as `bin/rails routes`:
|
|
150
157
|
#
|
|
151
|
-
#
|
|
158
|
+
# request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
|
|
152
159
|
def route_uri_pattern
|
|
153
|
-
get_header("action_dispatch.route_uri_pattern")
|
|
160
|
+
unless pattern = get_header("action_dispatch.route_uri_pattern")
|
|
161
|
+
route = get_header("action_dispatch.route")
|
|
162
|
+
return if route.nil?
|
|
163
|
+
pattern = route.path.spec.to_s
|
|
164
|
+
set_header("action_dispatch.route_uri_pattern", pattern)
|
|
165
|
+
end
|
|
166
|
+
pattern
|
|
154
167
|
end
|
|
155
168
|
|
|
156
|
-
def
|
|
157
|
-
|
|
169
|
+
def route=(route) # :nodoc:
|
|
170
|
+
@env["action_dispatch.route"] = route
|
|
158
171
|
end
|
|
159
172
|
|
|
160
173
|
def routes # :nodoc:
|
|
@@ -196,12 +209,11 @@ module ActionDispatch
|
|
|
196
209
|
HTTP_METHOD_LOOKUP[request_method]
|
|
197
210
|
end
|
|
198
211
|
|
|
199
|
-
# Returns the original value of the environment's REQUEST_METHOD,
|
|
200
|
-
#
|
|
201
|
-
# more information.
|
|
212
|
+
# Returns the original value of the environment's REQUEST_METHOD, even if it was
|
|
213
|
+
# overridden by middleware. See #request_method for more information.
|
|
202
214
|
#
|
|
203
|
-
# For debugging purposes, when called with arguments this method will
|
|
204
|
-
#
|
|
215
|
+
# For debugging purposes, when called with arguments this method will fall back
|
|
216
|
+
# to Object#method
|
|
205
217
|
def method(*args)
|
|
206
218
|
if args.empty?
|
|
207
219
|
@method ||= check_method(
|
|
@@ -221,74 +233,73 @@ module ActionDispatch
|
|
|
221
233
|
|
|
222
234
|
# Provides access to the request's HTTP headers, for example:
|
|
223
235
|
#
|
|
224
|
-
#
|
|
236
|
+
# request.headers["Content-Type"] # => "text/plain"
|
|
225
237
|
def headers
|
|
226
238
|
@headers ||= Http::Headers.new(self)
|
|
227
239
|
end
|
|
228
240
|
|
|
229
|
-
# Early Hints is an HTTP/2 status code that indicates hints to help a client
|
|
230
|
-
# making preparations for processing the final response.
|
|
241
|
+
# Early Hints is an HTTP/2 status code that indicates hints to help a client
|
|
242
|
+
# start making preparations for processing the final response.
|
|
231
243
|
#
|
|
232
|
-
# If the env contains
|
|
244
|
+
# If the env contains `rack.early_hints` then the server accepts HTTP2 push for
|
|
233
245
|
# link headers.
|
|
234
246
|
#
|
|
235
|
-
# The
|
|
247
|
+
# The `send_early_hints` method accepts a hash of links as follows:
|
|
236
248
|
#
|
|
237
|
-
#
|
|
249
|
+
# send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")
|
|
238
250
|
#
|
|
239
|
-
# If you are using
|
|
240
|
-
#
|
|
251
|
+
# If you are using {javascript_include_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#javascript_include_tag]
|
|
252
|
+
# or {stylesheet_link_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#stylesheet_link_tag]
|
|
253
|
+
# the Early Hints headers are included by default if supported.
|
|
241
254
|
def send_early_hints(links)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
env["rack.early_hints"].call(links)
|
|
255
|
+
env["rack.early_hints"]&.call(links)
|
|
245
256
|
end
|
|
246
257
|
|
|
247
|
-
# Returns a
|
|
258
|
+
# Returns a `String` with the last requested path including their params.
|
|
248
259
|
#
|
|
249
|
-
#
|
|
250
|
-
#
|
|
260
|
+
# # get '/foo'
|
|
261
|
+
# request.original_fullpath # => '/foo'
|
|
251
262
|
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
263
|
+
# # get '/foo?bar'
|
|
264
|
+
# request.original_fullpath # => '/foo?bar'
|
|
254
265
|
def original_fullpath
|
|
255
266
|
@original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
|
|
256
267
|
end
|
|
257
268
|
|
|
258
|
-
# Returns the
|
|
269
|
+
# Returns the `String` full path including params of the last URL requested.
|
|
259
270
|
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
271
|
+
# # get "/articles"
|
|
272
|
+
# request.fullpath # => "/articles"
|
|
262
273
|
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
274
|
+
# # get "/articles?page=2"
|
|
275
|
+
# request.fullpath # => "/articles?page=2"
|
|
265
276
|
def fullpath
|
|
266
277
|
@fullpath ||= super
|
|
267
278
|
end
|
|
268
279
|
|
|
269
|
-
# Returns the original request URL as a
|
|
280
|
+
# Returns the original request URL as a `String`.
|
|
270
281
|
#
|
|
271
|
-
#
|
|
272
|
-
#
|
|
282
|
+
# # get "/articles?page=2"
|
|
283
|
+
# request.original_url # => "http://www.example.com/articles?page=2"
|
|
273
284
|
def original_url
|
|
274
285
|
base_url + original_fullpath
|
|
275
286
|
end
|
|
276
287
|
|
|
277
|
-
# The
|
|
288
|
+
# The `String` MIME type of the request.
|
|
278
289
|
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
290
|
+
# # get "/articles"
|
|
291
|
+
# request.media_type # => "application/x-www-form-urlencoded"
|
|
281
292
|
def media_type
|
|
282
293
|
content_mime_type&.to_s
|
|
283
294
|
end
|
|
284
295
|
|
|
285
296
|
# Returns the content length of the request as an integer.
|
|
286
297
|
def content_length
|
|
287
|
-
return raw_post.bytesize if
|
|
298
|
+
return raw_post.bytesize if has_header?(TRANSFER_ENCODING)
|
|
288
299
|
super.to_i
|
|
289
300
|
end
|
|
290
301
|
|
|
291
|
-
# Returns true if the
|
|
302
|
+
# Returns true if the `X-Requested-With` header contains "XMLHttpRequest"
|
|
292
303
|
# (case-insensitive), which may need to be manually added depending on the
|
|
293
304
|
# choice of JavaScript libraries and frameworks.
|
|
294
305
|
def xml_http_request?
|
|
@@ -296,13 +307,13 @@ module ActionDispatch
|
|
|
296
307
|
end
|
|
297
308
|
alias :xhr? :xml_http_request?
|
|
298
309
|
|
|
299
|
-
# Returns the IP address of client as a
|
|
310
|
+
# Returns the IP address of client as a `String`.
|
|
300
311
|
def ip
|
|
301
312
|
@ip ||= super
|
|
302
313
|
end
|
|
303
314
|
|
|
304
|
-
# Returns the IP address of client as a
|
|
305
|
-
#
|
|
315
|
+
# Returns the IP address of client as a `String`, usually set by the RemoteIp
|
|
316
|
+
# middleware.
|
|
306
317
|
def remote_ip
|
|
307
318
|
@remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
|
|
308
319
|
end
|
|
@@ -314,12 +325,14 @@ module ActionDispatch
|
|
|
314
325
|
|
|
315
326
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
|
316
327
|
|
|
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
|
|
328
|
+
# Returns the unique request id, which is based on either the `X-Request-Id`
|
|
329
|
+
# header that can be generated by a firewall, load balancer, or web server, or
|
|
330
|
+
# by the RequestId middleware (which sets the `action_dispatch.request_id`
|
|
331
|
+
# environment variable).
|
|
320
332
|
#
|
|
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
|
|
333
|
+
# This unique ID is useful for tracing a request from end-to-end as part of
|
|
334
|
+
# logging or debugging. This relies on the Rack variable set by the
|
|
335
|
+
# ActionDispatch::RequestId middleware.
|
|
323
336
|
def request_id
|
|
324
337
|
get_header ACTION_DISPATCH_REQUEST_ID
|
|
325
338
|
end
|
|
@@ -335,8 +348,8 @@ module ActionDispatch
|
|
|
335
348
|
(get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
|
|
336
349
|
end
|
|
337
350
|
|
|
338
|
-
# Read the request
|
|
339
|
-
#
|
|
351
|
+
# Read the request body. This is useful for web services that need to work with
|
|
352
|
+
# raw requests directly.
|
|
340
353
|
def raw_post
|
|
341
354
|
unless has_header? "RAW_POST_DATA"
|
|
342
355
|
set_header("RAW_POST_DATA", read_body_stream)
|
|
@@ -355,14 +368,13 @@ module ActionDispatch
|
|
|
355
368
|
end
|
|
356
369
|
end
|
|
357
370
|
|
|
358
|
-
# Determine whether the request body contains form-data by checking
|
|
359
|
-
#
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
# +FORM_DATA_MEDIA_TYPES+ array.
|
|
371
|
+
# Determine whether the request body contains form-data by checking the request
|
|
372
|
+
# `Content-Type` for one of the media-types: `application/x-www-form-urlencoded`
|
|
373
|
+
# or `multipart/form-data`. The list of form-data media types can be modified
|
|
374
|
+
# through the `FORM_DATA_MEDIA_TYPES` array.
|
|
363
375
|
#
|
|
364
|
-
# A request body is not assumed to contain form-data when no
|
|
365
|
-
#
|
|
376
|
+
# A request body is not assumed to contain form-data when no `Content-Type`
|
|
377
|
+
# header is provided and the request_method is POST.
|
|
366
378
|
def form_data?
|
|
367
379
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
|
368
380
|
end
|
|
@@ -387,15 +399,12 @@ module ActionDispatch
|
|
|
387
399
|
# Override Rack's GET method to support indifferent access.
|
|
388
400
|
def GET
|
|
389
401
|
fetch_header("action_dispatch.request.query_parameters") do |k|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
# Check for non UTF-8 parameter values, which would cause errors later
|
|
395
|
-
Request::Utils.check_param_encoding(rack_query_params)
|
|
396
|
-
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
|
402
|
+
encoding_template = Request::Utils::CustomParamEncoder.action_encoding_template(self, path_parameters[:controller], path_parameters[:action])
|
|
403
|
+
rack_query_params = ActionDispatch::ParamBuilder.from_query_string(rack_request.query_string, encoding_template: encoding_template)
|
|
404
|
+
|
|
405
|
+
set_header k, rack_query_params
|
|
397
406
|
end
|
|
398
|
-
rescue
|
|
407
|
+
rescue ActionDispatch::ParamError => e
|
|
399
408
|
raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
|
|
400
409
|
end
|
|
401
410
|
alias :query_parameters :GET
|
|
@@ -403,20 +412,56 @@ module ActionDispatch
|
|
|
403
412
|
# Override Rack's POST method to support indifferent access.
|
|
404
413
|
def POST
|
|
405
414
|
fetch_header("action_dispatch.request.request_parameters") do
|
|
406
|
-
|
|
407
|
-
|
|
415
|
+
encoding_template = Request::Utils::CustomParamEncoder.action_encoding_template(self, path_parameters[:controller], path_parameters[:action])
|
|
416
|
+
|
|
417
|
+
param_list = nil
|
|
418
|
+
pr = parse_formatted_parameters(params_parsers) do
|
|
419
|
+
if param_list = request_parameters_list
|
|
420
|
+
ActionDispatch::ParamBuilder.from_pairs(param_list, encoding_template: encoding_template)
|
|
421
|
+
else
|
|
422
|
+
# We're not using a version of Rack that provides raw form
|
|
423
|
+
# pairs; we must use its hash (and thus post-process it below).
|
|
424
|
+
fallback_request_parameters
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# If the request body was parsed by a custom parser like JSON
|
|
429
|
+
# (and thus the above block was not run), we need to
|
|
430
|
+
# post-process the result hash.
|
|
431
|
+
if param_list.nil?
|
|
432
|
+
pr = ActionDispatch::ParamBuilder.from_hash(pr, encoding_template: encoding_template)
|
|
408
433
|
end
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
|
434
|
+
|
|
435
|
+
self.request_parameters = pr
|
|
412
436
|
end
|
|
413
|
-
rescue
|
|
437
|
+
rescue ActionDispatch::ParamError, EOFError => e
|
|
414
438
|
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
|
415
439
|
end
|
|
416
440
|
alias :request_parameters :POST
|
|
417
441
|
|
|
418
|
-
|
|
419
|
-
|
|
442
|
+
def request_parameters_list
|
|
443
|
+
# We don't use Rack's parse result, but we must call it so Rack
|
|
444
|
+
# can populate the rack.request.* keys we need.
|
|
445
|
+
rack_post = rack_request.POST
|
|
446
|
+
|
|
447
|
+
if form_pairs = get_header("rack.request.form_pairs")
|
|
448
|
+
# Multipart
|
|
449
|
+
form_pairs
|
|
450
|
+
elsif form_vars = get_header("rack.request.form_vars")
|
|
451
|
+
# URL-encoded
|
|
452
|
+
ActionDispatch::QueryParser.each_pair(form_vars)
|
|
453
|
+
elsif rack_post && !rack_post.empty?
|
|
454
|
+
# It was multipart, but Rack did not preserve a pair list
|
|
455
|
+
# (probably too old). Flat parameter list is not available.
|
|
456
|
+
nil
|
|
457
|
+
else
|
|
458
|
+
# No request body, or not a format Rack knows
|
|
459
|
+
[]
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Returns the authorization header regardless of whether it was specified
|
|
464
|
+
# directly or through one of the proxy alternatives.
|
|
420
465
|
def authorization
|
|
421
466
|
get_header("HTTP_AUTHORIZATION") ||
|
|
422
467
|
get_header("X-HTTP_AUTHORIZATION") ||
|
|
@@ -456,7 +501,7 @@ module ActionDispatch
|
|
|
456
501
|
private
|
|
457
502
|
def check_method(name)
|
|
458
503
|
if name
|
|
459
|
-
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS
|
|
504
|
+
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(locale: false)}")
|
|
460
505
|
end
|
|
461
506
|
|
|
462
507
|
name
|
|
@@ -469,7 +514,7 @@ module ActionDispatch
|
|
|
469
514
|
def read_body_stream
|
|
470
515
|
if body_stream
|
|
471
516
|
reset_stream(body_stream) do
|
|
472
|
-
if
|
|
517
|
+
if has_header?(TRANSFER_ENCODING)
|
|
473
518
|
body_stream.read # Read body stream until EOF if "Transfer-Encoding" is present
|
|
474
519
|
else
|
|
475
520
|
body_stream.read(content_length)
|
|
@@ -491,6 +536,10 @@ module ActionDispatch
|
|
|
491
536
|
yield
|
|
492
537
|
end
|
|
493
538
|
end
|
|
539
|
+
|
|
540
|
+
def fallback_request_parameters
|
|
541
|
+
rack_request.POST
|
|
542
|
+
end
|
|
494
543
|
end
|
|
495
544
|
end
|
|
496
545
|
|