Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge URI-0.12.0 for Ruby 3.1 #7261

Merged
merged 2 commits into from Mar 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/uri.rb
Expand Up @@ -101,3 +101,4 @@ module URI
require_relative 'uri/ldaps'
require_relative 'uri/mailto'
require_relative 'uri/ws'
require_relative 'uri/wss'
52 changes: 41 additions & 11 deletions lib/uri/common.rb
Expand Up @@ -13,6 +13,8 @@
require_relative "rfc3986_parser"

module URI
include RFC2396_REGEXP

REGEXP = RFC2396_REGEXP
Parser = RFC2396_Parser
RFC3986_PARSER = RFC3986_Parser.new
Expand Down Expand Up @@ -62,14 +64,17 @@ def make_components_hash(klass, array_hash)
module_function :make_components_hash
end

include REGEXP

module Schemes
end
private_constant :Schemes

#
# Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
# Note that currently only schemes which after .upcase are valid constant names
# can be registered (no -/+/. allowed).
#
def self.register_scheme(scheme, klass)
Schemes.const_set(scheme, klass)
Schemes.const_set(scheme.to_s.upcase, klass)
end

# Returns a Hash of the defined schemes.
Expand Down Expand Up @@ -295,6 +300,7 @@ def self.regexp(schemes = nil)
256.times do |i|
TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i)
end
TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze
TBLENCWWWCOMP_[' '] = '+'
TBLENCWWWCOMP_.freeze
TBLDECWWWCOMP_ = {} # :nodoc:
Expand All @@ -320,6 +326,33 @@ def self.regexp(schemes = nil)
#
# See URI.decode_www_form_component, URI.encode_www_form.
def self.encode_www_form_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
end

# Decodes given +str+ of URL-encoded form data.
#
# This decodes + to SP.
#
# See URI.encode_www_form_component, URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/\+|%\h\h/, str, enc)
end

# Encodes +str+ using URL encoding
#
# This encodes SP to %20 instead of +.
def self.encode_uri_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
end

# Decodes given +str+ of URL-encoded data.
#
# This does not decode + to SP.
def self.decode_uri_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/%\h\h/, str, enc)
end

def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
if enc && enc != Encoding::ASCII_8BIT
Expand All @@ -328,19 +361,16 @@ def self.encode_www_form_component(str, enc=nil)
end
str.force_encoding(Encoding::ASCII_8BIT)
end
str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_)
str.gsub!(regexp, table)
str.force_encoding(Encoding::US_ASCII)
end
private_class_method :_encode_uri_component

# Decodes given +str+ of URL-encoded form data.
#
# This decodes + to SP.
#
# See URI.encode_www_form_component, URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
def self._decode_uri_component(regexp, str, enc)
raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str)
str.b.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc)
end
private_class_method :_decode_uri_component

# Generates URL-encoded form data from given +enum+.
#
Expand Down
6 changes: 6 additions & 0 deletions lib/uri/file.rb
Expand Up @@ -33,6 +33,9 @@ class File < Generic
# If an Array is used, the components must be passed in the
# order <code>[host, path]</code>.
#
# A path from e.g. the File class should be escaped before
# being passed.
#
# Examples:
#
# require 'uri'
Expand All @@ -44,6 +47,9 @@ class File < Generic
# :path => '/ruby/src'})
# uri2.to_s # => "file://host.example.com/ruby/src"
#
# uri3 = URI::File.build({:path => URI::escape('/path/my file.txt')})
# uri3.to_s # => "file:///path/my%20file.txt"
#
def self.build(args)
tmp = Util::make_components_hash(self, args)
super(tmp)
Expand Down
14 changes: 12 additions & 2 deletions lib/uri/generic.rb
Expand Up @@ -564,16 +564,26 @@ def userinfo
end
end

# Returns the user component.
# Returns the user component (without URI decoding).
def user
@user
end

# Returns the password component.
# Returns the password component (without URI decoding).
def password
@password
end

# Returns the user component after URI decoding.
def decoded_user
URI.decode_uri_component(@user) if @user
end

# Returns the password component after URI decoding.
def decoded_password
URI.decode_uri_component(@password) if @password
end

#
# Checks the host +v+ component for RFC2396 compliance
# and against the URI::Parser Regexp for :HOST.
Expand Down
2 changes: 1 addition & 1 deletion lib/uri/mailto.rb
Expand Up @@ -15,7 +15,7 @@ module URI
# RFC6068, the mailto URL scheme.
#
class MailTo < Generic
include REGEXP
include RFC2396_REGEXP

# A Default port of nil for URI::MailTo.
DEFAULT_PORT = nil
Expand Down
5 changes: 2 additions & 3 deletions lib/uri/rfc3986_parser.rb
Expand Up @@ -2,9 +2,8 @@
module URI
class RFC3986_Parser # :nodoc:
# URI defined in RFC3986
# this regexp is modified not to host is not empty string
RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
attr_reader :regexp

def initialize
Expand Down
2 changes: 1 addition & 1 deletion lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
VERSION_CODE = '001100'.freeze
VERSION_CODE = '001200'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
92 changes: 89 additions & 3 deletions test/uri/test_common.rb
Expand Up @@ -41,18 +41,52 @@ def test_ractor
RUBY
end

DEFAULT_SCHEMES = ["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS", "WSS"].sort.freeze

def test_register_scheme
assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS"].sort, URI.scheme_list.keys.sort)
assert_equal(DEFAULT_SCHEMES, URI.scheme_list.keys.sort)

foobar = Class.new(URI::Generic)
URI.register_scheme 'FOOBAR', foobar
begin
assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS", "FOOBAR"].sort, URI.scheme_list.keys.sort)
assert_include(URI.scheme_list.keys, "FOOBAR")
assert_equal foobar, URI.parse('foobar://localhost').class
ensure
URI.const_get(:Schemes).send(:remove_const, :FOOBAR)
end

assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS"].sort, URI.scheme_list.keys.sort)
assert_equal(DEFAULT_SCHEMES, URI.scheme_list.keys.sort)
end

def test_register_scheme_lowercase
assert_equal(DEFAULT_SCHEMES, URI.scheme_list.keys.sort)

foobar = Class.new(URI::Generic)
URI.register_scheme 'foobarlower', foobar
begin
assert_include(URI.scheme_list.keys, "FOOBARLOWER")
assert_equal foobar, URI.parse('foobarlower://localhost').class
ensure
URI.const_get(:Schemes).send(:remove_const, :FOOBARLOWER)
end

assert_equal(DEFAULT_SCHEMES, URI.scheme_list.keys.sort)
end

def test_register_scheme_with_symbols
# Valid schemes from https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
some_uri_class = Class.new(URI::Generic)
assert_raise(NameError) { URI.register_scheme 'ms-search', some_uri_class }
assert_raise(NameError) { URI.register_scheme 'microsoft.windows.camera', some_uri_class }
assert_raise(NameError) { URI.register_scheme 'coaps+ws', some_uri_class }

ms_search_class = Class.new(URI::Generic)
URI.register_scheme 'MS_SEARCH', ms_search_class
begin
assert_equal URI::Generic, URI.parse('ms-search://localhost').class
ensure
URI.const_get(:Schemes).send(:remove_const, :MS_SEARCH)
end
end

def test_regexp
Expand Down Expand Up @@ -130,6 +164,58 @@ def test_decode_www_form_component
assert_nothing_raised(ArgumentError){URI.decode_www_form_component("x"*(1024*1024))}
end

def test_encode_uri_component
assert_equal("%00%20%21%22%23%24%25%26%27%28%29*%2B%2C-.%2F09%3A%3B%3C%3D%3E%3F%40" \
"AZ%5B%5C%5D%5E_%60az%7B%7C%7D%7E",
URI.encode_uri_component("\x00 !\"\#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~"))
assert_equal("%95A", URI.encode_uri_component(
"\x95\x41".force_encoding(Encoding::Shift_JIS)))
assert_equal("0B", URI.encode_uri_component(
"\x30\x42".force_encoding(Encoding::UTF_16BE)))
assert_equal("%1B%24B%24%22%1B%28B", URI.encode_uri_component(
"\e$B$\"\e(B".force_encoding(Encoding::ISO_2022_JP)))

assert_equal("%E3%81%82", URI.encode_uri_component(
"\u3042", Encoding::ASCII_8BIT))
assert_equal("%82%A0", URI.encode_uri_component(
"\u3042", Encoding::Windows_31J))
assert_equal("%E3%81%82", URI.encode_uri_component(
"\u3042", Encoding::UTF_8))

assert_equal("%82%A0", URI.encode_uri_component(
"\u3042".encode("sjis"), Encoding::ASCII_8BIT))
assert_equal("%A4%A2", URI.encode_uri_component(
"\u3042".encode("sjis"), Encoding::EUC_JP))
assert_equal("%E3%81%82", URI.encode_uri_component(
"\u3042".encode("sjis"), Encoding::UTF_8))
assert_equal("B0", URI.encode_uri_component(
"\u3042".encode("sjis"), Encoding::UTF_16LE))
assert_equal("%26%23730%3B", URI.encode_uri_component(
"\u02DA", Encoding::WINDOWS_1252))

# invalid
assert_equal("%EF%BF%BD%EF%BF%BD", URI.encode_uri_component(
"\xE3\x81\xFF", "utf-8"))
assert_equal("%E6%9F%8A%EF%BF%BD%EF%BF%BD", URI.encode_uri_component(
"\x95\x41\xff\xff".force_encoding(Encoding::Shift_JIS), "utf-8"))
end

def test_decode_uri_component
assert_equal(" +!\"\#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~",
URI.decode_uri_component(
"%20+%21%22%23%24%25%26%27%28%29*%2B%2C-.%2F09%3A%3B%3C%3D%3E%3F%40" \
"AZ%5B%5C%5D%5E_%60az%7B%7C%7D%7E"))
assert_equal("\xA1\xA2".force_encoding(Encoding::EUC_JP),
URI.decode_uri_component("%A1%A2", "EUC-JP"))
assert_equal("\xE3\x81\x82\xE3\x81\x82".force_encoding("UTF-8"),
URI.decode_uri_component("\xE3\x81\x82%E3%81%82".force_encoding("UTF-8")))

assert_raise(ArgumentError){URI.decode_uri_component("%")}
assert_raise(ArgumentError){URI.decode_uri_component("%a")}
assert_raise(ArgumentError){URI.decode_uri_component("x%a_")}
assert_nothing_raised(ArgumentError){URI.decode_uri_component("x"*(1024*1024))}
end

def test_encode_www_form
assert_equal("a=1", URI.encode_www_form("a" => "1"))
assert_equal("a=1", URI.encode_www_form(a: 1))
Expand Down
9 changes: 8 additions & 1 deletion test/uri/test_generic.rb
Expand Up @@ -24,7 +24,8 @@ def test_to_s

assert_equal "file:///foo", URI("file:///foo").to_s
assert_equal "postgres:///foo", URI("postgres:///foo").to_s
assert_equal "http:/foo", URI("http:///foo").to_s
assert_equal "http:///foo", URI("http:///foo").to_s
assert_equal "http:/foo", URI("http:/foo").to_s
end

def test_parse
Expand Down Expand Up @@ -157,6 +158,12 @@ def test_parse
assert_equal(nil, url.user)
assert_equal(nil, url.password)
assert_equal(nil, url.userinfo)

# sec-156615
url = URI.parse('http:////example.com')
# must be empty string to identify as path-abempty, not path-absolute
assert_equal('', url.host)
assert_equal('http:////example.com', url.to_s)
end

def test_parse_scheme_with_symbols
Expand Down
6 changes: 3 additions & 3 deletions test/uri/test_ldap.rb
Expand Up @@ -39,7 +39,7 @@ def test_parse
# from RFC2255, section 6.
{
'ldap:///o=University%20of%20Michigan,c=US' =>
['ldap', nil, URI::LDAP::DEFAULT_PORT,
['ldap', '', URI::LDAP::DEFAULT_PORT,
'o=University%20of%20Michigan,c=US',
nil, nil, nil, nil],

Expand Down Expand Up @@ -74,12 +74,12 @@ def test_parse
nil, '(int=%5c00%5c00%5c00%5c04)', nil, nil],

'ldap:///??sub??bindname=cn=Manager%2co=Foo' =>
['ldap', nil, URI::LDAP::DEFAULT_PORT,
['ldap', '', URI::LDAP::DEFAULT_PORT,
'',
nil, 'sub', nil, 'bindname=cn=Manager%2co=Foo'],

'ldap:///??sub??!bindname=cn=Manager%2co=Foo' =>
['ldap', nil, URI::LDAP::DEFAULT_PORT,
['ldap', '', URI::LDAP::DEFAULT_PORT,
'',
nil, 'sub', nil, '!bindname=cn=Manager%2co=Foo'],
}.each do |url2, ary|
Expand Down
16 changes: 16 additions & 0 deletions test/uri/test_parser.rb
Expand Up @@ -50,6 +50,15 @@ def test_parse_query_pct_encoded
assert_raise(URI::InvalidURIError) { URI.parse('https://www.example.com/search?q=%XX') }
end

def test_parse_auth
str = "http://al%40ice:p%40s%25sword@example.com/dir%2Fname/subdir?foo=bar%40example.com"
uri = URI.parse(str)
assert_equal "al%40ice", uri.user
assert_equal "p%40s%25sword", uri.password
assert_equal "al@ice", uri.decoded_user
assert_equal "p@s%sword", uri.decoded_password
end

def test_raise_bad_uri_for_integer
assert_raise(URI::InvalidURIError) do
URI.parse(1)
Expand All @@ -63,4 +72,11 @@ def test_unescape
assert_equal("\u3042", p1.unescape('%e3%81%82'.force_encoding(Encoding::US_ASCII)))
assert_equal("\xe3\x83\x90\xe3\x83\x90", p1.unescape("\xe3\x83\x90%e3%83%90"))
end

def test_split
assert_equal(["http", nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("http://example.com"))
assert_equal(["http", nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("http://[0::0]"))
assert_equal([nil, nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("//example.com"))
assert_equal([nil, nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("//[0::0]"))
end
end