addressable 2.8.1 → 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 +11 -2
- data/Rakefile +2 -1
- data/addressable.gemspec +28 -0
- data/lib/addressable/idna/native.rb +0 -4
- data/lib/addressable/idna/pure.rb +2 -184
- data/lib/addressable/template.rb +7 -5
- data/lib/addressable/uri.rb +112 -96
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +6 -5
- data/spec/addressable/template_spec.rb +24 -0
- data/spec/addressable/uri_spec.rb +56 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b18375911dede706411b9ec0d6c8b104e9f49a2ebf53ea18d89aec89a349d8f2
|
4
|
+
data.tar.gz: 4701c220482e3e92a10ebe9605ecb03fcf5d295bbef20346aeb49fdfbab4bbb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e6c9605ceec0aa65ceb3b4a1152d9c89830f1748e20c6667746634a9952a13fcff404ec1783f904e9240d642b11e2907914d43581fd8c451971c48106e70710
|
7
|
+
data.tar.gz: 7865e8accde73f97022353c51e9556f7f1f1786ed2e004789a9c4e5ffa82486ae2abe17166fa724f2bf17b8e853e40f185abf0ee16a4108aca712c202540b3e2
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,22 @@
|
|
1
|
+
# Addressable 2.8.2
|
2
|
+
- Improve cache hits and JIT friendliness ([#486](https://github.com/sporkmonger/addressable/pull/486))
|
3
|
+
- Improve code style and test coverage ([#482](https://github.com/sporkmonger/addressable/pull/482))
|
4
|
+
- Ensure reset of deferred validation ([#481](https://github.com/sporkmonger/addressable/pull/481))
|
5
|
+
- Resolve normalization differences between `IDNA::Native` and `IDNA::Pure` ([#408](https://github.com/sporkmonger/addressable/issues/408), [#492])
|
6
|
+
- Remove redundant colon in `Addressable::URI::CharacterClasses::AUTHORITY` regex ([#438](https://github.com/sporkmonger/addressable/pull/438)) (accidentally reverted by [#449] merge but [added back](https://github.com/sporkmonger/addressable/pull/492#discussion_r1105125280) in [#492])
|
7
|
+
|
8
|
+
[#492]: https://github.com/sporkmonger/addressable/pull/492
|
9
|
+
|
1
10
|
# Addressable 2.8.1
|
2
11
|
- refactor `Addressable::URI.normalize_path` to address linter offenses ([#430](https://github.com/sporkmonger/addressable/pull/430))
|
3
|
-
- remove redundant colon in `Addressable::URI::CharacterClasses::AUTHORITY` regex ([#438](https://github.com/sporkmonger/addressable/pull/438))
|
4
12
|
- update gemspec to reflect supported Ruby versions ([#466], [#464], [#463])
|
5
13
|
- compatibility w/ public_suffix 5.x ([#466], [#465], [#460])
|
6
14
|
- fixes "invalid byte sequence in UTF-8" exception when unencoding URLs containing non UTF-8 characters ([#459](https://github.com/sporkmonger/addressable/pull/459))
|
7
|
-
- `Ractor` compatibility ([#449]
|
15
|
+
- `Ractor` compatibility ([#449])
|
8
16
|
- use the whole string instead of a single line for template match ([#431](https://github.com/sporkmonger/addressable/pull/431))
|
9
17
|
- force UTF-8 encoding only if needed ([#341](https://github.com/sporkmonger/addressable/pull/341))
|
10
18
|
|
19
|
+
[#449]: https://github.com/sporkmonger/addressable/pull/449
|
11
20
|
[#460]: https://github.com/sporkmonger/addressable/pull/460
|
12
21
|
[#463]: https://github.com/sporkmonger/addressable/pull/463
|
13
22
|
[#464]: https://github.com/sporkmonger/addressable/pull/464
|
data/Rakefile
CHANGED
@@ -24,7 +24,8 @@ PKG_FILES = FileList[
|
|
24
24
|
"tasks/**/*",
|
25
25
|
"[A-Z]*", "Rakefile"
|
26
26
|
].exclude(/pkg/).exclude(/database\.yml/).
|
27
|
-
exclude(/Gemfile\.lock/).exclude(/[_\.]git$/)
|
27
|
+
exclude(/Gemfile\.lock/).exclude(/[_\.]git$/).
|
28
|
+
exclude(/coverage/)
|
28
29
|
|
29
30
|
task :default => "spec"
|
30
31
|
|
data/addressable.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: addressable 2.8.2 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "addressable".freeze
|
6
|
+
s.version = "2.8.2"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.metadata = { "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md" } if s.respond_to? :metadata=
|
10
|
+
s.require_paths = ["lib".freeze]
|
11
|
+
s.authors = ["Bob Aman".freeze]
|
12
|
+
s.date = "2023-04-01"
|
13
|
+
s.description = "Addressable is an alternative implementation to the URI implementation that is\npart of Ruby's standard library. It is flexible, offers heuristic parsing, and\nadditionally provides extensive support for IRIs and URI templates.\n".freeze
|
14
|
+
s.email = "bob@sporkmonger.com".freeze
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze]
|
16
|
+
s.files = ["CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "addressable.gemspec".freeze, "data/unicode.data".freeze, "lib/addressable.rb".freeze, "lib/addressable/idna.rb".freeze, "lib/addressable/idna/native.rb".freeze, "lib/addressable/idna/pure.rb".freeze, "lib/addressable/template.rb".freeze, "lib/addressable/uri.rb".freeze, "lib/addressable/version.rb".freeze, "spec/addressable/idna_spec.rb".freeze, "spec/addressable/net_http_compat_spec.rb".freeze, "spec/addressable/security_spec.rb".freeze, "spec/addressable/template_spec.rb".freeze, "spec/addressable/uri_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tasks/clobber.rake".freeze, "tasks/gem.rake".freeze, "tasks/git.rake".freeze, "tasks/metrics.rake".freeze, "tasks/profile.rake".freeze, "tasks/rspec.rake".freeze, "tasks/yard.rake".freeze]
|
17
|
+
s.homepage = "https://github.com/sporkmonger/addressable".freeze
|
18
|
+
s.licenses = ["Apache-2.0".freeze]
|
19
|
+
s.rdoc_options = ["--main".freeze, "README.md".freeze]
|
20
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze)
|
21
|
+
s.rubygems_version = "3.4.8".freeze
|
22
|
+
s.summary = "URI Implementation".freeze
|
23
|
+
|
24
|
+
s.specification_version = 4
|
25
|
+
|
26
|
+
s.add_runtime_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 6.0"])
|
27
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
28
|
+
end
|
@@ -29,10 +29,6 @@ module Addressable
|
|
29
29
|
IDN::Punycode.decode(value.to_s)
|
30
30
|
end
|
31
31
|
|
32
|
-
def self.unicode_normalize_kc(value)
|
33
|
-
IDN::Stringprep.nfkc_normalize(value.to_s)
|
34
|
-
end
|
35
|
-
|
36
32
|
def self.to_ascii(value)
|
37
33
|
value.to_s.split('.', -1).map do |segment|
|
38
34
|
if segment.size > 0 && segment.size < 64
|
@@ -66,7 +66,7 @@ module Addressable
|
|
66
66
|
# domain name as described in RFC 3490.
|
67
67
|
def self.to_ascii(input)
|
68
68
|
input = input.to_s unless input.is_a?(String)
|
69
|
-
input = input.dup
|
69
|
+
input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc)
|
70
70
|
if input.respond_to?(:force_encoding)
|
71
71
|
input.force_encoding(Encoding::ASCII_8BIT)
|
72
72
|
end
|
@@ -77,7 +77,7 @@ module Addressable
|
|
77
77
|
part.force_encoding(Encoding::ASCII_8BIT)
|
78
78
|
end
|
79
79
|
if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE
|
80
|
-
ACE_PREFIX + punycode_encode(
|
80
|
+
ACE_PREFIX + punycode_encode(part)
|
81
81
|
else
|
82
82
|
part
|
83
83
|
end
|
@@ -112,15 +112,6 @@ module Addressable
|
|
112
112
|
output
|
113
113
|
end
|
114
114
|
|
115
|
-
# Unicode normalization form KC.
|
116
|
-
def self.unicode_normalize_kc(input)
|
117
|
-
input = input.to_s unless input.is_a?(String)
|
118
|
-
unpacked = input.unpack("U*")
|
119
|
-
unpacked =
|
120
|
-
unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked)))
|
121
|
-
return unpacked.pack("U*")
|
122
|
-
end
|
123
|
-
|
124
115
|
##
|
125
116
|
# Unicode aware downcase method.
|
126
117
|
#
|
@@ -136,164 +127,6 @@ module Addressable
|
|
136
127
|
end
|
137
128
|
private_class_method :unicode_downcase
|
138
129
|
|
139
|
-
def self.unicode_compose(unpacked)
|
140
|
-
unpacked_result = []
|
141
|
-
length = unpacked.length
|
142
|
-
|
143
|
-
return unpacked if length == 0
|
144
|
-
|
145
|
-
starter = unpacked[0]
|
146
|
-
starter_cc = lookup_unicode_combining_class(starter)
|
147
|
-
starter_cc = 256 if starter_cc != 0
|
148
|
-
for i in 1...length
|
149
|
-
ch = unpacked[i]
|
150
|
-
|
151
|
-
if (starter_cc == 0 &&
|
152
|
-
(composite = unicode_compose_pair(starter, ch)) != nil)
|
153
|
-
starter = composite
|
154
|
-
else
|
155
|
-
unpacked_result << starter
|
156
|
-
starter = ch
|
157
|
-
end
|
158
|
-
end
|
159
|
-
unpacked_result << starter
|
160
|
-
return unpacked_result
|
161
|
-
end
|
162
|
-
private_class_method :unicode_compose
|
163
|
-
|
164
|
-
def self.unicode_compose_pair(ch_one, ch_two)
|
165
|
-
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
166
|
-
ch_two >= HANGUL_VBASE && ch_two < HANGUL_VBASE + HANGUL_VCOUNT
|
167
|
-
# Hangul L + V
|
168
|
-
return HANGUL_SBASE + (
|
169
|
-
(ch_one - HANGUL_LBASE) * HANGUL_VCOUNT + (ch_two - HANGUL_VBASE)
|
170
|
-
) * HANGUL_TCOUNT
|
171
|
-
elsif ch_one >= HANGUL_SBASE &&
|
172
|
-
ch_one < HANGUL_SBASE + HANGUL_SCOUNT &&
|
173
|
-
(ch_one - HANGUL_SBASE) % HANGUL_TCOUNT == 0 &&
|
174
|
-
ch_two >= HANGUL_TBASE && ch_two < HANGUL_TBASE + HANGUL_TCOUNT
|
175
|
-
# Hangul LV + T
|
176
|
-
return ch_one + (ch_two - HANGUL_TBASE)
|
177
|
-
end
|
178
|
-
|
179
|
-
p = []
|
180
|
-
|
181
|
-
ucs4_to_utf8(ch_one, p)
|
182
|
-
ucs4_to_utf8(ch_two, p)
|
183
|
-
|
184
|
-
return lookup_unicode_composition(p)
|
185
|
-
end
|
186
|
-
private_class_method :unicode_compose_pair
|
187
|
-
|
188
|
-
def self.ucs4_to_utf8(char, buffer)
|
189
|
-
if char < 128
|
190
|
-
buffer << char
|
191
|
-
elsif char < 2048
|
192
|
-
buffer << (char >> 6 | 192)
|
193
|
-
buffer << (char & 63 | 128)
|
194
|
-
elsif char < 0x10000
|
195
|
-
buffer << (char >> 12 | 224)
|
196
|
-
buffer << (char >> 6 & 63 | 128)
|
197
|
-
buffer << (char & 63 | 128)
|
198
|
-
elsif char < 0x200000
|
199
|
-
buffer << (char >> 18 | 240)
|
200
|
-
buffer << (char >> 12 & 63 | 128)
|
201
|
-
buffer << (char >> 6 & 63 | 128)
|
202
|
-
buffer << (char & 63 | 128)
|
203
|
-
elsif char < 0x4000000
|
204
|
-
buffer << (char >> 24 | 248)
|
205
|
-
buffer << (char >> 18 & 63 | 128)
|
206
|
-
buffer << (char >> 12 & 63 | 128)
|
207
|
-
buffer << (char >> 6 & 63 | 128)
|
208
|
-
buffer << (char & 63 | 128)
|
209
|
-
elsif char < 0x80000000
|
210
|
-
buffer << (char >> 30 | 252)
|
211
|
-
buffer << (char >> 24 & 63 | 128)
|
212
|
-
buffer << (char >> 18 & 63 | 128)
|
213
|
-
buffer << (char >> 12 & 63 | 128)
|
214
|
-
buffer << (char >> 6 & 63 | 128)
|
215
|
-
buffer << (char & 63 | 128)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
private_class_method :ucs4_to_utf8
|
219
|
-
|
220
|
-
def self.unicode_sort_canonical(unpacked)
|
221
|
-
unpacked = unpacked.dup
|
222
|
-
i = 1
|
223
|
-
length = unpacked.length
|
224
|
-
|
225
|
-
return unpacked if length < 2
|
226
|
-
|
227
|
-
while i < length
|
228
|
-
last = unpacked[i-1]
|
229
|
-
ch = unpacked[i]
|
230
|
-
last_cc = lookup_unicode_combining_class(last)
|
231
|
-
cc = lookup_unicode_combining_class(ch)
|
232
|
-
if cc != 0 && last_cc != 0 && last_cc > cc
|
233
|
-
unpacked[i] = last
|
234
|
-
unpacked[i-1] = ch
|
235
|
-
i -= 1 if i > 1
|
236
|
-
else
|
237
|
-
i += 1
|
238
|
-
end
|
239
|
-
end
|
240
|
-
return unpacked
|
241
|
-
end
|
242
|
-
private_class_method :unicode_sort_canonical
|
243
|
-
|
244
|
-
def self.unicode_decompose(unpacked)
|
245
|
-
unpacked_result = []
|
246
|
-
for cp in unpacked
|
247
|
-
if cp >= HANGUL_SBASE && cp < HANGUL_SBASE + HANGUL_SCOUNT
|
248
|
-
l, v, t = unicode_decompose_hangul(cp)
|
249
|
-
unpacked_result << l
|
250
|
-
unpacked_result << v if v
|
251
|
-
unpacked_result << t if t
|
252
|
-
else
|
253
|
-
dc = lookup_unicode_compatibility(cp)
|
254
|
-
unless dc
|
255
|
-
unpacked_result << cp
|
256
|
-
else
|
257
|
-
unpacked_result.concat(unicode_decompose(dc.unpack("U*")))
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
return unpacked_result
|
262
|
-
end
|
263
|
-
private_class_method :unicode_decompose
|
264
|
-
|
265
|
-
def self.unicode_decompose_hangul(codepoint)
|
266
|
-
sindex = codepoint - HANGUL_SBASE;
|
267
|
-
if sindex < 0 || sindex >= HANGUL_SCOUNT
|
268
|
-
l = codepoint
|
269
|
-
v = t = nil
|
270
|
-
return l, v, t
|
271
|
-
end
|
272
|
-
l = HANGUL_LBASE + sindex / HANGUL_NCOUNT
|
273
|
-
v = HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
|
274
|
-
t = HANGUL_TBASE + sindex % HANGUL_TCOUNT
|
275
|
-
if t == HANGUL_TBASE
|
276
|
-
t = nil
|
277
|
-
end
|
278
|
-
return l, v, t
|
279
|
-
end
|
280
|
-
private_class_method :unicode_decompose_hangul
|
281
|
-
|
282
|
-
def self.lookup_unicode_combining_class(codepoint)
|
283
|
-
codepoint_data = UNICODE_DATA[codepoint]
|
284
|
-
(codepoint_data ?
|
285
|
-
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
286
|
-
0)
|
287
|
-
end
|
288
|
-
private_class_method :lookup_unicode_combining_class
|
289
|
-
|
290
|
-
def self.lookup_unicode_compatibility(codepoint)
|
291
|
-
codepoint_data = UNICODE_DATA[codepoint]
|
292
|
-
(codepoint_data ?
|
293
|
-
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
294
|
-
end
|
295
|
-
private_class_method :lookup_unicode_compatibility
|
296
|
-
|
297
130
|
def self.lookup_unicode_lowercase(codepoint)
|
298
131
|
codepoint_data = UNICODE_DATA[codepoint]
|
299
132
|
(codepoint_data ?
|
@@ -302,21 +135,6 @@ module Addressable
|
|
302
135
|
end
|
303
136
|
private_class_method :lookup_unicode_lowercase
|
304
137
|
|
305
|
-
def self.lookup_unicode_composition(unpacked)
|
306
|
-
return COMPOSITION_TABLE[unpacked]
|
307
|
-
end
|
308
|
-
private_class_method :lookup_unicode_composition
|
309
|
-
|
310
|
-
HANGUL_SBASE = 0xac00
|
311
|
-
HANGUL_LBASE = 0x1100
|
312
|
-
HANGUL_LCOUNT = 19
|
313
|
-
HANGUL_VBASE = 0x1161
|
314
|
-
HANGUL_VCOUNT = 21
|
315
|
-
HANGUL_TBASE = 0x11a7
|
316
|
-
HANGUL_TCOUNT = 28
|
317
|
-
HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT # 588
|
318
|
-
HANGUL_SCOUNT = HANGUL_LCOUNT * HANGUL_NCOUNT # 11172
|
319
|
-
|
320
138
|
UNICODE_DATA_COMBINING_CLASS = 0
|
321
139
|
UNICODE_DATA_EXCLUSION = 1
|
322
140
|
UNICODE_DATA_CANONICAL = 2
|
data/lib/addressable/template.rb
CHANGED
@@ -892,7 +892,7 @@ module Addressable
|
|
892
892
|
# operator.
|
893
893
|
#
|
894
894
|
# @param [Hash, Array, String] value
|
895
|
-
# Normalizes keys and values with
|
895
|
+
# Normalizes unicode keys and values with String#unicode_normalize (NFC)
|
896
896
|
#
|
897
897
|
# @return [Hash, Array, String] The normalized values
|
898
898
|
def normalize_value(value)
|
@@ -902,15 +902,17 @@ module Addressable
|
|
902
902
|
|
903
903
|
# Handle unicode normalization
|
904
904
|
if value.kind_of?(Array)
|
905
|
-
value.map! { |val|
|
905
|
+
value.map! { |val| normalize_value(val) }
|
906
906
|
elsif value.kind_of?(Hash)
|
907
907
|
value = value.inject({}) { |acc, (k, v)|
|
908
|
-
acc[
|
909
|
-
Addressable::IDNA.unicode_normalize_kc(v)
|
908
|
+
acc[normalize_value(k)] = normalize_value(v)
|
910
909
|
acc
|
911
910
|
}
|
912
911
|
else
|
913
|
-
value
|
912
|
+
if value.encoding != Encoding::UTF_8
|
913
|
+
value = value.dup.force_encoding(Encoding::UTF_8)
|
914
|
+
end
|
915
|
+
value = value.unicode_normalize(:nfc)
|
914
916
|
end
|
915
917
|
value
|
916
918
|
end
|
data/lib/addressable/uri.rb
CHANGED
@@ -53,7 +53,7 @@ module Addressable
|
|
53
53
|
PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
|
54
54
|
SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
|
55
55
|
HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
|
56
|
-
AUTHORITY = (PCHAR + "\\[
|
56
|
+
AUTHORITY = (PCHAR + "\\[\\]").freeze
|
57
57
|
PATH = (PCHAR + "\\/").freeze
|
58
58
|
QUERY = (PCHAR + "\\/\\?").freeze
|
59
59
|
FRAGMENT = (PCHAR + "\\/\\?").freeze
|
@@ -117,7 +117,7 @@ module Addressable
|
|
117
117
|
uri = uri.to_str
|
118
118
|
rescue TypeError, NoMethodError
|
119
119
|
raise TypeError, "Can't convert #{uri.class} into String."
|
120
|
-
end
|
120
|
+
end unless uri.is_a?(String)
|
121
121
|
|
122
122
|
# This Regexp supplied as an example in RFC 3986, and it works great.
|
123
123
|
scan = uri.scan(URIREGEX)
|
@@ -138,15 +138,15 @@ module Addressable
|
|
138
138
|
user = userinfo.strip[/^([^:]*):?/, 1]
|
139
139
|
password = userinfo.strip[/:(.*)$/, 1]
|
140
140
|
end
|
141
|
+
|
141
142
|
host = authority.sub(
|
142
143
|
/^([^\[\]]*)@/, EMPTY_STR
|
143
144
|
).sub(
|
144
145
|
/:([^:@\[\]]*?)$/, EMPTY_STR
|
145
146
|
)
|
147
|
+
|
146
148
|
port = authority[/:([^:@\[\]]*?)$/, 1]
|
147
|
-
|
148
|
-
if port == EMPTY_STR
|
149
|
-
port = nil
|
149
|
+
port = nil if port == EMPTY_STR
|
150
150
|
end
|
151
151
|
|
152
152
|
return new(
|
@@ -189,7 +189,7 @@ module Addressable
|
|
189
189
|
uri = uri.to_s
|
190
190
|
end
|
191
191
|
|
192
|
-
|
192
|
+
unless uri.respond_to?(:to_str)
|
193
193
|
raise TypeError, "Can't convert #{uri.class} into String."
|
194
194
|
end
|
195
195
|
# Otherwise, convert to a String
|
@@ -281,7 +281,7 @@ module Addressable
|
|
281
281
|
return nil unless path
|
282
282
|
# If a URI object is passed, just return itself.
|
283
283
|
return path if path.kind_of?(self)
|
284
|
-
|
284
|
+
unless path.respond_to?(:to_str)
|
285
285
|
raise TypeError, "Can't convert #{path.class} into String."
|
286
286
|
end
|
287
287
|
# Otherwise, convert to a String
|
@@ -329,13 +329,13 @@ module Addressable
|
|
329
329
|
# #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
|
330
330
|
def self.join(*uris)
|
331
331
|
uri_objects = uris.collect do |uri|
|
332
|
-
|
332
|
+
unless uri.respond_to?(:to_str)
|
333
333
|
raise TypeError, "Can't convert #{uri.class} into String."
|
334
334
|
end
|
335
335
|
uri.kind_of?(self) ? uri : self.parse(uri.to_str)
|
336
336
|
end
|
337
337
|
result = uri_objects.shift.dup
|
338
|
-
|
338
|
+
uri_objects.each do |uri|
|
339
339
|
result.join!(uri)
|
340
340
|
end
|
341
341
|
return result
|
@@ -481,7 +481,7 @@ module Addressable
|
|
481
481
|
leave_encoded.include?(c) ? sequence : c
|
482
482
|
end
|
483
483
|
|
484
|
-
result.force_encoding(
|
484
|
+
result.force_encoding(Encoding::UTF_8)
|
485
485
|
if return_type == String
|
486
486
|
return result
|
487
487
|
elsif return_type == ::Addressable::URI
|
@@ -579,7 +579,7 @@ module Addressable
|
|
579
579
|
unencoded = self.unencode_component(component, String, leave_encoded)
|
580
580
|
begin
|
581
581
|
encoded = self.encode_component(
|
582
|
-
|
582
|
+
unencoded.unicode_normalize(:nfc),
|
583
583
|
character_class,
|
584
584
|
leave_encoded
|
585
585
|
)
|
@@ -687,8 +687,7 @@ module Addressable
|
|
687
687
|
components.each do |key, value|
|
688
688
|
if value != nil
|
689
689
|
begin
|
690
|
-
components[key] =
|
691
|
-
Addressable::IDNA.unicode_normalize_kc(value.to_str)
|
690
|
+
components[key] = value.to_str.unicode_normalize(:nfc)
|
692
691
|
rescue ArgumentError
|
693
692
|
# Likely a malformed UTF-8 character, skip unicode normalization
|
694
693
|
components[key] = value.to_str
|
@@ -836,7 +835,9 @@ module Addressable
|
|
836
835
|
end
|
837
836
|
end
|
838
837
|
|
839
|
-
|
838
|
+
reset_ivs
|
839
|
+
|
840
|
+
defer_validation do
|
840
841
|
# Bunch of crazy logic required because of the composite components
|
841
842
|
# like userinfo and authority.
|
842
843
|
self.scheme = options[:scheme] if options[:scheme]
|
@@ -851,7 +852,8 @@ module Addressable
|
|
851
852
|
self.query_values = options[:query_values] if options[:query_values]
|
852
853
|
self.fragment = options[:fragment] if options[:fragment]
|
853
854
|
end
|
854
|
-
|
855
|
+
|
856
|
+
to_s # force path validation
|
855
857
|
end
|
856
858
|
|
857
859
|
##
|
@@ -878,9 +880,7 @@ module Addressable
|
|
878
880
|
# The scheme component for this URI.
|
879
881
|
#
|
880
882
|
# @return [String] The scheme component.
|
881
|
-
|
882
|
-
return defined?(@scheme) ? @scheme : nil
|
883
|
-
end
|
883
|
+
attr_reader :scheme
|
884
884
|
|
885
885
|
##
|
886
886
|
# The scheme component for this URI, normalized.
|
@@ -888,8 +888,8 @@ module Addressable
|
|
888
888
|
# @return [String] The scheme component, normalized.
|
889
889
|
def normalized_scheme
|
890
890
|
return nil unless self.scheme
|
891
|
-
@normalized_scheme
|
892
|
-
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
891
|
+
if @normalized_scheme == NONE
|
892
|
+
@normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
893
893
|
"svn+ssh".dup
|
894
894
|
else
|
895
895
|
Addressable::URI.normalize_component(
|
@@ -920,7 +920,7 @@ module Addressable
|
|
920
920
|
@scheme = nil if @scheme.to_s.strip.empty?
|
921
921
|
|
922
922
|
# Reset dependent values
|
923
|
-
|
923
|
+
@normalized_scheme = NONE
|
924
924
|
remove_composite_values
|
925
925
|
|
926
926
|
# Ensure we haven't created an invalid URI
|
@@ -931,9 +931,7 @@ module Addressable
|
|
931
931
|
# The user component for this URI.
|
932
932
|
#
|
933
933
|
# @return [String] The user component.
|
934
|
-
|
935
|
-
return defined?(@user) ? @user : nil
|
936
|
-
end
|
934
|
+
attr_reader :user
|
937
935
|
|
938
936
|
##
|
939
937
|
# The user component for this URI, normalized.
|
@@ -941,8 +939,8 @@ module Addressable
|
|
941
939
|
# @return [String] The user component, normalized.
|
942
940
|
def normalized_user
|
943
941
|
return nil unless self.user
|
944
|
-
return @normalized_user
|
945
|
-
@normalized_user
|
942
|
+
return @normalized_user unless @normalized_user == NONE
|
943
|
+
@normalized_user = begin
|
946
944
|
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
947
945
|
(!self.password || self.password.strip.empty?)
|
948
946
|
nil
|
@@ -970,14 +968,14 @@ module Addressable
|
|
970
968
|
|
971
969
|
# You can't have a nil user with a non-nil password
|
972
970
|
if password != nil
|
973
|
-
@user = EMPTY_STR
|
971
|
+
@user = EMPTY_STR unless user
|
974
972
|
end
|
975
973
|
|
976
974
|
# Reset dependent values
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
975
|
+
@userinfo = nil
|
976
|
+
@normalized_userinfo = NONE
|
977
|
+
@authority = nil
|
978
|
+
@normalized_user = NONE
|
981
979
|
remove_composite_values
|
982
980
|
|
983
981
|
# Ensure we haven't created an invalid URI
|
@@ -988,9 +986,7 @@ module Addressable
|
|
988
986
|
# The password component for this URI.
|
989
987
|
#
|
990
988
|
# @return [String] The password component.
|
991
|
-
|
992
|
-
return defined?(@password) ? @password : nil
|
993
|
-
end
|
989
|
+
attr_reader :password
|
994
990
|
|
995
991
|
##
|
996
992
|
# The password component for this URI, normalized.
|
@@ -998,8 +994,8 @@ module Addressable
|
|
998
994
|
# @return [String] The password component, normalized.
|
999
995
|
def normalized_password
|
1000
996
|
return nil unless self.password
|
1001
|
-
return @normalized_password
|
1002
|
-
@normalized_password
|
997
|
+
return @normalized_password unless @normalized_password == NONE
|
998
|
+
@normalized_password = begin
|
1003
999
|
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
1004
1000
|
(!self.user || self.user.strip.empty?)
|
1005
1001
|
nil
|
@@ -1026,17 +1022,15 @@ module Addressable
|
|
1026
1022
|
@password = new_password ? new_password.to_str : nil
|
1027
1023
|
|
1028
1024
|
# You can't have a nil user with a non-nil password
|
1029
|
-
@password ||= nil
|
1030
|
-
@user ||= nil
|
1031
1025
|
if @password != nil
|
1032
|
-
|
1026
|
+
self.user = EMPTY_STR if user.nil?
|
1033
1027
|
end
|
1034
1028
|
|
1035
1029
|
# Reset dependent values
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1030
|
+
@userinfo = nil
|
1031
|
+
@normalized_userinfo = NONE
|
1032
|
+
@authority = nil
|
1033
|
+
@normalized_password = NONE
|
1040
1034
|
remove_composite_values
|
1041
1035
|
|
1042
1036
|
# Ensure we haven't created an invalid URI
|
@@ -1066,8 +1060,8 @@ module Addressable
|
|
1066
1060
|
# @return [String] The userinfo component, normalized.
|
1067
1061
|
def normalized_userinfo
|
1068
1062
|
return nil unless self.userinfo
|
1069
|
-
return @normalized_userinfo
|
1070
|
-
@normalized_userinfo
|
1063
|
+
return @normalized_userinfo unless @normalized_userinfo == NONE
|
1064
|
+
@normalized_userinfo = begin
|
1071
1065
|
current_user = self.normalized_user
|
1072
1066
|
current_password = self.normalized_password
|
1073
1067
|
if !current_user && !current_password
|
@@ -1105,7 +1099,7 @@ module Addressable
|
|
1105
1099
|
self.user = new_user
|
1106
1100
|
|
1107
1101
|
# Reset dependent values
|
1108
|
-
|
1102
|
+
@authority = nil
|
1109
1103
|
remove_composite_values
|
1110
1104
|
|
1111
1105
|
# Ensure we haven't created an invalid URI
|
@@ -1116,9 +1110,7 @@ module Addressable
|
|
1116
1110
|
# The host component for this URI.
|
1117
1111
|
#
|
1118
1112
|
# @return [String] The host component.
|
1119
|
-
|
1120
|
-
return defined?(@host) ? @host : nil
|
1121
|
-
end
|
1113
|
+
attr_reader :host
|
1122
1114
|
|
1123
1115
|
##
|
1124
1116
|
# The host component for this URI, normalized.
|
@@ -1161,8 +1153,8 @@ module Addressable
|
|
1161
1153
|
@host = new_host ? new_host.to_str : nil
|
1162
1154
|
|
1163
1155
|
# Reset dependent values
|
1164
|
-
|
1165
|
-
|
1156
|
+
@authority = nil
|
1157
|
+
@normalized_host = nil
|
1166
1158
|
remove_composite_values
|
1167
1159
|
|
1168
1160
|
# Ensure we haven't created an invalid URI
|
@@ -1293,14 +1285,14 @@ module Addressable
|
|
1293
1285
|
end
|
1294
1286
|
|
1295
1287
|
# Password assigned first to ensure validity in case of nil
|
1296
|
-
self.password =
|
1297
|
-
self.user =
|
1298
|
-
self.host =
|
1299
|
-
self.port =
|
1288
|
+
self.password = new_password
|
1289
|
+
self.user = new_user
|
1290
|
+
self.host = new_host
|
1291
|
+
self.port = new_port
|
1300
1292
|
|
1301
1293
|
# Reset dependent values
|
1302
|
-
|
1303
|
-
|
1294
|
+
@userinfo = nil
|
1295
|
+
@normalized_userinfo = NONE
|
1304
1296
|
remove_composite_values
|
1305
1297
|
|
1306
1298
|
# Ensure we haven't created an invalid URI
|
@@ -1348,16 +1340,16 @@ module Addressable
|
|
1348
1340
|
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
1349
1341
|
end
|
1350
1342
|
|
1351
|
-
self.scheme =
|
1352
|
-
self.host =
|
1353
|
-
self.port =
|
1343
|
+
self.scheme = new_scheme
|
1344
|
+
self.host = new_host
|
1345
|
+
self.port = new_port
|
1354
1346
|
self.userinfo = nil
|
1355
1347
|
|
1356
1348
|
# Reset dependent values
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1349
|
+
@userinfo = nil
|
1350
|
+
@normalized_userinfo = NONE
|
1351
|
+
@authority = nil
|
1352
|
+
@normalized_authority = nil
|
1361
1353
|
remove_composite_values
|
1362
1354
|
|
1363
1355
|
# Ensure we haven't created an invalid URI
|
@@ -1384,9 +1376,7 @@ module Addressable
|
|
1384
1376
|
# infer port numbers from default values.
|
1385
1377
|
#
|
1386
1378
|
# @return [Integer] The port component.
|
1387
|
-
|
1388
|
-
return defined?(@port) ? @port : nil
|
1389
|
-
end
|
1379
|
+
attr_reader :port
|
1390
1380
|
|
1391
1381
|
##
|
1392
1382
|
# The port component for this URI, normalized.
|
@@ -1394,8 +1384,8 @@ module Addressable
|
|
1394
1384
|
# @return [Integer] The port component, normalized.
|
1395
1385
|
def normalized_port
|
1396
1386
|
return nil unless self.port
|
1397
|
-
return @normalized_port
|
1398
|
-
@normalized_port
|
1387
|
+
return @normalized_port unless @normalized_port == NONE
|
1388
|
+
@normalized_port = begin
|
1399
1389
|
if URI.port_mapping[self.normalized_scheme] == self.port
|
1400
1390
|
nil
|
1401
1391
|
else
|
@@ -1426,8 +1416,8 @@ module Addressable
|
|
1426
1416
|
@port = nil if @port == 0
|
1427
1417
|
|
1428
1418
|
# Reset dependent values
|
1429
|
-
|
1430
|
-
|
1419
|
+
@authority = nil
|
1420
|
+
@normalized_port = NONE
|
1431
1421
|
remove_composite_values
|
1432
1422
|
|
1433
1423
|
# Ensure we haven't created an invalid URI
|
@@ -1528,9 +1518,7 @@ module Addressable
|
|
1528
1518
|
# The path component for this URI.
|
1529
1519
|
#
|
1530
1520
|
# @return [String] The path component.
|
1531
|
-
|
1532
|
-
return defined?(@path) ? @path : EMPTY_STR
|
1533
|
-
end
|
1521
|
+
attr_reader :path
|
1534
1522
|
|
1535
1523
|
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
1536
1524
|
##
|
@@ -1579,7 +1567,7 @@ module Addressable
|
|
1579
1567
|
end
|
1580
1568
|
|
1581
1569
|
# Reset dependent values
|
1582
|
-
|
1570
|
+
@normalized_path = nil
|
1583
1571
|
remove_composite_values
|
1584
1572
|
|
1585
1573
|
# Ensure we haven't created an invalid URI
|
@@ -1609,9 +1597,7 @@ module Addressable
|
|
1609
1597
|
# The query component for this URI.
|
1610
1598
|
#
|
1611
1599
|
# @return [String] The query component.
|
1612
|
-
|
1613
|
-
return defined?(@query) ? @query : nil
|
1614
|
-
end
|
1600
|
+
attr_reader :query
|
1615
1601
|
|
1616
1602
|
##
|
1617
1603
|
# The query component for this URI, normalized.
|
@@ -1619,8 +1605,8 @@ module Addressable
|
|
1619
1605
|
# @return [String] The query component, normalized.
|
1620
1606
|
def normalized_query(*flags)
|
1621
1607
|
return nil unless self.query
|
1622
|
-
return @normalized_query
|
1623
|
-
@normalized_query
|
1608
|
+
return @normalized_query unless @normalized_query == NONE
|
1609
|
+
@normalized_query = begin
|
1624
1610
|
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
1625
1611
|
# Make sure possible key-value pair delimiters are escaped.
|
1626
1612
|
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
@@ -1652,7 +1638,7 @@ module Addressable
|
|
1652
1638
|
@query = new_query ? new_query.to_str : nil
|
1653
1639
|
|
1654
1640
|
# Reset dependent values
|
1655
|
-
|
1641
|
+
@normalized_query = NONE
|
1656
1642
|
remove_composite_values
|
1657
1643
|
end
|
1658
1644
|
|
@@ -1814,9 +1800,7 @@ module Addressable
|
|
1814
1800
|
# The fragment component for this URI.
|
1815
1801
|
#
|
1816
1802
|
# @return [String] The fragment component.
|
1817
|
-
|
1818
|
-
return defined?(@fragment) ? @fragment : nil
|
1819
|
-
end
|
1803
|
+
attr_reader :fragment
|
1820
1804
|
|
1821
1805
|
##
|
1822
1806
|
# The fragment component for this URI, normalized.
|
@@ -1824,8 +1808,8 @@ module Addressable
|
|
1824
1808
|
# @return [String] The fragment component, normalized.
|
1825
1809
|
def normalized_fragment
|
1826
1810
|
return nil unless self.fragment
|
1827
|
-
return @normalized_fragment
|
1828
|
-
@normalized_fragment
|
1811
|
+
return @normalized_fragment unless @normalized_fragment == NONE
|
1812
|
+
@normalized_fragment = begin
|
1829
1813
|
component = Addressable::URI.normalize_component(
|
1830
1814
|
self.fragment,
|
1831
1815
|
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
@@ -1848,7 +1832,7 @@ module Addressable
|
|
1848
1832
|
@fragment = new_fragment ? new_fragment.to_str : nil
|
1849
1833
|
|
1850
1834
|
# Reset dependent values
|
1851
|
-
|
1835
|
+
@normalized_fragment = NONE
|
1852
1836
|
remove_composite_values
|
1853
1837
|
|
1854
1838
|
# Ensure we haven't created an invalid URI
|
@@ -2014,7 +1998,7 @@ module Addressable
|
|
2014
1998
|
#
|
2015
1999
|
# @see Hash#merge
|
2016
2000
|
def merge(hash)
|
2017
|
-
|
2001
|
+
unless hash.respond_to?(:to_hash)
|
2018
2002
|
raise TypeError, "Can't convert #{hash.class} into Hash."
|
2019
2003
|
end
|
2020
2004
|
hash = hash.to_hash
|
@@ -2408,7 +2392,8 @@ module Addressable
|
|
2408
2392
|
yield
|
2409
2393
|
@validation_deferred = false
|
2410
2394
|
validate
|
2411
|
-
|
2395
|
+
ensure
|
2396
|
+
@validation_deferred = false
|
2412
2397
|
end
|
2413
2398
|
|
2414
2399
|
protected
|
@@ -2507,11 +2492,7 @@ module Addressable
|
|
2507
2492
|
# @return [Addressable::URI] <code>self</code>.
|
2508
2493
|
def replace_self(uri)
|
2509
2494
|
# Reset dependent values
|
2510
|
-
|
2511
|
-
if instance_variable_defined?(var) && var != :@validation_deferred
|
2512
|
-
remove_instance_variable(var)
|
2513
|
-
end
|
2514
|
-
end
|
2495
|
+
reset_ivs
|
2515
2496
|
|
2516
2497
|
@scheme = uri.scheme
|
2517
2498
|
@user = uri.user
|
@@ -2543,8 +2524,8 @@ module Addressable
|
|
2543
2524
|
#
|
2544
2525
|
# @api private
|
2545
2526
|
def remove_composite_values
|
2546
|
-
|
2547
|
-
|
2527
|
+
@uri_string = nil
|
2528
|
+
@hash = nil
|
2548
2529
|
end
|
2549
2530
|
|
2550
2531
|
##
|
@@ -2556,5 +2537,40 @@ module Addressable
|
|
2556
2537
|
str.force_encoding(Encoding::UTF_8)
|
2557
2538
|
end
|
2558
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
|
2559
2575
|
end
|
2560
2576
|
end
|
data/lib/addressable/version.rb
CHANGED
@@ -38,6 +38,12 @@ shared_examples_for "converting from unicode to ASCII" do
|
|
38
38
|
)).to eq("www.xn--8ws00zhy3a.com")
|
39
39
|
end
|
40
40
|
|
41
|
+
it "also accepts unicode strings encoded as ascii-8bit" do
|
42
|
+
expect(Addressable::IDNA.to_ascii(
|
43
|
+
"www.詹姆斯.com".b
|
44
|
+
)).to eq("www.xn--8ws00zhy3a.com")
|
45
|
+
end
|
46
|
+
|
41
47
|
it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do
|
42
48
|
"www.Iñtërnâtiônàlizætiøn.com"
|
43
49
|
expect(Addressable::IDNA.to_ascii(
|
@@ -249,11 +255,6 @@ shared_examples_for "converting from ASCII to unicode" do
|
|
249
255
|
"example..host"
|
250
256
|
)).to eq("example..host")
|
251
257
|
end
|
252
|
-
|
253
|
-
it "should normalize 'string' correctly" do
|
254
|
-
expect(Addressable::IDNA.unicode_normalize_kc(:'string')).to eq("string")
|
255
|
-
expect(Addressable::IDNA.unicode_normalize_kc("string")).to eq("string")
|
256
|
-
end
|
257
258
|
end
|
258
259
|
|
259
260
|
describe Addressable::IDNA, "when using the pure-Ruby implementation" do
|
@@ -1021,6 +1021,19 @@ describe Addressable::Template do
|
|
1021
1021
|
)
|
1022
1022
|
end
|
1023
1023
|
|
1024
|
+
it "normalizes as unicode even with wrong encoding specified" do
|
1025
|
+
template = subject.partial_expand("query" => "Cafe\u0301".b)
|
1026
|
+
expect(template.pattern).to eq(
|
1027
|
+
"http://example.com/{resource}/Caf%C3%A9/"
|
1028
|
+
)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
it "raises on invalid unicode input" do
|
1032
|
+
expect {
|
1033
|
+
subject.partial_expand("query" => "M\xE9thode".b)
|
1034
|
+
}.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
|
1035
|
+
end
|
1036
|
+
|
1024
1037
|
it "does not normalize unicode when byte semantics requested" do
|
1025
1038
|
template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false)
|
1026
1039
|
expect(template.pattern).to eq(
|
@@ -1081,6 +1094,17 @@ describe Addressable::Template do
|
|
1081
1094
|
expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
|
1082
1095
|
end
|
1083
1096
|
|
1097
|
+
it "normalizes as unicode even with wrong encoding specified" do
|
1098
|
+
uri = subject.expand("query" => "Cafe\u0301".b).to_str
|
1099
|
+
expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
it "raises on invalid unicode input" do
|
1103
|
+
expect {
|
1104
|
+
subject.expand("query" => "M\xE9thode".b).to_str
|
1105
|
+
}.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
|
1106
|
+
end
|
1107
|
+
|
1084
1108
|
it "does not normalize unicode when byte semantics requested" do
|
1085
1109
|
uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str
|
1086
1110
|
expect(uri).to eq("http://example.com/search/Cafe%CC%81/")
|
@@ -3021,6 +3021,20 @@ describe Addressable::URI, "when parsed from " +
|
|
3021
3021
|
end
|
3022
3022
|
end
|
3023
3023
|
|
3024
|
+
describe Addressable::URI, "when parsed with empty port" do
|
3025
|
+
subject(:uri) do
|
3026
|
+
Addressable::URI.parse("//example.com:")
|
3027
|
+
end
|
3028
|
+
|
3029
|
+
it "should not infer a port" do
|
3030
|
+
expect(uri.port).to be(nil)
|
3031
|
+
end
|
3032
|
+
|
3033
|
+
it "should have a site value of '//example.com'" do
|
3034
|
+
expect(uri.site).to eq("//example.com")
|
3035
|
+
end
|
3036
|
+
end
|
3037
|
+
|
3024
3038
|
describe Addressable::URI, "when parsed from " +
|
3025
3039
|
"'http://example.com/%2E/'" do
|
3026
3040
|
before do
|
@@ -5939,6 +5953,26 @@ describe Addressable::URI, "when normalizing a path with an encoded slash" do
|
|
5939
5953
|
end
|
5940
5954
|
end
|
5941
5955
|
|
5956
|
+
describe Addressable::URI, "when normalizing a path with special unicode" do
|
5957
|
+
it "does not stop at or ignore null bytes" do
|
5958
|
+
expect(Addressable::URI.parse("/path%00segment/").normalize.path).to eq(
|
5959
|
+
"/path%00segment/"
|
5960
|
+
)
|
5961
|
+
end
|
5962
|
+
|
5963
|
+
it "does apply NFC unicode normalization" do
|
5964
|
+
expect(Addressable::URI.parse("/%E2%84%A6").normalize.path).to eq(
|
5965
|
+
"/%CE%A9"
|
5966
|
+
)
|
5967
|
+
end
|
5968
|
+
|
5969
|
+
it "does not apply NFKC unicode normalization" do
|
5970
|
+
expect(Addressable::URI.parse("/%C2%AF%C2%A0").normalize.path).to eq(
|
5971
|
+
"/%C2%AF%C2%A0"
|
5972
|
+
)
|
5973
|
+
end
|
5974
|
+
end
|
5975
|
+
|
5942
5976
|
describe Addressable::URI, "when normalizing a partially encoded string" do
|
5943
5977
|
it "should result in correct percent encoded sequence" do
|
5944
5978
|
expect(Addressable::URI.normalize_component(
|
@@ -6743,3 +6777,25 @@ describe Addressable::URI, "when initialized in a non-main `Ractor`" do
|
|
6743
6777
|
).to eq(main)
|
6744
6778
|
end
|
6745
6779
|
end
|
6780
|
+
|
6781
|
+
describe Addressable::URI, "when deferring validation" do
|
6782
|
+
subject(:deferred) { uri.instance_variable_get(:@validation_deferred) }
|
6783
|
+
|
6784
|
+
let(:uri) { Addressable::URI.parse("http://example.com") }
|
6785
|
+
|
6786
|
+
it "defers validation within the block" do
|
6787
|
+
uri.defer_validation do
|
6788
|
+
expect(deferred).to be true
|
6789
|
+
end
|
6790
|
+
end
|
6791
|
+
|
6792
|
+
it "always resets deferral afterward" do
|
6793
|
+
expect { uri.defer_validation { raise "boom" } }.to raise_error("boom")
|
6794
|
+
expect(deferred).to be false
|
6795
|
+
end
|
6796
|
+
|
6797
|
+
it "returns nil" do
|
6798
|
+
res = uri.defer_validation {}
|
6799
|
+
expect(res).to be nil
|
6800
|
+
end
|
6801
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: addressable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.8.
|
4
|
+
version: 2.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Aman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: public_suffix
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- LICENSE.txt
|
66
66
|
- README.md
|
67
67
|
- Rakefile
|
68
|
+
- addressable.gemspec
|
68
69
|
- data/unicode.data
|
69
70
|
- lib/addressable.rb
|
70
71
|
- lib/addressable/idna.rb
|
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
109
|
- !ruby/object:Gem::Version
|
109
110
|
version: '0'
|
110
111
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
112
|
+
rubygems_version: 3.4.8
|
112
113
|
signing_key:
|
113
114
|
specification_version: 4
|
114
115
|
summary: URI Implementation
|