actionpack 4.1.7 → 4.2.11
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 +404 -451
- data/README.rdoc +7 -2
- data/lib/abstract_controller/base.rb +16 -6
- data/lib/abstract_controller/callbacks.rb +28 -51
- data/lib/abstract_controller/helpers.rb +11 -4
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/rendering.rb +7 -1
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/action_controller/base.rb +3 -2
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +26 -26
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +1 -1
- data/lib/action_controller/metal/head.rb +7 -3
- data/lib/action_controller/metal/http_authentication.rb +20 -10
- data/lib/action_controller/metal/instrumentation.rb +8 -5
- data/lib/action_controller/metal/live.rb +57 -6
- data/lib/action_controller/metal/mime_responds.rb +25 -246
- data/lib/action_controller/metal/params_wrapper.rb +5 -5
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +14 -8
- data/lib/action_controller/metal/renderers.rb +29 -11
- data/lib/action_controller/metal/rendering.rb +2 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +129 -14
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +12 -11
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +4 -0
- data/lib/action_controller/test_case.rb +119 -75
- data/lib/action_controller.rb +1 -1
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/headers.rb +43 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
- data/lib/action_dispatch/http/mime_type.rb +18 -4
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +11 -26
- data/lib/action_dispatch/http/request.rb +37 -11
- data/lib/action_dispatch/http/response.rb +74 -23
- data/lib/action_dispatch/http/upload.rb +9 -8
- data/lib/action_dispatch/http/url.rb +89 -70
- data/lib/action_dispatch/journey/formatter.rb +34 -18
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +52 -60
- data/lib/action_dispatch/journey/parser.y +11 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +4 -19
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router/utils.rb +1 -1
- data/lib/action_dispatch/journey/router.rb +53 -77
- data/lib/action_dispatch/journey/routes.rb +4 -0
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -92
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +34 -34
- data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
- data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
- data/lib/action_dispatch/middleware/flash.rb +13 -7
- data/lib/action_dispatch/middleware/params_parser.rb +1 -1
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
- data/lib/action_dispatch/middleware/ssl.rb +1 -1
- data/lib/action_dispatch/middleware/static.rb +75 -39
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/railtie.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -12
- data/lib/action_dispatch/routing/mapper.rb +414 -283
- data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
- data/lib/action_dispatch/routing/redirection.rb +10 -12
- data/lib/action_dispatch/routing/route_set.rb +300 -173
- data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
- data/lib/action_dispatch/routing/url_for.rb +17 -5
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +2 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +28 -20
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +1 -5
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +55 -13
- data/lib/action_controller/metal/responder.rb +0 -297
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
require 'active_support/core_ext/string/filters'
|
3
|
+
require 'active_support/deprecation'
|
2
4
|
require 'action_dispatch/http/filter_redirect'
|
3
5
|
require 'monitor'
|
4
6
|
|
@@ -97,6 +99,9 @@ module ActionDispatch # :nodoc:
|
|
97
99
|
x
|
98
100
|
end
|
99
101
|
|
102
|
+
def abort
|
103
|
+
end
|
104
|
+
|
100
105
|
def close
|
101
106
|
@response.commit!
|
102
107
|
@closed = true
|
@@ -110,10 +115,11 @@ module ActionDispatch # :nodoc:
|
|
110
115
|
# The underlying body, as a streamable object.
|
111
116
|
attr_reader :stream
|
112
117
|
|
113
|
-
def initialize(status = 200, header = {}, body = [])
|
118
|
+
def initialize(status = 200, header = {}, body = [], options = {})
|
114
119
|
super()
|
115
120
|
|
116
|
-
|
121
|
+
default_headers = options.fetch(:default_headers, self.class.default_headers)
|
122
|
+
header = merge_default_headers(header, default_headers)
|
117
123
|
|
118
124
|
self.body, self.header, self.status = body, header, status
|
119
125
|
|
@@ -207,18 +213,6 @@ module ActionDispatch # :nodoc:
|
|
207
213
|
end
|
208
214
|
alias_method :status_message, :message
|
209
215
|
|
210
|
-
def respond_to?(method, include_private = false)
|
211
|
-
if method.to_s == 'to_path'
|
212
|
-
stream.respond_to?(method)
|
213
|
-
else
|
214
|
-
super
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def to_path
|
219
|
-
stream.to_path
|
220
|
-
end
|
221
|
-
|
222
216
|
# Returns the content of the response as a string. This contains the contents
|
223
217
|
# of any calls to <tt>render</tt>.
|
224
218
|
def body
|
@@ -271,13 +265,39 @@ module ActionDispatch # :nodoc:
|
|
271
265
|
stream.close if stream.respond_to?(:close)
|
272
266
|
end
|
273
267
|
|
268
|
+
def abort
|
269
|
+
if stream.respond_to?(:abort)
|
270
|
+
stream.abort
|
271
|
+
elsif stream.respond_to?(:close)
|
272
|
+
# `stream.close` should really be reserved for a close from the
|
273
|
+
# other direction, but we must fall back to it for
|
274
|
+
# compatibility.
|
275
|
+
stream.close
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
274
279
|
# Turns the Response into a Rack-compatible array of the status, headers,
|
275
|
-
# and body.
|
280
|
+
# and body. Allows explict splatting:
|
281
|
+
#
|
282
|
+
# status, headers, body = *response
|
276
283
|
def to_a
|
277
284
|
rack_response @status, @header.to_hash
|
278
285
|
end
|
279
286
|
alias prepare! to_a
|
280
|
-
|
287
|
+
|
288
|
+
# Be super clear that a response object is not an Array. Defining this
|
289
|
+
# would make implicit splatting work, but it also makes adding responses
|
290
|
+
# as arrays work, and "flattening" responses, cascading to the rack body!
|
291
|
+
# Not sensible behavior.
|
292
|
+
def to_ary
|
293
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
294
|
+
`ActionDispatch::Response#to_ary` no longer performs implicit conversion
|
295
|
+
to an array. Please use `response.to_a` instead, or a splat like `status,
|
296
|
+
headers, body = *response`.
|
297
|
+
MSG
|
298
|
+
|
299
|
+
to_a
|
300
|
+
end
|
281
301
|
|
282
302
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
283
303
|
#
|
@@ -296,9 +316,6 @@ module ActionDispatch # :nodoc:
|
|
296
316
|
cookies
|
297
317
|
end
|
298
318
|
|
299
|
-
def _status_code
|
300
|
-
@status
|
301
|
-
end
|
302
319
|
private
|
303
320
|
|
304
321
|
def before_committed
|
@@ -308,9 +325,7 @@ module ActionDispatch # :nodoc:
|
|
308
325
|
end
|
309
326
|
|
310
327
|
def merge_default_headers(original, default)
|
311
|
-
|
312
|
-
|
313
|
-
default.merge(original)
|
328
|
+
default.respond_to?(:merge) ? default.merge(original) : original
|
314
329
|
end
|
315
330
|
|
316
331
|
def build_buffer(response, body)
|
@@ -337,6 +352,42 @@ module ActionDispatch # :nodoc:
|
|
337
352
|
!@sending_file && @charset != false
|
338
353
|
end
|
339
354
|
|
355
|
+
class RackBody
|
356
|
+
def initialize(response)
|
357
|
+
@response = response
|
358
|
+
end
|
359
|
+
|
360
|
+
def each(*args, &block)
|
361
|
+
@response.each(*args, &block)
|
362
|
+
end
|
363
|
+
|
364
|
+
def close
|
365
|
+
# Rack "close" maps to Response#abort, and *not* Response#close
|
366
|
+
# (which is used when the controller's finished writing)
|
367
|
+
@response.abort
|
368
|
+
end
|
369
|
+
|
370
|
+
def body
|
371
|
+
@response.body
|
372
|
+
end
|
373
|
+
|
374
|
+
def respond_to?(method, include_private = false)
|
375
|
+
if method.to_s == 'to_path'
|
376
|
+
@response.stream.respond_to?(method)
|
377
|
+
else
|
378
|
+
super
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def to_path
|
383
|
+
@response.stream.to_path
|
384
|
+
end
|
385
|
+
|
386
|
+
def to_ary
|
387
|
+
nil
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
340
391
|
def rack_response(status, header)
|
341
392
|
assign_default_content_type_and_charset!(header)
|
342
393
|
handle_conditional_get!
|
@@ -347,7 +398,7 @@ module ActionDispatch # :nodoc:
|
|
347
398
|
header.delete CONTENT_TYPE
|
348
399
|
[status, header, []]
|
349
400
|
else
|
350
|
-
[status, header,
|
401
|
+
[status, header, RackBody.new(self)]
|
351
402
|
end
|
352
403
|
end
|
353
404
|
end
|
@@ -18,6 +18,7 @@ module ActionDispatch
|
|
18
18
|
# A +Tempfile+ object with the actual uploaded file. Note that some of
|
19
19
|
# its interface is available directly.
|
20
20
|
attr_accessor :tempfile
|
21
|
+
alias :to_io :tempfile
|
21
22
|
|
22
23
|
# A string with the headers of the multipart request.
|
23
24
|
attr_accessor :headers
|
@@ -26,7 +27,14 @@ module ActionDispatch
|
|
26
27
|
@tempfile = hash[:tempfile]
|
27
28
|
raise(ArgumentError, ':tempfile is required') unless @tempfile
|
28
29
|
|
29
|
-
@original_filename =
|
30
|
+
@original_filename = hash[:filename]
|
31
|
+
if @original_filename
|
32
|
+
begin
|
33
|
+
@original_filename.encode!(Encoding::UTF_8)
|
34
|
+
rescue EncodingError
|
35
|
+
@original_filename.force_encoding(Encoding::UTF_8)
|
36
|
+
end
|
37
|
+
end
|
30
38
|
@content_type = hash[:type]
|
31
39
|
@headers = hash[:head]
|
32
40
|
end
|
@@ -65,13 +73,6 @@ module ActionDispatch
|
|
65
73
|
def eof?
|
66
74
|
@tempfile.eof?
|
67
75
|
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def encode_filename(filename)
|
72
|
-
# Encode the filename in the utf8 encoding, unless it is nil
|
73
|
-
filename.force_encoding(Encoding::UTF_8).encode! if filename
|
74
|
-
end
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -5,51 +5,83 @@ module ActionDispatch
|
|
5
5
|
module Http
|
6
6
|
module URL
|
7
7
|
IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
|
8
|
-
HOST_REGEXP = /(
|
8
|
+
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
9
9
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
10
10
|
|
11
11
|
mattr_accessor :tld_length
|
12
12
|
self.tld_length = 1
|
13
13
|
|
14
14
|
class << self
|
15
|
-
def extract_domain(host, tld_length
|
16
|
-
host
|
15
|
+
def extract_domain(host, tld_length)
|
16
|
+
extract_domain_from(host, tld_length) if named_host?(host)
|
17
17
|
end
|
18
18
|
|
19
|
-
def extract_subdomains(host, tld_length
|
19
|
+
def extract_subdomains(host, tld_length)
|
20
20
|
if named_host?(host)
|
21
|
-
|
22
|
-
parts[0..-(tld_length + 2)]
|
21
|
+
extract_subdomains_from(host, tld_length)
|
23
22
|
else
|
24
23
|
[]
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
|
-
def extract_subdomain(host, tld_length
|
27
|
+
def extract_subdomain(host, tld_length)
|
29
28
|
extract_subdomains(host, tld_length).join('.')
|
30
29
|
end
|
31
30
|
|
32
|
-
def url_for(options
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def url_for(options)
|
32
|
+
if options[:only_path]
|
33
|
+
path_for options
|
34
|
+
else
|
35
|
+
full_url_for options
|
36
|
+
end
|
37
|
+
end
|
36
38
|
|
37
|
-
|
39
|
+
def full_url_for(options)
|
40
|
+
host = options[:host]
|
41
|
+
protocol = options[:protocol]
|
42
|
+
port = options[:port]
|
38
43
|
|
39
|
-
|
40
|
-
|
44
|
+
unless host
|
45
|
+
raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
|
46
|
+
end
|
41
47
|
|
42
|
-
|
48
|
+
build_host_url(host, port, protocol, options, path_for(options))
|
49
|
+
end
|
43
50
|
|
44
|
-
|
51
|
+
def path_for(options)
|
52
|
+
path = options[:script_name].to_s.chomp("/")
|
53
|
+
path << options[:path] if options.key?(:path)
|
45
54
|
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
56
|
+
add_params(path, options[:params]) if options.key?(:params)
|
57
|
+
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
58
|
+
|
59
|
+
path
|
49
60
|
end
|
50
61
|
|
51
62
|
private
|
52
63
|
|
64
|
+
def add_params(path, params)
|
65
|
+
params = { params: params } unless params.is_a?(Hash)
|
66
|
+
params.reject! { |_,v| v.to_param.nil? }
|
67
|
+
path << "?#{params.to_query}" unless params.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_anchor(path, anchor)
|
71
|
+
if anchor
|
72
|
+
path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def extract_domain_from(host, tld_length)
|
77
|
+
host.split('.').last(1 + tld_length).join('.')
|
78
|
+
end
|
79
|
+
|
80
|
+
def extract_subdomains_from(host, tld_length)
|
81
|
+
parts = host.split('.')
|
82
|
+
parts[0..-(tld_length + 2)]
|
83
|
+
end
|
84
|
+
|
53
85
|
def add_trailing_slash(path)
|
54
86
|
# includes querysting
|
55
87
|
if path.include?('?')
|
@@ -58,54 +90,38 @@ module ActionDispatch
|
|
58
90
|
elsif !path.include?(".")
|
59
91
|
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
60
92
|
end
|
61
|
-
|
62
|
-
path
|
63
93
|
end
|
64
94
|
|
65
|
-
def build_host_url(options)
|
66
|
-
if
|
67
|
-
|
95
|
+
def build_host_url(host, port, protocol, options, path)
|
96
|
+
if match = host.match(HOST_REGEXP)
|
97
|
+
protocol ||= match[1] unless protocol == false
|
98
|
+
host = match[2]
|
99
|
+
port = match[3] unless options.key? :port
|
68
100
|
end
|
69
101
|
|
70
|
-
|
102
|
+
protocol = normalize_protocol protocol
|
103
|
+
host = normalize_host(host, options)
|
71
104
|
|
72
|
-
|
73
|
-
if match = options[:host].match(HOST_REGEXP)
|
74
|
-
options[:protocol] ||= match[1] unless options[:protocol] == false
|
75
|
-
options[:host] = match[2]
|
76
|
-
options[:port] = match[3] unless options.key?(:port)
|
77
|
-
end
|
105
|
+
result = protocol.dup
|
78
106
|
|
79
|
-
|
80
|
-
options[:
|
81
|
-
options[:port] = normalize_port(options)
|
82
|
-
|
83
|
-
result << options[:protocol]
|
84
|
-
result << rewrite_authentication(options)
|
85
|
-
result << options[:host]
|
86
|
-
result << ":#{options[:port]}" if options[:port]
|
107
|
+
if options[:user] && options[:password]
|
108
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
87
109
|
end
|
88
|
-
result
|
89
|
-
end
|
90
110
|
|
91
|
-
|
92
|
-
|
93
|
-
|
111
|
+
result << host
|
112
|
+
normalize_port(port, protocol) { |normalized_port|
|
113
|
+
result << ":#{normalized_port}"
|
114
|
+
}
|
94
115
|
|
95
|
-
|
96
|
-
(options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
|
116
|
+
result.concat path
|
97
117
|
end
|
98
118
|
|
99
|
-
def
|
100
|
-
|
101
|
-
"#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
102
|
-
else
|
103
|
-
""
|
104
|
-
end
|
119
|
+
def named_host?(host)
|
120
|
+
IP_HOST_REGEXP !~ host
|
105
121
|
end
|
106
122
|
|
107
|
-
def normalize_protocol(
|
108
|
-
case
|
123
|
+
def normalize_protocol(protocol)
|
124
|
+
case protocol
|
109
125
|
when nil
|
110
126
|
"http://"
|
111
127
|
when false, "//"
|
@@ -113,36 +129,39 @@ module ActionDispatch
|
|
113
129
|
when PROTOCOL_REGEXP
|
114
130
|
"#{$1}://"
|
115
131
|
else
|
116
|
-
raise ArgumentError, "Invalid :protocol option: #{
|
132
|
+
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
117
133
|
end
|
118
134
|
end
|
119
135
|
|
120
|
-
def normalize_host(options)
|
121
|
-
return
|
136
|
+
def normalize_host(_host, options)
|
137
|
+
return _host unless named_host?(_host)
|
122
138
|
|
123
139
|
tld_length = options[:tld_length] || @@tld_length
|
140
|
+
subdomain = options.fetch :subdomain, true
|
141
|
+
domain = options[:domain]
|
124
142
|
|
125
143
|
host = ""
|
126
|
-
if
|
127
|
-
|
128
|
-
|
129
|
-
host <<
|
144
|
+
if subdomain == true
|
145
|
+
return _host if domain.nil?
|
146
|
+
|
147
|
+
host << extract_subdomains_from(_host, tld_length).join('.')
|
148
|
+
elsif subdomain
|
149
|
+
host << subdomain.to_param
|
130
150
|
end
|
131
151
|
host << "." unless host.empty?
|
132
|
-
host << (
|
152
|
+
host << (domain || extract_domain_from(_host, tld_length))
|
133
153
|
host
|
134
154
|
end
|
135
155
|
|
136
|
-
def normalize_port(
|
137
|
-
return
|
156
|
+
def normalize_port(port, protocol)
|
157
|
+
return unless port
|
138
158
|
|
139
|
-
case
|
140
|
-
when "//"
|
141
|
-
options[:port]
|
159
|
+
case protocol
|
160
|
+
when "//" then yield port
|
142
161
|
when "https://"
|
143
|
-
|
162
|
+
yield port unless port.to_i == 443
|
144
163
|
else
|
145
|
-
|
164
|
+
yield port unless port.to_i == 80
|
146
165
|
end
|
147
166
|
end
|
148
167
|
end
|
@@ -165,7 +184,7 @@ module ActionDispatch
|
|
165
184
|
|
166
185
|
# Returns the \host for this request, such as "example.com".
|
167
186
|
def raw_host_with_port
|
168
|
-
if forwarded = env["HTTP_X_FORWARDED_HOST"]
|
187
|
+
if forwarded = env["HTTP_X_FORWARDED_HOST"].presence
|
169
188
|
forwarded.split(/,\s?/).last
|
170
189
|
else
|
171
190
|
env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'action_controller/metal/exceptions'
|
2
|
+
require 'active_support/deprecation'
|
2
3
|
|
3
4
|
module ActionDispatch
|
4
5
|
module Journey
|
@@ -12,12 +13,12 @@ module ActionDispatch
|
|
12
13
|
@cache = nil
|
13
14
|
end
|
14
15
|
|
15
|
-
def generate(
|
16
|
-
constraints =
|
16
|
+
def generate(name, options, path_parameters, parameterize = nil)
|
17
|
+
constraints = path_parameters.merge(options)
|
17
18
|
missing_keys = []
|
18
19
|
|
19
20
|
match_route(name, constraints) do |route|
|
20
|
-
parameterized_parts = extract_parameterized_parts(route, options,
|
21
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
|
21
22
|
|
22
23
|
# Skip this route unless a name has been provided or it is a
|
23
24
|
# standard Rails route since we can't determine whether an options
|
@@ -30,11 +31,17 @@ module ActionDispatch
|
|
30
31
|
parameterized_parts.key?(key) || route.defaults.key?(key)
|
31
32
|
end
|
32
33
|
|
34
|
+
defaults = route.defaults
|
35
|
+
required_parts = route.required_parts
|
36
|
+
parameterized_parts.delete_if do |key, value|
|
37
|
+
value.to_s == defaults[key].to_s && !required_parts.include?(key)
|
38
|
+
end
|
39
|
+
|
33
40
|
return [route.format(parameterized_parts), params]
|
34
41
|
end
|
35
42
|
|
36
|
-
message = "No route matches #{Hash[constraints.
|
37
|
-
message << " missing required keys: #{missing_keys.sort.inspect}"
|
43
|
+
message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}"
|
44
|
+
message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
|
38
45
|
|
39
46
|
raise ActionController::UrlGenerationError, message
|
40
47
|
end
|
@@ -74,14 +81,28 @@ module ActionDispatch
|
|
74
81
|
if named_routes.key?(name)
|
75
82
|
yield named_routes[name]
|
76
83
|
else
|
77
|
-
|
84
|
+
# Make sure we don't show the deprecation warning more than once
|
85
|
+
warned = false
|
86
|
+
|
87
|
+
routes = non_recursive(cache, options)
|
78
88
|
|
79
89
|
hash = routes.group_by { |_, r| r.score(options) }
|
80
90
|
|
81
91
|
hash.keys.sort.reverse_each do |score|
|
82
|
-
|
92
|
+
break if score < 0
|
83
93
|
|
84
94
|
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
|
+
|
85
106
|
yield route
|
86
107
|
end
|
87
108
|
end
|
@@ -90,14 +111,14 @@ module ActionDispatch
|
|
90
111
|
|
91
112
|
def non_recursive(cache, options)
|
92
113
|
routes = []
|
93
|
-
|
114
|
+
queue = [cache]
|
94
115
|
|
95
|
-
while
|
96
|
-
c =
|
116
|
+
while queue.any?
|
117
|
+
c = queue.shift
|
97
118
|
routes.concat(c[:___routes]) if c.key?(:___routes)
|
98
119
|
|
99
120
|
options.each do |pair|
|
100
|
-
|
121
|
+
queue << c[pair] if c.key?(pair)
|
101
122
|
end
|
102
123
|
end
|
103
124
|
|
@@ -121,14 +142,9 @@ module ActionDispatch
|
|
121
142
|
def possibles(cache, options, depth = 0)
|
122
143
|
cache.fetch(:___routes) { [] } + options.find_all { |pair|
|
123
144
|
cache.key?(pair)
|
124
|
-
}.
|
145
|
+
}.flat_map { |pair|
|
125
146
|
possibles(cache[pair], options, depth + 1)
|
126
|
-
}
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns +true+ if no missing keys are present, otherwise +false+.
|
130
|
-
def verify_required_parts!(route, parts)
|
131
|
-
missing_keys(route, parts).empty?
|
147
|
+
}
|
132
148
|
end
|
133
149
|
|
134
150
|
def build_cache
|