actionpack 5.2.3.rc1 → 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 +124 -337
- 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.rb +1 -0
- 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 +20 -21
- 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 +16 -12
- 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 +22 -11
- data/lib/action_controller/metal/strong_parameters.rb +57 -32
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +1 -4
- data/lib/action_dispatch.rb +3 -1
- 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 +9 -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 +18 -17
- 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 -3
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- 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/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/cookie_store.rb +4 -10
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- 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 -0
- data/lib/action_dispatch/routing.rb +3 -2
- 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 +3 -4
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- 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 -4
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +19 -11
@@ -121,7 +121,7 @@ module ActionDispatch
|
|
121
121
|
# not contained within the headers hash.
|
122
122
|
def env_name(key)
|
123
123
|
key = key.to_s
|
124
|
-
if key
|
124
|
+
if HTTP_HEADER.match?(key)
|
125
125
|
key = key.upcase.tr("-", "_")
|
126
126
|
key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
|
127
127
|
end
|
@@ -7,6 +7,11 @@ module ActionDispatch
|
|
7
7
|
module MimeNegotiation
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
|
+
RESCUABLE_MIME_FORMAT_ERRORS = [
|
11
|
+
ActionController::BadRequest,
|
12
|
+
ActionDispatch::Http::Parameters::ParseError,
|
13
|
+
]
|
14
|
+
|
10
15
|
included do
|
11
16
|
mattr_accessor :ignore_accept_header, default: false
|
12
17
|
end
|
@@ -59,7 +64,7 @@ module ActionDispatch
|
|
59
64
|
fetch_header("action_dispatch.request.formats") do |k|
|
60
65
|
params_readable = begin
|
61
66
|
parameters[:format]
|
62
|
-
rescue
|
67
|
+
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
63
68
|
false
|
64
69
|
end
|
65
70
|
|
@@ -74,11 +79,6 @@ module ActionDispatch
|
|
74
79
|
else
|
75
80
|
[Mime[:html]]
|
76
81
|
end
|
77
|
-
|
78
|
-
v = v.select do |format|
|
79
|
-
format.symbol || format.ref == "*/*"
|
80
|
-
end
|
81
|
-
|
82
82
|
set_header k, v
|
83
83
|
end
|
84
84
|
end
|
@@ -90,10 +90,7 @@ module ActionDispatch
|
|
90
90
|
if variant.all? { |v| v.is_a?(Symbol) }
|
91
91
|
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
92
92
|
else
|
93
|
-
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols.
|
94
|
-
"For security reasons, never directly set the variant to a user-provided value, " \
|
95
|
-
"like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
|
96
|
-
"then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
|
93
|
+
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
|
97
94
|
end
|
98
95
|
end
|
99
96
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# -*- frozen-string-literal: true -*-
|
4
|
-
|
5
3
|
require "singleton"
|
6
4
|
require "active_support/core_ext/string/starts_ends_with"
|
7
5
|
|
@@ -74,7 +72,7 @@ module Mime
|
|
74
72
|
def initialize(index, name, q = nil)
|
75
73
|
@index = index
|
76
74
|
@name = name
|
77
|
-
q ||= 0.0 if @name == "*/*"
|
75
|
+
q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
|
78
76
|
@q = ((q || 1.0).to_f * 100).to_i
|
79
77
|
end
|
80
78
|
|
@@ -279,8 +277,6 @@ module Mime
|
|
279
277
|
|
280
278
|
def all?; false; end
|
281
279
|
|
282
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
283
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
284
280
|
protected
|
285
281
|
|
286
282
|
attr_reader :string, :synonyms
|
@@ -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,11 +78,10 @@ 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
|
-
CONTENT_TYPE_PARSER = /\A(?<type>[^;\s]+)?(?:.*;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?/ # :nodoc:
|
86
85
|
|
87
86
|
cattr_accessor :default_charset, default: "utf-8"
|
88
87
|
cattr_accessor :default_headers
|
@@ -106,7 +105,7 @@ module ActionDispatch # :nodoc:
|
|
106
105
|
|
107
106
|
def body
|
108
107
|
@str_body ||= begin
|
109
|
-
buf = ""
|
108
|
+
buf = +""
|
110
109
|
each { |chunk| buf << chunk }
|
111
110
|
buf
|
112
111
|
end
|
@@ -225,16 +224,6 @@ module ActionDispatch # :nodoc:
|
|
225
224
|
@status = Rack::Utils.status_code(status)
|
226
225
|
end
|
227
226
|
|
228
|
-
# Sets the HTTP content type.
|
229
|
-
def content_type=(content_type)
|
230
|
-
return unless content_type
|
231
|
-
new_header_info = parse_content_type(content_type.to_s)
|
232
|
-
prev_header_info = parsed_content_type_header
|
233
|
-
charset = new_header_info.charset || prev_header_info.charset
|
234
|
-
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
235
|
-
set_content_type new_header_info.mime_type, charset
|
236
|
-
end
|
237
|
-
|
238
227
|
# Sets the HTTP response's content MIME type. For example, in the controller
|
239
228
|
# you could write this:
|
240
229
|
#
|
@@ -243,7 +232,17 @@ module ActionDispatch # :nodoc:
|
|
243
232
|
# If a character set has been defined for this response (see charset=) then
|
244
233
|
# the character set information will also be included in the content type
|
245
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
|
246
243
|
|
244
|
+
# Content type of response.
|
245
|
+
# It returns just MIME type and does NOT contain charset part.
|
247
246
|
def content_type
|
248
247
|
parsed_content_type_header.mime_type
|
249
248
|
end
|
@@ -410,8 +409,10 @@ module ActionDispatch # :nodoc:
|
|
410
409
|
NullContentTypeHeader = ContentTypeHeader.new nil, nil
|
411
410
|
|
412
411
|
def parse_content_type(content_type)
|
413
|
-
if content_type
|
414
|
-
|
412
|
+
if content_type
|
413
|
+
type, charset = content_type.split(/;\s*charset=/)
|
414
|
+
type = nil if type && type.empty?
|
415
|
+
ContentTypeHeader.new(type, charset)
|
415
416
|
else
|
416
417
|
NullContentTypeHeader
|
417
418
|
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
|