addressable 2.8.0 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/Gemfile +4 -2
- data/Rakefile +2 -1
- data/addressable.gemspec +9 -18
- data/lib/addressable/idna/native.rb +8 -3
- data/lib/addressable/idna/pure.rb +10 -183
- data/lib/addressable/idna.rb +0 -1
- data/lib/addressable/template.rb +12 -14
- data/lib/addressable/uri.rb +168 -148
- data/lib/addressable/version.rb +1 -2
- data/spec/addressable/idna_spec.rb +6 -6
- data/spec/addressable/net_http_compat_spec.rb +0 -1
- data/spec/addressable/security_spec.rb +0 -1
- data/spec/addressable/template_spec.rb +69 -265
- data/spec/addressable/uri_spec.rb +137 -1
- data/tasks/gem.rake +5 -2
- metadata +11 -10
data/lib/addressable/uri.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# encoding:utf-8
|
4
3
|
#--
|
5
4
|
# Copyright (C) Bob Aman
|
6
5
|
#
|
@@ -38,20 +37,26 @@ module Addressable
|
|
38
37
|
##
|
39
38
|
# Container for the character classes specified in
|
40
39
|
# <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
|
40
|
+
#
|
41
|
+
# Note: Concatenated and interpolated `String`s are not affected by the
|
42
|
+
# `frozen_string_literal` directive and must be frozen explicitly.
|
43
|
+
#
|
44
|
+
# Interpolated `String`s *were* frozen this way before Ruby 3.0:
|
45
|
+
# https://bugs.ruby-lang.org/issues/17104
|
41
46
|
module CharacterClasses
|
42
47
|
ALPHA = "a-zA-Z"
|
43
48
|
DIGIT = "0-9"
|
44
49
|
GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
|
45
50
|
SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
|
46
|
-
RESERVED = GEN_DELIMS + SUB_DELIMS
|
47
|
-
UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
|
48
|
-
PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
|
49
|
-
SCHEME = ALPHA + DIGIT + "\\-\\+\\."
|
50
|
-
HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
|
51
|
-
AUTHORITY = PCHAR + "\\[
|
52
|
-
PATH = PCHAR + "\\/"
|
53
|
-
QUERY = PCHAR + "\\/\\?"
|
54
|
-
FRAGMENT = PCHAR + "\\/\\?"
|
51
|
+
RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze
|
52
|
+
UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze
|
53
|
+
PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
|
54
|
+
SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
|
55
|
+
HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
|
56
|
+
AUTHORITY = (PCHAR + "\\[\\]").freeze
|
57
|
+
PATH = (PCHAR + "\\/").freeze
|
58
|
+
QUERY = (PCHAR + "\\/\\?").freeze
|
59
|
+
FRAGMENT = (PCHAR + "\\/\\?").freeze
|
55
60
|
end
|
56
61
|
|
57
62
|
module NormalizeCharacterClasses
|
@@ -112,7 +117,7 @@ module Addressable
|
|
112
117
|
uri = uri.to_str
|
113
118
|
rescue TypeError, NoMethodError
|
114
119
|
raise TypeError, "Can't convert #{uri.class} into String."
|
115
|
-
end
|
120
|
+
end unless uri.is_a?(String)
|
116
121
|
|
117
122
|
# This Regexp supplied as an example in RFC 3986, and it works great.
|
118
123
|
scan = uri.scan(URIREGEX)
|
@@ -133,15 +138,15 @@ module Addressable
|
|
133
138
|
user = userinfo.strip[/^([^:]*):?/, 1]
|
134
139
|
password = userinfo.strip[/:(.*)$/, 1]
|
135
140
|
end
|
141
|
+
|
136
142
|
host = authority.sub(
|
137
143
|
/^([^\[\]]*)@/, EMPTY_STR
|
138
144
|
).sub(
|
139
145
|
/:([^:@\[\]]*?)$/, EMPTY_STR
|
140
146
|
)
|
147
|
+
|
141
148
|
port = authority[/:([^:@\[\]]*?)$/, 1]
|
142
|
-
|
143
|
-
if port == EMPTY_STR
|
144
|
-
port = nil
|
149
|
+
port = nil if port == EMPTY_STR
|
145
150
|
end
|
146
151
|
|
147
152
|
return new(
|
@@ -184,7 +189,7 @@ module Addressable
|
|
184
189
|
uri = uri.to_s
|
185
190
|
end
|
186
191
|
|
187
|
-
|
192
|
+
unless uri.respond_to?(:to_str)
|
188
193
|
raise TypeError, "Can't convert #{uri.class} into String."
|
189
194
|
end
|
190
195
|
# Otherwise, convert to a String
|
@@ -276,7 +281,7 @@ module Addressable
|
|
276
281
|
return nil unless path
|
277
282
|
# If a URI object is passed, just return itself.
|
278
283
|
return path if path.kind_of?(self)
|
279
|
-
|
284
|
+
unless path.respond_to?(:to_str)
|
280
285
|
raise TypeError, "Can't convert #{path.class} into String."
|
281
286
|
end
|
282
287
|
# Otherwise, convert to a String
|
@@ -324,13 +329,13 @@ module Addressable
|
|
324
329
|
# #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
|
325
330
|
def self.join(*uris)
|
326
331
|
uri_objects = uris.collect do |uri|
|
327
|
-
|
332
|
+
unless uri.respond_to?(:to_str)
|
328
333
|
raise TypeError, "Can't convert #{uri.class} into String."
|
329
334
|
end
|
330
335
|
uri.kind_of?(self) ? uri : self.parse(uri.to_str)
|
331
336
|
end
|
332
337
|
result = uri_objects.shift.dup
|
333
|
-
|
338
|
+
uri_objects.each do |uri|
|
334
339
|
result.join!(uri)
|
335
340
|
end
|
336
341
|
return result
|
@@ -469,20 +474,14 @@ module Addressable
|
|
469
474
|
"Expected Class (String or Addressable::URI), " +
|
470
475
|
"got #{return_type.inspect}"
|
471
476
|
end
|
472
|
-
uri = uri.dup
|
473
|
-
# Seriously, only use UTF-8. I'm really not kidding!
|
474
|
-
uri.force_encoding("utf-8")
|
475
477
|
|
476
|
-
|
477
|
-
leave_encoded = leave_encoded.dup.force_encoding("utf-8")
|
478
|
-
end
|
479
|
-
|
480
|
-
result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
|
478
|
+
result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
|
481
479
|
c = sequence[1..3].to_i(16).chr
|
482
|
-
c.force_encoding(
|
480
|
+
c.force_encoding(sequence.encoding)
|
483
481
|
leave_encoded.include?(c) ? sequence : c
|
484
482
|
end
|
485
|
-
|
483
|
+
|
484
|
+
result.force_encoding(Encoding::UTF_8)
|
486
485
|
if return_type == String
|
487
486
|
return result
|
488
487
|
elsif return_type == ::Addressable::URI
|
@@ -561,10 +560,10 @@ module Addressable
|
|
561
560
|
leave_re = if leave_encoded.length > 0
|
562
561
|
character_class = "#{character_class}%" unless character_class.include?('%')
|
563
562
|
|
564
|
-
"|%(?!#{leave_encoded.chars.
|
563
|
+
"|%(?!#{leave_encoded.chars.flat_map do |char|
|
565
564
|
seq = SEQUENCE_ENCODING_TABLE[char]
|
566
565
|
[seq.upcase, seq.downcase]
|
567
|
-
end.
|
566
|
+
end.join('|')})"
|
568
567
|
end
|
569
568
|
|
570
569
|
character_class = if leave_re
|
@@ -580,7 +579,7 @@ module Addressable
|
|
580
579
|
unencoded = self.unencode_component(component, String, leave_encoded)
|
581
580
|
begin
|
582
581
|
encoded = self.encode_component(
|
583
|
-
|
582
|
+
unencoded.unicode_normalize(:nfc),
|
584
583
|
character_class,
|
585
584
|
leave_encoded
|
586
585
|
)
|
@@ -688,8 +687,7 @@ module Addressable
|
|
688
687
|
components.each do |key, value|
|
689
688
|
if value != nil
|
690
689
|
begin
|
691
|
-
components[key] =
|
692
|
-
Addressable::IDNA.unicode_normalize_kc(value.to_str)
|
690
|
+
components[key] = value.to_str.unicode_normalize(:nfc)
|
693
691
|
rescue ArgumentError
|
694
692
|
# Likely a malformed UTF-8 character, skip unicode normalization
|
695
693
|
components[key] = value.to_str
|
@@ -837,7 +835,9 @@ module Addressable
|
|
837
835
|
end
|
838
836
|
end
|
839
837
|
|
840
|
-
|
838
|
+
reset_ivs
|
839
|
+
|
840
|
+
defer_validation do
|
841
841
|
# Bunch of crazy logic required because of the composite components
|
842
842
|
# like userinfo and authority.
|
843
843
|
self.scheme = options[:scheme] if options[:scheme]
|
@@ -852,7 +852,8 @@ module Addressable
|
|
852
852
|
self.query_values = options[:query_values] if options[:query_values]
|
853
853
|
self.fragment = options[:fragment] if options[:fragment]
|
854
854
|
end
|
855
|
-
|
855
|
+
|
856
|
+
to_s # force path validation
|
856
857
|
end
|
857
858
|
|
858
859
|
##
|
@@ -879,9 +880,7 @@ module Addressable
|
|
879
880
|
# The scheme component for this URI.
|
880
881
|
#
|
881
882
|
# @return [String] The scheme component.
|
882
|
-
|
883
|
-
return defined?(@scheme) ? @scheme : nil
|
884
|
-
end
|
883
|
+
attr_reader :scheme
|
885
884
|
|
886
885
|
##
|
887
886
|
# The scheme component for this URI, normalized.
|
@@ -889,8 +888,8 @@ module Addressable
|
|
889
888
|
# @return [String] The scheme component, normalized.
|
890
889
|
def normalized_scheme
|
891
890
|
return nil unless self.scheme
|
892
|
-
@normalized_scheme
|
893
|
-
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
891
|
+
if @normalized_scheme == NONE
|
892
|
+
@normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
894
893
|
"svn+ssh".dup
|
895
894
|
else
|
896
895
|
Addressable::URI.normalize_component(
|
@@ -900,7 +899,7 @@ module Addressable
|
|
900
899
|
end
|
901
900
|
end
|
902
901
|
# All normalized values should be UTF-8
|
903
|
-
@normalized_scheme
|
902
|
+
force_utf8_encoding_if_needed(@normalized_scheme)
|
904
903
|
@normalized_scheme
|
905
904
|
end
|
906
905
|
|
@@ -921,7 +920,7 @@ module Addressable
|
|
921
920
|
@scheme = nil if @scheme.to_s.strip.empty?
|
922
921
|
|
923
922
|
# Reset dependent values
|
924
|
-
|
923
|
+
@normalized_scheme = NONE
|
925
924
|
remove_composite_values
|
926
925
|
|
927
926
|
# Ensure we haven't created an invalid URI
|
@@ -932,9 +931,7 @@ module Addressable
|
|
932
931
|
# The user component for this URI.
|
933
932
|
#
|
934
933
|
# @return [String] The user component.
|
935
|
-
|
936
|
-
return defined?(@user) ? @user : nil
|
937
|
-
end
|
934
|
+
attr_reader :user
|
938
935
|
|
939
936
|
##
|
940
937
|
# The user component for this URI, normalized.
|
@@ -942,8 +939,8 @@ module Addressable
|
|
942
939
|
# @return [String] The user component, normalized.
|
943
940
|
def normalized_user
|
944
941
|
return nil unless self.user
|
945
|
-
return @normalized_user
|
946
|
-
@normalized_user
|
942
|
+
return @normalized_user unless @normalized_user == NONE
|
943
|
+
@normalized_user = begin
|
947
944
|
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
948
945
|
(!self.password || self.password.strip.empty?)
|
949
946
|
nil
|
@@ -955,7 +952,7 @@ module Addressable
|
|
955
952
|
end
|
956
953
|
end
|
957
954
|
# All normalized values should be UTF-8
|
958
|
-
@normalized_user
|
955
|
+
force_utf8_encoding_if_needed(@normalized_user)
|
959
956
|
@normalized_user
|
960
957
|
end
|
961
958
|
|
@@ -971,14 +968,14 @@ module Addressable
|
|
971
968
|
|
972
969
|
# You can't have a nil user with a non-nil password
|
973
970
|
if password != nil
|
974
|
-
@user = EMPTY_STR
|
971
|
+
@user = EMPTY_STR unless user
|
975
972
|
end
|
976
973
|
|
977
974
|
# Reset dependent values
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
975
|
+
@userinfo = nil
|
976
|
+
@normalized_userinfo = NONE
|
977
|
+
@authority = nil
|
978
|
+
@normalized_user = NONE
|
982
979
|
remove_composite_values
|
983
980
|
|
984
981
|
# Ensure we haven't created an invalid URI
|
@@ -989,9 +986,7 @@ module Addressable
|
|
989
986
|
# The password component for this URI.
|
990
987
|
#
|
991
988
|
# @return [String] The password component.
|
992
|
-
|
993
|
-
return defined?(@password) ? @password : nil
|
994
|
-
end
|
989
|
+
attr_reader :password
|
995
990
|
|
996
991
|
##
|
997
992
|
# The password component for this URI, normalized.
|
@@ -999,8 +994,8 @@ module Addressable
|
|
999
994
|
# @return [String] The password component, normalized.
|
1000
995
|
def normalized_password
|
1001
996
|
return nil unless self.password
|
1002
|
-
return @normalized_password
|
1003
|
-
@normalized_password
|
997
|
+
return @normalized_password unless @normalized_password == NONE
|
998
|
+
@normalized_password = begin
|
1004
999
|
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
1005
1000
|
(!self.user || self.user.strip.empty?)
|
1006
1001
|
nil
|
@@ -1012,9 +1007,7 @@ module Addressable
|
|
1012
1007
|
end
|
1013
1008
|
end
|
1014
1009
|
# All normalized values should be UTF-8
|
1015
|
-
|
1016
|
-
@normalized_password.force_encoding(Encoding::UTF_8)
|
1017
|
-
end
|
1010
|
+
force_utf8_encoding_if_needed(@normalized_password)
|
1018
1011
|
@normalized_password
|
1019
1012
|
end
|
1020
1013
|
|
@@ -1029,17 +1022,15 @@ module Addressable
|
|
1029
1022
|
@password = new_password ? new_password.to_str : nil
|
1030
1023
|
|
1031
1024
|
# You can't have a nil user with a non-nil password
|
1032
|
-
@password ||= nil
|
1033
|
-
@user ||= nil
|
1034
1025
|
if @password != nil
|
1035
|
-
|
1026
|
+
self.user = EMPTY_STR if user.nil?
|
1036
1027
|
end
|
1037
1028
|
|
1038
1029
|
# Reset dependent values
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1030
|
+
@userinfo = nil
|
1031
|
+
@normalized_userinfo = NONE
|
1032
|
+
@authority = nil
|
1033
|
+
@normalized_password = NONE
|
1043
1034
|
remove_composite_values
|
1044
1035
|
|
1045
1036
|
# Ensure we haven't created an invalid URI
|
@@ -1069,8 +1060,8 @@ module Addressable
|
|
1069
1060
|
# @return [String] The userinfo component, normalized.
|
1070
1061
|
def normalized_userinfo
|
1071
1062
|
return nil unless self.userinfo
|
1072
|
-
return @normalized_userinfo
|
1073
|
-
@normalized_userinfo
|
1063
|
+
return @normalized_userinfo unless @normalized_userinfo == NONE
|
1064
|
+
@normalized_userinfo = begin
|
1074
1065
|
current_user = self.normalized_user
|
1075
1066
|
current_password = self.normalized_password
|
1076
1067
|
if !current_user && !current_password
|
@@ -1082,9 +1073,7 @@ module Addressable
|
|
1082
1073
|
end
|
1083
1074
|
end
|
1084
1075
|
# All normalized values should be UTF-8
|
1085
|
-
|
1086
|
-
@normalized_userinfo.force_encoding(Encoding::UTF_8)
|
1087
|
-
end
|
1076
|
+
force_utf8_encoding_if_needed(@normalized_userinfo)
|
1088
1077
|
@normalized_userinfo
|
1089
1078
|
end
|
1090
1079
|
|
@@ -1110,7 +1099,7 @@ module Addressable
|
|
1110
1099
|
self.user = new_user
|
1111
1100
|
|
1112
1101
|
# Reset dependent values
|
1113
|
-
|
1102
|
+
@authority = nil
|
1114
1103
|
remove_composite_values
|
1115
1104
|
|
1116
1105
|
# Ensure we haven't created an invalid URI
|
@@ -1121,9 +1110,7 @@ module Addressable
|
|
1121
1110
|
# The host component for this URI.
|
1122
1111
|
#
|
1123
1112
|
# @return [String] The host component.
|
1124
|
-
|
1125
|
-
return defined?(@host) ? @host : nil
|
1126
|
-
end
|
1113
|
+
attr_reader :host
|
1127
1114
|
|
1128
1115
|
##
|
1129
1116
|
# The host component for this URI, normalized.
|
@@ -1151,9 +1138,7 @@ module Addressable
|
|
1151
1138
|
end
|
1152
1139
|
end
|
1153
1140
|
# All normalized values should be UTF-8
|
1154
|
-
|
1155
|
-
@normalized_host.force_encoding(Encoding::UTF_8)
|
1156
|
-
end
|
1141
|
+
force_utf8_encoding_if_needed(@normalized_host)
|
1157
1142
|
@normalized_host
|
1158
1143
|
end
|
1159
1144
|
|
@@ -1168,8 +1153,8 @@ module Addressable
|
|
1168
1153
|
@host = new_host ? new_host.to_str : nil
|
1169
1154
|
|
1170
1155
|
# Reset dependent values
|
1171
|
-
|
1172
|
-
|
1156
|
+
@authority = nil
|
1157
|
+
@normalized_host = nil
|
1173
1158
|
remove_composite_values
|
1174
1159
|
|
1175
1160
|
# Ensure we haven't created an invalid URI
|
@@ -1271,9 +1256,7 @@ module Addressable
|
|
1271
1256
|
authority
|
1272
1257
|
end
|
1273
1258
|
# All normalized values should be UTF-8
|
1274
|
-
|
1275
|
-
@normalized_authority.force_encoding(Encoding::UTF_8)
|
1276
|
-
end
|
1259
|
+
force_utf8_encoding_if_needed(@normalized_authority)
|
1277
1260
|
@normalized_authority
|
1278
1261
|
end
|
1279
1262
|
|
@@ -1302,14 +1285,14 @@ module Addressable
|
|
1302
1285
|
end
|
1303
1286
|
|
1304
1287
|
# Password assigned first to ensure validity in case of nil
|
1305
|
-
self.password =
|
1306
|
-
self.user =
|
1307
|
-
self.host =
|
1308
|
-
self.port =
|
1288
|
+
self.password = new_password
|
1289
|
+
self.user = new_user
|
1290
|
+
self.host = new_host
|
1291
|
+
self.port = new_port
|
1309
1292
|
|
1310
1293
|
# Reset dependent values
|
1311
|
-
|
1312
|
-
|
1294
|
+
@userinfo = nil
|
1295
|
+
@normalized_userinfo = NONE
|
1313
1296
|
remove_composite_values
|
1314
1297
|
|
1315
1298
|
# Ensure we haven't created an invalid URI
|
@@ -1357,16 +1340,16 @@ module Addressable
|
|
1357
1340
|
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
1358
1341
|
end
|
1359
1342
|
|
1360
|
-
self.scheme =
|
1361
|
-
self.host =
|
1362
|
-
self.port =
|
1343
|
+
self.scheme = new_scheme
|
1344
|
+
self.host = new_host
|
1345
|
+
self.port = new_port
|
1363
1346
|
self.userinfo = nil
|
1364
1347
|
|
1365
1348
|
# Reset dependent values
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1349
|
+
@userinfo = nil
|
1350
|
+
@normalized_userinfo = NONE
|
1351
|
+
@authority = nil
|
1352
|
+
@normalized_authority = nil
|
1370
1353
|
remove_composite_values
|
1371
1354
|
|
1372
1355
|
# Ensure we haven't created an invalid URI
|
@@ -1393,9 +1376,7 @@ module Addressable
|
|
1393
1376
|
# infer port numbers from default values.
|
1394
1377
|
#
|
1395
1378
|
# @return [Integer] The port component.
|
1396
|
-
|
1397
|
-
return defined?(@port) ? @port : nil
|
1398
|
-
end
|
1379
|
+
attr_reader :port
|
1399
1380
|
|
1400
1381
|
##
|
1401
1382
|
# The port component for this URI, normalized.
|
@@ -1403,8 +1384,8 @@ module Addressable
|
|
1403
1384
|
# @return [Integer] The port component, normalized.
|
1404
1385
|
def normalized_port
|
1405
1386
|
return nil unless self.port
|
1406
|
-
return @normalized_port
|
1407
|
-
@normalized_port
|
1387
|
+
return @normalized_port unless @normalized_port == NONE
|
1388
|
+
@normalized_port = begin
|
1408
1389
|
if URI.port_mapping[self.normalized_scheme] == self.port
|
1409
1390
|
nil
|
1410
1391
|
else
|
@@ -1435,8 +1416,8 @@ module Addressable
|
|
1435
1416
|
@port = nil if @port == 0
|
1436
1417
|
|
1437
1418
|
# Reset dependent values
|
1438
|
-
|
1439
|
-
|
1419
|
+
@authority = nil
|
1420
|
+
@normalized_port = NONE
|
1440
1421
|
remove_composite_values
|
1441
1422
|
|
1442
1423
|
# Ensure we haven't created an invalid URI
|
@@ -1507,7 +1488,7 @@ module Addressable
|
|
1507
1488
|
site_string
|
1508
1489
|
end
|
1509
1490
|
# All normalized values should be UTF-8
|
1510
|
-
@normalized_site
|
1491
|
+
force_utf8_encoding_if_needed(@normalized_site)
|
1511
1492
|
@normalized_site
|
1512
1493
|
end
|
1513
1494
|
|
@@ -1537,9 +1518,7 @@ module Addressable
|
|
1537
1518
|
# The path component for this URI.
|
1538
1519
|
#
|
1539
1520
|
# @return [String] The path component.
|
1540
|
-
|
1541
|
-
return defined?(@path) ? @path : EMPTY_STR
|
1542
|
-
end
|
1521
|
+
attr_reader :path
|
1543
1522
|
|
1544
1523
|
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
1545
1524
|
##
|
@@ -1570,7 +1549,7 @@ module Addressable
|
|
1570
1549
|
result
|
1571
1550
|
end
|
1572
1551
|
# All normalized values should be UTF-8
|
1573
|
-
@normalized_path
|
1552
|
+
force_utf8_encoding_if_needed(@normalized_path)
|
1574
1553
|
@normalized_path
|
1575
1554
|
end
|
1576
1555
|
|
@@ -1588,7 +1567,7 @@ module Addressable
|
|
1588
1567
|
end
|
1589
1568
|
|
1590
1569
|
# Reset dependent values
|
1591
|
-
|
1570
|
+
@normalized_path = nil
|
1592
1571
|
remove_composite_values
|
1593
1572
|
|
1594
1573
|
# Ensure we haven't created an invalid URI
|
@@ -1618,9 +1597,7 @@ module Addressable
|
|
1618
1597
|
# The query component for this URI.
|
1619
1598
|
#
|
1620
1599
|
# @return [String] The query component.
|
1621
|
-
|
1622
|
-
return defined?(@query) ? @query : nil
|
1623
|
-
end
|
1600
|
+
attr_reader :query
|
1624
1601
|
|
1625
1602
|
##
|
1626
1603
|
# The query component for this URI, normalized.
|
@@ -1628,8 +1605,8 @@ module Addressable
|
|
1628
1605
|
# @return [String] The query component, normalized.
|
1629
1606
|
def normalized_query(*flags)
|
1630
1607
|
return nil unless self.query
|
1631
|
-
return @normalized_query
|
1632
|
-
@normalized_query
|
1608
|
+
return @normalized_query unless @normalized_query == NONE
|
1609
|
+
@normalized_query = begin
|
1633
1610
|
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
1634
1611
|
# Make sure possible key-value pair delimiters are escaped.
|
1635
1612
|
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
@@ -1646,7 +1623,7 @@ module Addressable
|
|
1646
1623
|
component == "" ? nil : component
|
1647
1624
|
end
|
1648
1625
|
# All normalized values should be UTF-8
|
1649
|
-
@normalized_query
|
1626
|
+
force_utf8_encoding_if_needed(@normalized_query)
|
1650
1627
|
@normalized_query
|
1651
1628
|
end
|
1652
1629
|
|
@@ -1661,7 +1638,7 @@ module Addressable
|
|
1661
1638
|
@query = new_query ? new_query.to_str : nil
|
1662
1639
|
|
1663
1640
|
# Reset dependent values
|
1664
|
-
|
1641
|
+
@normalized_query = NONE
|
1665
1642
|
remove_composite_values
|
1666
1643
|
end
|
1667
1644
|
|
@@ -1823,9 +1800,7 @@ module Addressable
|
|
1823
1800
|
# The fragment component for this URI.
|
1824
1801
|
#
|
1825
1802
|
# @return [String] The fragment component.
|
1826
|
-
|
1827
|
-
return defined?(@fragment) ? @fragment : nil
|
1828
|
-
end
|
1803
|
+
attr_reader :fragment
|
1829
1804
|
|
1830
1805
|
##
|
1831
1806
|
# The fragment component for this URI, normalized.
|
@@ -1833,8 +1808,8 @@ module Addressable
|
|
1833
1808
|
# @return [String] The fragment component, normalized.
|
1834
1809
|
def normalized_fragment
|
1835
1810
|
return nil unless self.fragment
|
1836
|
-
return @normalized_fragment
|
1837
|
-
@normalized_fragment
|
1811
|
+
return @normalized_fragment unless @normalized_fragment == NONE
|
1812
|
+
@normalized_fragment = begin
|
1838
1813
|
component = Addressable::URI.normalize_component(
|
1839
1814
|
self.fragment,
|
1840
1815
|
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
@@ -1842,9 +1817,7 @@ module Addressable
|
|
1842
1817
|
component == "" ? nil : component
|
1843
1818
|
end
|
1844
1819
|
# All normalized values should be UTF-8
|
1845
|
-
|
1846
|
-
@normalized_fragment.force_encoding(Encoding::UTF_8)
|
1847
|
-
end
|
1820
|
+
force_utf8_encoding_if_needed(@normalized_fragment)
|
1848
1821
|
@normalized_fragment
|
1849
1822
|
end
|
1850
1823
|
|
@@ -1859,7 +1832,7 @@ module Addressable
|
|
1859
1832
|
@fragment = new_fragment ? new_fragment.to_str : nil
|
1860
1833
|
|
1861
1834
|
# Reset dependent values
|
1862
|
-
|
1835
|
+
@normalized_fragment = NONE
|
1863
1836
|
remove_composite_values
|
1864
1837
|
|
1865
1838
|
# Ensure we haven't created an invalid URI
|
@@ -2025,7 +1998,7 @@ module Addressable
|
|
2025
1998
|
#
|
2026
1999
|
# @see Hash#merge
|
2027
2000
|
def merge(hash)
|
2028
|
-
|
2001
|
+
unless hash.respond_to?(:to_hash)
|
2029
2002
|
raise TypeError, "Can't convert #{hash.class} into Hash."
|
2030
2003
|
end
|
2031
2004
|
hash = hash.to_hash
|
@@ -2419,7 +2392,8 @@ module Addressable
|
|
2419
2392
|
yield
|
2420
2393
|
@validation_deferred = false
|
2421
2394
|
validate
|
2422
|
-
|
2395
|
+
ensure
|
2396
|
+
@validation_deferred = false
|
2423
2397
|
end
|
2424
2398
|
|
2425
2399
|
protected
|
@@ -2440,30 +2414,35 @@ module Addressable
|
|
2440
2414
|
def self.normalize_path(path)
|
2441
2415
|
# Section 5.2.4 of RFC 3986
|
2442
2416
|
|
2443
|
-
return
|
2417
|
+
return if path.nil?
|
2444
2418
|
normalized_path = path.dup
|
2445
|
-
|
2446
|
-
mod = nil
|
2419
|
+
loop do
|
2447
2420
|
mod ||= normalized_path.gsub!(RULE_2A, SLASH)
|
2448
2421
|
|
2449
2422
|
pair = normalized_path.match(RULE_2B_2C)
|
2450
|
-
|
2423
|
+
if pair
|
2424
|
+
parent = pair[1]
|
2425
|
+
current = pair[2]
|
2426
|
+
else
|
2427
|
+
parent = nil
|
2428
|
+
current = nil
|
2429
|
+
end
|
2430
|
+
|
2431
|
+
regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|"
|
2432
|
+
regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
|
2433
|
+
|
2451
2434
|
if pair && ((parent != SELF_REF && parent != PARENT) ||
|
2452
2435
|
(current != SELF_REF && current != PARENT))
|
2453
|
-
mod ||= normalized_path.gsub!(
|
2454
|
-
Regexp.new(
|
2455
|
-
"/#{Regexp.escape(parent.to_s)}/\\.\\./|" +
|
2456
|
-
"(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
|
2457
|
-
), SLASH
|
2458
|
-
)
|
2436
|
+
mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH)
|
2459
2437
|
end
|
2460
2438
|
|
2461
2439
|
mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
|
2462
2440
|
# Non-standard, removes prefixed dotted segments from path.
|
2463
2441
|
mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
|
2464
|
-
|
2442
|
+
break if mod.nil?
|
2443
|
+
end
|
2465
2444
|
|
2466
|
-
|
2445
|
+
normalized_path
|
2467
2446
|
end
|
2468
2447
|
|
2469
2448
|
##
|
@@ -2513,11 +2492,7 @@ module Addressable
|
|
2513
2492
|
# @return [Addressable::URI] <code>self</code>.
|
2514
2493
|
def replace_self(uri)
|
2515
2494
|
# Reset dependent values
|
2516
|
-
|
2517
|
-
if instance_variable_defined?(var) && var != :@validation_deferred
|
2518
|
-
remove_instance_variable(var)
|
2519
|
-
end
|
2520
|
-
end
|
2495
|
+
reset_ivs
|
2521
2496
|
|
2522
2497
|
@scheme = uri.scheme
|
2523
2498
|
@user = uri.user
|
@@ -2549,8 +2524,53 @@ module Addressable
|
|
2549
2524
|
#
|
2550
2525
|
# @api private
|
2551
2526
|
def remove_composite_values
|
2552
|
-
|
2553
|
-
|
2527
|
+
@uri_string = nil
|
2528
|
+
@hash = nil
|
2529
|
+
end
|
2530
|
+
|
2531
|
+
##
|
2532
|
+
# Converts the string to be UTF-8 if it is not already UTF-8
|
2533
|
+
#
|
2534
|
+
# @api private
|
2535
|
+
def force_utf8_encoding_if_needed(str)
|
2536
|
+
if str && str.encoding != Encoding::UTF_8
|
2537
|
+
str.force_encoding(Encoding::UTF_8)
|
2538
|
+
end
|
2554
2539
|
end
|
2540
|
+
|
2541
|
+
private
|
2542
|
+
|
2543
|
+
##
|
2544
|
+
# Resets instance variables
|
2545
|
+
#
|
2546
|
+
# @api private
|
2547
|
+
def reset_ivs
|
2548
|
+
@scheme = nil
|
2549
|
+
@user = nil
|
2550
|
+
@normalized_scheme = NONE
|
2551
|
+
@normalized_user = NONE
|
2552
|
+
@uri_string = nil
|
2553
|
+
@hash = nil
|
2554
|
+
@userinfo = nil
|
2555
|
+
@normalized_userinfo = NONE
|
2556
|
+
@authority = nil
|
2557
|
+
@password = nil
|
2558
|
+
@normalized_authority = nil
|
2559
|
+
@port = nil
|
2560
|
+
@normalized_password = NONE
|
2561
|
+
@host = nil
|
2562
|
+
@normalized_host = nil
|
2563
|
+
@normalized_port = NONE
|
2564
|
+
@path = EMPTY_STR
|
2565
|
+
@normalized_path = nil
|
2566
|
+
@normalized_query = NONE
|
2567
|
+
@fragment = nil
|
2568
|
+
@normalized_fragment = NONE
|
2569
|
+
@query = nil
|
2570
|
+
end
|
2571
|
+
|
2572
|
+
NONE = Object.new.freeze
|
2573
|
+
|
2574
|
+
private_constant :NONE
|
2555
2575
|
end
|
2556
2576
|
end
|