actionpack 4.2.11.1 → 6.1.3.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 +4 -4
- data/CHANGELOG.md +291 -489
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +102 -120
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +83 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +296 -422
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +107 -56
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +79 -51
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +90 -43
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.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 +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +78 -48
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- 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/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- 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,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,26 @@ module ActionDispatch
|
|
8
9
|
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
9
10
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
10
11
|
|
11
|
-
mattr_accessor :
|
12
|
-
|
12
|
+
mattr_accessor :secure_protocol, default: false
|
13
|
+
mattr_accessor :tld_length, default: 1
|
13
14
|
|
14
15
|
class << self
|
16
|
+
# Returns the domain part of a host given the domain level.
|
17
|
+
#
|
18
|
+
# # Top-level domain example
|
19
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
20
|
+
# # Second-level domain example
|
21
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
15
22
|
def extract_domain(host, tld_length)
|
16
23
|
extract_domain_from(host, tld_length) if named_host?(host)
|
17
24
|
end
|
18
25
|
|
26
|
+
# Returns the subdomains of a host as an Array given the domain level.
|
27
|
+
#
|
28
|
+
# # Top-level domain example
|
29
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
30
|
+
# # Second-level domain example
|
31
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
19
32
|
def extract_subdomains(host, tld_length)
|
20
33
|
if named_host?(host)
|
21
34
|
extract_subdomains_from(host, tld_length)
|
@@ -24,8 +37,14 @@ module ActionDispatch
|
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
40
|
+
# Returns the subdomains of a host as a String given the domain level.
|
41
|
+
#
|
42
|
+
# # Top-level domain example
|
43
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
44
|
+
# # Second-level domain example
|
45
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
27
46
|
def extract_subdomain(host, tld_length)
|
28
|
-
extract_subdomains(host, tld_length).join(
|
47
|
+
extract_subdomains(host, tld_length).join(".")
|
29
48
|
end
|
30
49
|
|
31
50
|
def url_for(options)
|
@@ -42,14 +61,14 @@ module ActionDispatch
|
|
42
61
|
port = options[:port]
|
43
62
|
|
44
63
|
unless host
|
45
|
-
raise ArgumentError,
|
64
|
+
raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
|
46
65
|
end
|
47
66
|
|
48
67
|
build_host_url(host, port, protocol, options, path_for(options))
|
49
68
|
end
|
50
69
|
|
51
70
|
def path_for(options)
|
52
|
-
path
|
71
|
+
path = options[:script_name].to_s.chomp("/")
|
53
72
|
path << options[:path] if options.key?(:path)
|
54
73
|
|
55
74
|
add_trailing_slash(path) if options[:trailing_slash]
|
@@ -60,149 +79,184 @@ module ActionDispatch
|
|
60
79
|
end
|
61
80
|
|
62
81
|
private
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def add_anchor(path, anchor)
|
71
|
-
if anchor
|
72
|
-
path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
|
82
|
+
def add_params(path, params)
|
83
|
+
params = { params: params } unless params.is_a?(Hash)
|
84
|
+
params.reject! { |_, v| v.to_param.nil? }
|
85
|
+
query = params.to_query
|
86
|
+
path << "?#{query}" unless query.empty?
|
73
87
|
end
|
74
|
-
end
|
75
88
|
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
def add_anchor(path, anchor)
|
90
|
+
if anchor
|
91
|
+
path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
|
92
|
+
end
|
93
|
+
end
|
79
94
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
95
|
+
def extract_domain_from(host, tld_length)
|
96
|
+
host.split(".").last(1 + tld_length).join(".")
|
97
|
+
end
|
84
98
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
path.sub!(/\?/, '/\&')
|
89
|
-
# does not have a .format
|
90
|
-
elsif !path.include?(".")
|
91
|
-
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
99
|
+
def extract_subdomains_from(host, tld_length)
|
100
|
+
parts = host.split(".")
|
101
|
+
parts[0..-(tld_length + 2)]
|
92
102
|
end
|
93
|
-
end
|
94
103
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
104
|
+
def add_trailing_slash(path)
|
105
|
+
if path.include?("?")
|
106
|
+
path.sub!(/\?/, '/\&')
|
107
|
+
elsif !path.include?(".")
|
108
|
+
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
109
|
+
end
|
100
110
|
end
|
101
111
|
|
102
|
-
|
103
|
-
|
112
|
+
def build_host_url(host, port, protocol, options, path)
|
113
|
+
if match = host.match(HOST_REGEXP)
|
114
|
+
protocol ||= match[1] unless protocol == false
|
115
|
+
host = match[2]
|
116
|
+
port = match[3] unless options.key? :port
|
117
|
+
end
|
104
118
|
|
105
|
-
|
119
|
+
protocol = normalize_protocol protocol
|
120
|
+
host = normalize_host(host, options)
|
106
121
|
|
107
|
-
|
108
|
-
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
109
|
-
end
|
122
|
+
result = protocol.dup
|
110
123
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
}
|
124
|
+
if options[:user] && options[:password]
|
125
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
126
|
+
end
|
115
127
|
|
116
|
-
|
117
|
-
|
128
|
+
result << host
|
129
|
+
normalize_port(port, protocol) { |normalized_port|
|
130
|
+
result << ":#{normalized_port}"
|
131
|
+
}
|
118
132
|
|
119
|
-
|
120
|
-
|
121
|
-
end
|
133
|
+
result.concat path
|
134
|
+
end
|
122
135
|
|
123
|
-
|
124
|
-
|
125
|
-
when nil
|
126
|
-
"http://"
|
127
|
-
when false, "//"
|
128
|
-
"//"
|
129
|
-
when PROTOCOL_REGEXP
|
130
|
-
"#{$1}://"
|
131
|
-
else
|
132
|
-
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
136
|
+
def named_host?(host)
|
137
|
+
!IP_HOST_REGEXP.match?(host)
|
133
138
|
end
|
134
|
-
end
|
135
139
|
|
136
|
-
|
137
|
-
|
140
|
+
def normalize_protocol(protocol)
|
141
|
+
case protocol
|
142
|
+
when nil
|
143
|
+
secure_protocol ? "https://" : "http://"
|
144
|
+
when false, "//"
|
145
|
+
"//"
|
146
|
+
when PROTOCOL_REGEXP
|
147
|
+
"#{$1}://"
|
148
|
+
else
|
149
|
+
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def normalize_host(_host, options)
|
154
|
+
return _host unless named_host?(_host)
|
138
155
|
|
139
|
-
|
140
|
-
|
141
|
-
|
156
|
+
tld_length = options[:tld_length] || @@tld_length
|
157
|
+
subdomain = options.fetch :subdomain, true
|
158
|
+
domain = options[:domain]
|
142
159
|
|
143
|
-
|
144
|
-
|
145
|
-
|
160
|
+
host = +""
|
161
|
+
if subdomain == true
|
162
|
+
return _host if domain.nil?
|
146
163
|
|
147
|
-
|
148
|
-
|
149
|
-
|
164
|
+
host << extract_subdomains_from(_host, tld_length).join(".")
|
165
|
+
elsif subdomain
|
166
|
+
host << subdomain.to_param
|
167
|
+
end
|
168
|
+
host << "." unless host.empty?
|
169
|
+
host << (domain || extract_domain_from(_host, tld_length))
|
170
|
+
host
|
150
171
|
end
|
151
|
-
host << "." unless host.empty?
|
152
|
-
host << (domain || extract_domain_from(_host, tld_length))
|
153
|
-
host
|
154
|
-
end
|
155
172
|
|
156
|
-
|
157
|
-
|
173
|
+
def normalize_port(port, protocol)
|
174
|
+
return unless port
|
158
175
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
176
|
+
case protocol
|
177
|
+
when "//" then yield port
|
178
|
+
when "https://"
|
179
|
+
yield port unless port.to_i == 443
|
180
|
+
else
|
181
|
+
yield port unless port.to_i == 80
|
182
|
+
end
|
165
183
|
end
|
166
|
-
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+$/, "")
|
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,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)
|
@@ -13,12 +15,53 @@ module ActionDispatch
|
|
13
15
|
@cache = nil
|
14
16
|
end
|
15
17
|
|
16
|
-
|
18
|
+
class RouteWithParams
|
19
|
+
attr_reader :params
|
20
|
+
|
21
|
+
def initialize(route, parameterized_parts, params)
|
22
|
+
@route = route
|
23
|
+
@parameterized_parts = parameterized_parts
|
24
|
+
@params = params
|
25
|
+
end
|
26
|
+
|
27
|
+
def path(_)
|
28
|
+
@route.format(@parameterized_parts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class MissingRoute
|
33
|
+
attr_reader :routes, :name, :constraints, :missing_keys, :unmatched_keys
|
34
|
+
|
35
|
+
def initialize(constraints, missing_keys, unmatched_keys, routes, name)
|
36
|
+
@constraints = constraints
|
37
|
+
@missing_keys = missing_keys
|
38
|
+
@unmatched_keys = unmatched_keys
|
39
|
+
@routes = routes
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
|
43
|
+
def path(method_name)
|
44
|
+
raise ActionController::UrlGenerationError.new(message, routes, name, method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def params
|
48
|
+
path("unknown")
|
49
|
+
end
|
50
|
+
|
51
|
+
def message
|
52
|
+
message = +"No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}"
|
53
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
54
|
+
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
55
|
+
message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate(name, options, path_parameters)
|
17
60
|
constraints = path_parameters.merge(options)
|
18
|
-
missing_keys =
|
61
|
+
missing_keys = nil
|
19
62
|
|
20
63
|
match_route(name, constraints) do |route|
|
21
|
-
parameterized_parts = extract_parameterized_parts(route, options, path_parameters
|
64
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters)
|
22
65
|
|
23
66
|
# Skip this route unless a name has been provided or it is a
|
24
67
|
# standard Rails route since we can't determine whether an options
|
@@ -26,24 +69,29 @@ module ActionDispatch
|
|
26
69
|
next unless name || route.dispatcher?
|
27
70
|
|
28
71
|
missing_keys = missing_keys(route, parameterized_parts)
|
29
|
-
next
|
72
|
+
next if missing_keys && !missing_keys.empty?
|
30
73
|
params = options.dup.delete_if do |key, _|
|
31
74
|
parameterized_parts.key?(key) || route.defaults.key?(key)
|
32
75
|
end
|
33
76
|
|
34
77
|
defaults = route.defaults
|
35
78
|
required_parts = route.required_parts
|
36
|
-
|
37
|
-
|
79
|
+
|
80
|
+
route.parts.reverse_each do |key|
|
81
|
+
break if defaults[key].nil? && parameterized_parts[key].present?
|
82
|
+
next if parameterized_parts[key].to_s != defaults[key].to_s
|
83
|
+
break if required_parts.include?(key)
|
84
|
+
|
85
|
+
parameterized_parts.delete(key)
|
38
86
|
end
|
39
87
|
|
40
|
-
return
|
88
|
+
return RouteWithParams.new(route, parameterized_parts, params)
|
41
89
|
end
|
42
90
|
|
43
|
-
|
44
|
-
|
91
|
+
unmatched_keys = (missing_keys || []) & constraints.keys
|
92
|
+
missing_keys = (missing_keys || []) - unmatched_keys
|
45
93
|
|
46
|
-
|
94
|
+
MissingRoute.new(constraints, missing_keys, unmatched_keys, routes, name)
|
47
95
|
end
|
48
96
|
|
49
97
|
def clear
|
@@ -51,21 +99,22 @@ module ActionDispatch
|
|
51
99
|
end
|
52
100
|
|
53
101
|
private
|
54
|
-
|
55
|
-
def extract_parameterized_parts(route, options, recall, parameterize = nil)
|
102
|
+
def extract_parameterized_parts(route, options, recall)
|
56
103
|
parameterized_parts = recall.merge(options)
|
57
104
|
|
58
|
-
keys_to_keep = route.parts.
|
59
|
-
!options.key?(part) || (options[part] || recall[part]).nil?
|
105
|
+
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
106
|
+
!(options.key?(part) || route.scope_options.key?(part)) || (options[part] || recall[part]).nil?
|
60
107
|
} | route.required_parts
|
61
108
|
|
62
|
-
|
63
|
-
|
109
|
+
parameterized_parts.delete_if do |bad_key, _|
|
110
|
+
!keys_to_keep.include?(bad_key)
|
64
111
|
end
|
65
112
|
|
66
|
-
|
67
|
-
|
68
|
-
parameterized_parts[k] =
|
113
|
+
parameterized_parts.each do |k, v|
|
114
|
+
if k == :controller
|
115
|
+
parameterized_parts[k] = v
|
116
|
+
else
|
117
|
+
parameterized_parts[k] = v.to_param
|
69
118
|
end
|
70
119
|
end
|
71
120
|
|
@@ -81,28 +130,18 @@ module ActionDispatch
|
|
81
130
|
if named_routes.key?(name)
|
82
131
|
yield named_routes[name]
|
83
132
|
else
|
84
|
-
# Make sure we don't show the deprecation warning more than once
|
85
|
-
warned = false
|
86
|
-
|
87
133
|
routes = non_recursive(cache, options)
|
88
134
|
|
89
|
-
|
135
|
+
supplied_keys = options.each_with_object({}) do |(k, v), h|
|
136
|
+
h[k.to_s] = true if v
|
137
|
+
end
|
138
|
+
|
139
|
+
hash = routes.group_by { |_, r| r.score(supplied_keys) }
|
90
140
|
|
91
141
|
hash.keys.sort.reverse_each do |score|
|
92
142
|
break if score < 0
|
93
143
|
|
94
144
|
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
145
|
yield route
|
107
146
|
end
|
108
147
|
end
|
@@ -127,13 +166,20 @@ module ActionDispatch
|
|
127
166
|
|
128
167
|
# Returns an array populated with missing keys if any are present.
|
129
168
|
def missing_keys(route, parts)
|
130
|
-
missing_keys =
|
131
|
-
tests = route.path.
|
169
|
+
missing_keys = nil
|
170
|
+
tests = route.path.requirements_for_missing_keys_check
|
132
171
|
route.required_parts.each { |key|
|
133
|
-
|
134
|
-
|
172
|
+
case tests[key]
|
173
|
+
when nil
|
174
|
+
unless parts[key]
|
175
|
+
missing_keys ||= []
|
176
|
+
missing_keys << key
|
177
|
+
end
|
135
178
|
else
|
136
|
-
|
179
|
+
unless tests[key].match?(parts[key])
|
180
|
+
missing_keys ||= []
|
181
|
+
missing_keys << key
|
182
|
+
end
|
137
183
|
end
|
138
184
|
}
|
139
185
|
missing_keys
|
@@ -149,7 +195,7 @@ module ActionDispatch
|
|
149
195
|
|
150
196
|
def build_cache
|
151
197
|
root = { ___routes: [] }
|
152
|
-
routes.each_with_index do |route, i|
|
198
|
+
routes.routes.each_with_index do |route, i|
|
153
199
|
leaf = route.required_defaults.inject(root) do |h, tuple|
|
154
200
|
h[tuple] ||= {}
|
155
201
|
end
|
@@ -163,4 +209,5 @@ module ActionDispatch
|
|
163
209
|
end
|
164
210
|
end
|
165
211
|
end
|
212
|
+
# :startdoc:
|
166
213
|
end
|