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,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch
|
|
@@ -9,26 +11,123 @@ module ActionDispatch
|
|
|
9
11
|
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
|
10
12
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
|
11
13
|
|
|
14
|
+
# DomainExtractor provides utility methods for extracting domain and subdomain
|
|
15
|
+
# information from host strings. This module is used internally by Action Dispatch
|
|
16
|
+
# to parse host names and separate the domain from subdomains based on the
|
|
17
|
+
# top-level domain (TLD) length.
|
|
18
|
+
#
|
|
19
|
+
# The module assumes a standard domain structure where domains consist of:
|
|
20
|
+
# - Subdomains (optional, can be multiple levels)
|
|
21
|
+
# - Domain name
|
|
22
|
+
# - Top-level domain (TLD, can be multiple levels like .co.uk)
|
|
23
|
+
#
|
|
24
|
+
# For example, in "api.staging.example.co.uk":
|
|
25
|
+
# - Subdomains: ["api", "staging"]
|
|
26
|
+
# - Domain: "example.co.uk" (with tld_length=2)
|
|
27
|
+
# - TLD: "co.uk"
|
|
28
|
+
module DomainExtractor
|
|
29
|
+
extend self
|
|
30
|
+
|
|
31
|
+
# Extracts the domain part from a host string, including the specified
|
|
32
|
+
# number of top-level domain components.
|
|
33
|
+
#
|
|
34
|
+
# The domain includes the main domain name plus the TLD components.
|
|
35
|
+
# The +tld_length+ parameter specifies how many components from the right
|
|
36
|
+
# should be considered part of the TLD.
|
|
37
|
+
#
|
|
38
|
+
# ==== Parameters
|
|
39
|
+
#
|
|
40
|
+
# [+host+]
|
|
41
|
+
# The host string to extract the domain from.
|
|
42
|
+
#
|
|
43
|
+
# [+tld_length+]
|
|
44
|
+
# The number of domain components that make up the TLD. For example,
|
|
45
|
+
# use 1 for ".com" or 2 for ".co.uk".
|
|
46
|
+
#
|
|
47
|
+
# ==== Examples
|
|
48
|
+
#
|
|
49
|
+
# # Standard TLD (tld_length = 1)
|
|
50
|
+
# DomainExtractor.domain_from("www.example.com", 1)
|
|
51
|
+
# # => "example.com"
|
|
52
|
+
#
|
|
53
|
+
# # Country-code TLD (tld_length = 2)
|
|
54
|
+
# DomainExtractor.domain_from("www.example.co.uk", 2)
|
|
55
|
+
# # => "example.co.uk"
|
|
56
|
+
#
|
|
57
|
+
# # Multiple subdomains
|
|
58
|
+
# DomainExtractor.domain_from("api.staging.myapp.herokuapp.com", 1)
|
|
59
|
+
# # => "herokuapp.com"
|
|
60
|
+
#
|
|
61
|
+
# # Single component (returns the host itself)
|
|
62
|
+
# DomainExtractor.domain_from("localhost", 1)
|
|
63
|
+
# # => "localhost"
|
|
64
|
+
def domain_from(host, tld_length)
|
|
65
|
+
host.split(".").last(1 + tld_length).join(".")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Extracts the subdomain components from a host string as an Array.
|
|
69
|
+
#
|
|
70
|
+
# Returns all the components that come before the domain and TLD parts.
|
|
71
|
+
# The +tld_length+ parameter is used to determine where the domain begins
|
|
72
|
+
# so that everything before it is considered a subdomain.
|
|
73
|
+
#
|
|
74
|
+
# ==== Parameters
|
|
75
|
+
#
|
|
76
|
+
# [+host+]
|
|
77
|
+
# The host string to extract subdomains from.
|
|
78
|
+
#
|
|
79
|
+
# [+tld_length+]
|
|
80
|
+
# The number of domain components that make up the TLD. This affects
|
|
81
|
+
# where the domain boundary is calculated.
|
|
82
|
+
#
|
|
83
|
+
# ==== Examples
|
|
84
|
+
#
|
|
85
|
+
# # Standard TLD (tld_length = 1)
|
|
86
|
+
# DomainExtractor.subdomains_from("www.example.com", 1)
|
|
87
|
+
# # => ["www"]
|
|
88
|
+
#
|
|
89
|
+
# # Country-code TLD (tld_length = 2)
|
|
90
|
+
# DomainExtractor.subdomains_from("api.staging.example.co.uk", 2)
|
|
91
|
+
# # => ["api", "staging"]
|
|
92
|
+
#
|
|
93
|
+
# # No subdomains
|
|
94
|
+
# DomainExtractor.subdomains_from("example.com", 1)
|
|
95
|
+
# # => []
|
|
96
|
+
#
|
|
97
|
+
# # Single subdomain with complex TLD
|
|
98
|
+
# DomainExtractor.subdomains_from("www.mysite.co.uk", 2)
|
|
99
|
+
# # => ["www"]
|
|
100
|
+
#
|
|
101
|
+
# # Multiple levels of subdomains
|
|
102
|
+
# DomainExtractor.subdomains_from("dev.api.staging.example.com", 1)
|
|
103
|
+
# # => ["dev", "api", "staging"]
|
|
104
|
+
def subdomains_from(host, tld_length)
|
|
105
|
+
parts = host.split(".")
|
|
106
|
+
parts[0..-(tld_length + 2)]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
12
110
|
mattr_accessor :secure_protocol, default: false
|
|
13
111
|
mattr_accessor :tld_length, default: 1
|
|
112
|
+
mattr_accessor :domain_extractor, default: DomainExtractor
|
|
14
113
|
|
|
15
114
|
class << self
|
|
16
115
|
# Returns the domain part of a host given the domain level.
|
|
17
116
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
117
|
+
# # Top-level domain example
|
|
118
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
|
119
|
+
# # Second-level domain example
|
|
120
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
|
22
121
|
def extract_domain(host, tld_length)
|
|
23
122
|
extract_domain_from(host, tld_length) if named_host?(host)
|
|
24
123
|
end
|
|
25
124
|
|
|
26
125
|
# Returns the subdomains of a host as an Array given the domain level.
|
|
27
126
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
127
|
+
# # Top-level domain example
|
|
128
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
|
129
|
+
# # Second-level domain example
|
|
130
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
|
32
131
|
def extract_subdomains(host, tld_length)
|
|
33
132
|
if named_host?(host)
|
|
34
133
|
extract_subdomains_from(host, tld_length)
|
|
@@ -39,10 +138,10 @@ module ActionDispatch
|
|
|
39
138
|
|
|
40
139
|
# Returns the subdomains of a host as a String given the domain level.
|
|
41
140
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
141
|
+
# # Top-level domain example
|
|
142
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
|
143
|
+
# # Second-level domain example
|
|
144
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
|
46
145
|
def extract_subdomain(host, tld_length)
|
|
47
146
|
extract_subdomains(host, tld_length).join(".")
|
|
48
147
|
end
|
|
@@ -94,34 +193,33 @@ module ActionDispatch
|
|
|
94
193
|
end
|
|
95
194
|
|
|
96
195
|
def extract_domain_from(host, tld_length)
|
|
97
|
-
|
|
196
|
+
domain_extractor.domain_from(host, tld_length)
|
|
98
197
|
end
|
|
99
198
|
|
|
100
199
|
def extract_subdomains_from(host, tld_length)
|
|
101
|
-
|
|
102
|
-
parts[0..-(tld_length + 2)]
|
|
200
|
+
domain_extractor.subdomains_from(host, tld_length)
|
|
103
201
|
end
|
|
104
202
|
|
|
105
203
|
def build_host_url(host, port, protocol, options, path)
|
|
106
204
|
if match = host.match(HOST_REGEXP)
|
|
107
|
-
|
|
108
|
-
host
|
|
109
|
-
port
|
|
205
|
+
protocol_from_host = match[1] if protocol.nil?
|
|
206
|
+
host = match[2]
|
|
207
|
+
port = match[3] unless options.key? :port
|
|
110
208
|
end
|
|
111
209
|
|
|
112
|
-
protocol = normalize_protocol
|
|
210
|
+
protocol = protocol_from_host || normalize_protocol(protocol).dup
|
|
113
211
|
host = normalize_host(host, options)
|
|
212
|
+
port = normalize_port(port, protocol)
|
|
114
213
|
|
|
115
|
-
result = protocol
|
|
214
|
+
result = protocol
|
|
116
215
|
|
|
117
216
|
if options[:user] && options[:password]
|
|
118
217
|
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
|
119
218
|
end
|
|
120
219
|
|
|
121
220
|
result << host
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
221
|
+
|
|
222
|
+
result << ":" << port.to_s if port
|
|
125
223
|
|
|
126
224
|
result.concat path
|
|
127
225
|
end
|
|
@@ -167,11 +265,11 @@ module ActionDispatch
|
|
|
167
265
|
return unless port
|
|
168
266
|
|
|
169
267
|
case protocol
|
|
170
|
-
when "//" then
|
|
268
|
+
when "//" then port
|
|
171
269
|
when "https://"
|
|
172
|
-
|
|
270
|
+
port unless port.to_i == 443
|
|
173
271
|
else
|
|
174
|
-
|
|
272
|
+
port unless port.to_i == 80
|
|
175
273
|
end
|
|
176
274
|
end
|
|
177
275
|
end
|
|
@@ -184,33 +282,33 @@ module ActionDispatch
|
|
|
184
282
|
|
|
185
283
|
# Returns the complete URL used for this request.
|
|
186
284
|
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
285
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
286
|
+
# req.url # => "http://example.com"
|
|
189
287
|
def url
|
|
190
288
|
protocol + host_with_port + fullpath
|
|
191
289
|
end
|
|
192
290
|
|
|
193
291
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
|
194
292
|
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
293
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
294
|
+
# req.protocol # => "http://"
|
|
197
295
|
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
296
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
|
|
297
|
+
# req.protocol # => "https://"
|
|
200
298
|
def protocol
|
|
201
299
|
@protocol ||= ssl? ? "https://" : "http://"
|
|
202
300
|
end
|
|
203
301
|
|
|
204
|
-
# Returns the
|
|
302
|
+
# Returns the host and port for this request, such as "example.com:8080".
|
|
205
303
|
#
|
|
206
|
-
#
|
|
207
|
-
#
|
|
304
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
305
|
+
# req.raw_host_with_port # => "example.com"
|
|
208
306
|
#
|
|
209
|
-
#
|
|
210
|
-
#
|
|
307
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
308
|
+
# req.raw_host_with_port # => "example.com:80"
|
|
211
309
|
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
310
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
311
|
+
# req.raw_host_with_port # => "example.com:8080"
|
|
214
312
|
def raw_host_with_port
|
|
215
313
|
if forwarded = x_forwarded_host.presence
|
|
216
314
|
forwarded.split(/,\s?/).last
|
|
@@ -221,35 +319,35 @@ module ActionDispatch
|
|
|
221
319
|
|
|
222
320
|
# Returns the host for this request, such as "example.com".
|
|
223
321
|
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
322
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
323
|
+
# req.host # => "example.com"
|
|
226
324
|
def host
|
|
227
325
|
raw_host_with_port.sub(/:\d+$/, "")
|
|
228
326
|
end
|
|
229
327
|
|
|
230
|
-
# Returns a
|
|
231
|
-
# "example.com:8080". Port is only included if it is not a default port
|
|
232
|
-
#
|
|
328
|
+
# Returns a host:port string for this request, such as "example.com" or
|
|
329
|
+
# "example.com:8080". Port is only included if it is not a default port (80 or
|
|
330
|
+
# 443)
|
|
233
331
|
#
|
|
234
|
-
#
|
|
235
|
-
#
|
|
332
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
333
|
+
# req.host_with_port # => "example.com"
|
|
236
334
|
#
|
|
237
|
-
#
|
|
238
|
-
#
|
|
335
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
336
|
+
# req.host_with_port # => "example.com"
|
|
239
337
|
#
|
|
240
|
-
#
|
|
241
|
-
#
|
|
338
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
339
|
+
# req.host_with_port # => "example.com:8080"
|
|
242
340
|
def host_with_port
|
|
243
341
|
"#{host}#{port_string}"
|
|
244
342
|
end
|
|
245
343
|
|
|
246
344
|
# Returns the port number of this request as an integer.
|
|
247
345
|
#
|
|
248
|
-
#
|
|
249
|
-
#
|
|
346
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
347
|
+
# req.port # => 80
|
|
250
348
|
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
349
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
350
|
+
# req.port # => 8080
|
|
253
351
|
def port
|
|
254
352
|
@port ||= if raw_host_with_port =~ /:(\d+)$/
|
|
255
353
|
$1.to_i
|
|
@@ -258,10 +356,10 @@ module ActionDispatch
|
|
|
258
356
|
end
|
|
259
357
|
end
|
|
260
358
|
|
|
261
|
-
# Returns the standard
|
|
359
|
+
# Returns the standard port number for this request's protocol.
|
|
262
360
|
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
361
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
362
|
+
# req.standard_port # => 80
|
|
265
363
|
def standard_port
|
|
266
364
|
if "https://" == protocol
|
|
267
365
|
443
|
|
@@ -270,70 +368,70 @@ module ActionDispatch
|
|
|
270
368
|
end
|
|
271
369
|
end
|
|
272
370
|
|
|
273
|
-
# Returns whether this request is using the standard port
|
|
371
|
+
# Returns whether this request is using the standard port.
|
|
274
372
|
#
|
|
275
|
-
#
|
|
276
|
-
#
|
|
373
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
374
|
+
# req.standard_port? # => true
|
|
277
375
|
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
376
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
377
|
+
# req.standard_port? # => false
|
|
280
378
|
def standard_port?
|
|
281
379
|
port == standard_port
|
|
282
380
|
end
|
|
283
381
|
|
|
284
|
-
# Returns a number
|
|
285
|
-
#
|
|
382
|
+
# Returns a number port suffix like 8080 if the port number of this request is
|
|
383
|
+
# not the default HTTP port 80 or HTTPS port 443.
|
|
286
384
|
#
|
|
287
|
-
#
|
|
288
|
-
#
|
|
385
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
386
|
+
# req.optional_port # => nil
|
|
289
387
|
#
|
|
290
|
-
#
|
|
291
|
-
#
|
|
388
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
389
|
+
# req.optional_port # => 8080
|
|
292
390
|
def optional_port
|
|
293
391
|
standard_port? ? nil : port
|
|
294
392
|
end
|
|
295
393
|
|
|
296
|
-
# Returns a string
|
|
297
|
-
#
|
|
394
|
+
# Returns a string port suffix, including colon, like ":8080" if the port number
|
|
395
|
+
# of this request is not the default HTTP port 80 or HTTPS port 443.
|
|
298
396
|
#
|
|
299
|
-
#
|
|
300
|
-
#
|
|
397
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
398
|
+
# req.port_string # => ""
|
|
301
399
|
#
|
|
302
|
-
#
|
|
303
|
-
#
|
|
400
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
401
|
+
# req.port_string # => ":8080"
|
|
304
402
|
def port_string
|
|
305
403
|
standard_port? ? "" : ":#{port}"
|
|
306
404
|
end
|
|
307
405
|
|
|
308
|
-
# Returns the requested port, such as 8080, based on SERVER_PORT
|
|
406
|
+
# Returns the requested port, such as 8080, based on SERVER_PORT.
|
|
309
407
|
#
|
|
310
|
-
#
|
|
311
|
-
#
|
|
408
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
|
|
409
|
+
# req.server_port # => 80
|
|
312
410
|
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
411
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
|
|
412
|
+
# req.server_port # => 8080
|
|
315
413
|
def server_port
|
|
316
414
|
get_header("SERVER_PORT").to_i
|
|
317
415
|
end
|
|
318
416
|
|
|
319
|
-
# Returns the
|
|
320
|
-
# a different
|
|
417
|
+
# Returns the domain part of a host, such as "rubyonrails.org" in
|
|
418
|
+
# "www.rubyonrails.org". You can specify a different `tld_length`, such as 2 to
|
|
419
|
+
# catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
|
|
321
420
|
def domain(tld_length = @@tld_length)
|
|
322
421
|
ActionDispatch::Http::URL.extract_domain(host, tld_length)
|
|
323
422
|
end
|
|
324
423
|
|
|
325
|
-
# Returns all the
|
|
326
|
-
#
|
|
327
|
-
#
|
|
328
|
-
#
|
|
424
|
+
# Returns all the subdomains as an array, so `["dev", "www"]` would be returned
|
|
425
|
+
# for "dev.www.rubyonrails.org". You can specify a different `tld_length`, such
|
|
426
|
+
# as 2 to catch `["www"]` instead of `["www", "rubyonrails"]` in
|
|
427
|
+
# "www.rubyonrails.co.uk".
|
|
329
428
|
def subdomains(tld_length = @@tld_length)
|
|
330
429
|
ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
|
|
331
430
|
end
|
|
332
431
|
|
|
333
|
-
# Returns all the
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
# in "www.rubyonrails.co.uk".
|
|
432
|
+
# Returns all the subdomains as a string, so `"dev.www"` would be returned for
|
|
433
|
+
# "dev.www.rubyonrails.org". You can specify a different `tld_length`, such as 2
|
|
434
|
+
# to catch `"www"` instead of `"www.rubyonrails"` in "www.rubyonrails.co.uk".
|
|
337
435
|
def subdomain(tld_length = @@tld_length)
|
|
338
436
|
ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
|
|
339
437
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "action_controller/metal/exceptions"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch
|
|
6
8
|
# :stopdoc:
|
|
7
9
|
module Journey
|
|
8
10
|
# The Formatter class is used for formatting URLs. For example, parameters
|
|
9
|
-
# passed to
|
|
11
|
+
# passed to `url_for` in Rails will eventually call Formatter#generate.
|
|
10
12
|
class Formatter
|
|
11
13
|
attr_reader :routes
|
|
12
14
|
|
|
@@ -58,26 +60,31 @@ module ActionDispatch
|
|
|
58
60
|
|
|
59
61
|
def generate(name, options, path_parameters)
|
|
60
62
|
original_options = options.dup
|
|
61
|
-
path_params = options.delete(:path_params)
|
|
62
|
-
|
|
63
|
+
path_params = options.delete(:path_params)
|
|
64
|
+
if path_params.is_a?(Hash)
|
|
65
|
+
options = path_params.merge(options)
|
|
66
|
+
else
|
|
67
|
+
path_params = nil
|
|
68
|
+
options = options.dup
|
|
69
|
+
end
|
|
63
70
|
constraints = path_parameters.merge(options)
|
|
64
71
|
missing_keys = nil
|
|
65
72
|
|
|
66
73
|
match_route(name, constraints) do |route|
|
|
67
74
|
parameterized_parts = extract_parameterized_parts(route, options, path_parameters)
|
|
68
75
|
|
|
69
|
-
# Skip this route unless a name has been provided or it is a
|
|
70
|
-
#
|
|
71
|
-
#
|
|
76
|
+
# Skip this route unless a name has been provided or it is a standard Rails
|
|
77
|
+
# route since we can't determine whether an options hash passed to url_for
|
|
78
|
+
# matches a Rack application or a redirect.
|
|
72
79
|
next unless name || route.dispatcher?
|
|
73
80
|
|
|
74
81
|
missing_keys = missing_keys(route, parameterized_parts)
|
|
75
82
|
next if missing_keys && !missing_keys.empty?
|
|
76
83
|
params = options.delete_if do |key, _|
|
|
77
|
-
# top-level params' normal behavior of generating query_params
|
|
78
|
-
#
|
|
84
|
+
# top-level params' normal behavior of generating query_params should be
|
|
85
|
+
# preserved even if the same key is also a bind_param
|
|
79
86
|
parameterized_parts.key?(key) || route.defaults.key?(key) ||
|
|
80
|
-
(path_params
|
|
87
|
+
(path_params&.key?(key) && !original_options.key?(key))
|
|
81
88
|
end
|
|
82
89
|
|
|
83
90
|
defaults = route.defaults
|
|
@@ -104,6 +111,11 @@ module ActionDispatch
|
|
|
104
111
|
@cache = nil
|
|
105
112
|
end
|
|
106
113
|
|
|
114
|
+
def eager_load!
|
|
115
|
+
cache
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
|
|
107
119
|
private
|
|
108
120
|
def extract_parameterized_parts(route, options, recall)
|
|
109
121
|
parameterized_parts = recall.merge(options)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "action_dispatch/journey/gtg/transition_table"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch
|
|
@@ -66,9 +68,8 @@ module ActionDispatch
|
|
|
66
68
|
when Nodes::Group
|
|
67
69
|
true
|
|
68
70
|
when Nodes::Star
|
|
69
|
-
# the default star regex is /(.+)/ which is NOT nullable
|
|
70
|
-
#
|
|
71
|
-
# actually check if this is the case or not.
|
|
71
|
+
# the default star regex is /(.+)/ which is NOT nullable but since different
|
|
72
|
+
# constraints can be provided we must actually check if this is the case or not.
|
|
72
73
|
node.regexp.match?("")
|
|
73
74
|
when Nodes::Or
|
|
74
75
|
node.children.any? { |c| nullable?(c) }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# :markup: markdown
|
|
4
4
|
|
|
5
5
|
module ActionDispatch
|
|
6
6
|
module Journey # :nodoc:
|
|
@@ -14,7 +14,13 @@ module ActionDispatch
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class Simulator # :nodoc:
|
|
17
|
-
|
|
17
|
+
STATIC_TOKENS = Array.new(64)
|
|
18
|
+
STATIC_TOKENS[".".ord] = "."
|
|
19
|
+
STATIC_TOKENS["/".ord] = "/"
|
|
20
|
+
STATIC_TOKENS["?".ord] = "?"
|
|
21
|
+
STATIC_TOKENS.freeze
|
|
22
|
+
|
|
23
|
+
INITIAL_STATE = [0, nil].freeze
|
|
18
24
|
|
|
19
25
|
attr_reader :tt
|
|
20
26
|
|
|
@@ -23,21 +29,38 @@ module ActionDispatch
|
|
|
23
29
|
end
|
|
24
30
|
|
|
25
31
|
def memos(string)
|
|
26
|
-
input = StringScanner.new(string)
|
|
27
32
|
state = INITIAL_STATE
|
|
28
|
-
start_index = 0
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
pos = 0
|
|
35
|
+
eos = string.bytesize
|
|
36
|
+
|
|
37
|
+
while pos < eos
|
|
38
|
+
start_index = pos
|
|
39
|
+
pos += 1
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
if (token = STATIC_TOKENS[string.getbyte(start_index)])
|
|
42
|
+
state = tt.move(state, string, token, start_index, false)
|
|
43
|
+
else
|
|
44
|
+
while pos < eos && STATIC_TOKENS[string.getbyte(pos)].nil?
|
|
45
|
+
pos += 1
|
|
46
|
+
end
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
token = string.byteslice(start_index, pos - start_index)
|
|
49
|
+
state = tt.move(state, string, token, start_index, true)
|
|
50
|
+
end
|
|
36
51
|
end
|
|
37
52
|
|
|
38
|
-
acceptance_states =
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
acceptance_states = []
|
|
54
|
+
states_count = state.size
|
|
55
|
+
i = 0
|
|
56
|
+
while i < states_count
|
|
57
|
+
if state[i + 1].nil?
|
|
58
|
+
s = state[i]
|
|
59
|
+
if tt.accepting?(s)
|
|
60
|
+
acceptance_states.concat(tt.memo(s))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
i += 2
|
|
41
64
|
end
|
|
42
65
|
|
|
43
66
|
acceptance_states.empty? ? yield : acceptance_states
|