addressable 2.8.0 → 2.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/Gemfile +4 -2
- data/Rakefile +2 -1
- data/addressable.gemspec +9 -18
- data/lib/addressable/idna/native.rb +0 -5
- data/lib/addressable/idna/pure.rb +2 -185
- data/lib/addressable/idna.rb +0 -1
- data/lib/addressable/template.rb +10 -9
- 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 +33 -1
- 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
|