diff options
Diffstat (limited to 'lib/uri')
| -rw-r--r-- | lib/uri/common.rb | 70 | ||||
| -rw-r--r-- | lib/uri/generic.rb | 55 | ||||
| -rw-r--r-- | lib/uri/http.rb | 12 | ||||
| -rw-r--r-- | lib/uri/rfc2396_parser.rb | 17 | ||||
| -rw-r--r-- | lib/uri/version.rb | 4 |
5 files changed, 113 insertions, 45 deletions
diff --git a/lib/uri/common.rb b/lib/uri/common.rb index 1115736297..a2fb531631 100644 --- a/lib/uri/common.rb +++ b/lib/uri/common.rb @@ -30,6 +30,9 @@ module URI remove_const(:Parser) if defined?(::URI::Parser) const_set("Parser", parser.class) + remove_const(:PARSER) if defined?(::URI::PARSER) + const_set("PARSER", parser) + remove_const(:REGEXP) if defined?(::URI::REGEXP) remove_const(:PATTERN) if defined?(::URI::PATTERN) if Parser == RFC2396_Parser @@ -92,6 +95,40 @@ module URI end module Schemes # :nodoc: + class << self + ReservedChars = ".+-" + EscapedChars = "\u01C0\u01C1\u01C2" + # Use Lo category chars as escaped chars for TruffleRuby, which + # does not allow Symbol categories as identifiers. + + def escape(name) + unless name and name.ascii_only? + return nil + end + name.upcase.tr(ReservedChars, EscapedChars) + end + + def unescape(name) + name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase + end + + def find(name) + const_get(name, false) if name and const_defined?(name, false) + end + + def register(name, klass) + unless scheme = escape(name) + raise ArgumentError, "invalid character as scheme - #{name}" + end + const_set(scheme, klass) + end + + def list + constants.map { |name| + [unescape(name.to_s), const_get(name)] + }.to_h + end + end end private_constant :Schemes @@ -104,7 +141,7 @@ module URI # Note that after calling String#upcase on +scheme+, it must be a valid # constant name. def self.register_scheme(scheme, klass) - Schemes.const_set(scheme.to_s.upcase, klass) + Schemes.register(scheme, klass) end # Returns a hash of the defined schemes: @@ -122,14 +159,14 @@ module URI # # Related: URI.register_scheme. def self.scheme_list - Schemes.constants.map { |name| - [name.to_s.upcase, Schemes.const_get(name)] - }.to_h + Schemes.list end + # :stopdoc: INITIAL_SCHEMES = scheme_list private_constant :INITIAL_SCHEMES Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor) + # :startdoc: # Returns a new object constructed from the given +scheme+, +arguments+, # and +default+: @@ -148,12 +185,10 @@ module URI # # => #<URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top> # def self.for(scheme, *arguments, default: Generic) - const_name = scheme.to_s.upcase + const_name = Schemes.escape(scheme) uri_class = INITIAL_SCHEMES[const_name] - uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false) - Schemes.const_get(const_name, false) - end + uri_class ||= Schemes.find(const_name) uri_class ||= default return uri_class.new(scheme, *arguments) @@ -195,7 +230,7 @@ module URI # ["fragment", "top"]] # def self.split(uri) - DEFAULT_PARSER.split(uri) + PARSER.split(uri) end # Returns a new \URI object constructed from the given string +uri+: @@ -205,11 +240,11 @@ module URI # URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top') # # => #<URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top> # - # It's recommended to first ::escape string +uri+ + # It's recommended to first URI::RFC2396_PARSER.escape string +uri+ # if it may contain invalid URI characters. # def self.parse(uri) - DEFAULT_PARSER.parse(uri) + PARSER.parse(uri) end # Merges the given URI strings +str+ @@ -236,7 +271,7 @@ module URI # # => #<URI::HTTP http://example.com/foo/bar> # def self.join(*str) - DEFAULT_PARSER.join(*str) + PARSER.join(*str) end # @@ -265,7 +300,7 @@ module URI # def self.extract(str, schemes = nil, &block) # :nodoc: warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE - DEFAULT_PARSER.extract(str, schemes, &block) + PARSER.extract(str, schemes, &block) end # @@ -302,7 +337,7 @@ module URI # def self.regexp(schemes = nil)# :nodoc: warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE - DEFAULT_PARSER.make_regexp(schemes) + PARSER.make_regexp(schemes) end TBLENCWWWCOMP_ = {} # :nodoc: @@ -407,6 +442,8 @@ module URI _decode_uri_component(/%\h\h/, str, enc) end + # Returns a string derived from the given string +str+ with + # URI-encoded characters matching +regexp+ according to +table+. def self._encode_uri_component(regexp, table, str, enc) str = str.to_s.dup if str.encoding != Encoding::ASCII_8BIT @@ -421,6 +458,8 @@ module URI end private_class_method :_encode_uri_component + # Returns a string decoding characters matching +regexp+ from the + # given \URL-encoded string +str+. def self._decode_uri_component(regexp, str, enc) raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str) str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc) @@ -859,6 +898,7 @@ module Kernel # Returns a \URI object derived from the given +uri+, # which may be a \URI string or an existing \URI object: # + # require 'uri' # # Returns a new URI. # uri = URI('http://github.com/ruby/ruby') # # => #<URI::HTTP http://github.com/ruby/ruby> @@ -866,6 +906,8 @@ module Kernel # URI(uri) # # => #<URI::HTTP http://github.com/ruby/ruby> # + # You must require 'uri' to use this method. + # def URI(uri) if uri.is_a?(URI::Generic) uri diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb index 07f329e3d1..6a0f638d76 100644 --- a/lib/uri/generic.rb +++ b/lib/uri/generic.rb @@ -126,9 +126,9 @@ module URI end end else - component = self.class.component rescue ::URI::Generic::COMPONENT + component = self.component rescue ::URI::Generic::COMPONENT raise ArgumentError, - "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})" + "expected Array of or Hash of components of #{self} (#{component.join(', ')})" end tmp << nil @@ -186,18 +186,18 @@ module URI if arg_check self.scheme = scheme - self.userinfo = userinfo self.hostname = host self.port = port + self.userinfo = userinfo self.path = path self.query = query self.opaque = opaque self.fragment = fragment else self.set_scheme(scheme) - self.set_userinfo(userinfo) self.set_host(host) self.set_port(port) + self.set_userinfo(userinfo) self.set_path(path) self.query = query self.set_opaque(opaque) @@ -284,7 +284,7 @@ module URI # Returns the parser to be used. # - # Unless a URI::Parser is defined, DEFAULT_PARSER is used. + # Unless the +parser+ is defined, DEFAULT_PARSER is used. # def parser if !defined?(@parser) || !@parser @@ -315,7 +315,7 @@ module URI end # - # Checks the scheme +v+ component against the URI::Parser Regexp for :SCHEME. + # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME. # def check_scheme(v) if v && parser.regexp[:SCHEME] !~ v @@ -385,7 +385,7 @@ module URI # # Checks the user +v+ component for RFC2396 compliance - # and against the URI::Parser Regexp for :USERINFO. + # and against the +parser+ Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. @@ -409,7 +409,7 @@ module URI # # Checks the password +v+ component for RFC2396 compliance - # and against the URI::Parser Regexp for :USERINFO. + # and against the +parser+ Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. @@ -466,7 +466,7 @@ module URI # # uri = URI.parse("http://john:S3nsit1ve@my.example.com") # uri.user = "sam" - # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com" + # uri.to_s #=> "http://sam@my.example.com" # def user=(user) check_user(user) @@ -511,7 +511,7 @@ module URI user, password = split_userinfo(user) end @user = user - @password = password if password + @password = password [@user, @password] end @@ -522,7 +522,7 @@ module URI # See also URI::Generic.user=. # def set_user(v) - set_userinfo(v, @password) + set_userinfo(v, nil) v end protected :set_user @@ -574,6 +574,12 @@ module URI @password end + # Returns the authority info (array of user, password, host and + # port), if any is set. Or returns +nil+. + def authority + return @user, @password, @host, @port if @user || @password || @host || @port + end + # Returns the user component after URI decoding. def decoded_user URI.decode_uri_component(@user) if @user @@ -586,7 +592,7 @@ module URI # # Checks the host +v+ component for RFC2396 compliance - # and against the URI::Parser Regexp for :HOST. + # and against the +parser+ Regexp for :HOST. # # Can not have a registry or opaque component defined, # with a host component defined. @@ -615,6 +621,13 @@ module URI end protected :set_host + # Protected setter for the authority info (+user+, +password+, +host+ + # and +port+). If +port+ is +nil+, +default_port+ will be set. + # + protected def set_authority(user, password, host, port = nil) + @user, @password, @host, @port = user, password, host, port || self.default_port + end + # # == Args # @@ -639,6 +652,7 @@ module URI def host=(v) check_host(v) set_host(v) + set_userinfo(nil) v end @@ -675,7 +689,7 @@ module URI # # Checks the port +v+ component for RFC2396 compliance - # and against the URI::Parser Regexp for :PORT. + # and against the +parser+ Regexp for :PORT. # # Can not have a registry or opaque component defined, # with a port component defined. @@ -729,6 +743,7 @@ module URI def port=(v) check_port(v) set_port(v) + set_userinfo(nil) port end @@ -748,7 +763,7 @@ module URI # # Checks the path +v+ component for RFC2396 compliance - # and against the URI::Parser Regexp + # and against the +parser+ Regexp # for :ABS_PATH and :REL_PATH. # # Can not have a opaque component defined, @@ -853,7 +868,7 @@ module URI # # Checks the opaque +v+ component for RFC2396 compliance and - # against the URI::Parser Regexp for :OPAQUE. + # against the +parser+ Regexp for :OPAQUE. # # Can not have a host, port, user, or path component defined, # with an opaque component defined. @@ -905,7 +920,7 @@ module URI end # - # Checks the fragment +v+ component against the URI::Parser Regexp for :FRAGMENT. + # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT. # # # == Args @@ -1121,7 +1136,7 @@ module URI base = self.dup - authority = rel.userinfo || rel.host || rel.port + authority = rel.authority # RFC2396, Section 5.2, 2) if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query @@ -1134,9 +1149,7 @@ module URI # RFC2396, Section 5.2, 4) if authority - base.set_userinfo(rel.userinfo) - base.set_host(rel.host) - base.set_port(rel.port || base.default_port) + base.set_authority(*authority) base.set_path(rel.path) elsif base.path && rel.path base.set_path(merge_path(base.path, rel.path)) @@ -1527,7 +1540,7 @@ module URI else unless proxy_uri = env[name] if proxy_uri = env[name.upcase] - warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1 + warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1 end end end diff --git a/lib/uri/http.rb b/lib/uri/http.rb index 900b132c8c..3c41cd4e93 100644 --- a/lib/uri/http.rb +++ b/lib/uri/http.rb @@ -61,6 +61,18 @@ module URI super(tmp) end + # Do not allow empty host names, as they are not allowed by RFC 3986. + def check_host(v) + ret = super + + if ret && v.empty? + raise InvalidComponentError, + "bad component(expected host component): #{v}" + end + + ret + end + # # == Description # diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb index 75a2d2dbde..cefd126cc6 100644 --- a/lib/uri/rfc2396_parser.rb +++ b/lib/uri/rfc2396_parser.rb @@ -67,7 +67,7 @@ module URI # # == Synopsis # - # URI::Parser.new([opts]) + # URI::RFC2396_Parser.new([opts]) # # == Args # @@ -86,7 +86,7 @@ module URI # # == Examples # - # p = URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})") + # p = URI::RFC2396_Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})") # u = p.parse("http://example.jp/%uABCD") #=> #<URI::HTTP http://example.jp/%uABCD> # URI.parse(u.to_s) #=> raises URI::InvalidURIError # @@ -108,12 +108,12 @@ module URI # The Hash of patterns. # - # See also URI::Parser.initialize_pattern. + # See also #initialize_pattern. attr_reader :pattern # The Hash of Regexp. # - # See also URI::Parser.initialize_regexp. + # See also #initialize_regexp. attr_reader :regexp # Returns a split URI against +regexp[:ABS_URI]+. @@ -202,8 +202,7 @@ module URI # # == Usage # - # p = URI::Parser.new - # p.parse("ldap://ldap.example.com/dc=example?user=john") + # URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john") # #=> #<URI::LDAP ldap://ldap.example.com/dc=example?user=john> # def parse(uri) @@ -244,7 +243,7 @@ module URI # If no +block+ given, then returns the result, # else it calls +block+ for each element in result. # - # See also URI::Parser.make_regexp. + # See also #make_regexp. # def extract(str, schemes = nil) if block_given? @@ -263,7 +262,7 @@ module URI unless schemes @regexp[:ABS_URI_REF] else - /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x + /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x end end @@ -524,6 +523,8 @@ module URI ret end + # Returns +uri+ as-is if it is URI, or convert it to URI if it is + # a String. def convert_to_uri(uri) if uri.is_a?(URI::Generic) uri diff --git a/lib/uri/version.rb b/lib/uri/version.rb index b6a8ce1543..1f810602eb 100644 --- a/lib/uri/version.rb +++ b/lib/uri/version.rb @@ -1,6 +1,6 @@ module URI # :stopdoc: - VERSION_CODE = '010003'.freeze - VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze + VERSION = '1.1.1'.freeze + VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze # :startdoc: end |
