addressable 2.8.1 → 2.8.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -42
- data/Rakefile +11 -5
- 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 +9 -10
- data/lib/addressable/uri.rb +176 -134
- 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 +1 -1
- metadata +5 -4
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
|
##
|
@@ -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
|