addressable 2.8.0 → 2.8.2
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 +25 -0
- data/Gemfile +4 -2
- data/Rakefile +2 -1
- data/addressable.gemspec +9 -18
- data/lib/addressable/idna/native.rb +0 -5
- data/lib/addressable/idna/pure.rb +2 -185
- data/lib/addressable/idna.rb +0 -1
- data/lib/addressable/template.rb +10 -9
- data/lib/addressable/uri.rb +168 -148
- data/lib/addressable/version.rb +1 -2
- data/spec/addressable/idna_spec.rb +6 -6
- data/spec/addressable/net_http_compat_spec.rb +0 -1
- data/spec/addressable/security_spec.rb +0 -1
- data/spec/addressable/template_spec.rb +33 -1
- data/spec/addressable/uri_spec.rb +137 -1
- data/tasks/gem.rake +5 -2
- metadata +11 -10
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,3 +1,28 @@
|
|
|
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
|
+
|
|
10
|
+
# Addressable 2.8.1
|
|
11
|
+
- refactor `Addressable::URI.normalize_path` to address linter offenses ([#430](https://github.com/sporkmonger/addressable/pull/430))
|
|
12
|
+
- update gemspec to reflect supported Ruby versions ([#466], [#464], [#463])
|
|
13
|
+
- compatibility w/ public_suffix 5.x ([#466], [#465], [#460])
|
|
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))
|
|
15
|
+
- `Ractor` compatibility ([#449])
|
|
16
|
+
- use the whole string instead of a single line for template match ([#431](https://github.com/sporkmonger/addressable/pull/431))
|
|
17
|
+
- force UTF-8 encoding only if needed ([#341](https://github.com/sporkmonger/addressable/pull/341))
|
|
18
|
+
|
|
19
|
+
[#449]: https://github.com/sporkmonger/addressable/pull/449
|
|
20
|
+
[#460]: https://github.com/sporkmonger/addressable/pull/460
|
|
21
|
+
[#463]: https://github.com/sporkmonger/addressable/pull/463
|
|
22
|
+
[#464]: https://github.com/sporkmonger/addressable/pull/464
|
|
23
|
+
[#465]: https://github.com/sporkmonger/addressable/pull/465
|
|
24
|
+
[#466]: https://github.com/sporkmonger/addressable/pull/466
|
|
25
|
+
|
|
1
26
|
# Addressable 2.8.0
|
|
2
27
|
- fixes ReDoS vulnerability in Addressable::Template#match
|
|
3
28
|
- no longer replaces `+` with spaces in queries for non-http(s) schemes
|
data/Gemfile
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
gemspec
|
|
5
|
+
gemspec
|
|
6
6
|
|
|
7
7
|
group :test do
|
|
8
8
|
gem 'rspec', '~> 3.8'
|
|
@@ -25,4 +25,6 @@ group :test, :development do
|
|
|
25
25
|
gem "rake", ">= 12.3.3"
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
unless ENV["IDNA_MODE"] == "pure"
|
|
29
|
+
gem "idn-ruby", platform: :mri
|
|
30
|
+
end
|
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
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: addressable 2.8.
|
|
2
|
+
# stub: addressable 2.8.2 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "addressable".freeze
|
|
6
|
-
s.version = "2.8.
|
|
6
|
+
s.version = "2.8.2"
|
|
7
7
|
|
|
8
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=
|
|
9
10
|
s.require_paths = ["lib".freeze]
|
|
10
11
|
s.authors = ["Bob Aman".freeze]
|
|
11
|
-
s.date = "
|
|
12
|
+
s.date = "2023-04-01"
|
|
12
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
|
|
13
14
|
s.email = "bob@sporkmonger.com".freeze
|
|
14
15
|
s.extra_rdoc_files = ["README.md".freeze]
|
|
@@ -16,22 +17,12 @@ Gem::Specification.new do |s|
|
|
|
16
17
|
s.homepage = "https://github.com/sporkmonger/addressable".freeze
|
|
17
18
|
s.licenses = ["Apache-2.0".freeze]
|
|
18
19
|
s.rdoc_options = ["--main".freeze, "README.md".freeze]
|
|
19
|
-
s.required_ruby_version = Gem::Requirement.new(">= 2.
|
|
20
|
-
s.rubygems_version = "3.
|
|
20
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze)
|
|
21
|
+
s.rubygems_version = "3.4.8".freeze
|
|
21
22
|
s.summary = "URI Implementation".freeze
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
s.specification_version = 4
|
|
24
|
+
s.specification_version = 4
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
s.add_development_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
|
29
|
-
else
|
|
30
|
-
s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
|
31
|
-
s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
|
32
|
-
end
|
|
33
|
-
else
|
|
34
|
-
s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
|
35
|
-
s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
|
36
|
-
end
|
|
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"])
|
|
37
28
|
end
|
|
@@ -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
|
#
|
|
@@ -30,10 +29,6 @@ module Addressable
|
|
|
30
29
|
IDN::Punycode.decode(value.to_s)
|
|
31
30
|
end
|
|
32
31
|
|
|
33
|
-
def self.unicode_normalize_kc(value)
|
|
34
|
-
IDN::Stringprep.nfkc_normalize(value.to_s)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
32
|
def self.to_ascii(value)
|
|
38
33
|
value.to_s.split('.', -1).map do |segment|
|
|
39
34
|
if segment.size > 0 && segment.size < 64
|
|
@@ -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
|
#
|
|
@@ -67,7 +66,7 @@ module Addressable
|
|
|
67
66
|
# domain name as described in RFC 3490.
|
|
68
67
|
def self.to_ascii(input)
|
|
69
68
|
input = input.to_s unless input.is_a?(String)
|
|
70
|
-
input = input.dup
|
|
69
|
+
input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc)
|
|
71
70
|
if input.respond_to?(:force_encoding)
|
|
72
71
|
input.force_encoding(Encoding::ASCII_8BIT)
|
|
73
72
|
end
|
|
@@ -78,7 +77,7 @@ module Addressable
|
|
|
78
77
|
part.force_encoding(Encoding::ASCII_8BIT)
|
|
79
78
|
end
|
|
80
79
|
if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE
|
|
81
|
-
ACE_PREFIX + punycode_encode(
|
|
80
|
+
ACE_PREFIX + punycode_encode(part)
|
|
82
81
|
else
|
|
83
82
|
part
|
|
84
83
|
end
|
|
@@ -113,15 +112,6 @@ module Addressable
|
|
|
113
112
|
output
|
|
114
113
|
end
|
|
115
114
|
|
|
116
|
-
# Unicode normalization form KC.
|
|
117
|
-
def self.unicode_normalize_kc(input)
|
|
118
|
-
input = input.to_s unless input.is_a?(String)
|
|
119
|
-
unpacked = input.unpack("U*")
|
|
120
|
-
unpacked =
|
|
121
|
-
unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked)))
|
|
122
|
-
return unpacked.pack("U*")
|
|
123
|
-
end
|
|
124
|
-
|
|
125
115
|
##
|
|
126
116
|
# Unicode aware downcase method.
|
|
127
117
|
#
|
|
@@ -137,164 +127,6 @@ module Addressable
|
|
|
137
127
|
end
|
|
138
128
|
private_class_method :unicode_downcase
|
|
139
129
|
|
|
140
|
-
def self.unicode_compose(unpacked)
|
|
141
|
-
unpacked_result = []
|
|
142
|
-
length = unpacked.length
|
|
143
|
-
|
|
144
|
-
return unpacked if length == 0
|
|
145
|
-
|
|
146
|
-
starter = unpacked[0]
|
|
147
|
-
starter_cc = lookup_unicode_combining_class(starter)
|
|
148
|
-
starter_cc = 256 if starter_cc != 0
|
|
149
|
-
for i in 1...length
|
|
150
|
-
ch = unpacked[i]
|
|
151
|
-
|
|
152
|
-
if (starter_cc == 0 &&
|
|
153
|
-
(composite = unicode_compose_pair(starter, ch)) != nil)
|
|
154
|
-
starter = composite
|
|
155
|
-
else
|
|
156
|
-
unpacked_result << starter
|
|
157
|
-
starter = ch
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
unpacked_result << starter
|
|
161
|
-
return unpacked_result
|
|
162
|
-
end
|
|
163
|
-
private_class_method :unicode_compose
|
|
164
|
-
|
|
165
|
-
def self.unicode_compose_pair(ch_one, ch_two)
|
|
166
|
-
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
|
167
|
-
ch_two >= HANGUL_VBASE && ch_two < HANGUL_VBASE + HANGUL_VCOUNT
|
|
168
|
-
# Hangul L + V
|
|
169
|
-
return HANGUL_SBASE + (
|
|
170
|
-
(ch_one - HANGUL_LBASE) * HANGUL_VCOUNT + (ch_two - HANGUL_VBASE)
|
|
171
|
-
) * HANGUL_TCOUNT
|
|
172
|
-
elsif ch_one >= HANGUL_SBASE &&
|
|
173
|
-
ch_one < HANGUL_SBASE + HANGUL_SCOUNT &&
|
|
174
|
-
(ch_one - HANGUL_SBASE) % HANGUL_TCOUNT == 0 &&
|
|
175
|
-
ch_two >= HANGUL_TBASE && ch_two < HANGUL_TBASE + HANGUL_TCOUNT
|
|
176
|
-
# Hangul LV + T
|
|
177
|
-
return ch_one + (ch_two - HANGUL_TBASE)
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
p = []
|
|
181
|
-
|
|
182
|
-
ucs4_to_utf8(ch_one, p)
|
|
183
|
-
ucs4_to_utf8(ch_two, p)
|
|
184
|
-
|
|
185
|
-
return lookup_unicode_composition(p)
|
|
186
|
-
end
|
|
187
|
-
private_class_method :unicode_compose_pair
|
|
188
|
-
|
|
189
|
-
def self.ucs4_to_utf8(char, buffer)
|
|
190
|
-
if char < 128
|
|
191
|
-
buffer << char
|
|
192
|
-
elsif char < 2048
|
|
193
|
-
buffer << (char >> 6 | 192)
|
|
194
|
-
buffer << (char & 63 | 128)
|
|
195
|
-
elsif char < 0x10000
|
|
196
|
-
buffer << (char >> 12 | 224)
|
|
197
|
-
buffer << (char >> 6 & 63 | 128)
|
|
198
|
-
buffer << (char & 63 | 128)
|
|
199
|
-
elsif char < 0x200000
|
|
200
|
-
buffer << (char >> 18 | 240)
|
|
201
|
-
buffer << (char >> 12 & 63 | 128)
|
|
202
|
-
buffer << (char >> 6 & 63 | 128)
|
|
203
|
-
buffer << (char & 63 | 128)
|
|
204
|
-
elsif char < 0x4000000
|
|
205
|
-
buffer << (char >> 24 | 248)
|
|
206
|
-
buffer << (char >> 18 & 63 | 128)
|
|
207
|
-
buffer << (char >> 12 & 63 | 128)
|
|
208
|
-
buffer << (char >> 6 & 63 | 128)
|
|
209
|
-
buffer << (char & 63 | 128)
|
|
210
|
-
elsif char < 0x80000000
|
|
211
|
-
buffer << (char >> 30 | 252)
|
|
212
|
-
buffer << (char >> 24 & 63 | 128)
|
|
213
|
-
buffer << (char >> 18 & 63 | 128)
|
|
214
|
-
buffer << (char >> 12 & 63 | 128)
|
|
215
|
-
buffer << (char >> 6 & 63 | 128)
|
|
216
|
-
buffer << (char & 63 | 128)
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
private_class_method :ucs4_to_utf8
|
|
220
|
-
|
|
221
|
-
def self.unicode_sort_canonical(unpacked)
|
|
222
|
-
unpacked = unpacked.dup
|
|
223
|
-
i = 1
|
|
224
|
-
length = unpacked.length
|
|
225
|
-
|
|
226
|
-
return unpacked if length < 2
|
|
227
|
-
|
|
228
|
-
while i < length
|
|
229
|
-
last = unpacked[i-1]
|
|
230
|
-
ch = unpacked[i]
|
|
231
|
-
last_cc = lookup_unicode_combining_class(last)
|
|
232
|
-
cc = lookup_unicode_combining_class(ch)
|
|
233
|
-
if cc != 0 && last_cc != 0 && last_cc > cc
|
|
234
|
-
unpacked[i] = last
|
|
235
|
-
unpacked[i-1] = ch
|
|
236
|
-
i -= 1 if i > 1
|
|
237
|
-
else
|
|
238
|
-
i += 1
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
return unpacked
|
|
242
|
-
end
|
|
243
|
-
private_class_method :unicode_sort_canonical
|
|
244
|
-
|
|
245
|
-
def self.unicode_decompose(unpacked)
|
|
246
|
-
unpacked_result = []
|
|
247
|
-
for cp in unpacked
|
|
248
|
-
if cp >= HANGUL_SBASE && cp < HANGUL_SBASE + HANGUL_SCOUNT
|
|
249
|
-
l, v, t = unicode_decompose_hangul(cp)
|
|
250
|
-
unpacked_result << l
|
|
251
|
-
unpacked_result << v if v
|
|
252
|
-
unpacked_result << t if t
|
|
253
|
-
else
|
|
254
|
-
dc = lookup_unicode_compatibility(cp)
|
|
255
|
-
unless dc
|
|
256
|
-
unpacked_result << cp
|
|
257
|
-
else
|
|
258
|
-
unpacked_result.concat(unicode_decompose(dc.unpack("U*")))
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
return unpacked_result
|
|
263
|
-
end
|
|
264
|
-
private_class_method :unicode_decompose
|
|
265
|
-
|
|
266
|
-
def self.unicode_decompose_hangul(codepoint)
|
|
267
|
-
sindex = codepoint - HANGUL_SBASE;
|
|
268
|
-
if sindex < 0 || sindex >= HANGUL_SCOUNT
|
|
269
|
-
l = codepoint
|
|
270
|
-
v = t = nil
|
|
271
|
-
return l, v, t
|
|
272
|
-
end
|
|
273
|
-
l = HANGUL_LBASE + sindex / HANGUL_NCOUNT
|
|
274
|
-
v = HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
|
|
275
|
-
t = HANGUL_TBASE + sindex % HANGUL_TCOUNT
|
|
276
|
-
if t == HANGUL_TBASE
|
|
277
|
-
t = nil
|
|
278
|
-
end
|
|
279
|
-
return l, v, t
|
|
280
|
-
end
|
|
281
|
-
private_class_method :unicode_decompose_hangul
|
|
282
|
-
|
|
283
|
-
def self.lookup_unicode_combining_class(codepoint)
|
|
284
|
-
codepoint_data = UNICODE_DATA[codepoint]
|
|
285
|
-
(codepoint_data ?
|
|
286
|
-
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
|
287
|
-
0)
|
|
288
|
-
end
|
|
289
|
-
private_class_method :lookup_unicode_combining_class
|
|
290
|
-
|
|
291
|
-
def self.lookup_unicode_compatibility(codepoint)
|
|
292
|
-
codepoint_data = UNICODE_DATA[codepoint]
|
|
293
|
-
(codepoint_data ?
|
|
294
|
-
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
|
295
|
-
end
|
|
296
|
-
private_class_method :lookup_unicode_compatibility
|
|
297
|
-
|
|
298
130
|
def self.lookup_unicode_lowercase(codepoint)
|
|
299
131
|
codepoint_data = UNICODE_DATA[codepoint]
|
|
300
132
|
(codepoint_data ?
|
|
@@ -303,21 +135,6 @@ module Addressable
|
|
|
303
135
|
end
|
|
304
136
|
private_class_method :lookup_unicode_lowercase
|
|
305
137
|
|
|
306
|
-
def self.lookup_unicode_composition(unpacked)
|
|
307
|
-
return COMPOSITION_TABLE[unpacked]
|
|
308
|
-
end
|
|
309
|
-
private_class_method :lookup_unicode_composition
|
|
310
|
-
|
|
311
|
-
HANGUL_SBASE = 0xac00
|
|
312
|
-
HANGUL_LBASE = 0x1100
|
|
313
|
-
HANGUL_LCOUNT = 19
|
|
314
|
-
HANGUL_VBASE = 0x1161
|
|
315
|
-
HANGUL_VCOUNT = 21
|
|
316
|
-
HANGUL_TBASE = 0x11a7
|
|
317
|
-
HANGUL_TCOUNT = 28
|
|
318
|
-
HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT # 588
|
|
319
|
-
HANGUL_SCOUNT = HANGUL_LCOUNT * HANGUL_NCOUNT # 11172
|
|
320
|
-
|
|
321
138
|
UNICODE_DATA_COMBINING_CLASS = 0
|
|
322
139
|
UNICODE_DATA_EXCLUSION = 1
|
|
323
140
|
UNICODE_DATA_CANONICAL = 2
|
data/lib/addressable/idna.rb
CHANGED
data/lib/addressable/template.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
|
#
|
|
@@ -657,12 +656,12 @@ module Addressable
|
|
|
657
656
|
def ordered_variable_defaults
|
|
658
657
|
@ordered_variable_defaults ||= begin
|
|
659
658
|
expansions, _ = parse_template_pattern(pattern)
|
|
660
|
-
expansions.
|
|
659
|
+
expansions.flat_map do |capture|
|
|
661
660
|
_, _, varlist = *capture.match(EXPRESSION)
|
|
662
661
|
varlist.split(',').map do |varspec|
|
|
663
662
|
varspec[VARSPEC, 1]
|
|
664
663
|
end
|
|
665
|
-
end
|
|
664
|
+
end
|
|
666
665
|
end
|
|
667
666
|
end
|
|
668
667
|
|
|
@@ -893,7 +892,7 @@ module Addressable
|
|
|
893
892
|
# operator.
|
|
894
893
|
#
|
|
895
894
|
# @param [Hash, Array, String] value
|
|
896
|
-
# Normalizes keys and values with
|
|
895
|
+
# Normalizes unicode keys and values with String#unicode_normalize (NFC)
|
|
897
896
|
#
|
|
898
897
|
# @return [Hash, Array, String] The normalized values
|
|
899
898
|
def normalize_value(value)
|
|
@@ -903,15 +902,17 @@ module Addressable
|
|
|
903
902
|
|
|
904
903
|
# Handle unicode normalization
|
|
905
904
|
if value.kind_of?(Array)
|
|
906
|
-
value.map! { |val|
|
|
905
|
+
value.map! { |val| normalize_value(val) }
|
|
907
906
|
elsif value.kind_of?(Hash)
|
|
908
907
|
value = value.inject({}) { |acc, (k, v)|
|
|
909
|
-
acc[
|
|
910
|
-
Addressable::IDNA.unicode_normalize_kc(v)
|
|
908
|
+
acc[normalize_value(k)] = normalize_value(v)
|
|
911
909
|
acc
|
|
912
910
|
}
|
|
913
911
|
else
|
|
914
|
-
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)
|
|
915
916
|
end
|
|
916
917
|
value
|
|
917
918
|
end
|
|
@@ -1023,7 +1024,7 @@ module Addressable
|
|
|
1023
1024
|
end
|
|
1024
1025
|
|
|
1025
1026
|
# Ensure that the regular expression matches the whole URI.
|
|
1026
|
-
regexp_string = "
|
|
1027
|
+
regexp_string = "\\A#{regexp_string}\\z"
|
|
1027
1028
|
return expansions, Regexp.new(regexp_string)
|
|
1028
1029
|
end
|
|
1029
1030
|
|