addressable 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](
|
11
|
-
[![Build Status](https://
|
10
|
+
[![Gem Version](https://img.shields.io/gem/dt/addressable.svg)][gem]
|
11
|
+
[![Build Status](https://github.com/sporkmonger/addressable/workflows/CI/badge.svg)][actions]
|
12
12
|
[![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls]
|
13
|
-
[![Documentation Coverage Status](
|
13
|
+
[![Documentation Coverage Status](https://inch-ci.org/github/sporkmonger/addressable.svg?branch=master)][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
|