addressable 2.8.1 → 2.8.7
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 +81 -42
- data/Gemfile +1 -0
- data/Rakefile +11 -8
- data/addressable.gemspec +28 -0
- data/lib/addressable/idna/native.rb +8 -2
- data/lib/addressable/idna/pure.rb +10 -182
- data/lib/addressable/template.rb +10 -11
- data/lib/addressable/uri.rb +177 -135
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +6 -5
- data/spec/addressable/template_spec.rb +60 -264
- data/spec/addressable/uri_spec.rb +95 -0
- data/tasks/gem.rake +4 -4
- metadata +10 -9
data/lib/addressable/uri.rb
CHANGED
@@ -50,10 +50,11 @@ module Addressable
|
|
50
50
|
SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
|
51
51
|
RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze
|
52
52
|
UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze
|
53
|
+
RESERVED_AND_UNRESERVED = RESERVED + UNRESERVED
|
53
54
|
PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
|
54
55
|
SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
|
55
56
|
HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
|
56
|
-
AUTHORITY = (PCHAR + "\\[
|
57
|
+
AUTHORITY = (PCHAR + "\\[\\]").freeze
|
57
58
|
PATH = (PCHAR + "\\/").freeze
|
58
59
|
QUERY = (PCHAR + "\\/\\?").freeze
|
59
60
|
FRAGMENT = (PCHAR + "\\/\\?").freeze
|
@@ -68,6 +69,18 @@ module Addressable
|
|
68
69
|
QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
|
69
70
|
end
|
70
71
|
|
72
|
+
module CharacterClassesRegexps
|
73
|
+
AUTHORITY = /[^#{CharacterClasses::AUTHORITY}]/
|
74
|
+
FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
|
75
|
+
HOST = /[^#{CharacterClasses::HOST}]/
|
76
|
+
PATH = /[^#{CharacterClasses::PATH}]/
|
77
|
+
QUERY = /[^#{CharacterClasses::QUERY}]/
|
78
|
+
RESERVED = /[^#{CharacterClasses::RESERVED}]/
|
79
|
+
RESERVED_AND_UNRESERVED = /[^#{CharacterClasses::RESERVED_AND_UNRESERVED}]/
|
80
|
+
SCHEME = /[^#{CharacterClasses::SCHEME}]/
|
81
|
+
UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
|
82
|
+
end
|
83
|
+
|
71
84
|
SLASH = '/'
|
72
85
|
EMPTY_STR = ''
|
73
86
|
|
@@ -117,7 +130,7 @@ module Addressable
|
|
117
130
|
uri = uri.to_str
|
118
131
|
rescue TypeError, NoMethodError
|
119
132
|
raise TypeError, "Can't convert #{uri.class} into String."
|
120
|
-
end
|
133
|
+
end unless uri.is_a?(String)
|
121
134
|
|
122
135
|
# This Regexp supplied as an example in RFC 3986, and it works great.
|
123
136
|
scan = uri.scan(URIREGEX)
|
@@ -138,15 +151,15 @@ module Addressable
|
|
138
151
|
user = userinfo.strip[/^([^:]*):?/, 1]
|
139
152
|
password = userinfo.strip[/:(.*)$/, 1]
|
140
153
|
end
|
154
|
+
|
141
155
|
host = authority.sub(
|
142
156
|
/^([^\[\]]*)@/, EMPTY_STR
|
143
157
|
).sub(
|
144
158
|
/:([^:@\[\]]*?)$/, EMPTY_STR
|
145
159
|
)
|
160
|
+
|
146
161
|
port = authority[/:([^:@\[\]]*?)$/, 1]
|
147
|
-
|
148
|
-
if port == EMPTY_STR
|
149
|
-
port = nil
|
162
|
+
port = nil if port == EMPTY_STR
|
150
163
|
end
|
151
164
|
|
152
165
|
return new(
|
@@ -189,7 +202,7 @@ module Addressable
|
|
189
202
|
uri = uri.to_s
|
190
203
|
end
|
191
204
|
|
192
|
-
|
205
|
+
unless uri.respond_to?(:to_str)
|
193
206
|
raise TypeError, "Can't convert #{uri.class} into String."
|
194
207
|
end
|
195
208
|
# Otherwise, convert to a String
|
@@ -281,7 +294,7 @@ module Addressable
|
|
281
294
|
return nil unless path
|
282
295
|
# If a URI object is passed, just return itself.
|
283
296
|
return path if path.kind_of?(self)
|
284
|
-
|
297
|
+
unless path.respond_to?(:to_str)
|
285
298
|
raise TypeError, "Can't convert #{path.class} into String."
|
286
299
|
end
|
287
300
|
# Otherwise, convert to a String
|
@@ -329,13 +342,13 @@ module Addressable
|
|
329
342
|
# #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
|
330
343
|
def self.join(*uris)
|
331
344
|
uri_objects = uris.collect do |uri|
|
332
|
-
|
345
|
+
unless uri.respond_to?(:to_str)
|
333
346
|
raise TypeError, "Can't convert #{uri.class} into String."
|
334
347
|
end
|
335
348
|
uri.kind_of?(self) ? uri : self.parse(uri.to_str)
|
336
349
|
end
|
337
350
|
result = uri_objects.shift.dup
|
338
|
-
|
351
|
+
uri_objects.each do |uri|
|
339
352
|
result.join!(uri)
|
340
353
|
end
|
341
354
|
return result
|
@@ -344,17 +357,13 @@ module Addressable
|
|
344
357
|
##
|
345
358
|
# Tables used to optimize encoding operations in `self.encode_component`
|
346
359
|
# and `self.normalize_component`
|
347
|
-
SEQUENCE_ENCODING_TABLE =
|
348
|
-
|
349
|
-
|
350
|
-
end.join
|
351
|
-
end
|
360
|
+
SEQUENCE_ENCODING_TABLE = (0..255).map do |byte|
|
361
|
+
format("%02x", byte).freeze
|
362
|
+
end.freeze
|
352
363
|
|
353
|
-
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE =
|
354
|
-
|
355
|
-
|
356
|
-
end.join
|
357
|
-
end
|
364
|
+
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte|
|
365
|
+
format("%%%02X", byte).freeze
|
366
|
+
end.freeze
|
358
367
|
|
359
368
|
##
|
360
369
|
# Percent encodes a URI component.
|
@@ -391,9 +400,7 @@ module Addressable
|
|
391
400
|
# "simple/example", Addressable::URI::CharacterClasses::UNRESERVED
|
392
401
|
# )
|
393
402
|
# => "simple%2Fexample"
|
394
|
-
def self.encode_component(component, character_class=
|
395
|
-
CharacterClasses::RESERVED + CharacterClasses::UNRESERVED,
|
396
|
-
upcase_encoded='')
|
403
|
+
def self.encode_component(component, character_class=CharacterClassesRegexps::RESERVED_AND_UNRESERVED, upcase_encoded='')
|
397
404
|
return nil if component.nil?
|
398
405
|
|
399
406
|
begin
|
@@ -421,16 +428,17 @@ module Addressable
|
|
421
428
|
component = component.dup
|
422
429
|
component.force_encoding(Encoding::ASCII_8BIT)
|
423
430
|
# Avoiding gsub! because there are edge cases with frozen strings
|
424
|
-
component = component.gsub(character_class) do |
|
425
|
-
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[
|
431
|
+
component = component.gsub(character_class) do |char|
|
432
|
+
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord]
|
426
433
|
end
|
427
434
|
if upcase_encoded.length > 0
|
428
|
-
upcase_encoded_chars = upcase_encoded.
|
429
|
-
SEQUENCE_ENCODING_TABLE[
|
435
|
+
upcase_encoded_chars = upcase_encoded.bytes.map do |byte|
|
436
|
+
SEQUENCE_ENCODING_TABLE[byte]
|
430
437
|
end
|
431
438
|
component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
|
432
439
|
&:upcase)
|
433
440
|
end
|
441
|
+
|
434
442
|
return component
|
435
443
|
end
|
436
444
|
|
@@ -481,7 +489,7 @@ module Addressable
|
|
481
489
|
leave_encoded.include?(c) ? sequence : c
|
482
490
|
end
|
483
491
|
|
484
|
-
result.force_encoding(
|
492
|
+
result.force_encoding(Encoding::UTF_8)
|
485
493
|
if return_type == String
|
486
494
|
return result
|
487
495
|
elsif return_type == ::Addressable::URI
|
@@ -542,7 +550,7 @@ module Addressable
|
|
542
550
|
# )
|
543
551
|
# => "one two%2Fthree&four"
|
544
552
|
def self.normalize_component(component, character_class=
|
545
|
-
|
553
|
+
CharacterClassesRegexps::RESERVED_AND_UNRESERVED,
|
546
554
|
leave_encoded='')
|
547
555
|
return nil if component.nil?
|
548
556
|
|
@@ -560,10 +568,9 @@ module Addressable
|
|
560
568
|
leave_re = if leave_encoded.length > 0
|
561
569
|
character_class = "#{character_class}%" unless character_class.include?('%')
|
562
570
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
end.join('|')})"
|
571
|
+
bytes = leave_encoded.bytes
|
572
|
+
leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|')
|
573
|
+
"|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})"
|
567
574
|
end
|
568
575
|
|
569
576
|
character_class = if leave_re
|
@@ -579,7 +586,7 @@ module Addressable
|
|
579
586
|
unencoded = self.unencode_component(component, String, leave_encoded)
|
580
587
|
begin
|
581
588
|
encoded = self.encode_component(
|
582
|
-
|
589
|
+
unencoded.unicode_normalize(:nfc),
|
583
590
|
character_class,
|
584
591
|
leave_encoded
|
585
592
|
)
|
@@ -623,15 +630,15 @@ module Addressable
|
|
623
630
|
uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
|
624
631
|
encoded_uri = Addressable::URI.new(
|
625
632
|
:scheme => self.encode_component(uri_object.scheme,
|
626
|
-
Addressable::URI::
|
633
|
+
Addressable::URI::CharacterClassesRegexps::SCHEME),
|
627
634
|
:authority => self.encode_component(uri_object.authority,
|
628
|
-
Addressable::URI::
|
635
|
+
Addressable::URI::CharacterClassesRegexps::AUTHORITY),
|
629
636
|
:path => self.encode_component(uri_object.path,
|
630
|
-
Addressable::URI::
|
637
|
+
Addressable::URI::CharacterClassesRegexps::PATH),
|
631
638
|
:query => self.encode_component(uri_object.query,
|
632
|
-
Addressable::URI::
|
639
|
+
Addressable::URI::CharacterClassesRegexps::QUERY),
|
633
640
|
:fragment => self.encode_component(uri_object.fragment,
|
634
|
-
Addressable::URI::
|
641
|
+
Addressable::URI::CharacterClassesRegexps::FRAGMENT)
|
635
642
|
)
|
636
643
|
if return_type == String
|
637
644
|
return encoded_uri.to_s
|
@@ -687,8 +694,7 @@ module Addressable
|
|
687
694
|
components.each do |key, value|
|
688
695
|
if value != nil
|
689
696
|
begin
|
690
|
-
components[key] =
|
691
|
-
Addressable::IDNA.unicode_normalize_kc(value.to_str)
|
697
|
+
components[key] = value.to_str.unicode_normalize(:nfc)
|
692
698
|
rescue ArgumentError
|
693
699
|
# Likely a malformed UTF-8 character, skip unicode normalization
|
694
700
|
components[key] = value.to_str
|
@@ -697,19 +703,19 @@ module Addressable
|
|
697
703
|
end
|
698
704
|
encoded_uri = Addressable::URI.new(
|
699
705
|
:scheme => self.encode_component(components[:scheme],
|
700
|
-
Addressable::URI::
|
706
|
+
Addressable::URI::CharacterClassesRegexps::SCHEME),
|
701
707
|
:user => self.encode_component(components[:user],
|
702
|
-
Addressable::URI::
|
708
|
+
Addressable::URI::CharacterClassesRegexps::UNRESERVED),
|
703
709
|
:password => self.encode_component(components[:password],
|
704
|
-
Addressable::URI::
|
710
|
+
Addressable::URI::CharacterClassesRegexps::UNRESERVED),
|
705
711
|
:host => components[:host],
|
706
712
|
:port => components[:port],
|
707
713
|
:path => self.encode_component(components[:path],
|
708
|
-
Addressable::URI::
|
714
|
+
Addressable::URI::CharacterClassesRegexps::PATH),
|
709
715
|
:query => self.encode_component(components[:query],
|
710
|
-
Addressable::URI::
|
716
|
+
Addressable::URI::CharacterClassesRegexps::QUERY),
|
711
717
|
:fragment => self.encode_component(components[:fragment],
|
712
|
-
Addressable::URI::
|
718
|
+
Addressable::URI::CharacterClassesRegexps::FRAGMENT)
|
713
719
|
)
|
714
720
|
if return_type == String
|
715
721
|
return encoded_uri.to_s
|
@@ -760,11 +766,11 @@ module Addressable
|
|
760
766
|
[
|
761
767
|
self.encode_component(
|
762
768
|
key.gsub(/(\r\n|\n|\r)/, "\r\n"),
|
763
|
-
|
769
|
+
CharacterClassesRegexps::UNRESERVED
|
764
770
|
).gsub("%20", "+"),
|
765
771
|
self.encode_component(
|
766
772
|
value.gsub(/(\r\n|\n|\r)/, "\r\n"),
|
767
|
-
|
773
|
+
CharacterClassesRegexps::UNRESERVED
|
768
774
|
).gsub("%20", "+")
|
769
775
|
]
|
770
776
|
end
|
@@ -836,7 +842,9 @@ module Addressable
|
|
836
842
|
end
|
837
843
|
end
|
838
844
|
|
839
|
-
|
845
|
+
reset_ivs
|
846
|
+
|
847
|
+
defer_validation do
|
840
848
|
# Bunch of crazy logic required because of the composite components
|
841
849
|
# like userinfo and authority.
|
842
850
|
self.scheme = options[:scheme] if options[:scheme]
|
@@ -851,7 +859,8 @@ module Addressable
|
|
851
859
|
self.query_values = options[:query_values] if options[:query_values]
|
852
860
|
self.fragment = options[:fragment] if options[:fragment]
|
853
861
|
end
|
854
|
-
|
862
|
+
|
863
|
+
to_s # force path validation
|
855
864
|
end
|
856
865
|
|
857
866
|
##
|
@@ -878,9 +887,7 @@ module Addressable
|
|
878
887
|
# The scheme component for this URI.
|
879
888
|
#
|
880
889
|
# @return [String] The scheme component.
|
881
|
-
|
882
|
-
return defined?(@scheme) ? @scheme : nil
|
883
|
-
end
|
890
|
+
attr_reader :scheme
|
884
891
|
|
885
892
|
##
|
886
893
|
# The scheme component for this URI, normalized.
|
@@ -888,8 +895,8 @@ module Addressable
|
|
888
895
|
# @return [String] The scheme component, normalized.
|
889
896
|
def normalized_scheme
|
890
897
|
return nil unless self.scheme
|
891
|
-
@normalized_scheme
|
892
|
-
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
898
|
+
if @normalized_scheme == NONE
|
899
|
+
@normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
893
900
|
"svn+ssh".dup
|
894
901
|
else
|
895
902
|
Addressable::URI.normalize_component(
|
@@ -920,7 +927,7 @@ module Addressable
|
|
920
927
|
@scheme = nil if @scheme.to_s.strip.empty?
|
921
928
|
|
922
929
|
# Reset dependent values
|
923
|
-
|
930
|
+
@normalized_scheme = NONE
|
924
931
|
remove_composite_values
|
925
932
|
|
926
933
|
# Ensure we haven't created an invalid URI
|
@@ -931,9 +938,7 @@ module Addressable
|
|
931
938
|
# The user component for this URI.
|
932
939
|
#
|
933
940
|
# @return [String] The user component.
|
934
|
-
|
935
|
-
return defined?(@user) ? @user : nil
|
936
|
-
end
|
941
|
+
attr_reader :user
|
937
942
|
|
938
943
|
##
|
939
944
|
# The user component for this URI, normalized.
|
@@ -941,8 +946,8 @@ module Addressable
|
|
941
946
|
# @return [String] The user component, normalized.
|
942
947
|
def normalized_user
|
943
948
|
return nil unless self.user
|
944
|
-
return @normalized_user
|
945
|
-
@normalized_user
|
949
|
+
return @normalized_user unless @normalized_user == NONE
|
950
|
+
@normalized_user = begin
|
946
951
|
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
947
952
|
(!self.password || self.password.strip.empty?)
|
948
953
|
nil
|
@@ -970,14 +975,14 @@ module Addressable
|
|
970
975
|
|
971
976
|
# You can't have a nil user with a non-nil password
|
972
977
|
if password != nil
|
973
|
-
@user = EMPTY_STR
|
978
|
+
@user = EMPTY_STR unless user
|
974
979
|
end
|
975
980
|
|
976
981
|
# Reset dependent values
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
982
|
+
@userinfo = nil
|
983
|
+
@normalized_userinfo = NONE
|
984
|
+
@authority = nil
|
985
|
+
@normalized_user = NONE
|
981
986
|
remove_composite_values
|
982
987
|
|
983
988
|
# Ensure we haven't created an invalid URI
|
@@ -988,9 +993,7 @@ module Addressable
|
|
988
993
|
# The password component for this URI.
|
989
994
|
#
|
990
995
|
# @return [String] The password component.
|
991
|
-
|
992
|
-
return defined?(@password) ? @password : nil
|
993
|
-
end
|
996
|
+
attr_reader :password
|
994
997
|
|
995
998
|
##
|
996
999
|
# The password component for this URI, normalized.
|
@@ -998,8 +1001,8 @@ module Addressable
|
|
998
1001
|
# @return [String] The password component, normalized.
|
999
1002
|
def normalized_password
|
1000
1003
|
return nil unless self.password
|
1001
|
-
return @normalized_password
|
1002
|
-
@normalized_password
|
1004
|
+
return @normalized_password unless @normalized_password == NONE
|
1005
|
+
@normalized_password = begin
|
1003
1006
|
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
1004
1007
|
(!self.user || self.user.strip.empty?)
|
1005
1008
|
nil
|
@@ -1026,17 +1029,15 @@ module Addressable
|
|
1026
1029
|
@password = new_password ? new_password.to_str : nil
|
1027
1030
|
|
1028
1031
|
# You can't have a nil user with a non-nil password
|
1029
|
-
@password ||= nil
|
1030
|
-
@user ||= nil
|
1031
1032
|
if @password != nil
|
1032
|
-
|
1033
|
+
self.user = EMPTY_STR if user.nil?
|
1033
1034
|
end
|
1034
1035
|
|
1035
1036
|
# Reset dependent values
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1037
|
+
@userinfo = nil
|
1038
|
+
@normalized_userinfo = NONE
|
1039
|
+
@authority = nil
|
1040
|
+
@normalized_password = NONE
|
1040
1041
|
remove_composite_values
|
1041
1042
|
|
1042
1043
|
# Ensure we haven't created an invalid URI
|
@@ -1066,8 +1067,8 @@ module Addressable
|
|
1066
1067
|
# @return [String] The userinfo component, normalized.
|
1067
1068
|
def normalized_userinfo
|
1068
1069
|
return nil unless self.userinfo
|
1069
|
-
return @normalized_userinfo
|
1070
|
-
@normalized_userinfo
|
1070
|
+
return @normalized_userinfo unless @normalized_userinfo == NONE
|
1071
|
+
@normalized_userinfo = begin
|
1071
1072
|
current_user = self.normalized_user
|
1072
1073
|
current_password = self.normalized_password
|
1073
1074
|
if !current_user && !current_password
|
@@ -1105,7 +1106,7 @@ module Addressable
|
|
1105
1106
|
self.user = new_user
|
1106
1107
|
|
1107
1108
|
# Reset dependent values
|
1108
|
-
|
1109
|
+
@authority = nil
|
1109
1110
|
remove_composite_values
|
1110
1111
|
|
1111
1112
|
# Ensure we haven't created an invalid URI
|
@@ -1116,9 +1117,7 @@ module Addressable
|
|
1116
1117
|
# The host component for this URI.
|
1117
1118
|
#
|
1118
1119
|
# @return [String] The host component.
|
1119
|
-
|
1120
|
-
return defined?(@host) ? @host : nil
|
1121
|
-
end
|
1120
|
+
attr_reader :host
|
1122
1121
|
|
1123
1122
|
##
|
1124
1123
|
# The host component for this URI, normalized.
|
@@ -1161,8 +1160,8 @@ module Addressable
|
|
1161
1160
|
@host = new_host ? new_host.to_str : nil
|
1162
1161
|
|
1163
1162
|
# Reset dependent values
|
1164
|
-
|
1165
|
-
|
1163
|
+
@authority = nil
|
1164
|
+
@normalized_host = nil
|
1166
1165
|
remove_composite_values
|
1167
1166
|
|
1168
1167
|
# Ensure we haven't created an invalid URI
|
@@ -1293,14 +1292,14 @@ module Addressable
|
|
1293
1292
|
end
|
1294
1293
|
|
1295
1294
|
# Password assigned first to ensure validity in case of nil
|
1296
|
-
self.password =
|
1297
|
-
self.user =
|
1298
|
-
self.host =
|
1299
|
-
self.port =
|
1295
|
+
self.password = new_password
|
1296
|
+
self.user = new_user
|
1297
|
+
self.host = new_host
|
1298
|
+
self.port = new_port
|
1300
1299
|
|
1301
1300
|
# Reset dependent values
|
1302
|
-
|
1303
|
-
|
1301
|
+
@userinfo = nil
|
1302
|
+
@normalized_userinfo = NONE
|
1304
1303
|
remove_composite_values
|
1305
1304
|
|
1306
1305
|
# Ensure we haven't created an invalid URI
|
@@ -1348,16 +1347,16 @@ module Addressable
|
|
1348
1347
|
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
1349
1348
|
end
|
1350
1349
|
|
1351
|
-
self.scheme =
|
1352
|
-
self.host =
|
1353
|
-
self.port =
|
1350
|
+
self.scheme = new_scheme
|
1351
|
+
self.host = new_host
|
1352
|
+
self.port = new_port
|
1354
1353
|
self.userinfo = nil
|
1355
1354
|
|
1356
1355
|
# Reset dependent values
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1356
|
+
@userinfo = nil
|
1357
|
+
@normalized_userinfo = NONE
|
1358
|
+
@authority = nil
|
1359
|
+
@normalized_authority = nil
|
1361
1360
|
remove_composite_values
|
1362
1361
|
|
1363
1362
|
# Ensure we haven't created an invalid URI
|
@@ -1384,9 +1383,7 @@ module Addressable
|
|
1384
1383
|
# infer port numbers from default values.
|
1385
1384
|
#
|
1386
1385
|
# @return [Integer] The port component.
|
1387
|
-
|
1388
|
-
return defined?(@port) ? @port : nil
|
1389
|
-
end
|
1386
|
+
attr_reader :port
|
1390
1387
|
|
1391
1388
|
##
|
1392
1389
|
# The port component for this URI, normalized.
|
@@ -1394,8 +1391,8 @@ module Addressable
|
|
1394
1391
|
# @return [Integer] The port component, normalized.
|
1395
1392
|
def normalized_port
|
1396
1393
|
return nil unless self.port
|
1397
|
-
return @normalized_port
|
1398
|
-
@normalized_port
|
1394
|
+
return @normalized_port unless @normalized_port == NONE
|
1395
|
+
@normalized_port = begin
|
1399
1396
|
if URI.port_mapping[self.normalized_scheme] == self.port
|
1400
1397
|
nil
|
1401
1398
|
else
|
@@ -1426,8 +1423,8 @@ module Addressable
|
|
1426
1423
|
@port = nil if @port == 0
|
1427
1424
|
|
1428
1425
|
# Reset dependent values
|
1429
|
-
|
1430
|
-
|
1426
|
+
@authority = nil
|
1427
|
+
@normalized_port = NONE
|
1431
1428
|
remove_composite_values
|
1432
1429
|
|
1433
1430
|
# Ensure we haven't created an invalid URI
|
@@ -1528,9 +1525,7 @@ module Addressable
|
|
1528
1525
|
# The path component for this URI.
|
1529
1526
|
#
|
1530
1527
|
# @return [String] The path component.
|
1531
|
-
|
1532
|
-
return defined?(@path) ? @path : EMPTY_STR
|
1533
|
-
end
|
1528
|
+
attr_reader :path
|
1534
1529
|
|
1535
1530
|
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
1536
1531
|
##
|
@@ -1544,7 +1539,7 @@ module Addressable
|
|
1544
1539
|
# Relative paths with colons in the first segment are ambiguous.
|
1545
1540
|
path = path.sub(":", "%2F")
|
1546
1541
|
end
|
1547
|
-
# String#split(
|
1542
|
+
# String#split(delimiter, -1) uses the more strict splitting behavior
|
1548
1543
|
# found by default in Python.
|
1549
1544
|
result = path.strip.split(SLASH, -1).map do |segment|
|
1550
1545
|
Addressable::URI.normalize_component(
|
@@ -1579,7 +1574,7 @@ module Addressable
|
|
1579
1574
|
end
|
1580
1575
|
|
1581
1576
|
# Reset dependent values
|
1582
|
-
|
1577
|
+
@normalized_path = nil
|
1583
1578
|
remove_composite_values
|
1584
1579
|
|
1585
1580
|
# Ensure we haven't created an invalid URI
|
@@ -1609,9 +1604,7 @@ module Addressable
|
|
1609
1604
|
# The query component for this URI.
|
1610
1605
|
#
|
1611
1606
|
# @return [String] The query component.
|
1612
|
-
|
1613
|
-
return defined?(@query) ? @query : nil
|
1614
|
-
end
|
1607
|
+
attr_reader :query
|
1615
1608
|
|
1616
1609
|
##
|
1617
1610
|
# The query component for this URI, normalized.
|
@@ -1619,8 +1612,8 @@ module Addressable
|
|
1619
1612
|
# @return [String] The query component, normalized.
|
1620
1613
|
def normalized_query(*flags)
|
1621
1614
|
return nil unless self.query
|
1622
|
-
return @normalized_query
|
1623
|
-
@normalized_query
|
1615
|
+
return @normalized_query unless @normalized_query == NONE
|
1616
|
+
@normalized_query = begin
|
1624
1617
|
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
1625
1618
|
# Make sure possible key-value pair delimiters are escaped.
|
1626
1619
|
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
@@ -1652,7 +1645,7 @@ module Addressable
|
|
1652
1645
|
@query = new_query ? new_query.to_str : nil
|
1653
1646
|
|
1654
1647
|
# Reset dependent values
|
1655
|
-
|
1648
|
+
@normalized_query = NONE
|
1656
1649
|
remove_composite_values
|
1657
1650
|
end
|
1658
1651
|
|
@@ -1752,20 +1745,20 @@ module Addressable
|
|
1752
1745
|
buffer = "".dup
|
1753
1746
|
new_query_values.each do |key, value|
|
1754
1747
|
encoded_key = URI.encode_component(
|
1755
|
-
key,
|
1748
|
+
key, CharacterClassesRegexps::UNRESERVED
|
1756
1749
|
)
|
1757
1750
|
if value == nil
|
1758
1751
|
buffer << "#{encoded_key}&"
|
1759
1752
|
elsif value.kind_of?(Array)
|
1760
1753
|
value.each do |sub_value|
|
1761
1754
|
encoded_value = URI.encode_component(
|
1762
|
-
sub_value,
|
1755
|
+
sub_value, CharacterClassesRegexps::UNRESERVED
|
1763
1756
|
)
|
1764
1757
|
buffer << "#{encoded_key}=#{encoded_value}&"
|
1765
1758
|
end
|
1766
1759
|
else
|
1767
1760
|
encoded_value = URI.encode_component(
|
1768
|
-
value,
|
1761
|
+
value, CharacterClassesRegexps::UNRESERVED
|
1769
1762
|
)
|
1770
1763
|
buffer << "#{encoded_key}=#{encoded_value}&"
|
1771
1764
|
end
|
@@ -1814,9 +1807,7 @@ module Addressable
|
|
1814
1807
|
# The fragment component for this URI.
|
1815
1808
|
#
|
1816
1809
|
# @return [String] The fragment component.
|
1817
|
-
|
1818
|
-
return defined?(@fragment) ? @fragment : nil
|
1819
|
-
end
|
1810
|
+
attr_reader :fragment
|
1820
1811
|
|
1821
1812
|
##
|
1822
1813
|
# The fragment component for this URI, normalized.
|
@@ -1824,8 +1815,8 @@ module Addressable
|
|
1824
1815
|
# @return [String] The fragment component, normalized.
|
1825
1816
|
def normalized_fragment
|
1826
1817
|
return nil unless self.fragment
|
1827
|
-
return @normalized_fragment
|
1828
|
-
@normalized_fragment
|
1818
|
+
return @normalized_fragment unless @normalized_fragment == NONE
|
1819
|
+
@normalized_fragment = begin
|
1829
1820
|
component = Addressable::URI.normalize_component(
|
1830
1821
|
self.fragment,
|
1831
1822
|
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
@@ -1848,7 +1839,7 @@ module Addressable
|
|
1848
1839
|
@fragment = new_fragment ? new_fragment.to_str : nil
|
1849
1840
|
|
1850
1841
|
# Reset dependent values
|
1851
|
-
|
1842
|
+
@normalized_fragment = NONE
|
1852
1843
|
remove_composite_values
|
1853
1844
|
|
1854
1845
|
# Ensure we haven't created an invalid URI
|
@@ -2014,7 +2005,7 @@ module Addressable
|
|
2014
2005
|
#
|
2015
2006
|
# @see Hash#merge
|
2016
2007
|
def merge(hash)
|
2017
|
-
|
2008
|
+
unless hash.respond_to?(:to_hash)
|
2018
2009
|
raise TypeError, "Can't convert #{hash.class} into Hash."
|
2019
2010
|
end
|
2020
2011
|
hash = hash.to_hash
|
@@ -2408,7 +2399,27 @@ module Addressable
|
|
2408
2399
|
yield
|
2409
2400
|
@validation_deferred = false
|
2410
2401
|
validate
|
2411
|
-
|
2402
|
+
ensure
|
2403
|
+
@validation_deferred = false
|
2404
|
+
end
|
2405
|
+
|
2406
|
+
def encode_with(coder)
|
2407
|
+
instance_variables.each do |ivar|
|
2408
|
+
value = instance_variable_get(ivar)
|
2409
|
+
if value != NONE
|
2410
|
+
key = ivar.to_s.slice(1..-1)
|
2411
|
+
coder[key] = value
|
2412
|
+
end
|
2413
|
+
end
|
2414
|
+
nil
|
2415
|
+
end
|
2416
|
+
|
2417
|
+
def init_with(coder)
|
2418
|
+
reset_ivs
|
2419
|
+
coder.map.each do |key, value|
|
2420
|
+
instance_variable_set("@#{key}", value)
|
2421
|
+
end
|
2422
|
+
nil
|
2412
2423
|
end
|
2413
2424
|
|
2414
2425
|
protected
|
@@ -2507,11 +2518,7 @@ module Addressable
|
|
2507
2518
|
# @return [Addressable::URI] <code>self</code>.
|
2508
2519
|
def replace_self(uri)
|
2509
2520
|
# Reset dependent values
|
2510
|
-
|
2511
|
-
if instance_variable_defined?(var) && var != :@validation_deferred
|
2512
|
-
remove_instance_variable(var)
|
2513
|
-
end
|
2514
|
-
end
|
2521
|
+
reset_ivs
|
2515
2522
|
|
2516
2523
|
@scheme = uri.scheme
|
2517
2524
|
@user = uri.user
|
@@ -2543,8 +2550,8 @@ module Addressable
|
|
2543
2550
|
#
|
2544
2551
|
# @api private
|
2545
2552
|
def remove_composite_values
|
2546
|
-
|
2547
|
-
|
2553
|
+
@uri_string = nil
|
2554
|
+
@hash = nil
|
2548
2555
|
end
|
2549
2556
|
|
2550
2557
|
##
|
@@ -2556,5 +2563,40 @@ module Addressable
|
|
2556
2563
|
str.force_encoding(Encoding::UTF_8)
|
2557
2564
|
end
|
2558
2565
|
end
|
2566
|
+
|
2567
|
+
private
|
2568
|
+
|
2569
|
+
##
|
2570
|
+
# Resets instance variables
|
2571
|
+
#
|
2572
|
+
# @api private
|
2573
|
+
def reset_ivs
|
2574
|
+
@scheme = nil
|
2575
|
+
@user = nil
|
2576
|
+
@normalized_scheme = NONE
|
2577
|
+
@normalized_user = NONE
|
2578
|
+
@uri_string = nil
|
2579
|
+
@hash = nil
|
2580
|
+
@userinfo = nil
|
2581
|
+
@normalized_userinfo = NONE
|
2582
|
+
@authority = nil
|
2583
|
+
@password = nil
|
2584
|
+
@normalized_authority = nil
|
2585
|
+
@port = nil
|
2586
|
+
@normalized_password = NONE
|
2587
|
+
@host = nil
|
2588
|
+
@normalized_host = nil
|
2589
|
+
@normalized_port = NONE
|
2590
|
+
@path = EMPTY_STR
|
2591
|
+
@normalized_path = nil
|
2592
|
+
@normalized_query = NONE
|
2593
|
+
@fragment = nil
|
2594
|
+
@normalized_fragment = NONE
|
2595
|
+
@query = nil
|
2596
|
+
end
|
2597
|
+
|
2598
|
+
NONE = Module.new.freeze
|
2599
|
+
|
2600
|
+
private_constant :NONE
|
2559
2601
|
end
|
2560
2602
|
end
|