actionpack 5.2.7.1 → 6.0.0.beta1
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 +109 -472
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -21
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +17 -57
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +21 -22
- data/lib/action_controller/metal/implicit_render.rb +2 -12
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +28 -26
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +18 -14
- data/lib/action_controller/metal/redirecting.rb +32 -11
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +32 -97
- data/lib/action_controller/metal/strong_parameters.rb +57 -34
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +5 -9
- data/lib/action_controller.rb +1 -0
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +17 -8
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -10
- data/lib/action_dispatch/http/mime_type.rb +1 -5
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +14 -14
- data/lib/action_dispatch/http/upload.rb +5 -0
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +1 -1
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +3 -4
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +49 -70
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +50 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -14
- data/lib/action_dispatch/middleware/session/cache_store.rb +6 -11
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -27
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- 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 +20 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- 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 +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +1 -0
- data/lib/action_dispatch/request/session.rb +8 -6
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +7 -12
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/routing.rb +3 -2
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
- data/lib/action_dispatch/testing/integration.rb +11 -5
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +7 -6
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +25 -23
@@ -1,86 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/
|
3
|
+
require "active_support/deprecation/constant_accessor"
|
4
|
+
require "active_support/parameter_filter"
|
4
5
|
|
5
6
|
module ActionDispatch
|
6
7
|
module Http
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(filters = [])
|
11
|
-
@filters = filters
|
12
|
-
end
|
13
|
-
|
14
|
-
def filter(params)
|
15
|
-
compiled_filter.call(params)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def compiled_filter
|
21
|
-
@compiled_filter ||= CompiledFilter.compile(@filters)
|
22
|
-
end
|
23
|
-
|
24
|
-
class CompiledFilter # :nodoc:
|
25
|
-
def self.compile(filters)
|
26
|
-
return lambda { |params| params.dup } if filters.empty?
|
27
|
-
|
28
|
-
strings, regexps, blocks = [], [], []
|
29
|
-
|
30
|
-
filters.each do |item|
|
31
|
-
case item
|
32
|
-
when Proc
|
33
|
-
blocks << item
|
34
|
-
when Regexp
|
35
|
-
regexps << item
|
36
|
-
else
|
37
|
-
strings << Regexp.escape(item.to_s)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
|
42
|
-
deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
|
43
|
-
|
44
|
-
regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
|
45
|
-
deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
|
46
|
-
|
47
|
-
new regexps, deep_regexps, blocks
|
48
|
-
end
|
49
|
-
|
50
|
-
attr_reader :regexps, :deep_regexps, :blocks
|
51
|
-
|
52
|
-
def initialize(regexps, deep_regexps, blocks)
|
53
|
-
@regexps = regexps
|
54
|
-
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
55
|
-
@blocks = blocks
|
56
|
-
end
|
57
|
-
|
58
|
-
def call(original_params, parents = [])
|
59
|
-
filtered_params = original_params.class.new
|
60
|
-
|
61
|
-
original_params.each do |key, value|
|
62
|
-
parents.push(key) if deep_regexps
|
63
|
-
if regexps.any? { |r| key =~ r }
|
64
|
-
value = FILTERED
|
65
|
-
elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
|
66
|
-
value = FILTERED
|
67
|
-
elsif value.is_a?(Hash)
|
68
|
-
value = call(value, parents)
|
69
|
-
elsif value.is_a?(Array)
|
70
|
-
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
|
71
|
-
elsif blocks.any?
|
72
|
-
key = key.dup if key.duplicable?
|
73
|
-
value = value.dup if value.duplicable?
|
74
|
-
blocks.each { |b| b.call(key, value) }
|
75
|
-
end
|
76
|
-
parents.pop if deep_regexps
|
77
|
-
|
78
|
-
filtered_params[key] = value
|
79
|
-
end
|
80
|
-
|
81
|
-
filtered_params
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
8
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
9
|
+
deprecate_constant "ParameterFilter", "ActiveSupport::ParameterFilter",
|
10
|
+
message: "ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead."
|
85
11
|
end
|
86
12
|
end
|
@@ -111,13 +111,23 @@ module ActionDispatch
|
|
111
111
|
begin
|
112
112
|
strategy.call(raw_post)
|
113
113
|
rescue # JSON or Ruby code block errors.
|
114
|
-
|
115
|
-
my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
|
116
|
-
|
114
|
+
log_parse_error_once
|
117
115
|
raise ParseError
|
118
116
|
end
|
119
117
|
end
|
120
118
|
|
119
|
+
def log_parse_error_once
|
120
|
+
@parse_error_logged ||= begin
|
121
|
+
parse_logger = logger || ActiveSupport::Logger.new($stderr)
|
122
|
+
parse_logger.debug <<~MSG.chomp
|
123
|
+
Error occurred while parsing request parameters.
|
124
|
+
Contents:
|
125
|
+
|
126
|
+
#{raw_post}
|
127
|
+
MSG
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
121
131
|
def params_parsers
|
122
132
|
ActionDispatch::Request.parameter_parsers
|
123
133
|
end
|
@@ -136,11 +136,11 @@ module ActionDispatch
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def routes # :nodoc:
|
139
|
-
get_header("action_dispatch.routes"
|
139
|
+
get_header("action_dispatch.routes")
|
140
140
|
end
|
141
141
|
|
142
142
|
def routes=(routes) # :nodoc:
|
143
|
-
set_header("action_dispatch.routes"
|
143
|
+
set_header("action_dispatch.routes", routes)
|
144
144
|
end
|
145
145
|
|
146
146
|
def engine_script_name(_routes) # :nodoc:
|
@@ -158,11 +158,11 @@ module ActionDispatch
|
|
158
158
|
end
|
159
159
|
|
160
160
|
def controller_instance # :nodoc:
|
161
|
-
get_header("action_controller.instance"
|
161
|
+
get_header("action_controller.instance")
|
162
162
|
end
|
163
163
|
|
164
164
|
def controller_instance=(controller) # :nodoc:
|
165
|
-
set_header("action_controller.instance"
|
165
|
+
set_header("action_controller.instance", controller)
|
166
166
|
end
|
167
167
|
|
168
168
|
def http_auth_salt
|
@@ -173,7 +173,7 @@ module ActionDispatch
|
|
173
173
|
# We're treating `nil` as "unset", and we want the default setting to be
|
174
174
|
# `true`. This logic should be extracted to `env_config` and calculated
|
175
175
|
# once.
|
176
|
-
!(get_header("action_dispatch.show_exceptions"
|
176
|
+
!(get_header("action_dispatch.show_exceptions") == false)
|
177
177
|
end
|
178
178
|
|
179
179
|
# Returns a symbol form of the #request_method.
|
@@ -280,10 +280,10 @@ module ActionDispatch
|
|
280
280
|
end
|
281
281
|
|
282
282
|
def remote_ip=(remote_ip)
|
283
|
-
set_header "action_dispatch.remote_ip"
|
283
|
+
set_header "action_dispatch.remote_ip", remote_ip
|
284
284
|
end
|
285
285
|
|
286
|
-
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id"
|
286
|
+
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
287
287
|
|
288
288
|
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
289
289
|
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
@@ -383,9 +383,6 @@ module ActionDispatch
|
|
383
383
|
end
|
384
384
|
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
385
385
|
end
|
386
|
-
rescue Http::Parameters::ParseError # one of the parse strategies blew up
|
387
|
-
self.request_parameters = Request::Utils.normalize_encode_params(super || {})
|
388
|
-
raise
|
389
386
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
390
387
|
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
391
388
|
end
|
@@ -407,18 +404,18 @@ module ActionDispatch
|
|
407
404
|
|
408
405
|
def request_parameters=(params)
|
409
406
|
raise if params.nil?
|
410
|
-
set_header("action_dispatch.request.request_parameters"
|
407
|
+
set_header("action_dispatch.request.request_parameters", params)
|
411
408
|
end
|
412
409
|
|
413
410
|
def logger
|
414
|
-
get_header("action_dispatch.logger"
|
411
|
+
get_header("action_dispatch.logger")
|
415
412
|
end
|
416
413
|
|
417
414
|
def commit_flash
|
418
415
|
end
|
419
416
|
|
420
417
|
def ssl?
|
421
|
-
super || scheme == "wss"
|
418
|
+
super || scheme == "wss"
|
422
419
|
end
|
423
420
|
|
424
421
|
private
|
@@ -78,9 +78,9 @@ module ActionDispatch # :nodoc:
|
|
78
78
|
x
|
79
79
|
end
|
80
80
|
|
81
|
-
CONTENT_TYPE = "Content-Type"
|
82
|
-
SET_COOKIE = "Set-Cookie"
|
83
|
-
LOCATION = "Location"
|
81
|
+
CONTENT_TYPE = "Content-Type"
|
82
|
+
SET_COOKIE = "Set-Cookie"
|
83
|
+
LOCATION = "Location"
|
84
84
|
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
|
85
85
|
|
86
86
|
cattr_accessor :default_charset, default: "utf-8"
|
@@ -105,7 +105,7 @@ module ActionDispatch # :nodoc:
|
|
105
105
|
|
106
106
|
def body
|
107
107
|
@str_body ||= begin
|
108
|
-
buf = ""
|
108
|
+
buf = +""
|
109
109
|
each { |chunk| buf << chunk }
|
110
110
|
buf
|
111
111
|
end
|
@@ -224,16 +224,6 @@ module ActionDispatch # :nodoc:
|
|
224
224
|
@status = Rack::Utils.status_code(status)
|
225
225
|
end
|
226
226
|
|
227
|
-
# Sets the HTTP content type.
|
228
|
-
def content_type=(content_type)
|
229
|
-
return unless content_type
|
230
|
-
new_header_info = parse_content_type(content_type.to_s)
|
231
|
-
prev_header_info = parsed_content_type_header
|
232
|
-
charset = new_header_info.charset || prev_header_info.charset
|
233
|
-
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
234
|
-
set_content_type new_header_info.mime_type, charset
|
235
|
-
end
|
236
|
-
|
237
227
|
# Sets the HTTP response's content MIME type. For example, in the controller
|
238
228
|
# you could write this:
|
239
229
|
#
|
@@ -242,7 +232,17 @@ module ActionDispatch # :nodoc:
|
|
242
232
|
# If a character set has been defined for this response (see charset=) then
|
243
233
|
# the character set information will also be included in the content type
|
244
234
|
# information.
|
235
|
+
def content_type=(content_type)
|
236
|
+
return unless content_type
|
237
|
+
new_header_info = parse_content_type(content_type.to_s)
|
238
|
+
prev_header_info = parsed_content_type_header
|
239
|
+
charset = new_header_info.charset || prev_header_info.charset
|
240
|
+
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
241
|
+
set_content_type new_header_info.mime_type, charset
|
242
|
+
end
|
245
243
|
|
244
|
+
# Content type of response.
|
245
|
+
# It returns just MIME type and does NOT contain charset part.
|
246
246
|
def content_type
|
247
247
|
parsed_content_type_header.mime_type
|
248
248
|
end
|
@@ -67,7 +67,7 @@ module ActionDispatch
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def path_for(options)
|
70
|
-
path = options[:script_name].to_s.chomp("/"
|
70
|
+
path = options[:script_name].to_s.chomp("/")
|
71
71
|
path << options[:path] if options.key?(:path)
|
72
72
|
|
73
73
|
add_trailing_slash(path) if options[:trailing_slash]
|
@@ -79,108 +79,108 @@ module ActionDispatch
|
|
79
79
|
|
80
80
|
private
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
def add_anchor(path, anchor)
|
90
|
-
if anchor
|
91
|
-
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?
|
92
87
|
end
|
93
|
-
end
|
94
88
|
|
95
|
-
|
96
|
-
|
97
|
-
|
89
|
+
def add_anchor(path, anchor)
|
90
|
+
if anchor
|
91
|
+
path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
|
92
|
+
end
|
93
|
+
end
|
98
94
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
95
|
+
def extract_domain_from(host, tld_length)
|
96
|
+
host.split(".").last(1 + tld_length).join(".")
|
97
|
+
end
|
103
98
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
elsif !path.include?(".")
|
108
|
-
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
99
|
+
def extract_subdomains_from(host, tld_length)
|
100
|
+
parts = host.split(".")
|
101
|
+
parts[0..-(tld_length + 2)]
|
109
102
|
end
|
110
|
-
end
|
111
103
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
117
110
|
end
|
118
111
|
|
119
|
-
|
120
|
-
|
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
|
121
118
|
|
122
|
-
|
119
|
+
protocol = normalize_protocol protocol
|
120
|
+
host = normalize_host(host, options)
|
123
121
|
|
124
|
-
|
125
|
-
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
126
|
-
end
|
122
|
+
result = protocol.dup
|
127
123
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
}
|
124
|
+
if options[:user] && options[:password]
|
125
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
126
|
+
end
|
132
127
|
|
133
|
-
|
134
|
-
|
128
|
+
result << host
|
129
|
+
normalize_port(port, protocol) { |normalized_port|
|
130
|
+
result << ":#{normalized_port}"
|
131
|
+
}
|
135
132
|
|
136
|
-
|
137
|
-
|
138
|
-
end
|
133
|
+
result.concat path
|
134
|
+
end
|
139
135
|
|
140
|
-
|
141
|
-
|
142
|
-
when nil
|
143
|
-
"http://"
|
144
|
-
when false, "//"
|
145
|
-
"//"
|
146
|
-
when PROTOCOL_REGEXP
|
147
|
-
"#{$1}://"
|
148
|
-
else
|
149
|
-
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
136
|
+
def named_host?(host)
|
137
|
+
IP_HOST_REGEXP !~ host
|
150
138
|
end
|
151
|
-
end
|
152
139
|
|
153
|
-
|
154
|
-
|
140
|
+
def normalize_protocol(protocol)
|
141
|
+
case protocol
|
142
|
+
when nil
|
143
|
+
"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
|
155
152
|
|
156
|
-
|
157
|
-
|
158
|
-
domain = options[:domain]
|
153
|
+
def normalize_host(_host, options)
|
154
|
+
return _host unless named_host?(_host)
|
159
155
|
|
160
|
-
|
161
|
-
|
162
|
-
|
156
|
+
tld_length = options[:tld_length] || @@tld_length
|
157
|
+
subdomain = options.fetch :subdomain, true
|
158
|
+
domain = options[:domain]
|
163
159
|
|
164
|
-
host
|
165
|
-
|
166
|
-
|
160
|
+
host = +""
|
161
|
+
if subdomain == true
|
162
|
+
return _host if domain.nil?
|
163
|
+
|
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
|
167
171
|
end
|
168
|
-
host << "." unless host.empty?
|
169
|
-
host << (domain || extract_domain_from(_host, tld_length))
|
170
|
-
host
|
171
|
-
end
|
172
172
|
|
173
|
-
|
174
|
-
|
173
|
+
def normalize_port(port, protocol)
|
174
|
+
return unless port
|
175
175
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
182
183
|
end
|
183
|
-
end
|
184
184
|
end
|
185
185
|
|
186
186
|
def initialize
|
@@ -231,7 +231,7 @@ module ActionDispatch
|
|
231
231
|
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
232
232
|
# req.host # => "example.com"
|
233
233
|
def host
|
234
|
-
raw_host_with_port.sub(/:\d+$/, ""
|
234
|
+
raw_host_with_port.sub(/:\d+$/, "")
|
235
235
|
end
|
236
236
|
|
237
237
|
# Returns a \host:\port string for this request, such as "example.com" or
|
@@ -50,7 +50,7 @@ module ActionDispatch
|
|
50
50
|
unmatched_keys = (missing_keys || []) & constraints.keys
|
51
51
|
missing_keys = (missing_keys || []) - unmatched_keys
|
52
52
|
|
53
|
-
message = "No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}"
|
53
|
+
message = +"No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}"
|
54
54
|
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
55
55
|
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
56
56
|
|
@@ -32,7 +32,7 @@ module ActionDispatch
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def name
|
35
|
-
left.tr
|
35
|
+
-left.tr("*:", "")
|
36
36
|
end
|
37
37
|
|
38
38
|
def type
|
@@ -65,12 +65,12 @@ module ActionDispatch
|
|
65
65
|
def literal?; false; end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
class Slash < Terminal # :nodoc:
|
69
|
+
def type; :SLASH; end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Dot < Terminal # :nodoc:
|
73
|
+
def type; :DOT; end
|
74
74
|
end
|
75
75
|
|
76
76
|
class Symbol < Terminal # :nodoc:
|
@@ -82,13 +82,14 @@ module ActionDispatch
|
|
82
82
|
def initialize(left)
|
83
83
|
super
|
84
84
|
@regexp = DEFAULT_EXP
|
85
|
-
@name = left.tr
|
85
|
+
@name = -left.tr("*:", "")
|
86
86
|
end
|
87
87
|
|
88
88
|
def default_regexp?
|
89
89
|
regexp == DEFAULT_EXP
|
90
90
|
end
|
91
91
|
|
92
|
+
def type; :SYMBOL; end
|
92
93
|
def symbol?; true; end
|
93
94
|
end
|
94
95
|
|
@@ -90,7 +90,7 @@ module ActionDispatch
|
|
90
90
|
return @separator_re unless @matchers.key?(node)
|
91
91
|
|
92
92
|
re = @matchers[node]
|
93
|
-
"(#{re})"
|
93
|
+
"(#{Regexp.union(re)})"
|
94
94
|
end
|
95
95
|
|
96
96
|
def visit_GROUP(node)
|
@@ -119,8 +119,7 @@ module ActionDispatch
|
|
119
119
|
|
120
120
|
class UnanchoredRegexp < AnchoredRegexp # :nodoc:
|
121
121
|
def accept(node)
|
122
|
-
|
123
|
-
path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
|
122
|
+
%r{\A#{visit node}}
|
124
123
|
end
|
125
124
|
end
|
126
125
|
|
@@ -184,7 +183,7 @@ module ActionDispatch
|
|
184
183
|
node = node.to_sym
|
185
184
|
|
186
185
|
if @requirements.key?(node)
|
187
|
-
re = /#{@requirements[node]}|/
|
186
|
+
re = /#{Regexp.union(@requirements[node])}|/
|
188
187
|
@offsets.push((re.match("").length - 1) + @offsets.last)
|
189
188
|
else
|
190
189
|
@offsets << @offsets.last
|
@@ -17,11 +17,11 @@ module ActionDispatch
|
|
17
17
|
def self.normalize_path(path)
|
18
18
|
path ||= ""
|
19
19
|
encoding = path.encoding
|
20
|
-
path = "/#{path}"
|
21
|
-
path.squeeze!("/"
|
22
|
-
path.sub!(%r{/+\Z}, ""
|
20
|
+
path = +"/#{path}"
|
21
|
+
path.squeeze!("/")
|
22
|
+
path.sub!(%r{/+\Z}, "")
|
23
23
|
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
24
|
-
path = "/"
|
24
|
+
path = +"/" if path == ""
|
25
25
|
path.force_encoding(encoding)
|
26
26
|
path
|
27
27
|
end
|
@@ -29,16 +29,16 @@ module ActionDispatch
|
|
29
29
|
# URI path and fragment escaping
|
30
30
|
# https://tools.ietf.org/html/rfc3986
|
31
31
|
class UriEncoder # :nodoc:
|
32
|
-
ENCODE = "%%%02X"
|
32
|
+
ENCODE = "%%%02X"
|
33
33
|
US_ASCII = Encoding::US_ASCII
|
34
34
|
UTF_8 = Encoding::UTF_8
|
35
|
-
EMPTY = "".
|
35
|
+
EMPTY = (+"").force_encoding(US_ASCII).freeze
|
36
36
|
DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
|
37
37
|
|
38
|
-
ALPHA = "a-zA-Z"
|
39
|
-
DIGIT = "0-9"
|
40
|
-
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
41
|
-
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
38
|
+
ALPHA = "a-zA-Z"
|
39
|
+
DIGIT = "0-9"
|
40
|
+
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
41
|
+
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
42
42
|
|
43
43
|
ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
|
44
44
|
|
@@ -34,6 +34,13 @@ module ActionDispatch
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
+
# takes advantage of String @- deduping capabilities in Ruby 2.5 upwards
|
38
|
+
# see: https://bugs.ruby-lang.org/issues/13077
|
39
|
+
def dedup_scan(regex)
|
40
|
+
r = @ss.scan(regex)
|
41
|
+
r ? -r : nil
|
42
|
+
end
|
43
|
+
|
37
44
|
def scan
|
38
45
|
case
|
39
46
|
# /
|
@@ -47,15 +54,15 @@ module ActionDispatch
|
|
47
54
|
[:OR, "|"]
|
48
55
|
when @ss.skip(/\./)
|
49
56
|
[:DOT, "."]
|
50
|
-
when text =
|
57
|
+
when text = dedup_scan(/:\w+/)
|
51
58
|
[:SYMBOL, text]
|
52
|
-
when text =
|
59
|
+
when text = dedup_scan(/\*\w+/)
|
53
60
|
[:STAR, text]
|
54
61
|
when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
|
55
62
|
text.tr! "\\", ""
|
56
|
-
[:LITERAL, text]
|
63
|
+
[:LITERAL, -text]
|
57
64
|
# any char
|
58
|
-
when text =
|
65
|
+
when text = dedup_scan(/./)
|
59
66
|
[:LITERAL, text]
|
60
67
|
end
|
61
68
|
end
|