actionpack 4.2.8 → 5.2.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +285 -444
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller.rb +12 -5
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/action_controller.rb +29 -21
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +64 -57
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +582 -165
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +280 -411
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +734 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_pack.rb +4 -2
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- metadata +56 -39
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Http
|
3
5
|
# Models uploaded files.
|
@@ -24,23 +26,27 @@ module ActionDispatch
|
|
24
26
|
attr_accessor :headers
|
25
27
|
|
26
28
|
def initialize(hash) # :nodoc:
|
27
|
-
@tempfile
|
28
|
-
raise(ArgumentError,
|
29
|
+
@tempfile = hash[:tempfile]
|
30
|
+
raise(ArgumentError, ":tempfile is required") unless @tempfile
|
31
|
+
|
32
|
+
if hash[:filename]
|
33
|
+
@original_filename = hash[:filename].dup
|
29
34
|
|
30
|
-
@original_filename = hash[:filename]
|
31
|
-
if @original_filename
|
32
35
|
begin
|
33
36
|
@original_filename.encode!(Encoding::UTF_8)
|
34
37
|
rescue EncodingError
|
35
38
|
@original_filename.force_encoding(Encoding::UTF_8)
|
36
39
|
end
|
40
|
+
else
|
41
|
+
@original_filename = nil
|
37
42
|
end
|
43
|
+
|
38
44
|
@content_type = hash[:type]
|
39
45
|
@headers = hash[:head]
|
40
46
|
end
|
41
47
|
|
42
48
|
# Shortcut for +tempfile.read+.
|
43
|
-
def read(length=nil, buffer=nil)
|
49
|
+
def read(length = nil, buffer = nil)
|
44
50
|
@tempfile.read(length, buffer)
|
45
51
|
end
|
46
52
|
|
@@ -50,7 +56,7 @@ module ActionDispatch
|
|
50
56
|
end
|
51
57
|
|
52
58
|
# Shortcut for +tempfile.close+.
|
53
|
-
def close(unlink_now=false)
|
59
|
+
def close(unlink_now = false)
|
54
60
|
@tempfile.close(unlink_now)
|
55
61
|
end
|
56
62
|
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
3
4
|
|
4
5
|
module ActionDispatch
|
5
6
|
module Http
|
@@ -8,14 +9,25 @@ module ActionDispatch
|
|
8
9
|
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
9
10
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
10
11
|
|
11
|
-
mattr_accessor :tld_length
|
12
|
-
self.tld_length = 1
|
12
|
+
mattr_accessor :tld_length, default: 1
|
13
13
|
|
14
14
|
class << self
|
15
|
+
# Returns the domain part of a host given the domain level.
|
16
|
+
#
|
17
|
+
# # Top-level domain example
|
18
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
19
|
+
# # Second-level domain example
|
20
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
15
21
|
def extract_domain(host, tld_length)
|
16
22
|
extract_domain_from(host, tld_length) if named_host?(host)
|
17
23
|
end
|
18
24
|
|
25
|
+
# Returns the subdomains of a host as an Array given the domain level.
|
26
|
+
#
|
27
|
+
# # Top-level domain example
|
28
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
29
|
+
# # Second-level domain example
|
30
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
19
31
|
def extract_subdomains(host, tld_length)
|
20
32
|
if named_host?(host)
|
21
33
|
extract_subdomains_from(host, tld_length)
|
@@ -24,8 +36,14 @@ module ActionDispatch
|
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
39
|
+
# Returns the subdomains of a host as a String given the domain level.
|
40
|
+
#
|
41
|
+
# # Top-level domain example
|
42
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
43
|
+
# # Second-level domain example
|
44
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
27
45
|
def extract_subdomain(host, tld_length)
|
28
|
-
extract_subdomains(host, tld_length).join(
|
46
|
+
extract_subdomains(host, tld_length).join(".")
|
29
47
|
end
|
30
48
|
|
31
49
|
def url_for(options)
|
@@ -42,14 +60,14 @@ module ActionDispatch
|
|
42
60
|
port = options[:port]
|
43
61
|
|
44
62
|
unless host
|
45
|
-
raise ArgumentError,
|
63
|
+
raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
|
46
64
|
end
|
47
65
|
|
48
66
|
build_host_url(host, port, protocol, options, path_for(options))
|
49
67
|
end
|
50
68
|
|
51
69
|
def path_for(options)
|
52
|
-
path
|
70
|
+
path = options[:script_name].to_s.chomp("/".freeze)
|
53
71
|
path << options[:path] if options.key?(:path)
|
54
72
|
|
55
73
|
add_trailing_slash(path) if options[:trailing_slash]
|
@@ -63,8 +81,9 @@ module ActionDispatch
|
|
63
81
|
|
64
82
|
def add_params(path, params)
|
65
83
|
params = { params: params } unless params.is_a?(Hash)
|
66
|
-
params.reject! { |_,v| v.to_param.nil? }
|
67
|
-
|
84
|
+
params.reject! { |_, v| v.to_param.nil? }
|
85
|
+
query = params.to_query
|
86
|
+
path << "?#{query}" unless query.empty?
|
68
87
|
end
|
69
88
|
|
70
89
|
def add_anchor(path, anchor)
|
@@ -74,19 +93,17 @@ module ActionDispatch
|
|
74
93
|
end
|
75
94
|
|
76
95
|
def extract_domain_from(host, tld_length)
|
77
|
-
host.split(
|
96
|
+
host.split(".").last(1 + tld_length).join(".")
|
78
97
|
end
|
79
98
|
|
80
99
|
def extract_subdomains_from(host, tld_length)
|
81
|
-
parts = host.split(
|
100
|
+
parts = host.split(".")
|
82
101
|
parts[0..-(tld_length + 2)]
|
83
102
|
end
|
84
103
|
|
85
104
|
def add_trailing_slash(path)
|
86
|
-
|
87
|
-
if path.include?('?')
|
105
|
+
if path.include?("?")
|
88
106
|
path.sub!(/\?/, '/\&')
|
89
|
-
# does not have a .format
|
90
107
|
elsif !path.include?(".")
|
91
108
|
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
92
109
|
end
|
@@ -140,11 +157,11 @@ module ActionDispatch
|
|
140
157
|
subdomain = options.fetch :subdomain, true
|
141
158
|
domain = options[:domain]
|
142
159
|
|
143
|
-
host = ""
|
160
|
+
host = "".dup
|
144
161
|
if subdomain == true
|
145
162
|
return _host if domain.nil?
|
146
163
|
|
147
|
-
host << extract_subdomains_from(_host, tld_length).join(
|
164
|
+
host << extract_subdomains_from(_host, tld_length).join(".")
|
148
165
|
elsif subdomain
|
149
166
|
host << subdomain.to_param
|
150
167
|
end
|
@@ -166,43 +183,80 @@ module ActionDispatch
|
|
166
183
|
end
|
167
184
|
end
|
168
185
|
|
169
|
-
def initialize
|
186
|
+
def initialize
|
170
187
|
super
|
171
188
|
@protocol = nil
|
172
189
|
@port = nil
|
173
190
|
end
|
174
191
|
|
175
192
|
# Returns the complete URL used for this request.
|
193
|
+
#
|
194
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
195
|
+
# req.url # => "http://example.com"
|
176
196
|
def url
|
177
197
|
protocol + host_with_port + fullpath
|
178
198
|
end
|
179
199
|
|
180
200
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
201
|
+
#
|
202
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
203
|
+
# req.protocol # => "http://"
|
204
|
+
#
|
205
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
|
206
|
+
# req.protocol # => "https://"
|
181
207
|
def protocol
|
182
|
-
@protocol ||= ssl? ?
|
208
|
+
@protocol ||= ssl? ? "https://" : "http://"
|
183
209
|
end
|
184
210
|
|
185
|
-
# Returns the \host for this request, such as "example.com".
|
211
|
+
# Returns the \host and port for this request, such as "example.com:8080".
|
212
|
+
#
|
213
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
214
|
+
# req.raw_host_with_port # => "example.com"
|
215
|
+
#
|
216
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
217
|
+
# req.raw_host_with_port # => "example.com:80"
|
218
|
+
#
|
219
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
220
|
+
# req.raw_host_with_port # => "example.com:8080"
|
186
221
|
def raw_host_with_port
|
187
|
-
if forwarded =
|
222
|
+
if forwarded = x_forwarded_host.presence
|
188
223
|
forwarded.split(/,\s?/).last
|
189
224
|
else
|
190
|
-
|
225
|
+
get_header("HTTP_HOST") || "#{server_name || server_addr}:#{get_header('SERVER_PORT')}"
|
191
226
|
end
|
192
227
|
end
|
193
228
|
|
194
|
-
# Returns the host for this request, such as example.com.
|
229
|
+
# Returns the host for this request, such as "example.com".
|
230
|
+
#
|
231
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
232
|
+
# req.host # => "example.com"
|
195
233
|
def host
|
196
|
-
raw_host_with_port.sub(/:\d+$/,
|
234
|
+
raw_host_with_port.sub(/:\d+$/, "".freeze)
|
197
235
|
end
|
198
236
|
|
199
237
|
# Returns a \host:\port string for this request, such as "example.com" or
|
200
|
-
# "example.com:8080".
|
238
|
+
# "example.com:8080". Port is only included if it is not a default port
|
239
|
+
# (80 or 443)
|
240
|
+
#
|
241
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
242
|
+
# req.host_with_port # => "example.com"
|
243
|
+
#
|
244
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
245
|
+
# req.host_with_port # => "example.com"
|
246
|
+
#
|
247
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
248
|
+
# req.host_with_port # => "example.com:8080"
|
201
249
|
def host_with_port
|
202
250
|
"#{host}#{port_string}"
|
203
251
|
end
|
204
252
|
|
205
253
|
# Returns the port number of this request as an integer.
|
254
|
+
#
|
255
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
256
|
+
# req.port # => 80
|
257
|
+
#
|
258
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
259
|
+
# req.port # => 8080
|
206
260
|
def port
|
207
261
|
@port ||= begin
|
208
262
|
if raw_host_with_port =~ /:(\d+)$/
|
@@ -214,32 +268,60 @@ module ActionDispatch
|
|
214
268
|
end
|
215
269
|
|
216
270
|
# Returns the standard \port number for this request's protocol.
|
271
|
+
#
|
272
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
273
|
+
# req.standard_port # => 80
|
217
274
|
def standard_port
|
218
275
|
case protocol
|
219
|
-
|
220
|
-
|
276
|
+
when "https://" then 443
|
277
|
+
else 80
|
221
278
|
end
|
222
279
|
end
|
223
280
|
|
224
281
|
# Returns whether this request is using the standard port
|
282
|
+
#
|
283
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
284
|
+
# req.standard_port? # => true
|
285
|
+
#
|
286
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
287
|
+
# req.standard_port? # => false
|
225
288
|
def standard_port?
|
226
289
|
port == standard_port
|
227
290
|
end
|
228
291
|
|
229
292
|
# Returns a number \port suffix like 8080 if the \port number of this request
|
230
293
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
294
|
+
#
|
295
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
296
|
+
# req.optional_port # => nil
|
297
|
+
#
|
298
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
299
|
+
# req.optional_port # => 8080
|
231
300
|
def optional_port
|
232
301
|
standard_port? ? nil : port
|
233
302
|
end
|
234
303
|
|
235
304
|
# Returns a string \port suffix, including colon, like ":8080" if the \port
|
236
305
|
# number of this request is not the default HTTP \port 80 or HTTPS \port 443.
|
306
|
+
#
|
307
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
308
|
+
# req.port_string # => ""
|
309
|
+
#
|
310
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
311
|
+
# req.port_string # => ":8080"
|
237
312
|
def port_string
|
238
|
-
standard_port? ?
|
313
|
+
standard_port? ? "" : ":#{port}"
|
239
314
|
end
|
240
315
|
|
316
|
+
# Returns the requested port, such as 8080, based on SERVER_PORT
|
317
|
+
#
|
318
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
|
319
|
+
# req.server_port # => 80
|
320
|
+
#
|
321
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
|
322
|
+
# req.server_port # => 8080
|
241
323
|
def server_port
|
242
|
-
|
324
|
+
get_header("SERVER_PORT").to_i
|
243
325
|
end
|
244
326
|
|
245
327
|
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/journey/router"
|
4
|
+
require "action_dispatch/journey/gtg/builder"
|
5
|
+
require "action_dispatch/journey/gtg/simulator"
|
6
|
+
require "action_dispatch/journey/nfa/builder"
|
7
|
+
require "action_dispatch/journey/nfa/simulator"
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_controller/metal/exceptions"
|
3
4
|
|
4
5
|
module ActionDispatch
|
6
|
+
# :stopdoc:
|
5
7
|
module Journey
|
6
8
|
# The Formatter class is used for formatting URLs. For example, parameters
|
7
9
|
# passed to +url_for+ in Rails will eventually call Formatter#generate.
|
8
|
-
class Formatter
|
10
|
+
class Formatter
|
9
11
|
attr_reader :routes
|
10
12
|
|
11
13
|
def initialize(routes)
|
@@ -15,7 +17,7 @@ module ActionDispatch
|
|
15
17
|
|
16
18
|
def generate(name, options, path_parameters, parameterize = nil)
|
17
19
|
constraints = path_parameters.merge(options)
|
18
|
-
missing_keys =
|
20
|
+
missing_keys = nil
|
19
21
|
|
20
22
|
match_route(name, constraints) do |route|
|
21
23
|
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
|
@@ -26,22 +28,31 @@ module ActionDispatch
|
|
26
28
|
next unless name || route.dispatcher?
|
27
29
|
|
28
30
|
missing_keys = missing_keys(route, parameterized_parts)
|
29
|
-
next
|
31
|
+
next if missing_keys && !missing_keys.empty?
|
30
32
|
params = options.dup.delete_if do |key, _|
|
31
33
|
parameterized_parts.key?(key) || route.defaults.key?(key)
|
32
34
|
end
|
33
35
|
|
34
36
|
defaults = route.defaults
|
35
37
|
required_parts = route.required_parts
|
36
|
-
|
37
|
-
|
38
|
+
|
39
|
+
route.parts.reverse_each do |key|
|
40
|
+
break if defaults[key].nil? && parameterized_parts[key].present?
|
41
|
+
next if parameterized_parts[key].to_s != defaults[key].to_s
|
42
|
+
break if required_parts.include?(key)
|
43
|
+
|
44
|
+
parameterized_parts.delete(key)
|
38
45
|
end
|
39
46
|
|
40
47
|
return [route.format(parameterized_parts), params]
|
41
48
|
end
|
42
49
|
|
43
|
-
|
44
|
-
|
50
|
+
unmatched_keys = (missing_keys || []) & constraints.keys
|
51
|
+
missing_keys = (missing_keys || []) - unmatched_keys
|
52
|
+
|
53
|
+
message = "No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}".dup
|
54
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
55
|
+
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
45
56
|
|
46
57
|
raise ActionController::UrlGenerationError, message
|
47
58
|
end
|
@@ -55,12 +66,12 @@ module ActionDispatch
|
|
55
66
|
def extract_parameterized_parts(route, options, recall, parameterize = nil)
|
56
67
|
parameterized_parts = recall.merge(options)
|
57
68
|
|
58
|
-
keys_to_keep = route.parts.
|
69
|
+
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
59
70
|
!options.key?(part) || (options[part] || recall[part]).nil?
|
60
71
|
} | route.required_parts
|
61
72
|
|
62
|
-
|
63
|
-
|
73
|
+
parameterized_parts.delete_if do |bad_key, _|
|
74
|
+
!keys_to_keep.include?(bad_key)
|
64
75
|
end
|
65
76
|
|
66
77
|
if parameterize
|
@@ -81,28 +92,18 @@ module ActionDispatch
|
|
81
92
|
if named_routes.key?(name)
|
82
93
|
yield named_routes[name]
|
83
94
|
else
|
84
|
-
# Make sure we don't show the deprecation warning more than once
|
85
|
-
warned = false
|
86
|
-
|
87
95
|
routes = non_recursive(cache, options)
|
88
96
|
|
89
|
-
|
97
|
+
supplied_keys = options.each_with_object({}) do |(k, v), h|
|
98
|
+
h[k.to_s] = true if v
|
99
|
+
end
|
100
|
+
|
101
|
+
hash = routes.group_by { |_, r| r.score(supplied_keys) }
|
90
102
|
|
91
103
|
hash.keys.sort.reverse_each do |score|
|
92
104
|
break if score < 0
|
93
105
|
|
94
106
|
hash[score].sort_by { |i, _| i }.each do |_, route|
|
95
|
-
if name && !warned
|
96
|
-
ActiveSupport::Deprecation.warn <<-MSG.squish
|
97
|
-
You are trying to generate the URL for a named route called
|
98
|
-
#{name.inspect} but no such route was found. In the future,
|
99
|
-
this will result in an `ActionController::UrlGenerationError`
|
100
|
-
exception.
|
101
|
-
MSG
|
102
|
-
|
103
|
-
warned = true
|
104
|
-
end
|
105
|
-
|
106
107
|
yield route
|
107
108
|
end
|
108
109
|
end
|
@@ -125,15 +126,36 @@ module ActionDispatch
|
|
125
126
|
routes
|
126
127
|
end
|
127
128
|
|
129
|
+
module RegexCaseComparator
|
130
|
+
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
|
131
|
+
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
|
132
|
+
|
133
|
+
def self.===(regex)
|
134
|
+
DEFAULT_INPUT == regex
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
128
138
|
# Returns an array populated with missing keys if any are present.
|
129
139
|
def missing_keys(route, parts)
|
130
|
-
missing_keys =
|
140
|
+
missing_keys = nil
|
131
141
|
tests = route.path.requirements
|
132
142
|
route.required_parts.each { |key|
|
133
|
-
|
134
|
-
|
143
|
+
case tests[key]
|
144
|
+
when nil
|
145
|
+
unless parts[key]
|
146
|
+
missing_keys ||= []
|
147
|
+
missing_keys << key
|
148
|
+
end
|
149
|
+
when RegexCaseComparator
|
150
|
+
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
|
151
|
+
missing_keys ||= []
|
152
|
+
missing_keys << key
|
153
|
+
end
|
135
154
|
else
|
136
|
-
|
155
|
+
unless /\A#{tests[key]}\Z/ === parts[key]
|
156
|
+
missing_keys ||= []
|
157
|
+
missing_keys << key
|
158
|
+
end
|
137
159
|
end
|
138
160
|
}
|
139
161
|
missing_keys
|
@@ -149,7 +171,7 @@ module ActionDispatch
|
|
149
171
|
|
150
172
|
def build_cache
|
151
173
|
root = { ___routes: [] }
|
152
|
-
routes.each_with_index do |route, i|
|
174
|
+
routes.routes.each_with_index do |route, i|
|
153
175
|
leaf = route.required_defaults.inject(root) do |h, tuple|
|
154
176
|
h[tuple] ||= {}
|
155
177
|
end
|
@@ -163,4 +185,5 @@ module ActionDispatch
|
|
163
185
|
end
|
164
186
|
end
|
165
187
|
end
|
188
|
+
# :startdoc:
|
166
189
|
end
|