addressable 2.8.0 → 2.8.5
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 +45 -0
- data/Gemfile +4 -2
- data/Rakefile +11 -5
- 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 +199 -164
- 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 +176 -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
|
|
@@ -339,17 +344,13 @@ module Addressable
|
|
|
339
344
|
##
|
|
340
345
|
# Tables used to optimize encoding operations in `self.encode_component`
|
|
341
346
|
# and `self.normalize_component`
|
|
342
|
-
SEQUENCE_ENCODING_TABLE =
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
end.join
|
|
346
|
-
end
|
|
347
|
+
SEQUENCE_ENCODING_TABLE = (0..255).map do |byte|
|
|
348
|
+
format("%02x", byte).freeze
|
|
349
|
+
end.freeze
|
|
347
350
|
|
|
348
|
-
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE =
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
end.join
|
|
352
|
-
end
|
|
351
|
+
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte|
|
|
352
|
+
format("%%%02X", byte).freeze
|
|
353
|
+
end.freeze
|
|
353
354
|
|
|
354
355
|
##
|
|
355
356
|
# Percent encodes a URI component.
|
|
@@ -416,16 +417,17 @@ module Addressable
|
|
|
416
417
|
component = component.dup
|
|
417
418
|
component.force_encoding(Encoding::ASCII_8BIT)
|
|
418
419
|
# Avoiding gsub! because there are edge cases with frozen strings
|
|
419
|
-
component = component.gsub(character_class) do |
|
|
420
|
-
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[
|
|
420
|
+
component = component.gsub(character_class) do |char|
|
|
421
|
+
SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord]
|
|
421
422
|
end
|
|
422
423
|
if upcase_encoded.length > 0
|
|
423
|
-
upcase_encoded_chars = upcase_encoded.
|
|
424
|
-
SEQUENCE_ENCODING_TABLE[
|
|
424
|
+
upcase_encoded_chars = upcase_encoded.bytes.map do |byte|
|
|
425
|
+
SEQUENCE_ENCODING_TABLE[byte]
|
|
425
426
|
end
|
|
426
427
|
component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
|
|
427
428
|
&:upcase)
|
|
428
429
|
end
|
|
430
|
+
|
|
429
431
|
return component
|
|
430
432
|
end
|
|
431
433
|
|
|
@@ -469,20 +471,14 @@ module Addressable
|
|
|
469
471
|
"Expected Class (String or Addressable::URI), " +
|
|
470
472
|
"got #{return_type.inspect}"
|
|
471
473
|
end
|
|
472
|
-
uri = uri.dup
|
|
473
|
-
# Seriously, only use UTF-8. I'm really not kidding!
|
|
474
|
-
uri.force_encoding("utf-8")
|
|
475
|
-
|
|
476
|
-
unless leave_encoded.empty?
|
|
477
|
-
leave_encoded = leave_encoded.dup.force_encoding("utf-8")
|
|
478
|
-
end
|
|
479
474
|
|
|
480
|
-
result = uri.gsub(/%[0-9a-f]{2}/
|
|
475
|
+
result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
|
|
481
476
|
c = sequence[1..3].to_i(16).chr
|
|
482
|
-
c.force_encoding(
|
|
477
|
+
c.force_encoding(sequence.encoding)
|
|
483
478
|
leave_encoded.include?(c) ? sequence : c
|
|
484
479
|
end
|
|
485
|
-
|
|
480
|
+
|
|
481
|
+
result.force_encoding(Encoding::UTF_8)
|
|
486
482
|
if return_type == String
|
|
487
483
|
return result
|
|
488
484
|
elsif return_type == ::Addressable::URI
|
|
@@ -561,10 +557,9 @@ module Addressable
|
|
|
561
557
|
leave_re = if leave_encoded.length > 0
|
|
562
558
|
character_class = "#{character_class}%" unless character_class.include?('%')
|
|
563
559
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
end.flatten.join('|')})"
|
|
560
|
+
bytes = leave_encoded.bytes
|
|
561
|
+
leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|')
|
|
562
|
+
"|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})"
|
|
568
563
|
end
|
|
569
564
|
|
|
570
565
|
character_class = if leave_re
|
|
@@ -580,7 +575,7 @@ module Addressable
|
|
|
580
575
|
unencoded = self.unencode_component(component, String, leave_encoded)
|
|
581
576
|
begin
|
|
582
577
|
encoded = self.encode_component(
|
|
583
|
-
|
|
578
|
+
unencoded.unicode_normalize(:nfc),
|
|
584
579
|
character_class,
|
|
585
580
|
leave_encoded
|
|
586
581
|
)
|
|
@@ -688,8 +683,7 @@ module Addressable
|
|
|
688
683
|
components.each do |key, value|
|
|
689
684
|
if value != nil
|
|
690
685
|
begin
|
|
691
|
-
components[key] =
|
|
692
|
-
Addressable::IDNA.unicode_normalize_kc(value.to_str)
|
|
686
|
+
components[key] = value.to_str.unicode_normalize(:nfc)
|
|
693
687
|
rescue ArgumentError
|
|
694
688
|
# Likely a malformed UTF-8 character, skip unicode normalization
|
|
695
689
|
components[key] = value.to_str
|
|
@@ -837,7 +831,9 @@ module Addressable
|
|
|
837
831
|
end
|
|
838
832
|
end
|
|
839
833
|
|
|
840
|
-
|
|
834
|
+
reset_ivs
|
|
835
|
+
|
|
836
|
+
defer_validation do
|
|
841
837
|
# Bunch of crazy logic required because of the composite components
|
|
842
838
|
# like userinfo and authority.
|
|
843
839
|
self.scheme = options[:scheme] if options[:scheme]
|
|
@@ -852,7 +848,8 @@ module Addressable
|
|
|
852
848
|
self.query_values = options[:query_values] if options[:query_values]
|
|
853
849
|
self.fragment = options[:fragment] if options[:fragment]
|
|
854
850
|
end
|
|
855
|
-
|
|
851
|
+
|
|
852
|
+
to_s # force path validation
|
|
856
853
|
end
|
|
857
854
|
|
|
858
855
|
##
|
|
@@ -879,9 +876,7 @@ module Addressable
|
|
|
879
876
|
# The scheme component for this URI.
|
|
880
877
|
#
|
|
881
878
|
# @return [String] The scheme component.
|
|
882
|
-
|
|
883
|
-
return defined?(@scheme) ? @scheme : nil
|
|
884
|
-
end
|
|
879
|
+
attr_reader :scheme
|
|
885
880
|
|
|
886
881
|
##
|
|
887
882
|
# The scheme component for this URI, normalized.
|
|
@@ -889,8 +884,8 @@ module Addressable
|
|
|
889
884
|
# @return [String] The scheme component, normalized.
|
|
890
885
|
def normalized_scheme
|
|
891
886
|
return nil unless self.scheme
|
|
892
|
-
@normalized_scheme
|
|
893
|
-
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
|
887
|
+
if @normalized_scheme == NONE
|
|
888
|
+
@normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
|
894
889
|
"svn+ssh".dup
|
|
895
890
|
else
|
|
896
891
|
Addressable::URI.normalize_component(
|
|
@@ -900,7 +895,7 @@ module Addressable
|
|
|
900
895
|
end
|
|
901
896
|
end
|
|
902
897
|
# All normalized values should be UTF-8
|
|
903
|
-
@normalized_scheme
|
|
898
|
+
force_utf8_encoding_if_needed(@normalized_scheme)
|
|
904
899
|
@normalized_scheme
|
|
905
900
|
end
|
|
906
901
|
|
|
@@ -921,7 +916,7 @@ module Addressable
|
|
|
921
916
|
@scheme = nil if @scheme.to_s.strip.empty?
|
|
922
917
|
|
|
923
918
|
# Reset dependent values
|
|
924
|
-
|
|
919
|
+
@normalized_scheme = NONE
|
|
925
920
|
remove_composite_values
|
|
926
921
|
|
|
927
922
|
# Ensure we haven't created an invalid URI
|
|
@@ -932,9 +927,7 @@ module Addressable
|
|
|
932
927
|
# The user component for this URI.
|
|
933
928
|
#
|
|
934
929
|
# @return [String] The user component.
|
|
935
|
-
|
|
936
|
-
return defined?(@user) ? @user : nil
|
|
937
|
-
end
|
|
930
|
+
attr_reader :user
|
|
938
931
|
|
|
939
932
|
##
|
|
940
933
|
# The user component for this URI, normalized.
|
|
@@ -942,8 +935,8 @@ module Addressable
|
|
|
942
935
|
# @return [String] The user component, normalized.
|
|
943
936
|
def normalized_user
|
|
944
937
|
return nil unless self.user
|
|
945
|
-
return @normalized_user
|
|
946
|
-
@normalized_user
|
|
938
|
+
return @normalized_user unless @normalized_user == NONE
|
|
939
|
+
@normalized_user = begin
|
|
947
940
|
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
|
948
941
|
(!self.password || self.password.strip.empty?)
|
|
949
942
|
nil
|
|
@@ -955,7 +948,7 @@ module Addressable
|
|
|
955
948
|
end
|
|
956
949
|
end
|
|
957
950
|
# All normalized values should be UTF-8
|
|
958
|
-
@normalized_user
|
|
951
|
+
force_utf8_encoding_if_needed(@normalized_user)
|
|
959
952
|
@normalized_user
|
|
960
953
|
end
|
|
961
954
|
|
|
@@ -971,14 +964,14 @@ module Addressable
|
|
|
971
964
|
|
|
972
965
|
# You can't have a nil user with a non-nil password
|
|
973
966
|
if password != nil
|
|
974
|
-
@user = EMPTY_STR
|
|
967
|
+
@user = EMPTY_STR unless user
|
|
975
968
|
end
|
|
976
969
|
|
|
977
970
|
# Reset dependent values
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
971
|
+
@userinfo = nil
|
|
972
|
+
@normalized_userinfo = NONE
|
|
973
|
+
@authority = nil
|
|
974
|
+
@normalized_user = NONE
|
|
982
975
|
remove_composite_values
|
|
983
976
|
|
|
984
977
|
# Ensure we haven't created an invalid URI
|
|
@@ -989,9 +982,7 @@ module Addressable
|
|
|
989
982
|
# The password component for this URI.
|
|
990
983
|
#
|
|
991
984
|
# @return [String] The password component.
|
|
992
|
-
|
|
993
|
-
return defined?(@password) ? @password : nil
|
|
994
|
-
end
|
|
985
|
+
attr_reader :password
|
|
995
986
|
|
|
996
987
|
##
|
|
997
988
|
# The password component for this URI, normalized.
|
|
@@ -999,8 +990,8 @@ module Addressable
|
|
|
999
990
|
# @return [String] The password component, normalized.
|
|
1000
991
|
def normalized_password
|
|
1001
992
|
return nil unless self.password
|
|
1002
|
-
return @normalized_password
|
|
1003
|
-
@normalized_password
|
|
993
|
+
return @normalized_password unless @normalized_password == NONE
|
|
994
|
+
@normalized_password = begin
|
|
1004
995
|
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
|
1005
996
|
(!self.user || self.user.strip.empty?)
|
|
1006
997
|
nil
|
|
@@ -1012,9 +1003,7 @@ module Addressable
|
|
|
1012
1003
|
end
|
|
1013
1004
|
end
|
|
1014
1005
|
# All normalized values should be UTF-8
|
|
1015
|
-
|
|
1016
|
-
@normalized_password.force_encoding(Encoding::UTF_8)
|
|
1017
|
-
end
|
|
1006
|
+
force_utf8_encoding_if_needed(@normalized_password)
|
|
1018
1007
|
@normalized_password
|
|
1019
1008
|
end
|
|
1020
1009
|
|
|
@@ -1029,17 +1018,15 @@ module Addressable
|
|
|
1029
1018
|
@password = new_password ? new_password.to_str : nil
|
|
1030
1019
|
|
|
1031
1020
|
# You can't have a nil user with a non-nil password
|
|
1032
|
-
@password ||= nil
|
|
1033
|
-
@user ||= nil
|
|
1034
1021
|
if @password != nil
|
|
1035
|
-
|
|
1022
|
+
self.user = EMPTY_STR if user.nil?
|
|
1036
1023
|
end
|
|
1037
1024
|
|
|
1038
1025
|
# Reset dependent values
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1026
|
+
@userinfo = nil
|
|
1027
|
+
@normalized_userinfo = NONE
|
|
1028
|
+
@authority = nil
|
|
1029
|
+
@normalized_password = NONE
|
|
1043
1030
|
remove_composite_values
|
|
1044
1031
|
|
|
1045
1032
|
# Ensure we haven't created an invalid URI
|
|
@@ -1069,8 +1056,8 @@ module Addressable
|
|
|
1069
1056
|
# @return [String] The userinfo component, normalized.
|
|
1070
1057
|
def normalized_userinfo
|
|
1071
1058
|
return nil unless self.userinfo
|
|
1072
|
-
return @normalized_userinfo
|
|
1073
|
-
@normalized_userinfo
|
|
1059
|
+
return @normalized_userinfo unless @normalized_userinfo == NONE
|
|
1060
|
+
@normalized_userinfo = begin
|
|
1074
1061
|
current_user = self.normalized_user
|
|
1075
1062
|
current_password = self.normalized_password
|
|
1076
1063
|
if !current_user && !current_password
|
|
@@ -1082,9 +1069,7 @@ module Addressable
|
|
|
1082
1069
|
end
|
|
1083
1070
|
end
|
|
1084
1071
|
# All normalized values should be UTF-8
|
|
1085
|
-
|
|
1086
|
-
@normalized_userinfo.force_encoding(Encoding::UTF_8)
|
|
1087
|
-
end
|
|
1072
|
+
force_utf8_encoding_if_needed(@normalized_userinfo)
|
|
1088
1073
|
@normalized_userinfo
|
|
1089
1074
|
end
|
|
1090
1075
|
|
|
@@ -1110,7 +1095,7 @@ module Addressable
|
|
|
1110
1095
|
self.user = new_user
|
|
1111
1096
|
|
|
1112
1097
|
# Reset dependent values
|
|
1113
|
-
|
|
1098
|
+
@authority = nil
|
|
1114
1099
|
remove_composite_values
|
|
1115
1100
|
|
|
1116
1101
|
# Ensure we haven't created an invalid URI
|
|
@@ -1121,9 +1106,7 @@ module Addressable
|
|
|
1121
1106
|
# The host component for this URI.
|
|
1122
1107
|
#
|
|
1123
1108
|
# @return [String] The host component.
|
|
1124
|
-
|
|
1125
|
-
return defined?(@host) ? @host : nil
|
|
1126
|
-
end
|
|
1109
|
+
attr_reader :host
|
|
1127
1110
|
|
|
1128
1111
|
##
|
|
1129
1112
|
# The host component for this URI, normalized.
|
|
@@ -1151,9 +1134,7 @@ module Addressable
|
|
|
1151
1134
|
end
|
|
1152
1135
|
end
|
|
1153
1136
|
# All normalized values should be UTF-8
|
|
1154
|
-
|
|
1155
|
-
@normalized_host.force_encoding(Encoding::UTF_8)
|
|
1156
|
-
end
|
|
1137
|
+
force_utf8_encoding_if_needed(@normalized_host)
|
|
1157
1138
|
@normalized_host
|
|
1158
1139
|
end
|
|
1159
1140
|
|
|
@@ -1168,8 +1149,8 @@ module Addressable
|
|
|
1168
1149
|
@host = new_host ? new_host.to_str : nil
|
|
1169
1150
|
|
|
1170
1151
|
# Reset dependent values
|
|
1171
|
-
|
|
1172
|
-
|
|
1152
|
+
@authority = nil
|
|
1153
|
+
@normalized_host = nil
|
|
1173
1154
|
remove_composite_values
|
|
1174
1155
|
|
|
1175
1156
|
# Ensure we haven't created an invalid URI
|
|
@@ -1271,9 +1252,7 @@ module Addressable
|
|
|
1271
1252
|
authority
|
|
1272
1253
|
end
|
|
1273
1254
|
# All normalized values should be UTF-8
|
|
1274
|
-
|
|
1275
|
-
@normalized_authority.force_encoding(Encoding::UTF_8)
|
|
1276
|
-
end
|
|
1255
|
+
force_utf8_encoding_if_needed(@normalized_authority)
|
|
1277
1256
|
@normalized_authority
|
|
1278
1257
|
end
|
|
1279
1258
|
|
|
@@ -1302,14 +1281,14 @@ module Addressable
|
|
|
1302
1281
|
end
|
|
1303
1282
|
|
|
1304
1283
|
# Password assigned first to ensure validity in case of nil
|
|
1305
|
-
self.password =
|
|
1306
|
-
self.user =
|
|
1307
|
-
self.host =
|
|
1308
|
-
self.port =
|
|
1284
|
+
self.password = new_password
|
|
1285
|
+
self.user = new_user
|
|
1286
|
+
self.host = new_host
|
|
1287
|
+
self.port = new_port
|
|
1309
1288
|
|
|
1310
1289
|
# Reset dependent values
|
|
1311
|
-
|
|
1312
|
-
|
|
1290
|
+
@userinfo = nil
|
|
1291
|
+
@normalized_userinfo = NONE
|
|
1313
1292
|
remove_composite_values
|
|
1314
1293
|
|
|
1315
1294
|
# Ensure we haven't created an invalid URI
|
|
@@ -1357,16 +1336,16 @@ module Addressable
|
|
|
1357
1336
|
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
|
1358
1337
|
end
|
|
1359
1338
|
|
|
1360
|
-
self.scheme =
|
|
1361
|
-
self.host =
|
|
1362
|
-
self.port =
|
|
1339
|
+
self.scheme = new_scheme
|
|
1340
|
+
self.host = new_host
|
|
1341
|
+
self.port = new_port
|
|
1363
1342
|
self.userinfo = nil
|
|
1364
1343
|
|
|
1365
1344
|
# Reset dependent values
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1345
|
+
@userinfo = nil
|
|
1346
|
+
@normalized_userinfo = NONE
|
|
1347
|
+
@authority = nil
|
|
1348
|
+
@normalized_authority = nil
|
|
1370
1349
|
remove_composite_values
|
|
1371
1350
|
|
|
1372
1351
|
# Ensure we haven't created an invalid URI
|
|
@@ -1393,9 +1372,7 @@ module Addressable
|
|
|
1393
1372
|
# infer port numbers from default values.
|
|
1394
1373
|
#
|
|
1395
1374
|
# @return [Integer] The port component.
|
|
1396
|
-
|
|
1397
|
-
return defined?(@port) ? @port : nil
|
|
1398
|
-
end
|
|
1375
|
+
attr_reader :port
|
|
1399
1376
|
|
|
1400
1377
|
##
|
|
1401
1378
|
# The port component for this URI, normalized.
|
|
@@ -1403,8 +1380,8 @@ module Addressable
|
|
|
1403
1380
|
# @return [Integer] The port component, normalized.
|
|
1404
1381
|
def normalized_port
|
|
1405
1382
|
return nil unless self.port
|
|
1406
|
-
return @normalized_port
|
|
1407
|
-
@normalized_port
|
|
1383
|
+
return @normalized_port unless @normalized_port == NONE
|
|
1384
|
+
@normalized_port = begin
|
|
1408
1385
|
if URI.port_mapping[self.normalized_scheme] == self.port
|
|
1409
1386
|
nil
|
|
1410
1387
|
else
|
|
@@ -1435,8 +1412,8 @@ module Addressable
|
|
|
1435
1412
|
@port = nil if @port == 0
|
|
1436
1413
|
|
|
1437
1414
|
# Reset dependent values
|
|
1438
|
-
|
|
1439
|
-
|
|
1415
|
+
@authority = nil
|
|
1416
|
+
@normalized_port = NONE
|
|
1440
1417
|
remove_composite_values
|
|
1441
1418
|
|
|
1442
1419
|
# Ensure we haven't created an invalid URI
|
|
@@ -1507,7 +1484,7 @@ module Addressable
|
|
|
1507
1484
|
site_string
|
|
1508
1485
|
end
|
|
1509
1486
|
# All normalized values should be UTF-8
|
|
1510
|
-
@normalized_site
|
|
1487
|
+
force_utf8_encoding_if_needed(@normalized_site)
|
|
1511
1488
|
@normalized_site
|
|
1512
1489
|
end
|
|
1513
1490
|
|
|
@@ -1537,9 +1514,7 @@ module Addressable
|
|
|
1537
1514
|
# The path component for this URI.
|
|
1538
1515
|
#
|
|
1539
1516
|
# @return [String] The path component.
|
|
1540
|
-
|
|
1541
|
-
return defined?(@path) ? @path : EMPTY_STR
|
|
1542
|
-
end
|
|
1517
|
+
attr_reader :path
|
|
1543
1518
|
|
|
1544
1519
|
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
|
1545
1520
|
##
|
|
@@ -1570,7 +1545,7 @@ module Addressable
|
|
|
1570
1545
|
result
|
|
1571
1546
|
end
|
|
1572
1547
|
# All normalized values should be UTF-8
|
|
1573
|
-
@normalized_path
|
|
1548
|
+
force_utf8_encoding_if_needed(@normalized_path)
|
|
1574
1549
|
@normalized_path
|
|
1575
1550
|
end
|
|
1576
1551
|
|
|
@@ -1588,7 +1563,7 @@ module Addressable
|
|
|
1588
1563
|
end
|
|
1589
1564
|
|
|
1590
1565
|
# Reset dependent values
|
|
1591
|
-
|
|
1566
|
+
@normalized_path = nil
|
|
1592
1567
|
remove_composite_values
|
|
1593
1568
|
|
|
1594
1569
|
# Ensure we haven't created an invalid URI
|
|
@@ -1618,9 +1593,7 @@ module Addressable
|
|
|
1618
1593
|
# The query component for this URI.
|
|
1619
1594
|
#
|
|
1620
1595
|
# @return [String] The query component.
|
|
1621
|
-
|
|
1622
|
-
return defined?(@query) ? @query : nil
|
|
1623
|
-
end
|
|
1596
|
+
attr_reader :query
|
|
1624
1597
|
|
|
1625
1598
|
##
|
|
1626
1599
|
# The query component for this URI, normalized.
|
|
@@ -1628,8 +1601,8 @@ module Addressable
|
|
|
1628
1601
|
# @return [String] The query component, normalized.
|
|
1629
1602
|
def normalized_query(*flags)
|
|
1630
1603
|
return nil unless self.query
|
|
1631
|
-
return @normalized_query
|
|
1632
|
-
@normalized_query
|
|
1604
|
+
return @normalized_query unless @normalized_query == NONE
|
|
1605
|
+
@normalized_query = begin
|
|
1633
1606
|
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
|
1634
1607
|
# Make sure possible key-value pair delimiters are escaped.
|
|
1635
1608
|
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
|
@@ -1646,7 +1619,7 @@ module Addressable
|
|
|
1646
1619
|
component == "" ? nil : component
|
|
1647
1620
|
end
|
|
1648
1621
|
# All normalized values should be UTF-8
|
|
1649
|
-
@normalized_query
|
|
1622
|
+
force_utf8_encoding_if_needed(@normalized_query)
|
|
1650
1623
|
@normalized_query
|
|
1651
1624
|
end
|
|
1652
1625
|
|
|
@@ -1661,7 +1634,7 @@ module Addressable
|
|
|
1661
1634
|
@query = new_query ? new_query.to_str : nil
|
|
1662
1635
|
|
|
1663
1636
|
# Reset dependent values
|
|
1664
|
-
|
|
1637
|
+
@normalized_query = NONE
|
|
1665
1638
|
remove_composite_values
|
|
1666
1639
|
end
|
|
1667
1640
|
|
|
@@ -1823,9 +1796,7 @@ module Addressable
|
|
|
1823
1796
|
# The fragment component for this URI.
|
|
1824
1797
|
#
|
|
1825
1798
|
# @return [String] The fragment component.
|
|
1826
|
-
|
|
1827
|
-
return defined?(@fragment) ? @fragment : nil
|
|
1828
|
-
end
|
|
1799
|
+
attr_reader :fragment
|
|
1829
1800
|
|
|
1830
1801
|
##
|
|
1831
1802
|
# The fragment component for this URI, normalized.
|
|
@@ -1833,8 +1804,8 @@ module Addressable
|
|
|
1833
1804
|
# @return [String] The fragment component, normalized.
|
|
1834
1805
|
def normalized_fragment
|
|
1835
1806
|
return nil unless self.fragment
|
|
1836
|
-
return @normalized_fragment
|
|
1837
|
-
@normalized_fragment
|
|
1807
|
+
return @normalized_fragment unless @normalized_fragment == NONE
|
|
1808
|
+
@normalized_fragment = begin
|
|
1838
1809
|
component = Addressable::URI.normalize_component(
|
|
1839
1810
|
self.fragment,
|
|
1840
1811
|
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
|
@@ -1842,9 +1813,7 @@ module Addressable
|
|
|
1842
1813
|
component == "" ? nil : component
|
|
1843
1814
|
end
|
|
1844
1815
|
# All normalized values should be UTF-8
|
|
1845
|
-
|
|
1846
|
-
@normalized_fragment.force_encoding(Encoding::UTF_8)
|
|
1847
|
-
end
|
|
1816
|
+
force_utf8_encoding_if_needed(@normalized_fragment)
|
|
1848
1817
|
@normalized_fragment
|
|
1849
1818
|
end
|
|
1850
1819
|
|
|
@@ -1859,7 +1828,7 @@ module Addressable
|
|
|
1859
1828
|
@fragment = new_fragment ? new_fragment.to_str : nil
|
|
1860
1829
|
|
|
1861
1830
|
# Reset dependent values
|
|
1862
|
-
|
|
1831
|
+
@normalized_fragment = NONE
|
|
1863
1832
|
remove_composite_values
|
|
1864
1833
|
|
|
1865
1834
|
# Ensure we haven't created an invalid URI
|
|
@@ -2025,7 +1994,7 @@ module Addressable
|
|
|
2025
1994
|
#
|
|
2026
1995
|
# @see Hash#merge
|
|
2027
1996
|
def merge(hash)
|
|
2028
|
-
|
|
1997
|
+
unless hash.respond_to?(:to_hash)
|
|
2029
1998
|
raise TypeError, "Can't convert #{hash.class} into Hash."
|
|
2030
1999
|
end
|
|
2031
2000
|
hash = hash.to_hash
|
|
@@ -2419,7 +2388,27 @@ module Addressable
|
|
|
2419
2388
|
yield
|
|
2420
2389
|
@validation_deferred = false
|
|
2421
2390
|
validate
|
|
2422
|
-
|
|
2391
|
+
ensure
|
|
2392
|
+
@validation_deferred = false
|
|
2393
|
+
end
|
|
2394
|
+
|
|
2395
|
+
def encode_with(coder)
|
|
2396
|
+
instance_variables.each do |ivar|
|
|
2397
|
+
value = instance_variable_get(ivar)
|
|
2398
|
+
if value != NONE
|
|
2399
|
+
key = ivar.to_s.slice(1..-1)
|
|
2400
|
+
coder[key] = value
|
|
2401
|
+
end
|
|
2402
|
+
end
|
|
2403
|
+
nil
|
|
2404
|
+
end
|
|
2405
|
+
|
|
2406
|
+
def init_with(coder)
|
|
2407
|
+
reset_ivs
|
|
2408
|
+
coder.map.each do |key, value|
|
|
2409
|
+
instance_variable_set("@#{key}", value)
|
|
2410
|
+
end
|
|
2411
|
+
nil
|
|
2423
2412
|
end
|
|
2424
2413
|
|
|
2425
2414
|
protected
|
|
@@ -2440,30 +2429,35 @@ module Addressable
|
|
|
2440
2429
|
def self.normalize_path(path)
|
|
2441
2430
|
# Section 5.2.4 of RFC 3986
|
|
2442
2431
|
|
|
2443
|
-
return
|
|
2432
|
+
return if path.nil?
|
|
2444
2433
|
normalized_path = path.dup
|
|
2445
|
-
|
|
2446
|
-
mod = nil
|
|
2434
|
+
loop do
|
|
2447
2435
|
mod ||= normalized_path.gsub!(RULE_2A, SLASH)
|
|
2448
2436
|
|
|
2449
2437
|
pair = normalized_path.match(RULE_2B_2C)
|
|
2450
|
-
|
|
2438
|
+
if pair
|
|
2439
|
+
parent = pair[1]
|
|
2440
|
+
current = pair[2]
|
|
2441
|
+
else
|
|
2442
|
+
parent = nil
|
|
2443
|
+
current = nil
|
|
2444
|
+
end
|
|
2445
|
+
|
|
2446
|
+
regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|"
|
|
2447
|
+
regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
|
|
2448
|
+
|
|
2451
2449
|
if pair && ((parent != SELF_REF && parent != PARENT) ||
|
|
2452
2450
|
(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
|
-
)
|
|
2451
|
+
mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH)
|
|
2459
2452
|
end
|
|
2460
2453
|
|
|
2461
2454
|
mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
|
|
2462
2455
|
# Non-standard, removes prefixed dotted segments from path.
|
|
2463
2456
|
mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
|
|
2464
|
-
|
|
2457
|
+
break if mod.nil?
|
|
2458
|
+
end
|
|
2465
2459
|
|
|
2466
|
-
|
|
2460
|
+
normalized_path
|
|
2467
2461
|
end
|
|
2468
2462
|
|
|
2469
2463
|
##
|
|
@@ -2513,11 +2507,7 @@ module Addressable
|
|
|
2513
2507
|
# @return [Addressable::URI] <code>self</code>.
|
|
2514
2508
|
def replace_self(uri)
|
|
2515
2509
|
# Reset dependent values
|
|
2516
|
-
|
|
2517
|
-
if instance_variable_defined?(var) && var != :@validation_deferred
|
|
2518
|
-
remove_instance_variable(var)
|
|
2519
|
-
end
|
|
2520
|
-
end
|
|
2510
|
+
reset_ivs
|
|
2521
2511
|
|
|
2522
2512
|
@scheme = uri.scheme
|
|
2523
2513
|
@user = uri.user
|
|
@@ -2549,8 +2539,53 @@ module Addressable
|
|
|
2549
2539
|
#
|
|
2550
2540
|
# @api private
|
|
2551
2541
|
def remove_composite_values
|
|
2552
|
-
|
|
2553
|
-
|
|
2542
|
+
@uri_string = nil
|
|
2543
|
+
@hash = nil
|
|
2544
|
+
end
|
|
2545
|
+
|
|
2546
|
+
##
|
|
2547
|
+
# Converts the string to be UTF-8 if it is not already UTF-8
|
|
2548
|
+
#
|
|
2549
|
+
# @api private
|
|
2550
|
+
def force_utf8_encoding_if_needed(str)
|
|
2551
|
+
if str && str.encoding != Encoding::UTF_8
|
|
2552
|
+
str.force_encoding(Encoding::UTF_8)
|
|
2553
|
+
end
|
|
2554
2554
|
end
|
|
2555
|
+
|
|
2556
|
+
private
|
|
2557
|
+
|
|
2558
|
+
##
|
|
2559
|
+
# Resets instance variables
|
|
2560
|
+
#
|
|
2561
|
+
# @api private
|
|
2562
|
+
def reset_ivs
|
|
2563
|
+
@scheme = nil
|
|
2564
|
+
@user = nil
|
|
2565
|
+
@normalized_scheme = NONE
|
|
2566
|
+
@normalized_user = NONE
|
|
2567
|
+
@uri_string = nil
|
|
2568
|
+
@hash = nil
|
|
2569
|
+
@userinfo = nil
|
|
2570
|
+
@normalized_userinfo = NONE
|
|
2571
|
+
@authority = nil
|
|
2572
|
+
@password = nil
|
|
2573
|
+
@normalized_authority = nil
|
|
2574
|
+
@port = nil
|
|
2575
|
+
@normalized_password = NONE
|
|
2576
|
+
@host = nil
|
|
2577
|
+
@normalized_host = nil
|
|
2578
|
+
@normalized_port = NONE
|
|
2579
|
+
@path = EMPTY_STR
|
|
2580
|
+
@normalized_path = nil
|
|
2581
|
+
@normalized_query = NONE
|
|
2582
|
+
@fragment = nil
|
|
2583
|
+
@normalized_fragment = NONE
|
|
2584
|
+
@query = nil
|
|
2585
|
+
end
|
|
2586
|
+
|
|
2587
|
+
NONE = Module.new.freeze
|
|
2588
|
+
|
|
2589
|
+
private_constant :NONE
|
|
2555
2590
|
end
|
|
2556
2591
|
end
|