addressable 2.3.6 → 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 +76 -0
- data/Gemfile +18 -18
- data/README.md +37 -18
- data/Rakefile +8 -11
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/native.rb +24 -6
- data/lib/addressable/idna/pure.rb +67 -58
- data/lib/addressable/idna.rb +3 -1
- data/lib/addressable/template.rb +126 -33
- data/lib/addressable/uri.rb +416 -211
- data/lib/addressable/version.rb +5 -3
- data/lib/addressable.rb +4 -0
- data/spec/addressable/idna_spec.rb +110 -46
- data/spec/addressable/net_http_compat_spec.rb +4 -2
- data/spec/addressable/security_spec.rb +59 -0
- data/spec/addressable/template_spec.rb +297 -165
- data/spec/addressable/uri_spec.rb +2054 -1329
- data/spec/spec_helper.rb +28 -1
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +22 -16
- data/tasks/git.rake +3 -1
- data/tasks/metrics.rake +2 -0
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +10 -45
- data/tasks/yard.rake +2 -0
- metadata +44 -45
- data/tasks/rubyforge.rake +0 -73
- data/website/index.html +0 -110
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,3 +1,79 @@
|
|
|
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
|
+
|
|
13
|
+
# Addressable 2.7.0
|
|
14
|
+
- added `:compacted` flag to `normalized_query`
|
|
15
|
+
- `heuristic_parse` handles `mailto:` more intuitively
|
|
16
|
+
- dropped explicit support for JRuby 9.0.5.0
|
|
17
|
+
- compatibility w/ public_suffix 4.x
|
|
18
|
+
- performance improvements
|
|
19
|
+
|
|
20
|
+
# Addressable 2.6.0
|
|
21
|
+
- added `tld=` method to allow assignment to the public suffix
|
|
22
|
+
- most `heuristic_parse` patterns are now case-insensitive
|
|
23
|
+
- `heuristic_parse` handles more `file://` URI variations
|
|
24
|
+
- fixes bug in `heuristic_parse` when uri starts with digit
|
|
25
|
+
- fixes bug in `request_uri=` with query strings
|
|
26
|
+
- fixes template issues with `nil` and `?` operator
|
|
27
|
+
- `frozen_string_literal` pragmas added
|
|
28
|
+
- minor performance improvements in regexps
|
|
29
|
+
- fixes to eliminate warnings
|
|
30
|
+
|
|
31
|
+
# Addressable 2.5.2
|
|
32
|
+
- better support for frozen string literals
|
|
33
|
+
- fixed bug w/ uppercase characters in scheme
|
|
34
|
+
- IDNA errors w/ emoji URLs
|
|
35
|
+
- compatibility w/ public_suffix 3.x
|
|
36
|
+
|
|
37
|
+
# Addressable 2.5.1
|
|
38
|
+
- allow unicode normalization to be disabled for URI Template expansion
|
|
39
|
+
- removed duplicate test
|
|
40
|
+
|
|
41
|
+
# Addressable 2.5.0
|
|
42
|
+
- dropping support for Ruby 1.9
|
|
43
|
+
- adding support for Ruby 2.4 preview
|
|
44
|
+
- add support for public suffixes and tld; first runtime dependency
|
|
45
|
+
- hostname escaping should match RFC; underscores in hostnames no longer escaped
|
|
46
|
+
- paths beginning with // and missing an authority are now considered invalid
|
|
47
|
+
- validation now also takes place after setting a path
|
|
48
|
+
- handle backslashes in authority more like a browser for `heuristic_parse`
|
|
49
|
+
- unescaped backslashes in host now raise an `InvalidURIError`
|
|
50
|
+
- `merge!`, `join!`, `omit!` and `normalize!` don't disable deferred validation
|
|
51
|
+
- `heuristic_parse` now trims whitespace before parsing
|
|
52
|
+
- host parts longer than 63 bytes will be ignored and not passed to libidn
|
|
53
|
+
- normalized values always encoded as UTF-8
|
|
54
|
+
|
|
55
|
+
# Addressable 2.4.0
|
|
56
|
+
- support for 1.8.x dropped
|
|
57
|
+
- double quotes in a host now raises an error
|
|
58
|
+
- newlines in host will no longer get unescaped during normalization
|
|
59
|
+
- stricter handling of bogus scheme values
|
|
60
|
+
- stricter handling of encoded port values
|
|
61
|
+
- calling `require 'addressable'` will now load both the URI and Template files
|
|
62
|
+
- assigning to the `hostname` component with an `IPAddr` object is now supported
|
|
63
|
+
- assigning to the `origin` component is now supported
|
|
64
|
+
- fixed minor bug where an exception would be thrown for a missing ACE suffix
|
|
65
|
+
- better partial expansion of URI templates
|
|
66
|
+
|
|
67
|
+
# Addressable 2.3.8
|
|
68
|
+
- fix warnings
|
|
69
|
+
- update dependency gems
|
|
70
|
+
- support for 1.8.x officially deprecated
|
|
71
|
+
|
|
72
|
+
# Addressable 2.3.7
|
|
73
|
+
- fix scenario in which invalid URIs don't get an exception until inspected
|
|
74
|
+
- handle hostnames with two adjacent periods correctly
|
|
75
|
+
- upgrade of RSpec
|
|
76
|
+
|
|
1
77
|
# Addressable 2.3.6
|
|
2
78
|
- normalization drops empty query string
|
|
3
79
|
- better handling in template extract for missing values
|
data/Gemfile
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source 'https://rubygems.org'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
gem 'launchy'
|
|
5
|
-
gem 'yard'
|
|
6
|
-
gem 'redcarpet', :platform => :mri_19
|
|
7
|
-
gem 'rubyforge'
|
|
8
|
-
end
|
|
5
|
+
gemspec(path: __FILE__ == "(eval)" ? ".." : ".")
|
|
9
6
|
|
|
10
|
-
group :test
|
|
11
|
-
gem '
|
|
12
|
-
gem 'rspec', '
|
|
13
|
-
gem 'coveralls', :require => false
|
|
7
|
+
group :test do
|
|
8
|
+
gem 'rspec', '~> 3.8'
|
|
9
|
+
gem 'rspec-its', '~> 1.3'
|
|
14
10
|
end
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
gem
|
|
12
|
+
group :coverage do
|
|
13
|
+
gem "coveralls", "> 0.7", require: false, platforms: :mri
|
|
14
|
+
gem "simplecov", require: false
|
|
15
|
+
end
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
gem '
|
|
17
|
+
group :development do
|
|
18
|
+
gem 'launchy', '~> 2.4', '>= 2.4.3'
|
|
19
|
+
gem 'redcarpet', :platform => :mri_19
|
|
20
|
+
gem 'yard'
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
gem '
|
|
25
|
-
gem
|
|
23
|
+
group :test, :development do
|
|
24
|
+
gem 'memory_profiler'
|
|
25
|
+
gem "rake", ">= 12.3.3"
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
gem "idn-ruby", platform: :mri
|
data/README.md
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
# Addressable
|
|
2
2
|
|
|
3
3
|
<dl>
|
|
4
|
-
<dt>Homepage</dt><dd><a href="
|
|
4
|
+
<dt>Homepage</dt><dd><a href="https://github.com/sporkmonger/addressable">github.com/sporkmonger/addressable</a></dd>
|
|
5
5
|
<dt>Author</dt><dd><a href="mailto:bob@sporkmonger.com">Bob Aman</a></dd>
|
|
6
|
-
<dt>Copyright</dt><dd>Copyright ©
|
|
6
|
+
<dt>Copyright</dt><dd>Copyright © Bob Aman</dd>
|
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
|
8
8
|
</dl>
|
|
9
9
|
|
|
10
|
-
[][gem]
|
|
11
|
+
[][actions]
|
|
12
|
+
[][coveralls]
|
|
13
|
+
[][inch]
|
|
14
14
|
|
|
15
15
|
[gem]: https://rubygems.org/gems/addressable
|
|
16
|
-
[
|
|
17
|
-
[gemnasium]: https://gemnasium.com/sporkmonger/addressable
|
|
16
|
+
[actions]: https://github.com/sporkmonger/addressable/actions
|
|
18
17
|
[coveralls]: https://coveralls.io/r/sporkmonger/addressable
|
|
18
|
+
[inch]: https://inch-ci.org/github/sporkmonger/addressable
|
|
19
19
|
|
|
20
20
|
# Description
|
|
21
21
|
|
|
22
|
-
Addressable is
|
|
23
|
-
Ruby's standard library. It
|
|
24
|
-
|
|
22
|
+
Addressable is an alternative implementation to the URI implementation
|
|
23
|
+
that is part of Ruby's standard library. It is flexible, offers heuristic
|
|
24
|
+
parsing, and additionally provides extensive support for IRIs and URI templates.
|
|
25
|
+
|
|
26
|
+
Addressable closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4).
|
|
25
27
|
|
|
26
28
|
# Reference
|
|
27
29
|
|
|
@@ -56,7 +58,7 @@ For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt).
|
|
|
56
58
|
|
|
57
59
|
require "addressable/template"
|
|
58
60
|
|
|
59
|
-
template = Addressable::Template.new("http://example.com/{?query*}
|
|
61
|
+
template = Addressable::Template.new("http://example.com/{?query*}")
|
|
60
62
|
template.expand({
|
|
61
63
|
"query" => {
|
|
62
64
|
'foo' => 'bar',
|
|
@@ -65,12 +67,12 @@ template.expand({
|
|
|
65
67
|
})
|
|
66
68
|
#=> #<Addressable::URI:0xc9d95c URI:http://example.com/?foo=bar&color=red>
|
|
67
69
|
|
|
68
|
-
template = Addressable::Template.new("http://example.com/{?one,two,three}
|
|
70
|
+
template = Addressable::Template.new("http://example.com/{?one,two,three}")
|
|
69
71
|
template.partial_expand({"one" => "1", "three" => 3}).pattern
|
|
70
72
|
#=> "http://example.com/?one=1{&two}&three=3"
|
|
71
73
|
|
|
72
74
|
template = Addressable::Template.new(
|
|
73
|
-
"http://{host}{/segments}/{?one,two,bogus}{#fragment}"
|
|
75
|
+
"http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
|
|
74
76
|
)
|
|
75
77
|
uri = Addressable::URI.parse(
|
|
76
78
|
"http://example.com/a/b/c/?one=1&two=2#foo"
|
|
@@ -89,14 +91,31 @@ template.extract(uri)
|
|
|
89
91
|
# Install
|
|
90
92
|
|
|
91
93
|
```console
|
|
92
|
-
$
|
|
94
|
+
$ gem install addressable
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
You may optionally turn on native IDN support by installing libidn and the
|
|
96
98
|
idn gem:
|
|
97
99
|
|
|
98
100
|
```console
|
|
99
|
-
$ sudo apt-get install
|
|
100
|
-
$
|
|
101
|
-
$
|
|
101
|
+
$ sudo apt-get install libidn11-dev # Debian/Ubuntu
|
|
102
|
+
$ brew install libidn # OS X
|
|
103
|
+
$ gem install idn-ruby
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
# Semantic Versioning
|
|
107
|
+
|
|
108
|
+
This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your
|
|
109
|
+
dependency using a pessimistic version constraint covering the major and minor
|
|
110
|
+
values:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
spec.add_dependency 'addressable', '~> 2.7'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If you need a specific bug fix, you can also specify minimum tiny versions
|
|
117
|
+
without preventing updates to the latest minor release:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
spec.add_dependency 'addressable', '~> 2.3', '>= 2.3.7'
|
|
102
121
|
```
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'rubygems'
|
|
2
4
|
require 'rake'
|
|
3
5
|
|
|
@@ -10,25 +12,20 @@ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
|
|
10
12
|
|
|
11
13
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
|
12
14
|
|
|
13
|
-
RUBY_FORGE_PROJECT = PKG_NAME
|
|
14
|
-
RUBY_FORGE_USER = "sporkmonger"
|
|
15
|
-
RUBY_FORGE_PATH = "/var/www/gforge-projects/#{RUBY_FORGE_PROJECT}"
|
|
16
|
-
RUBY_FORGE_URL = "http://#{RUBY_FORGE_PROJECT}.rubyforge.org/"
|
|
17
|
-
|
|
18
15
|
PKG_SUMMARY = "URI Implementation"
|
|
19
16
|
PKG_DESCRIPTION = <<-TEXT
|
|
20
|
-
Addressable is
|
|
21
|
-
Ruby's standard library. It
|
|
22
|
-
|
|
17
|
+
Addressable is an alternative implementation to the URI implementation that is
|
|
18
|
+
part of Ruby's standard library. It is flexible, offers heuristic parsing, and
|
|
19
|
+
additionally provides extensive support for IRIs and URI templates.
|
|
23
20
|
TEXT
|
|
24
21
|
|
|
25
22
|
PKG_FILES = FileList[
|
|
26
23
|
"lib/**/*", "spec/**/*", "vendor/**/*", "data/**/*",
|
|
27
|
-
"tasks/**/*",
|
|
24
|
+
"tasks/**/*",
|
|
28
25
|
"[A-Z]*", "Rakefile"
|
|
29
|
-
].exclude(/
|
|
26
|
+
].exclude(/pkg/).exclude(/database\.yml/).
|
|
27
|
+
exclude(/Gemfile\.lock/).exclude(/[_\.]git$/)
|
|
30
28
|
|
|
31
|
-
RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/)
|
|
32
29
|
task :default => "spec"
|
|
33
30
|
|
|
34
31
|
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
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
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# encoding:utf-8
|
|
2
4
|
#--
|
|
3
|
-
# Copyright (C)
|
|
5
|
+
# Copyright (C) Bob Aman
|
|
4
6
|
#
|
|
5
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
8
|
# you may not use this file except in compliance with the License.
|
|
@@ -21,23 +23,39 @@ require "idn"
|
|
|
21
23
|
module Addressable
|
|
22
24
|
module IDNA
|
|
23
25
|
def self.punycode_encode(value)
|
|
24
|
-
IDN::Punycode.encode(value)
|
|
26
|
+
IDN::Punycode.encode(value.to_s)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def self.punycode_decode(value)
|
|
28
|
-
IDN::Punycode.decode(value)
|
|
30
|
+
IDN::Punycode.decode(value.to_s)
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def self.unicode_normalize_kc(value)
|
|
32
|
-
IDN::Stringprep.nfkc_normalize(value)
|
|
34
|
+
IDN::Stringprep.nfkc_normalize(value.to_s)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def self.to_ascii(value)
|
|
36
|
-
|
|
38
|
+
value.to_s.split('.', -1).map do |segment|
|
|
39
|
+
if segment.size > 0 && segment.size < 64
|
|
40
|
+
IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
|
41
|
+
elsif segment.size >= 64
|
|
42
|
+
segment
|
|
43
|
+
else
|
|
44
|
+
''
|
|
45
|
+
end
|
|
46
|
+
end.join('.')
|
|
37
47
|
end
|
|
38
48
|
|
|
39
49
|
def self.to_unicode(value)
|
|
40
|
-
|
|
50
|
+
value.to_s.split('.', -1).map do |segment|
|
|
51
|
+
if segment.size > 0 && segment.size < 64
|
|
52
|
+
IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
|
53
|
+
elsif segment.size >= 64
|
|
54
|
+
segment
|
|
55
|
+
else
|
|
56
|
+
''
|
|
57
|
+
end
|
|
58
|
+
end.join('.')
|
|
41
59
|
end
|
|
42
60
|
end
|
|
43
61
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# encoding:utf-8
|
|
2
4
|
#--
|
|
3
|
-
# Copyright (C)
|
|
5
|
+
# Copyright (C) Bob Aman
|
|
4
6
|
#
|
|
5
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
8
|
# you may not use this file except in compliance with the License.
|
|
@@ -64,6 +66,7 @@ module Addressable
|
|
|
64
66
|
# Converts from a Unicode internationalized domain name to an ASCII
|
|
65
67
|
# domain name as described in RFC 3490.
|
|
66
68
|
def self.to_ascii(input)
|
|
69
|
+
input = input.to_s unless input.is_a?(String)
|
|
67
70
|
input = input.dup
|
|
68
71
|
if input.respond_to?(:force_encoding)
|
|
69
72
|
input.force_encoding(Encoding::ASCII_8BIT)
|
|
@@ -89,10 +92,16 @@ module Addressable
|
|
|
89
92
|
# Converts from an ASCII domain name to a Unicode internationalized
|
|
90
93
|
# domain name as described in RFC 3490.
|
|
91
94
|
def self.to_unicode(input)
|
|
95
|
+
input = input.to_s unless input.is_a?(String)
|
|
92
96
|
parts = input.split('.')
|
|
93
97
|
parts.map! do |part|
|
|
94
|
-
if part =~ /^#{ACE_PREFIX}/
|
|
95
|
-
|
|
98
|
+
if part =~ /^#{ACE_PREFIX}(.+)/
|
|
99
|
+
begin
|
|
100
|
+
punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1])
|
|
101
|
+
rescue Addressable::IDNA::PunycodeBadInput
|
|
102
|
+
# toUnicode is explicitly defined as never-fails by the spec
|
|
103
|
+
part
|
|
104
|
+
end
|
|
96
105
|
else
|
|
97
106
|
part
|
|
98
107
|
end
|
|
@@ -121,11 +130,12 @@ module Addressable
|
|
|
121
130
|
# The input string.
|
|
122
131
|
# @return [String] The downcased result.
|
|
123
132
|
def self.unicode_downcase(input)
|
|
133
|
+
input = input.to_s unless input.is_a?(String)
|
|
124
134
|
unpacked = input.unpack("U*")
|
|
125
135
|
unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) }
|
|
126
136
|
return unpacked.pack("U*")
|
|
127
137
|
end
|
|
128
|
-
|
|
138
|
+
private_class_method :unicode_downcase
|
|
129
139
|
|
|
130
140
|
def self.unicode_compose(unpacked)
|
|
131
141
|
unpacked_result = []
|
|
@@ -138,22 +148,19 @@ module Addressable
|
|
|
138
148
|
starter_cc = 256 if starter_cc != 0
|
|
139
149
|
for i in 1...length
|
|
140
150
|
ch = unpacked[i]
|
|
141
|
-
cc = lookup_unicode_combining_class(ch)
|
|
142
151
|
|
|
143
152
|
if (starter_cc == 0 &&
|
|
144
153
|
(composite = unicode_compose_pair(starter, ch)) != nil)
|
|
145
154
|
starter = composite
|
|
146
|
-
startercc = lookup_unicode_combining_class(composite)
|
|
147
155
|
else
|
|
148
156
|
unpacked_result << starter
|
|
149
157
|
starter = ch
|
|
150
|
-
startercc = cc
|
|
151
158
|
end
|
|
152
159
|
end
|
|
153
160
|
unpacked_result << starter
|
|
154
161
|
return unpacked_result
|
|
155
162
|
end
|
|
156
|
-
|
|
163
|
+
private_class_method :unicode_compose
|
|
157
164
|
|
|
158
165
|
def self.unicode_compose_pair(ch_one, ch_two)
|
|
159
166
|
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
|
@@ -171,44 +178,45 @@ module Addressable
|
|
|
171
178
|
end
|
|
172
179
|
|
|
173
180
|
p = []
|
|
174
|
-
ucs4_to_utf8 = lambda do |ch|
|
|
175
|
-
# For some reason, rcov likes to drop BUS errors here.
|
|
176
|
-
if ch < 128
|
|
177
|
-
p << ch
|
|
178
|
-
elsif ch < 2048
|
|
179
|
-
p << (ch >> 6 | 192)
|
|
180
|
-
p << (ch & 63 | 128)
|
|
181
|
-
elsif ch < 0x10000
|
|
182
|
-
p << (ch >> 12 | 224)
|
|
183
|
-
p << (ch >> 6 & 63 | 128)
|
|
184
|
-
p << (ch & 63 | 128)
|
|
185
|
-
elsif ch < 0x200000
|
|
186
|
-
p << (ch >> 18 | 240)
|
|
187
|
-
p << (ch >> 12 & 63 | 128)
|
|
188
|
-
p << (ch >> 6 & 63 | 128)
|
|
189
|
-
p << (ch & 63 | 128)
|
|
190
|
-
elsif ch < 0x4000000
|
|
191
|
-
p << (ch >> 24 | 248)
|
|
192
|
-
p << (ch >> 18 & 63 | 128)
|
|
193
|
-
p << (ch >> 12 & 63 | 128)
|
|
194
|
-
p << (ch >> 6 & 63 | 128)
|
|
195
|
-
p << (ch & 63 | 128)
|
|
196
|
-
elsif ch < 0x80000000
|
|
197
|
-
p << (ch >> 30 | 252)
|
|
198
|
-
p << (ch >> 24 & 63 | 128)
|
|
199
|
-
p << (ch >> 18 & 63 | 128)
|
|
200
|
-
p << (ch >> 12 & 63 | 128)
|
|
201
|
-
p << (ch >> 6 & 63 | 128)
|
|
202
|
-
p << (ch & 63 | 128)
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
181
|
|
|
206
|
-
ucs4_to_utf8
|
|
207
|
-
ucs4_to_utf8
|
|
182
|
+
ucs4_to_utf8(ch_one, p)
|
|
183
|
+
ucs4_to_utf8(ch_two, p)
|
|
208
184
|
|
|
209
185
|
return lookup_unicode_composition(p)
|
|
210
186
|
end
|
|
211
|
-
|
|
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
|
|
212
220
|
|
|
213
221
|
def self.unicode_sort_canonical(unpacked)
|
|
214
222
|
unpacked = unpacked.dup
|
|
@@ -232,7 +240,7 @@ module Addressable
|
|
|
232
240
|
end
|
|
233
241
|
return unpacked
|
|
234
242
|
end
|
|
235
|
-
|
|
243
|
+
private_class_method :unicode_sort_canonical
|
|
236
244
|
|
|
237
245
|
def self.unicode_decompose(unpacked)
|
|
238
246
|
unpacked_result = []
|
|
@@ -253,7 +261,7 @@ module Addressable
|
|
|
253
261
|
end
|
|
254
262
|
return unpacked_result
|
|
255
263
|
end
|
|
256
|
-
|
|
264
|
+
private_class_method :unicode_decompose
|
|
257
265
|
|
|
258
266
|
def self.unicode_decompose_hangul(codepoint)
|
|
259
267
|
sindex = codepoint - HANGUL_SBASE;
|
|
@@ -270,7 +278,7 @@ module Addressable
|
|
|
270
278
|
end
|
|
271
279
|
return l, v, t
|
|
272
280
|
end
|
|
273
|
-
|
|
281
|
+
private_class_method :unicode_decompose_hangul
|
|
274
282
|
|
|
275
283
|
def self.lookup_unicode_combining_class(codepoint)
|
|
276
284
|
codepoint_data = UNICODE_DATA[codepoint]
|
|
@@ -278,14 +286,14 @@ module Addressable
|
|
|
278
286
|
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
|
279
287
|
0)
|
|
280
288
|
end
|
|
281
|
-
|
|
289
|
+
private_class_method :lookup_unicode_combining_class
|
|
282
290
|
|
|
283
291
|
def self.lookup_unicode_compatibility(codepoint)
|
|
284
292
|
codepoint_data = UNICODE_DATA[codepoint]
|
|
285
293
|
(codepoint_data ?
|
|
286
294
|
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
|
287
295
|
end
|
|
288
|
-
|
|
296
|
+
private_class_method :lookup_unicode_compatibility
|
|
289
297
|
|
|
290
298
|
def self.lookup_unicode_lowercase(codepoint)
|
|
291
299
|
codepoint_data = UNICODE_DATA[codepoint]
|
|
@@ -293,12 +301,12 @@ module Addressable
|
|
|
293
301
|
(codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) :
|
|
294
302
|
codepoint)
|
|
295
303
|
end
|
|
296
|
-
|
|
304
|
+
private_class_method :lookup_unicode_lowercase
|
|
297
305
|
|
|
298
306
|
def self.lookup_unicode_composition(unpacked)
|
|
299
307
|
return COMPOSITION_TABLE[unpacked]
|
|
300
308
|
end
|
|
301
|
-
|
|
309
|
+
private_class_method :lookup_unicode_composition
|
|
302
310
|
|
|
303
311
|
HANGUL_SBASE = 0xac00
|
|
304
312
|
HANGUL_LBASE = 0x1100
|
|
@@ -335,7 +343,7 @@ module Addressable
|
|
|
335
343
|
end
|
|
336
344
|
|
|
337
345
|
COMPOSITION_TABLE = {}
|
|
338
|
-
|
|
346
|
+
UNICODE_DATA.each do |codepoint, data|
|
|
339
347
|
canonical = data[UNICODE_DATA_CANONICAL]
|
|
340
348
|
exclusion = data[UNICODE_DATA_EXCLUSION]
|
|
341
349
|
|
|
@@ -376,6 +384,7 @@ module Addressable
|
|
|
376
384
|
class PunycodeOverflow < StandardError; end
|
|
377
385
|
|
|
378
386
|
def self.punycode_encode(unicode)
|
|
387
|
+
unicode = unicode.to_s unless unicode.is_a?(String)
|
|
379
388
|
input = unicode.unpack("U*")
|
|
380
389
|
output = [0] * (ACE_MAX_LENGTH + 1)
|
|
381
390
|
input_length = input.size
|
|
@@ -484,7 +493,7 @@ module Addressable
|
|
|
484
493
|
outlen.times do |j|
|
|
485
494
|
c = output[j]
|
|
486
495
|
unless c >= 0 && c <= 127
|
|
487
|
-
raise
|
|
496
|
+
raise StandardError, "Invalid output char."
|
|
488
497
|
end
|
|
489
498
|
unless PUNYCODE_PRINT_ASCII[c]
|
|
490
499
|
raise PunycodeBadInput, "Input is invalid."
|
|
@@ -493,7 +502,7 @@ module Addressable
|
|
|
493
502
|
|
|
494
503
|
output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "")
|
|
495
504
|
end
|
|
496
|
-
|
|
505
|
+
private_class_method :punycode_encode
|
|
497
506
|
|
|
498
507
|
def self.punycode_decode(punycode)
|
|
499
508
|
input = []
|
|
@@ -615,22 +624,22 @@ module Addressable
|
|
|
615
624
|
|
|
616
625
|
output.pack("U*")
|
|
617
626
|
end
|
|
618
|
-
|
|
627
|
+
private_class_method :punycode_decode
|
|
619
628
|
|
|
620
629
|
def self.punycode_basic?(codepoint)
|
|
621
630
|
codepoint < 0x80
|
|
622
631
|
end
|
|
623
|
-
|
|
632
|
+
private_class_method :punycode_basic?
|
|
624
633
|
|
|
625
634
|
def self.punycode_delimiter?(codepoint)
|
|
626
635
|
codepoint == PUNYCODE_DELIMITER
|
|
627
636
|
end
|
|
628
|
-
|
|
637
|
+
private_class_method :punycode_delimiter?
|
|
629
638
|
|
|
630
639
|
def self.punycode_encode_digit(d)
|
|
631
640
|
d + 22 + 75 * ((d < 26) ? 1 : 0)
|
|
632
641
|
end
|
|
633
|
-
|
|
642
|
+
private_class_method :punycode_encode_digit
|
|
634
643
|
|
|
635
644
|
# Returns the numeric value of a basic codepoint
|
|
636
645
|
# (for use in representing integers) in the range 0 to
|
|
@@ -646,7 +655,7 @@ module Addressable
|
|
|
646
655
|
PUNYCODE_BASE
|
|
647
656
|
end
|
|
648
657
|
end
|
|
649
|
-
|
|
658
|
+
private_class_method :punycode_decode_digit
|
|
650
659
|
|
|
651
660
|
# Bias adaptation method
|
|
652
661
|
def self.punycode_adapt(delta, numpoints, firsttime)
|
|
@@ -663,7 +672,7 @@ module Addressable
|
|
|
663
672
|
|
|
664
673
|
k + (difference + 1) * delta / (delta + PUNYCODE_SKEW)
|
|
665
674
|
end
|
|
666
|
-
|
|
675
|
+
private_class_method :punycode_adapt
|
|
667
676
|
end
|
|
668
677
|
# :startdoc:
|
|
669
678
|
end
|
data/lib/addressable/idna.rb
CHANGED