2015-12-16 00:07:31 -05:00
|
|
|
# frozen_string_literal: false
|
2014-06-21 20:22:19 -04:00
|
|
|
module URI
|
|
|
|
class RFC3986_Parser # :nodoc:
|
|
|
|
# URI defined in RFC3986
|
|
|
|
# this regexp is modified not to host is not empty string
|
2014-11-02 19:33:47 -05:00
|
|
|
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/
|
2014-12-24 18:50:37 -05:00
|
|
|
attr_reader :regexp
|
|
|
|
|
|
|
|
def initialize
|
|
|
|
@regexp = default_regexp.each_value(&:freeze).freeze
|
|
|
|
end
|
2014-06-21 20:22:19 -04:00
|
|
|
|
|
|
|
def split(uri) #:nodoc:
|
2014-09-26 23:13:22 -04:00
|
|
|
begin
|
|
|
|
uri = uri.to_str
|
|
|
|
rescue NoMethodError
|
|
|
|
raise InvalidURIError, "bad URI(is not URI?): #{uri}"
|
|
|
|
end
|
2014-12-24 18:50:37 -05:00
|
|
|
uri.ascii_only? or
|
2014-06-21 20:23:52 -04:00
|
|
|
raise InvalidURIError, "URI must be ascii only #{uri.dump}"
|
2014-06-21 20:22:19 -04:00
|
|
|
if m = RFC3986_URI.match(uri)
|
2014-12-24 18:50:37 -05:00
|
|
|
query = m["query".freeze]
|
|
|
|
scheme = m["scheme".freeze]
|
|
|
|
opaque = m["path-rootless".freeze]
|
|
|
|
if opaque
|
|
|
|
opaque << "?#{query}" if query
|
|
|
|
[ scheme,
|
|
|
|
nil, # userinfo
|
|
|
|
nil, # host
|
|
|
|
nil, # port
|
|
|
|
nil, # registry
|
|
|
|
nil, # path
|
|
|
|
opaque,
|
|
|
|
nil, # query
|
|
|
|
m["fragment".freeze]
|
|
|
|
]
|
2014-06-21 20:22:19 -04:00
|
|
|
else # normal
|
2014-12-24 18:50:37 -05:00
|
|
|
[ scheme,
|
|
|
|
m["userinfo".freeze],
|
|
|
|
m["host".freeze],
|
|
|
|
m["port".freeze],
|
|
|
|
nil, # registry
|
|
|
|
(m["path-abempty".freeze] ||
|
|
|
|
m["path-absolute".freeze] ||
|
|
|
|
m["path-empty".freeze]),
|
|
|
|
nil, # opaque
|
|
|
|
query,
|
|
|
|
m["fragment".freeze]
|
|
|
|
]
|
2014-06-21 20:22:19 -04:00
|
|
|
end
|
|
|
|
elsif m = RFC3986_relative_ref.match(uri)
|
2014-12-24 18:50:37 -05:00
|
|
|
[ nil, # scheme
|
|
|
|
m["userinfo".freeze],
|
|
|
|
m["host".freeze],
|
|
|
|
m["port".freeze],
|
|
|
|
nil, # registry,
|
|
|
|
(m["path-abempty".freeze] ||
|
|
|
|
m["path-absolute".freeze] ||
|
|
|
|
m["path-noscheme".freeze] ||
|
|
|
|
m["path-empty".freeze]),
|
|
|
|
nil, # opaque
|
|
|
|
m["query".freeze],
|
|
|
|
m["fragment".freeze]
|
|
|
|
]
|
2014-06-21 20:22:19 -04:00
|
|
|
else
|
|
|
|
raise InvalidURIError, "bad URI(is not URI?): #{uri}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse(uri) # :nodoc:
|
|
|
|
scheme, userinfo, host, port,
|
|
|
|
registry, path, opaque, query, fragment = self.split(uri)
|
2014-12-24 18:50:37 -05:00
|
|
|
scheme_list = URI.scheme_list
|
|
|
|
if scheme && scheme_list.include?(uc = scheme.upcase)
|
|
|
|
scheme_list[uc].new(scheme, userinfo, host, port,
|
|
|
|
registry, path, opaque, query,
|
|
|
|
fragment, self)
|
2014-06-21 20:22:19 -04:00
|
|
|
else
|
|
|
|
Generic.new(scheme, userinfo, host, port,
|
|
|
|
registry, path, opaque, query,
|
|
|
|
fragment, self)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def join(*uris) # :nodoc:
|
|
|
|
uris[0] = convert_to_uri(uris[0])
|
|
|
|
uris.inject :merge
|
|
|
|
end
|
|
|
|
|
|
|
|
@@to_s = Kernel.instance_method(:to_s)
|
|
|
|
def inspect
|
|
|
|
@@to_s.bind(self).call
|
|
|
|
end
|
|
|
|
|
2014-12-24 18:50:37 -05:00
|
|
|
private
|
|
|
|
|
|
|
|
def default_regexp # :nodoc:
|
2014-06-21 20:22:19 -04:00
|
|
|
{
|
|
|
|
SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/,
|
|
|
|
USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/,
|
|
|
|
HOST: /\A(?:(?<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{,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~])*))\z/,
|
|
|
|
ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
|
|
|
|
REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
|
2014-06-30 06:06:25 -04:00
|
|
|
QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
|
|
|
|
FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
|
2014-09-17 10:15:03 -04:00
|
|
|
OPAQUE: /\A(?:[^\/].*)?\z/,
|
2014-06-22 23:18:51 -04:00
|
|
|
PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\z/,
|
2014-06-21 20:22:19 -04:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def convert_to_uri(uri)
|
|
|
|
if uri.is_a?(URI::Generic)
|
|
|
|
uri
|
|
|
|
elsif uri = String.try_convert(uri)
|
|
|
|
parse(uri)
|
|
|
|
else
|
|
|
|
raise ArgumentError,
|
|
|
|
"bad argument (expected URI object or URI string)"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end # class Parser
|
|
|
|
end # module URI
|