addressable 2.7.0 → 2.8.0
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 +5 -5
- data/CHANGELOG.md +12 -1
- data/Gemfile +11 -15
- data/README.md +7 -7
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/pure.rb +34 -32
- data/lib/addressable/template.rb +25 -39
- data/lib/addressable/uri.rb +44 -17
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +3 -1
- data/spec/addressable/template_spec.rb +9 -0
- data/spec/addressable/uri_spec.rb +265 -203
- data/spec/spec_helper.rb +9 -0
- data/tasks/gem.rake +0 -1
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +1 -1
- metadata +5 -5
- data/spec/addressable/rack_mount_compat_spec.rb +0 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03a21b1eab156a16e90bd7963af85980edfbddc8f3dbe052766303dba76cc000
|
4
|
+
data.tar.gz: 03eca5d86f4c70f9320000f36e3cff4fd8023342a4e0ac855d0ef1ec89ee6183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d504f9475ad823f5bb077b9c039a2c91c83e52c20896247a7289b61725c61b1ddefe8ae06155fb018fc67087cf04276081b42105a18394b45e2374ad0b2fadb0
|
7
|
+
data.tar.gz: b81766fbcb9335d5ca94403b62d3b2a6fae31b66cd3c05f48e1885eaf07883bfa1321b6930271fe1415135aec687af51312a26ce27bd4b83b2ac6424dec597c9
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,18 @@
|
|
1
|
+
# Addressable 2.8.0
|
2
|
+
- fixes ReDoS vulnerability in Addressable::Template#match
|
3
|
+
- no longer replaces `+` with spaces in queries for non-http(s) schemes
|
4
|
+
- fixed encoding ipv6 literals
|
5
|
+
- the `:compacted` flag for `normalized_query` now dedupes parameters
|
6
|
+
- fix broken `escape_component` alias
|
7
|
+
- dropping support for Ruby 2.0 and 2.1
|
8
|
+
- adding Ruby 3.0 compatibility for development tasks
|
9
|
+
- drop support for `rack-mount` and remove Addressable::Template#generate
|
10
|
+
- performance improvements
|
11
|
+
- switch CI/CD to GitHub Actions
|
12
|
+
|
1
13
|
# Addressable 2.7.0
|
2
14
|
- added `:compacted` flag to `normalized_query`
|
3
15
|
- `heuristic_parse` handles `mailto:` more intuitively
|
4
|
-
- refactored validation to use a prepended module
|
5
16
|
- dropped explicit support for JRuby 9.0.5.0
|
6
17
|
- compatibility w/ public_suffix 4.x
|
7
18
|
- performance improvements
|
data/Gemfile
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
|
-
gemspec
|
5
|
+
gemspec(path: __FILE__ == "(eval)" ? ".." : ".")
|
4
6
|
|
5
7
|
group :test do
|
6
8
|
gem 'rspec', '~> 3.8'
|
7
9
|
gem 'rspec-its', '~> 1.3'
|
8
10
|
end
|
9
11
|
|
12
|
+
group :coverage do
|
13
|
+
gem "coveralls", "> 0.7", require: false, platforms: :mri
|
14
|
+
gem "simplecov", require: false
|
15
|
+
end
|
16
|
+
|
10
17
|
group :development do
|
11
18
|
gem 'launchy', '~> 2.4', '>= 2.4.3'
|
12
19
|
gem 'redcarpet', :platform => :mri_19
|
@@ -14,19 +21,8 @@ group :development do
|
|
14
21
|
end
|
15
22
|
|
16
23
|
group :test, :development do
|
17
|
-
gem '
|
18
|
-
gem
|
19
|
-
gem 'coveralls', :require => false, :platforms => [
|
20
|
-
:ruby_20, :ruby_21, :ruby_22, :ruby_23
|
21
|
-
]
|
22
|
-
# Used to test compatibility.
|
23
|
-
gem 'rack-mount', git: 'https://github.com/sporkmonger/rack-mount.git', require: 'rack/mount'
|
24
|
-
|
25
|
-
if RUBY_VERSION.start_with?('2.0', '2.1')
|
26
|
-
gem 'rack', '< 2', :require => false
|
27
|
-
else
|
28
|
-
gem 'rack', :require => false
|
29
|
-
end
|
24
|
+
gem 'memory_profiler'
|
25
|
+
gem "rake", ">= 12.3.3"
|
30
26
|
end
|
31
27
|
|
32
|
-
gem
|
28
|
+
gem "idn-ruby", platform: :mri
|
data/README.md
CHANGED
@@ -7,15 +7,15 @@
|
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
|
-
[][gem]
|
11
|
+
[][actions]
|
12
12
|
[][coveralls]
|
13
|
-
[][inch]
|
14
14
|
|
15
15
|
[gem]: https://rubygems.org/gems/addressable
|
16
|
-
[
|
16
|
+
[actions]: https://github.com/sporkmonger/addressable/actions
|
17
17
|
[coveralls]: https://coveralls.io/r/sporkmonger/addressable
|
18
|
-
[inch]:
|
18
|
+
[inch]: https://inch-ci.org/github/sporkmonger/addressable
|
19
19
|
|
20
20
|
# Description
|
21
21
|
|
@@ -98,7 +98,7 @@ You may optionally turn on native IDN support by installing libidn and the
|
|
98
98
|
idn gem:
|
99
99
|
|
100
100
|
```console
|
101
|
-
$ sudo apt-get install
|
101
|
+
$ sudo apt-get install libidn11-dev # Debian/Ubuntu
|
102
102
|
$ brew install libidn # OS X
|
103
103
|
$ gem install idn-ruby
|
104
104
|
```
|
@@ -110,7 +110,7 @@ dependency using a pessimistic version constraint covering the major and minor
|
|
110
110
|
values:
|
111
111
|
|
112
112
|
```ruby
|
113
|
-
spec.add_dependency 'addressable', '~> 2.
|
113
|
+
spec.add_dependency 'addressable', '~> 2.7'
|
114
114
|
```
|
115
115
|
|
116
116
|
If you need a specific bug fix, you can also specify minimum tiny versions
|
data/addressable.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: addressable 2.8.0 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "addressable".freeze
|
6
|
+
s.version = "2.8.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib".freeze]
|
10
|
+
s.authors = ["Bob Aman".freeze]
|
11
|
+
s.date = "2021-07-03"
|
12
|
+
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
|
+
s.email = "bob@sporkmonger.com".freeze
|
14
|
+
s.extra_rdoc_files = ["README.md".freeze]
|
15
|
+
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]
|
16
|
+
s.homepage = "https://github.com/sporkmonger/addressable".freeze
|
17
|
+
s.licenses = ["Apache-2.0".freeze]
|
18
|
+
s.rdoc_options = ["--main".freeze, "README.md".freeze]
|
19
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
|
20
|
+
s.rubygems_version = "3.0.3".freeze
|
21
|
+
s.summary = "URI Implementation".freeze
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
s.specification_version = 4
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
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
|
37
|
+
end
|
@@ -178,44 +178,46 @@ module Addressable
|
|
178
178
|
end
|
179
179
|
|
180
180
|
p = []
|
181
|
-
ucs4_to_utf8 = lambda do |ch|
|
182
|
-
if ch < 128
|
183
|
-
p << ch
|
184
|
-
elsif ch < 2048
|
185
|
-
p << (ch >> 6 | 192)
|
186
|
-
p << (ch & 63 | 128)
|
187
|
-
elsif ch < 0x10000
|
188
|
-
p << (ch >> 12 | 224)
|
189
|
-
p << (ch >> 6 & 63 | 128)
|
190
|
-
p << (ch & 63 | 128)
|
191
|
-
elsif ch < 0x200000
|
192
|
-
p << (ch >> 18 | 240)
|
193
|
-
p << (ch >> 12 & 63 | 128)
|
194
|
-
p << (ch >> 6 & 63 | 128)
|
195
|
-
p << (ch & 63 | 128)
|
196
|
-
elsif ch < 0x4000000
|
197
|
-
p << (ch >> 24 | 248)
|
198
|
-
p << (ch >> 18 & 63 | 128)
|
199
|
-
p << (ch >> 12 & 63 | 128)
|
200
|
-
p << (ch >> 6 & 63 | 128)
|
201
|
-
p << (ch & 63 | 128)
|
202
|
-
elsif ch < 0x80000000
|
203
|
-
p << (ch >> 30 | 252)
|
204
|
-
p << (ch >> 24 & 63 | 128)
|
205
|
-
p << (ch >> 18 & 63 | 128)
|
206
|
-
p << (ch >> 12 & 63 | 128)
|
207
|
-
p << (ch >> 6 & 63 | 128)
|
208
|
-
p << (ch & 63 | 128)
|
209
|
-
end
|
210
|
-
end
|
211
181
|
|
212
|
-
ucs4_to_utf8
|
213
|
-
ucs4_to_utf8
|
182
|
+
ucs4_to_utf8(ch_one, p)
|
183
|
+
ucs4_to_utf8(ch_two, p)
|
214
184
|
|
215
185
|
return lookup_unicode_composition(p)
|
216
186
|
end
|
217
187
|
private_class_method :unicode_compose_pair
|
218
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
|
+
|
219
221
|
def self.unicode_sort_canonical(unpacked)
|
220
222
|
unpacked = unpacked.dup
|
221
223
|
i = 1
|
data/lib/addressable/template.rb
CHANGED
@@ -37,7 +37,7 @@ module Addressable
|
|
37
37
|
Addressable::URI::CharacterClasses::DIGIT + '_'
|
38
38
|
|
39
39
|
var_char =
|
40
|
-
"(
|
40
|
+
"(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
|
41
41
|
RESERVED =
|
42
42
|
"(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
|
43
43
|
UNRESERVED =
|
@@ -412,7 +412,7 @@ module Addressable
|
|
412
412
|
# match.captures
|
413
413
|
# #=> ["a", ["b", "c"]]
|
414
414
|
def match(uri, processor=nil)
|
415
|
-
uri = Addressable::URI.parse(uri)
|
415
|
+
uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
|
416
416
|
mapping = {}
|
417
417
|
|
418
418
|
# First, we need to process the pattern, and extract the values.
|
@@ -653,40 +653,6 @@ module Addressable
|
|
653
653
|
self.to_regexp.named_captures
|
654
654
|
end
|
655
655
|
|
656
|
-
##
|
657
|
-
# Generates a route result for a given set of parameters.
|
658
|
-
# Should only be used by rack-mount.
|
659
|
-
#
|
660
|
-
# @param params [Hash] The set of parameters used to expand the template.
|
661
|
-
# @param recall [Hash] Default parameters used to expand the template.
|
662
|
-
# @param options [Hash] Either a `:processor` or a `:parameterize` block.
|
663
|
-
#
|
664
|
-
# @api private
|
665
|
-
def generate(params={}, recall={}, options={})
|
666
|
-
merged = recall.merge(params)
|
667
|
-
if options[:processor]
|
668
|
-
processor = options[:processor]
|
669
|
-
elsif options[:parameterize]
|
670
|
-
# TODO: This is sending me into fits trying to shoe-horn this into
|
671
|
-
# the existing API. I think I've got this backwards and processors
|
672
|
-
# should be a set of 4 optional blocks named :validate, :transform,
|
673
|
-
# :match, and :restore. Having to use a singleton here is a huge
|
674
|
-
# code smell.
|
675
|
-
processor = Object.new
|
676
|
-
class <<processor
|
677
|
-
attr_accessor :block
|
678
|
-
def transform(name, value)
|
679
|
-
block.call(name, value)
|
680
|
-
end
|
681
|
-
end
|
682
|
-
processor.block = options[:parameterize]
|
683
|
-
else
|
684
|
-
processor = nil
|
685
|
-
end
|
686
|
-
result = self.expand(merged, processor)
|
687
|
-
result.to_s if result
|
688
|
-
end
|
689
|
-
|
690
656
|
private
|
691
657
|
def ordered_variable_defaults
|
692
658
|
@ordered_variable_defaults ||= begin
|
@@ -973,15 +939,35 @@ module Addressable
|
|
973
939
|
end
|
974
940
|
end
|
975
941
|
|
942
|
+
##
|
943
|
+
# Generates the <tt>Regexp</tt> that parses a template pattern. Memoizes the
|
944
|
+
# value if template processor not set (processors may not be deterministic)
|
945
|
+
#
|
946
|
+
# @param [String] pattern The URI template pattern.
|
947
|
+
# @param [#match] processor The template processor to use.
|
948
|
+
#
|
949
|
+
# @return [Array, Regexp]
|
950
|
+
# An array of expansion variables nad a regular expression which may be
|
951
|
+
# used to parse a template pattern
|
952
|
+
def parse_template_pattern(pattern, processor = nil)
|
953
|
+
if processor.nil? && pattern == @pattern
|
954
|
+
@cached_template_parse ||=
|
955
|
+
parse_new_template_pattern(pattern, processor)
|
956
|
+
else
|
957
|
+
parse_new_template_pattern(pattern, processor)
|
958
|
+
end
|
959
|
+
end
|
960
|
+
|
976
961
|
##
|
977
962
|
# Generates the <tt>Regexp</tt> that parses a template pattern.
|
978
963
|
#
|
979
964
|
# @param [String] pattern The URI template pattern.
|
980
965
|
# @param [#match] processor The template processor to use.
|
981
966
|
#
|
982
|
-
# @return [Regexp]
|
983
|
-
#
|
984
|
-
|
967
|
+
# @return [Array, Regexp]
|
968
|
+
# An array of expansion variables nad a regular expression which may be
|
969
|
+
# used to parse a template pattern
|
970
|
+
def parse_new_template_pattern(pattern, processor = nil)
|
985
971
|
# Escape the pattern. The two gsubs restore the escaped curly braces
|
986
972
|
# back to their original form. Basically, escape everything that isn't
|
987
973
|
# within an expansion.
|
data/lib/addressable/uri.rb
CHANGED
@@ -48,12 +48,21 @@ module Addressable
|
|
48
48
|
PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
|
49
49
|
SCHEME = ALPHA + DIGIT + "\\-\\+\\."
|
50
50
|
HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
|
51
|
-
AUTHORITY = PCHAR
|
51
|
+
AUTHORITY = PCHAR + "\\[\\:\\]"
|
52
52
|
PATH = PCHAR + "\\/"
|
53
53
|
QUERY = PCHAR + "\\/\\?"
|
54
54
|
FRAGMENT = PCHAR + "\\/\\?"
|
55
55
|
end
|
56
56
|
|
57
|
+
module NormalizeCharacterClasses
|
58
|
+
HOST = /[^#{CharacterClasses::HOST}]/
|
59
|
+
UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
|
60
|
+
PCHAR = /[^#{CharacterClasses::PCHAR}]/
|
61
|
+
SCHEME = /[^#{CharacterClasses::SCHEME}]/
|
62
|
+
FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
|
63
|
+
QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
|
64
|
+
end
|
65
|
+
|
57
66
|
SLASH = '/'
|
58
67
|
EMPTY_STR = ''
|
59
68
|
|
@@ -73,7 +82,7 @@ module Addressable
|
|
73
82
|
"wais" => 210,
|
74
83
|
"ldap" => 389,
|
75
84
|
"prospero" => 1525
|
76
|
-
}
|
85
|
+
}.freeze
|
77
86
|
|
78
87
|
##
|
79
88
|
# Returns a URI object based on the parsed string.
|
@@ -421,7 +430,7 @@ module Addressable
|
|
421
430
|
end
|
422
431
|
|
423
432
|
class << self
|
424
|
-
alias_method :
|
433
|
+
alias_method :escape_component, :encode_component
|
425
434
|
end
|
426
435
|
|
427
436
|
##
|
@@ -463,7 +472,11 @@ module Addressable
|
|
463
472
|
uri = uri.dup
|
464
473
|
# Seriously, only use UTF-8. I'm really not kidding!
|
465
474
|
uri.force_encoding("utf-8")
|
466
|
-
|
475
|
+
|
476
|
+
unless leave_encoded.empty?
|
477
|
+
leave_encoded = leave_encoded.dup.force_encoding("utf-8")
|
478
|
+
end
|
479
|
+
|
467
480
|
result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
|
468
481
|
c = sequence[1..3].to_i(16).chr
|
469
482
|
c.force_encoding("utf-8")
|
@@ -554,7 +567,11 @@ module Addressable
|
|
554
567
|
end.flatten.join('|')})"
|
555
568
|
end
|
556
569
|
|
557
|
-
character_class =
|
570
|
+
character_class = if leave_re
|
571
|
+
/[^#{character_class}]#{leave_re}/
|
572
|
+
else
|
573
|
+
/[^#{character_class}]/
|
574
|
+
end
|
558
575
|
end
|
559
576
|
# We can't perform regexps on invalid UTF sequences, but
|
560
577
|
# here we need to, so switch to ASCII.
|
@@ -878,7 +895,7 @@ module Addressable
|
|
878
895
|
else
|
879
896
|
Addressable::URI.normalize_component(
|
880
897
|
self.scheme.strip.downcase,
|
881
|
-
Addressable::URI::
|
898
|
+
Addressable::URI::NormalizeCharacterClasses::SCHEME
|
882
899
|
)
|
883
900
|
end
|
884
901
|
end
|
@@ -898,7 +915,7 @@ module Addressable
|
|
898
915
|
new_scheme = new_scheme.to_str
|
899
916
|
end
|
900
917
|
if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
|
901
|
-
raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
|
918
|
+
raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'"
|
902
919
|
end
|
903
920
|
@scheme = new_scheme
|
904
921
|
@scheme = nil if @scheme.to_s.strip.empty?
|
@@ -933,7 +950,7 @@ module Addressable
|
|
933
950
|
else
|
934
951
|
Addressable::URI.normalize_component(
|
935
952
|
self.user.strip,
|
936
|
-
Addressable::URI::
|
953
|
+
Addressable::URI::NormalizeCharacterClasses::UNRESERVED
|
937
954
|
)
|
938
955
|
end
|
939
956
|
end
|
@@ -990,7 +1007,7 @@ module Addressable
|
|
990
1007
|
else
|
991
1008
|
Addressable::URI.normalize_component(
|
992
1009
|
self.password.strip,
|
993
|
-
Addressable::URI::
|
1010
|
+
Addressable::URI::NormalizeCharacterClasses::UNRESERVED
|
994
1011
|
)
|
995
1012
|
end
|
996
1013
|
end
|
@@ -1114,6 +1131,7 @@ module Addressable
|
|
1114
1131
|
# @return [String] The host component, normalized.
|
1115
1132
|
def normalized_host
|
1116
1133
|
return nil unless self.host
|
1134
|
+
|
1117
1135
|
@normalized_host ||= begin
|
1118
1136
|
if !self.host.strip.empty?
|
1119
1137
|
result = ::Addressable::IDNA.to_ascii(
|
@@ -1125,14 +1143,17 @@ module Addressable
|
|
1125
1143
|
end
|
1126
1144
|
result = Addressable::URI.normalize_component(
|
1127
1145
|
result,
|
1128
|
-
|
1146
|
+
NormalizeCharacterClasses::HOST
|
1147
|
+
)
|
1129
1148
|
result
|
1130
1149
|
else
|
1131
1150
|
EMPTY_STR.dup
|
1132
1151
|
end
|
1133
1152
|
end
|
1134
1153
|
# All normalized values should be UTF-8
|
1135
|
-
@normalized_host
|
1154
|
+
if @normalized_host && !@normalized_host.empty?
|
1155
|
+
@normalized_host.force_encoding(Encoding::UTF_8)
|
1156
|
+
end
|
1136
1157
|
@normalized_host
|
1137
1158
|
end
|
1138
1159
|
|
@@ -1537,7 +1558,7 @@ module Addressable
|
|
1537
1558
|
result = path.strip.split(SLASH, -1).map do |segment|
|
1538
1559
|
Addressable::URI.normalize_component(
|
1539
1560
|
segment,
|
1540
|
-
Addressable::URI::
|
1561
|
+
Addressable::URI::NormalizeCharacterClasses::PCHAR
|
1541
1562
|
)
|
1542
1563
|
end.join(SLASH)
|
1543
1564
|
|
@@ -1612,11 +1633,15 @@ module Addressable
|
|
1612
1633
|
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
1613
1634
|
# Make sure possible key-value pair delimiters are escaped.
|
1614
1635
|
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
1615
|
-
pairs = (
|
1616
|
-
pairs.delete_if(&:empty?) if flags.include?(:compacted)
|
1636
|
+
pairs = (query || "").split("&", -1)
|
1637
|
+
pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted)
|
1617
1638
|
pairs.sort! if flags.include?(:sorted)
|
1618
1639
|
component = pairs.map do |pair|
|
1619
|
-
Addressable::URI.normalize_component(
|
1640
|
+
Addressable::URI.normalize_component(
|
1641
|
+
pair,
|
1642
|
+
Addressable::URI::NormalizeCharacterClasses::QUERY,
|
1643
|
+
"+"
|
1644
|
+
)
|
1620
1645
|
end.join("&")
|
1621
1646
|
component == "" ? nil : component
|
1622
1647
|
end
|
@@ -1675,11 +1700,13 @@ module Addressable
|
|
1675
1700
|
# so it's best to make all changes in-place.
|
1676
1701
|
pair[0] = URI.unencode_component(pair[0])
|
1677
1702
|
if pair[1].respond_to?(:to_str)
|
1703
|
+
value = pair[1].to_str
|
1678
1704
|
# I loathe the fact that I have to do this. Stupid HTML 4.01.
|
1679
1705
|
# Treating '+' as a space was just an unbelievably bad idea.
|
1680
1706
|
# There was nothing wrong with '%20'!
|
1681
1707
|
# If it ain't broke, don't fix it!
|
1682
|
-
|
1708
|
+
value = value.tr("+", " ") if ["http", "https", nil].include?(scheme)
|
1709
|
+
pair[1] = URI.unencode_component(value)
|
1683
1710
|
end
|
1684
1711
|
if return_type == Hash
|
1685
1712
|
accu[pair[0]] = pair[1]
|
@@ -1810,7 +1837,7 @@ module Addressable
|
|
1810
1837
|
@normalized_fragment ||= begin
|
1811
1838
|
component = Addressable::URI.normalize_component(
|
1812
1839
|
self.fragment,
|
1813
|
-
Addressable::URI::
|
1840
|
+
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
1814
1841
|
)
|
1815
1842
|
component == "" ? nil : component
|
1816
1843
|
end
|