Object
This is an implementation of a URI parser based on RFC">www.ietf.org/rfc/rfc3986.txt">RFC 3986, RFC">www.ietf.org/rfc/rfc3987.txt">RFC 3987.
Converts a path to a file scheme URI. If the path supplied is relative, it will be returned as a relative URI. If the path supplied is actually a non-file URI, it will parse the URI as if it had been parsed with Addressable::URI.parse. Handles all of the various Microsoft-specific formats for specifying paths.
@param [String, Addressable::URI, #] path
Typically a String path to a file or directory, but will return a sensible return value if an absolute URI is supplied instead.
@return [Addressable::URI]
The parsed file scheme URI or the original URI if some other URI scheme was provided.
@example
base = Addressable::URI.convert_path("/absolute/path/") uri = Addressable::URI.convert_path("relative/path") (base + uri).to_s #=> "file:///absolute/path/relative/path" Addressable::URI.convert_path( "c:\\windows\\My Documents 100%20\\foo.txt" ).to_s #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" Addressable::URI.convert_path("http://example.com/").to_s #=> "http://example.com/"
# File lib/addressable/uri.rb, line 211 211: def self.convert_path(path) 212: # If we were given nil, return nil. 213: return nil unless path 214: # If a URI object is passed, just return itself. 215: return path if path.kind_of?(self) 216: if !path.respond_to?(:to_str) 217: raise TypeError, "Can't convert #{path.class} into String." 218: end 219: # Otherwise, convert to a String 220: path = path.to_str.strip 221: 222: path.gsub!(/^file:\/?\/?/, "") if path =~ /^file:\/?\/?/ 223: path = "/" + path if path =~ /^([a-zA-Z])[\|:]/ 224: uri = self.parse(path) 225: 226: if uri.scheme == nil 227: # Adjust windows-style uris 228: uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do 229: "/#{$1.downcase}:/" 230: end 231: uri.path.gsub!(/\\/, "/") 232: if File.exists?(uri.path) && 233: File.stat(uri.path).directory? 234: uri.path.gsub!(/\/$/, "") 235: uri.path = uri.path + '/' 236: end 237: 238: # If the path is absolute, set the scheme and host. 239: if uri.path =~ /^\// 240: uri.scheme = "file" 241: uri.host = "" 242: end 243: uri.normalize! 244: end 245: 246: return uri 247: end
Percent encodes any special characters in the URI.
@param [String, Addressable::URI, #] uri
The URI to encode.
@param [Class] returning
The type of object to return.
This value may only be set to String or Addressable::URI. All other values are invalid. Defaults to String.
@return [String, Addressable::URI]
The encoded URI.
The return type is determined by the returning parameter.
# File lib/addressable/uri.rb, line 459 459: def self.encode(uri, returning=String) 460: return nil if uri.nil? 461: if !uri.respond_to?(:to_str) 462: raise TypeError, "Can't convert #{uri.class} into String." 463: end 464: if ![String, ::Addressable::URI].include?(returning) 465: raise TypeError, 466: "Expected Class (String or Addressable::URI), " + 467: "got #{returning.inspect}" 468: end 469: uri_object = uri.kind_of?(self) ? uri : self.parse(uri.to_str) 470: encoded_uri = Addressable::URI.new( 471: :scheme => self.encode_component(uri_object.scheme, 472: Addressable::URI::CharacterClasses::SCHEME), 473: :authority => self.encode_component(uri_object.authority, 474: Addressable::URI::CharacterClasses::AUTHORITY), 475: :path => self.encode_component(uri_object.path, 476: Addressable::URI::CharacterClasses::PATH), 477: :query => self.encode_component(uri_object.query, 478: Addressable::URI::CharacterClasses::QUERY), 479: :fragment => self.encode_component(uri_object.fragment, 480: Addressable::URI::CharacterClasses::FRAGMENT) 481: ) 482: if returning == String 483: return encoded_uri.to_s 484: elsif returning == ::Addressable::URI 485: return encoded_uri 486: end 487: end
Percent encodes a URI component.
@param [String, #] component The URI component to encode.
@param [String, Regexp] character_class
The characters which are not percent encoded. If a String is passed, the String must be formatted as a regular expression character class. (Do not include the surrounding square brackets.) For example, "b-zB-Z0-9" would cause everything but the letters ‘b’ through ‘z’ and the numbers ‘0’ through ‘9’ to be percent encoded. If a Regexp is passed, the value /[^b-zB-Z0-9]/ would have the same effect. A set of useful String values may be found in the Addressable::URI::CharacterClasses module. The default value is the reserved plus unreserved character classes specified in RFC">www.ietf.org/rfc/rfc3986.txt">RFC 3986.
@return [String] The encoded component.
@example
Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") => "simple%2Fex%61mple" Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) => "simple%2Fex%61mple" Addressable::URI.encode_component( "simple/example", Addressable::URI::CharacterClasses::UNRESERVED ) => "simple%2Fexample"
# File lib/addressable/uri.rb, line 305 305: def self.encode_component(component, character_class= 306: CharacterClasses::RESERVED + CharacterClasses::UNRESERVED) 307: return nil if component.nil? 308: if !component.respond_to?(:to_str) 309: raise TypeError, "Can't convert #{component.class} into String." 310: end 311: component = component.to_str 312: if ![String, Regexp].include?(character_class.class) 313: raise TypeError, 314: "Expected String or Regexp, got #{character_class.inspect}" 315: end 316: if character_class.kind_of?(String) 317: character_class = /[^#{character_class}]/ 318: end 319: if component.respond_to?(:force_encoding) 320: # We can't perform regexps on invalid UTF sequences, but 321: # here we need to, so switch to ASCII. 322: component = component.dup 323: component.force_encoding(Encoding::ASCII_8BIT) 324: end 325: return component.gsub(character_class) do |sequence| 326: (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join("") 327: end 328: end
Converts an input to a URI. The input does not have to be a valid URI — the method will use heuristics to guess what URI was intended. This is not standards-compliant, merely user-friendly.
@param [String, Addressable::URI, #] uri
The URI string to parse.
No parsing is performed if the object is already an Addressable::URI. @param [Hash] hints
A <tt>Hash</tt> of hints to the heuristic parser.
Defaults to {:scheme => "http"}.
@return [Addressable::URI] The parsed URI.
# File lib/addressable/uri.rb, line 140 140: def self.heuristic_parse(uri, hints={}) 141: # If we were given nil, return nil. 142: return nil unless uri 143: # If a URI object is passed, just return itself. 144: return uri if uri.kind_of?(self) 145: if !uri.respond_to?(:to_str) 146: raise TypeError, "Can't convert #{uri.class} into String." 147: end 148: # Otherwise, convert to a String 149: uri = uri.to_str.dup 150: hints = { 151: :scheme => "http" 152: }.merge(hints) 153: case uri 154: when /^http:\/+/ 155: uri.gsub!(/^http:\/+/, "http://") 156: when /^feed:\/+http:\/+/ 157: uri.gsub!(/^feed:\/+http:\/+/, "feed:http://") 158: when /^feed:\/+/ 159: uri.gsub!(/^feed:\/+/, "feed://") 160: when /^file:\/+/ 161: uri.gsub!(/^file:\/+/, "file:///") 162: end 163: parsed = self.parse(uri) 164: if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ 165: parsed = self.parse(hints[:scheme] + "://" + uri) 166: end 167: if parsed.path.include?(".") 168: new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] 169: if new_host 170: parsed.defer_validation do 171: new_path = parsed.path.gsub( 172: Regexp.new("^" + Regexp.escape(new_host)), "") 173: parsed.host = new_host 174: parsed.path = new_path 175: parsed.scheme = hints[:scheme] unless parsed.scheme 176: end 177: end 178: end 179: return parsed 180: end
Returns an array of known ip-based schemes. These schemes typically use a
similar URI form:
//
# File lib/addressable/uri.rb, line 997 997: def self.ip_based_schemes 998: return self.port_mapping.keys 999: end
Joins several URIs together.
@param [String, Addressable::URI, #] *uris
The URIs to join.
@return [Addressable::URI] The joined URI.
@example
base = "http://example.com/" uri = Addressable::URI.parse("relative/path") Addressable::URI.join(base, uri) #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
# File lib/addressable/uri.rb, line 262 262: def self.join(*uris) 263: uri_objects = uris.collect do |uri| 264: if !uri.respond_to?(:to_str) 265: raise TypeError, "Can't convert #{uri.class} into String." 266: end 267: uri.kind_of?(self) ? uri : self.parse(uri.to_str) 268: end 269: result = uri_objects.shift.dup 270: for uri in uri_objects 271: result.join!(uri) 272: end 273: return result 274: end
Creates a new uri object from component parts.
@option [String, #] scheme The scheme component. @option [String, #] user The user component. @option [String, #] password The password component. @option [String, #] userinfo
The userinfo component. If this is supplied, the user and password components must be omitted.
@option [String, #] host The host component. @option [String, #] port The port component. @option [String, #] authority
The authority component. If this is supplied, the user, password, userinfo, host, and port components must be omitted.
@option [String, #] path The path component. @option [String, #] query The query component. @option [String, #] fragment The fragment component.
@return [Addressable::URI] The constructed URI object.
# File lib/addressable/uri.rb, line 582 582: def initialize(options={}) 583: if options.has_key?(:authority) 584: if (options.keys & [:userinfo, :user, :password, :host, :port]).any? 585: raise ArgumentError, 586: "Cannot specify both an authority and any of the components " + 587: "within the authority." 588: end 589: end 590: if options.has_key?(:userinfo) 591: if (options.keys & [:user, :password]).any? 592: raise ArgumentError, 593: "Cannot specify both a userinfo and either the user or password." 594: end 595: end 596: 597: self.defer_validation do 598: # Bunch of crazy logic required because of the composite components 599: # like userinfo and authority. 600: self.scheme = options[:scheme] if options[:scheme] 601: self.user = options[:user] if options[:user] 602: self.password = options[:password] if options[:password] 603: self.userinfo = options[:userinfo] if options[:userinfo] 604: self.host = options[:host] if options[:host] 605: self.port = options[:port] if options[:port] 606: self.authority = options[:authority] if options[:authority] 607: self.path = options[:path] if options[:path] 608: self.query = options[:query] if options[:query] 609: self.fragment = options[:fragment] if options[:fragment] 610: end 611: end
Normalizes the encoding of a URI component.
@param [String, #] component The URI component to encode.
@param [String, Regexp] character_class
The characters which are not percent encoded. If a String is passed, the String must be formatted as a regular expression character class. (Do not include the surrounding square brackets.) For example, "b-zB-Z0-9" would cause everything but the letters ‘b’ through ‘z’ and the numbers ‘0’ through ‘9’ to be percent encoded. If a Regexp is passed, the value /[^b-zB-Z0-9]/ would have the same effect. A set of useful String values may be found in the Addressable::URI::CharacterClasses module. The default value is the reserved plus unreserved character classes specified in RFC">www.ietf.org/rfc/rfc3986.txt">RFC 3986.
@return [String] The normalized component.
@example
Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") => "simple%2Fex%61mple" Addressable::URI.normalize_component( "simpl%65/%65xampl%65", /[^b-zB-Z]/ ) => "simple%2Fex%61mple" Addressable::URI.normalize_component( "simpl%65/%65xampl%65", Addressable::URI::CharacterClasses::UNRESERVED ) => "simple%2Fexample"
# File lib/addressable/uri.rb, line 412 412: def self.normalize_component(component, character_class= 413: CharacterClasses::RESERVED + CharacterClasses::UNRESERVED) 414: return nil if component.nil? 415: if !component.respond_to?(:to_str) 416: raise TypeError, "Can't convert #{component.class} into String." 417: end 418: component = component.to_str 419: if ![String, Regexp].include?(character_class.class) 420: raise TypeError, 421: "Expected String or Regexp, got #{character_class.inspect}" 422: end 423: if character_class.kind_of?(String) 424: character_class = /[^#{character_class}]/ 425: end 426: if component.respond_to?(:force_encoding) 427: # We can't perform regexps on invalid UTF sequences, but 428: # here we need to, so switch to ASCII. 429: component = component.dup 430: component.force_encoding(Encoding::ASCII_8BIT) 431: end 432: unencoded = self.unencode_component(component) 433: begin 434: encoded = self.encode_component( 435: Addressable::IDNA.unicode_normalize_kc(unencoded), 436: character_class 437: ) 438: rescue ArgumentError 439: encoded = self.encode_component(unencoded) 440: end 441: return encoded 442: end
Normalizes the encoding of a URI. Characters within a hostname are not percent encoded to allow for internationalized domain names.
@param [String, Addressable::URI, #] uri
The URI to encode.
@param [Class] returning
The type of object to return.
This value may only be set to String or Addressable::URI. All other values are invalid. Defaults to String.
@return [String, Addressable::URI]
The encoded URI.
The return type is determined by the returning parameter.
# File lib/addressable/uri.rb, line 509 509: def self.normalized_encode(uri, returning=String) 510: if !uri.respond_to?(:to_str) 511: raise TypeError, "Can't convert #{uri.class} into String." 512: end 513: if ![String, ::Addressable::URI].include?(returning) 514: raise TypeError, 515: "Expected Class (String or Addressable::URI), " + 516: "got #{returning.inspect}" 517: end 518: uri_object = uri.kind_of?(self) ? uri : self.parse(uri.to_str) 519: components = { 520: :scheme => self.unencode_component(uri_object.scheme), 521: :user => self.unencode_component(uri_object.user), 522: :password => self.unencode_component(uri_object.password), 523: :host => self.unencode_component(uri_object.host), 524: :port => uri_object.port, 525: :path => self.unencode_component(uri_object.path), 526: :query => self.unencode_component(uri_object.query), 527: :fragment => self.unencode_component(uri_object.fragment) 528: } 529: components.each do |key, value| 530: if value != nil 531: begin 532: components[key] = 533: Addressable::IDNA.unicode_normalize_kc(value.to_str) 534: rescue ArgumentError 535: # Likely a malformed UTF-8 character, skip unicode normalization 536: components[key] = value.to_str 537: end 538: end 539: end 540: encoded_uri = Addressable::URI.new( 541: :scheme => self.encode_component(components[:scheme], 542: Addressable::URI::CharacterClasses::SCHEME), 543: :user => self.encode_component(components[:user], 544: Addressable::URI::CharacterClasses::UNRESERVED), 545: :password => self.encode_component(components[:password], 546: Addressable::URI::CharacterClasses::UNRESERVED), 547: :host => components[:host], 548: :port => components[:port], 549: :path => self.encode_component(components[:path], 550: Addressable::URI::CharacterClasses::PATH), 551: :query => self.encode_component(components[:query], 552: Addressable::URI::CharacterClasses::QUERY), 553: :fragment => self.encode_component(components[:fragment], 554: Addressable::URI::CharacterClasses::FRAGMENT) 555: ) 556: if returning == String 557: return encoded_uri.to_s 558: elsif returning == ::Addressable::URI 559: return encoded_uri 560: end 561: end
Returns a URI object based on the parsed string.
@param [String, Addressable::URI, #] uri
The URI string to parse.
No parsing is performed if the object is already an Addressable::URI.
@return [Addressable::URI] The parsed URI.
# File lib/addressable/uri.rb, line 66 66: def self.parse(uri) 67: # If we were given nil, return nil. 68: return nil unless uri 69: # If a URI object is passed, just return itself. 70: return uri if uri.kind_of?(self) 71: 72: # If a URI object of the Ruby standard library variety is passed, 73: # convert it to a string, then parse the string. 74: # We do the check this way because we don't want to accidentally 75: # cause a missing constant exception to be thrown. 76: if uri.class.name =~ /^URI\b/ 77: uri = uri.to_s 78: end 79: 80: if !uri.respond_to?(:to_str) 81: raise TypeError, "Can't convert #{uri.class} into String." 82: end 83: # Otherwise, convert to a String 84: uri = uri.to_str 85: 86: # This Regexp supplied as an example in RFC 3986, and it works great. 87: uri_regex = 88: /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ 89: scan = uri.scan(uri_regex) 90: fragments = scan[0] 91: scheme = fragments[1] 92: authority = fragments[3] 93: path = fragments[4] 94: query = fragments[6] 95: fragment = fragments[8] 96: user = nil 97: password = nil 98: host = nil 99: port = nil 100: if authority != nil 101: # The Regexp above doesn't split apart the authority. 102: userinfo = authority[/^([^\[\]]*)@/, 1] 103: if userinfo != nil 104: user = userinfo.strip[/^([^:]*):?/, 1] 105: password = userinfo.strip[/:(.*)$/, 1] 106: end 107: host = authority.gsub(/^([^\[\]]*)@/, "").gsub(/:([^:@\[\]]*?)$/, "") 108: port = authority[/:([^:@\[\]]*?)$/, 1] 109: end 110: if port == "" 111: port = nil 112: end 113: 114: return Addressable::URI.new( 115: :scheme => scheme, 116: :user => user, 117: :password => password, 118: :host => host, 119: :port => port, 120: :path => path, 121: :query => query, 122: :fragment => fragment 123: ) 124: end
Returns a hash of common IP-based schemes and their default port numbers. Adding new schemes to this hash, as necessary, will allow for better URI normalization.
# File lib/addressable/uri.rb, line 1004 1004: def self.port_mapping 1005: @port_mapping ||= { 1006: "http" => 80, 1007: "https" => 443, 1008: "ftp" => 21, 1009: "tftp" => 69, 1010: "sftp" => 22, 1011: "ssh" => 22, 1012: "svn+ssh" => 22, 1013: "telnet" => 23, 1014: "nntp" => 119, 1015: "gopher" => 70, 1016: "wais" => 210, 1017: "ldap" => 389, 1018: "prospero" => 1525 1019: } 1020: end
Unencodes any percent encoded characters within a URI component. This method may be used for unencoding either components or full URIs, however, it is recommended to use the unencode_component alias when unencoding components.
@param [String, Addressable::URI, #] uri
The URI or component to unencode.
@param [Class] returning
The type of object to return.
This value may only be set to String or Addressable::URI. All other values are invalid. Defaults to String.
@return [String, Addressable::URI]
The unencoded component or URI.
The return type is determined by the returning parameter.
# File lib/addressable/uri.rb, line 352 352: def self.unencode(uri, returning=String) 353: return nil if uri.nil? 354: if !uri.respond_to?(:to_str) 355: raise TypeError, "Can't convert #{uri.class} into String." 356: end 357: if ![String, ::Addressable::URI].include?(returning) 358: raise TypeError, 359: "Expected Class (String or Addressable::URI), " + 360: "got #{returning.inspect}" 361: end 362: result = uri.to_str.gsub(/%[0-9a-f]{2}/) do |sequence| 363: sequence[1..3].to_i(16).chr 364: end 365: result.force_encoding("utf-8") if result.respond_to?(:force_encoding) 366: if returning == String 367: return result 368: elsif returning == ::Addressable::URI 369: return ::Addressable::URI.parse(result) 370: end 371: end
Resolves paths to their simplest form.
@param [String] path The path to normalize.
@return [String] The normalized path.
# File lib/addressable/uri.rb, line 2005 2005: def self.normalize_path(path) 2006: # Section 5.2.4 of RFC 3986 2007: 2008: return nil if path.nil? 2009: normalized_path = path.dup 2010: previous_state = normalized_path.dup 2011: begin 2012: previous_state = normalized_path.dup 2013: normalized_path.gsub!(/\/\.\//, "/") 2014: normalized_path.gsub!(/\/\.$/, "/") 2015: parent = normalized_path[/\/([^\/]+)\/\.\.\//, 1] 2016: if parent != "." && parent != ".." 2017: normalized_path.gsub!(/\/#{parent}\/\.\.\//, "/") 2018: end 2019: parent = normalized_path[/\/([^\/]+)\/\.\.$/, 1] 2020: if parent != "." && parent != ".." 2021: normalized_path.gsub!(/\/#{parent}\/\.\.$/, "/") 2022: end 2023: normalized_path.gsub!(/^\.\.?\/?/, "") 2024: normalized_path.gsub!(/^\/\.\.?\//, "/") 2025: end until previous_state == normalized_path 2026: return normalized_path 2027: end
Returns true if the URI objects are equal. This method normalizes both URIs before doing the comparison.
@param [Object] uri The URI to compare.
@return [TrueClass, FalseClass]
<tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
# File lib/addressable/uri.rb, line 1823 1823: def ==(uri) 1824: return false unless uri.kind_of?(self.class) 1825: return self.normalize.to_s == uri.normalize.to_s 1826: end
Returns true if the URI objects are equal. This method normalizes both URIs before doing the comparison, and allows comparison against Strings.
@param [Object] uri The URI to compare.
@return [TrueClass, FalseClass]
<tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
# File lib/addressable/uri.rb, line 1802 1802: def ===(uri) 1803: if uri.respond_to?(:normalize) 1804: uri_string = uri.normalize.to_s 1805: else 1806: begin 1807: uri_string = ::Addressable::URI.parse(uri).normalize.to_s 1808: rescue InvalidURIError, TypeError 1809: return false 1810: end 1811: end 1812: return self.normalize.to_s == uri_string 1813: end
The basename, if any, of the file in the path component.
@return [String] The path’s basename.
# File lib/addressable/uri.rb, line 1157 1157: def basename 1158: # Path cannot be nil 1159: return File.basename(self.path).gsub(/;[^\/]*$/, "") 1160: end
This method allows you to make several changes to a URI simultaneously, which separately would cause validation errors, but in conjunction, are valid. The URI will be revalidated as soon as the entire block has been executed.
@param [Proc] block
A set of operations to perform on a given URI.
# File lib/addressable/uri.rb, line 1989 1989: def defer_validation(&block) 1990: raise LocalJumpError, "No block given." unless block 1991: @validation_deferred = true 1992: block.call() 1993: @validation_deferred = false 1994: validate 1995: return nil 1996: end
Creates a URI suitable for display to users. If semantic attacks are likely, the application should try to detect these and warn the user. See RFC">www.ietf.org/rfc/rfc3986.txt">RFC 3986, section 7.6 for more information.
@return [Addressable::URI] A URI suitable for display purposes.
# File lib/addressable/uri.rb, line 1787 1787: def display_uri 1788: display_uri = self.normalize 1789: display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) 1790: return display_uri 1791: end
Clones the URI object.
@return [Addressable::URI] The cloned URI.
# File lib/addressable/uri.rb, line 1854 1854: def dup 1855: duplicated_uri = Addressable::URI.new( 1856: :scheme => self.scheme ? self.scheme.dup : nil, 1857: :user => self.user ? self.user.dup : nil, 1858: :password => self.password ? self.password.dup : nil, 1859: :host => self.host ? self.host.dup : nil, 1860: :port => self.port, 1861: :path => self.path ? self.path.dup : nil, 1862: :query => self.query ? self.query.dup : nil, 1863: :fragment => self.fragment ? self.fragment.dup : nil 1864: ) 1865: return duplicated_uri 1866: end
Returns true if the URI objects are equal. This method does NOT normalize either URI before doing the comparison.
@param [Object] uri The URI to compare.
@return [TrueClass, FalseClass]
<tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
# File lib/addressable/uri.rb, line 1836 1836: def eql?(uri) 1837: return false unless uri.kind_of?(self.class) 1838: return self.to_s == uri.to_s 1839: end
The extname, if any, of the file in the path component. Empty string if there is no extension.
@return [String] The path’s extname.
# File lib/addressable/uri.rb, line 1167 1167: def extname 1168: return nil unless self.path 1169: return File.extname(self.basename) 1170: end
The fragment component for this URI.
@return [String] The fragment component.
# File lib/addressable/uri.rb, line 1402 1402: def fragment 1403: return @fragment ||= nil 1404: end
Sets the fragment component for this URI.
@param [String, #] new_fragment The new fragment component.
# File lib/addressable/uri.rb, line 1427 1427: def fragment=(new_fragment) 1428: # Check for frozenness 1429: raise TypeError, "Can't modify frozen URI." if self.frozen? 1430: 1431: if new_fragment && !new_fragment.respond_to?(:to_str) 1432: raise TypeError, "Can't convert #{new_fragment.class} into String." 1433: end 1434: @fragment = new_fragment ? new_fragment.to_str : nil 1435: 1436: # Reset dependant values 1437: @normalized_fragment = nil 1438: @uri_string = nil 1439: 1440: # Ensure we haven't created an invalid URI 1441: validate() 1442: end
Freezes the URI object.
@return [Addressable::URI] The frozen URI.
# File lib/addressable/uri.rb, line 1872 1872: def freeze 1873: # Unfortunately, because of the memoized implementation of many of the 1874: # URI methods, the default freeze method will cause unexpected errors. 1875: # As an alternative, we freeze the string representation of the URI 1876: # instead. This should generally produce the desired effect. 1877: self.to_s.freeze 1878: return self 1879: end
Determines if the URI is frozen.
@return [TrueClass, FalseClass]
True if the URI is frozen, false otherwise.
# File lib/addressable/uri.rb, line 1886 1886: def frozen? 1887: self.to_s.frozen? 1888: end
The host component for this URI.
@return [String] The host component.
# File lib/addressable/uri.rb, line 858 858: def host 859: return @host ||= nil 860: end
Sets the host component for this URI.
@param [String, #] new_host The new host component.
# File lib/addressable/uri.rb, line 891 891: def host=(new_host) 892: # Check for frozenness 893: raise TypeError, "Can't modify frozen URI." if self.frozen? 894: 895: if new_host && !new_host.respond_to?(:to_str) 896: raise TypeError, "Can't convert #{new_host.class} into String." 897: end 898: @host = new_host ? new_host.to_str : nil 899: 900: # Reset dependant values 901: @authority = nil 902: @normalized_host = nil 903: @uri_string = nil 904: 905: # Ensure we haven't created an invalid URI 906: validate() 907: end
The inferred port component for this URI. This method will normalize to the default port for the URI’s scheme if the port isn’t explicitly specified in the URI.
@return [Integer] The inferred port component.
# File lib/addressable/uri.rb, line 1081 1081: def inferred_port 1082: @inferred_port ||= (begin 1083: if port.to_i == 0 1084: if scheme 1085: self.class.port_mapping[scheme.strip.downcase] 1086: else 1087: nil 1088: end 1089: else 1090: port.to_i 1091: end 1092: end) 1093: end
Determines if the scheme indicates an IP-based protocol.
@return [TrueClass, FalseClass] true if the scheme indicates an IP-based protocol. false otherwise.
# File lib/addressable/uri.rb, line 1450 1450: def ip_based? 1451: if self.scheme 1452: return self.class.ip_based_schemes.include?( 1453: self.scheme.strip.downcase) 1454: end 1455: return false 1456: end
Joins two URIs together.
@param [String, Addressable::URI, #] The URI to join with.
@return [Addressable::URI] The joined URI.
# File lib/addressable/uri.rb, line 1482 1482: def join(uri) 1483: if !uri.respond_to?(:to_str) 1484: raise TypeError, "Can't convert #{uri.class} into String." 1485: end 1486: if !uri.kind_of?(self.class) 1487: # Otherwise, convert to a String, then parse. 1488: uri = self.class.parse(uri.to_str) 1489: end 1490: if uri.to_s == "" 1491: return self.dup 1492: end 1493: 1494: joined_scheme = nil 1495: joined_user = nil 1496: joined_password = nil 1497: joined_host = nil 1498: joined_port = nil 1499: joined_path = nil 1500: joined_query = nil 1501: joined_fragment = nil 1502: 1503: # Section 5.2.2 of RFC 3986 1504: if uri.scheme != nil 1505: joined_scheme = uri.scheme 1506: joined_user = uri.user 1507: joined_password = uri.password 1508: joined_host = uri.host 1509: joined_port = uri.port 1510: joined_path = self.class.normalize_path(uri.path) 1511: joined_query = uri.query 1512: else 1513: if uri.authority != nil 1514: joined_user = uri.user 1515: joined_password = uri.password 1516: joined_host = uri.host 1517: joined_port = uri.port 1518: joined_path = self.class.normalize_path(uri.path) 1519: joined_query = uri.query 1520: else 1521: if uri.path == nil || uri.path == "" 1522: joined_path = self.path 1523: if uri.query != nil 1524: joined_query = uri.query 1525: else 1526: joined_query = self.query 1527: end 1528: else 1529: if uri.path[0..0] == "/" 1530: joined_path = self.class.normalize_path(uri.path) 1531: else 1532: base_path = self.path.dup 1533: base_path = "" if base_path == nil 1534: base_path = self.class.normalize_path(base_path) 1535: 1536: # Section 5.2.3 of RFC 3986 1537: # 1538: # Removes the right-most path segment from the base path. 1539: if base_path =~ /\// 1540: base_path.gsub!(/\/[^\/]+$/, "/") 1541: else 1542: base_path = "" 1543: end 1544: 1545: # If the base path is empty and an authority segment has been 1546: # defined, use a base path of "/" 1547: if base_path == "" && self.authority != nil 1548: base_path = "/" 1549: end 1550: 1551: joined_path = self.class.normalize_path(base_path + uri.path) 1552: end 1553: joined_query = uri.query 1554: end 1555: joined_user = self.user 1556: joined_password = self.password 1557: joined_host = self.host 1558: joined_port = self.port 1559: end 1560: joined_scheme = self.scheme 1561: end 1562: joined_fragment = uri.fragment 1563: 1564: return Addressable::URI.new( 1565: :scheme => joined_scheme, 1566: :user => joined_user, 1567: :password => joined_password, 1568: :host => joined_host, 1569: :port => joined_port, 1570: :path => joined_path, 1571: :query => joined_query, 1572: :fragment => joined_fragment 1573: ) 1574: end
Destructive form of join.
@param [String, Addressable::URI, #] The URI to join with.
@return [Addressable::URI] The joined URI.
# File lib/addressable/uri.rb, line 1585 1585: def join!(uri) 1586: replace_self(self.join(uri)) 1587: end
Merges a URI with a Hash of components. This method has different behavior from join. Any components present in the hash parameter will override the original components. The path component is not treated specially.
@param [Hash, Addressable::URI, #] The components to merge with.
@return [Addressable::URI] The merged URI.
@see Hash#merge
# File lib/addressable/uri.rb, line 1600 1600: def merge(hash) 1601: if !hash.respond_to?(:to_hash) 1602: raise TypeError, "Can't convert #{hash.class} into Hash." 1603: end 1604: hash = hash.to_hash 1605: 1606: if hash.has_key?(:authority) 1607: if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? 1608: raise ArgumentError, 1609: "Cannot specify both an authority and any of the components " + 1610: "within the authority." 1611: end 1612: end 1613: if hash.has_key?(:userinfo) 1614: if (hash.keys & [:user, :password]).any? 1615: raise ArgumentError, 1616: "Cannot specify both a userinfo and either the user or password." 1617: end 1618: end 1619: 1620: uri = Addressable::URI.new 1621: uri.defer_validation do 1622: # Bunch of crazy logic required because of the composite components 1623: # like userinfo and authority. 1624: uri.scheme = 1625: hash.has_key?(:scheme) ? hash[:scheme] : self.scheme 1626: if hash.has_key?(:authority) 1627: uri.authority = 1628: hash.has_key?(:authority) ? hash[:authority] : self.authority 1629: end 1630: if hash.has_key?(:userinfo) 1631: uri.userinfo = 1632: hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo 1633: end 1634: if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) 1635: uri.user = 1636: hash.has_key?(:user) ? hash[:user] : self.user 1637: uri.password = 1638: hash.has_key?(:password) ? hash[:password] : self.password 1639: end 1640: if !hash.has_key?(:authority) 1641: uri.host = 1642: hash.has_key?(:host) ? hash[:host] : self.host 1643: uri.port = 1644: hash.has_key?(:port) ? hash[:port] : self.port 1645: end 1646: uri.path = 1647: hash.has_key?(:path) ? hash[:path] : self.path 1648: uri.query = 1649: hash.has_key?(:query) ? hash[:query] : self.query 1650: uri.fragment = 1651: hash.has_key?(:fragment) ? hash[:fragment] : self.fragment 1652: end 1653: 1654: return uri 1655: end
Destructive form of merge.
@param [Hash, Addressable::URI, #] The components to merge with.
@return [Addressable::URI] The merged URI.
# File lib/addressable/uri.rb, line 1665 1665: def merge!(uri) 1666: replace_self(self.merge(uri)) 1667: end
Returns a normalized URI object.
NOTE: This method does not attempt to fully conform to specifications. It exists largely to correct other people’s failures to read the specifications, and also to deal with caching issues since several different URIs may represent the same resource and should not be cached multiple times.
@return [Addressable::URI] The normalized URI.
# File lib/addressable/uri.rb, line 1750 1750: def normalize 1751: # This is a special exception for the frequently misused feed 1752: # URI scheme. 1753: if normalized_scheme == "feed" 1754: if self.to_s =~ /^feed:\/*http:\/*/ 1755: return self.class.parse( 1756: self.to_s[/^feed:\/*(http:\/*.*)/, 1] 1757: ).normalize 1758: end 1759: end 1760: 1761: return Addressable::URI.new( 1762: :scheme => normalized_scheme, 1763: :authority => normalized_authority, 1764: :path => normalized_path, 1765: :query => normalized_query, 1766: :fragment => normalized_fragment 1767: ) 1768: end
Destructively normalizes this URI object.
@return [Addressable::URI] The normalized URI.
@see Addressable::URI#normalize
# File lib/addressable/uri.rb, line 1776 1776: def normalize! 1777: replace_self(self.normalize) 1778: end
The fragment component for this URI, normalized.
@return [String] The fragment component, normalized.
# File lib/addressable/uri.rb, line 1410 1410: def normalized_fragment 1411: @normalized_fragment ||= (begin 1412: if self.fragment 1413: Addressable::URI.normalize_component( 1414: self.fragment.strip, 1415: Addressable::URI::CharacterClasses::FRAGMENT 1416: ) 1417: else 1418: nil 1419: end 1420: end) 1421: end
The host component for this URI, normalized.
@return [String] The host component, normalized.
# File lib/addressable/uri.rb, line 866 866: def normalized_host 867: @normalized_host ||= (begin 868: if self.host != nil 869: if self.host.strip != "" 870: result = ::Addressable::IDNA.to_ascii( 871: self.class.unencode_component(self.host.strip.downcase) 872: ) 873: if result[1..1] == "." 874: # Trailing dots are unnecessary 875: result = result[0...1] 876: end 877: result 878: else 879: "" 880: end 881: else 882: nil 883: end 884: end) 885: end
The password component for this URI, normalized.
@return [String] The password component, normalized.
# File lib/addressable/uri.rb, line 736 736: def normalized_password 737: @normalized_password ||= (begin 738: if self.password 739: if normalized_scheme =~ /https?/ && self.password.strip == "" && 740: (!self.user || self.user.strip == "") 741: nil 742: else 743: Addressable::URI.normalize_component( 744: self.password.strip, 745: Addressable::URI::CharacterClasses::UNRESERVED 746: ) 747: end 748: else 749: nil 750: end 751: end) 752: end
The path component for this URI, normalized.
@return [String] The path component, normalized.
# File lib/addressable/uri.rb, line 1108 1108: def normalized_path 1109: @normalized_path ||= (begin 1110: if self.scheme == nil && self.path != nil && self.path != "" && 1111: self.path =~ /^(?!\/)[^\/:]*:.*$/ 1112: # Relative paths with colons in the first segment are ambiguous. 1113: self.path.sub!(":", "%2F") 1114: end 1115: # String#split(delimeter, -1) uses the more strict splitting behavior 1116: # found by default in Python. 1117: result = (self.path.strip.split("/", 1).map do |segment| 1118: Addressable::URI.normalize_component( 1119: segment, 1120: Addressable::URI::CharacterClasses::PCHAR 1121: ) 1122: end).join("/") 1123: result = self.class.normalize_path(result) 1124: if result == "" && 1125: ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) 1126: result = "/" 1127: end 1128: result 1129: end) 1130: end
The port component for this URI, normalized.
@return [Integer] The port component, normalized.
# File lib/addressable/uri.rb, line 1036 1036: def normalized_port 1037: @normalized_port ||= (begin 1038: if self.class.port_mapping[normalized_scheme] == self.port 1039: nil 1040: else 1041: self.port 1042: end 1043: end) 1044: end
The query component for this URI, normalized.
@return [String] The query component, normalized.
# File lib/addressable/uri.rb, line 1184 1184: def normalized_query 1185: @normalized_query ||= (begin 1186: if self.query 1187: Addressable::URI.normalize_component( 1188: self.query.strip, 1189: Addressable::URI::CharacterClasses::QUERY 1190: ) 1191: else 1192: nil 1193: end 1194: end) 1195: end
The scheme component for this URI, normalized.
@return [String] The scheme component, normalized.
# File lib/addressable/uri.rb, line 625 625: def normalized_scheme 626: @normalized_scheme ||= (begin 627: if self.scheme != nil 628: if self.scheme =~ /^\s*ssh\+svn\s*$/ 629: "svn+ssh" 630: else 631: Addressable::URI.normalize_component( 632: self.scheme.strip.downcase, 633: Addressable::URI::CharacterClasses::SCHEME 634: ) 635: end 636: else 637: nil 638: end 639: end) 640: end
The user component for this URI, normalized.
@return [String] The user component, normalized.
# File lib/addressable/uri.rb, line 676 676: def normalized_user 677: @normalized_user ||= (begin 678: if self.user 679: if normalized_scheme =~ /https?/ && self.user.strip == "" && 680: (!self.password || self.password.strip == "") 681: nil 682: else 683: Addressable::URI.normalize_component( 684: self.user.strip, 685: Addressable::URI::CharacterClasses::UNRESERVED 686: ) 687: end 688: else 689: nil 690: end 691: end) 692: end
The userinfo component for this URI, normalized.
@return [String] The userinfo component, normalized.
# File lib/addressable/uri.rb, line 808 808: def normalized_userinfo 809: @normalized_userinfo ||= (begin 810: current_user = self.normalized_user 811: current_password = self.normalized_password 812: if !current_user && !current_password 813: nil 814: elsif current_user && current_password 815: "#{current_user}:#{current_password}" 816: elsif current_user && !current_password 817: "#{current_user}" 818: end 819: end) 820: end
Omits components from a URI.
@param [Symbol] *components The components to be omitted.
@return [Addressable::URI] The URI with components omitted.
@example
uri = Addressable::URI.parse("http://example.com/path?query") #=> #<Addressable::URI:0xcc5e7a URI:http://example.com/path?query> uri.omit(:scheme, :authority) #=> #<Addressable::URI:0xcc4d86 URI:/path?query>
# File lib/addressable/uri.rb, line 1902 1902: def omit(*components) 1903: invalid_components = components - [ 1904: :scheme, :user, :password, :userinfo, :host, :port, :authority, 1905: :path, :query, :fragment 1906: ] 1907: unless invalid_components.empty? 1908: raise ArgumentError, 1909: "Invalid component names: #{invalid_components.inspect}." 1910: end 1911: duplicated_uri = self.dup 1912: duplicated_uri.defer_validation do 1913: components.each do |component| 1914: duplicated_uri.send((component.to_s + "=").to_sym, nil) 1915: end 1916: duplicated_uri.user = duplicated_uri.normalized_user 1917: end 1918: duplicated_uri 1919: end
Destructive form of omit.
@param [Symbol] *components The components to be omitted.
@return [Addressable::URI] The URI with components omitted.
# File lib/addressable/uri.rb, line 1929 1929: def omit!(*components) 1930: replace_self(self.omit(*components)) 1931: end
The password component for this URI.
@return [String] The password component.
# File lib/addressable/uri.rb, line 728 728: def password 729: return @password ||= nil 730: end
Sets the password component for this URI.
@param [String, #] new_password The new password component.
# File lib/addressable/uri.rb, line 758 758: def password=(new_password) 759: # Check for frozenness 760: raise TypeError, "Can't modify frozen URI." if self.frozen? 761: 762: if new_password && !new_password.respond_to?(:to_str) 763: raise TypeError, "Can't convert #{new_password.class} into String." 764: end 765: @password = new_password ? new_password.to_str : nil 766: 767: # You can't have a nil user with a non-nil password 768: @password ||= nil 769: @user ||= nil 770: if @password != nil 771: @user = "" if @user.nil? 772: end 773: 774: # Reset dependant values 775: @userinfo = nil 776: @normalized_userinfo = nil 777: @authority = nil 778: @normalized_password = nil 779: @uri_string = nil 780: 781: # Ensure we haven't created an invalid URI 782: validate() 783: end
The path component for this URI.
@return [String] The path component.
# File lib/addressable/uri.rb, line 1099 1099: def path 1100: @path ||= "" 1101: return @path 1102: end
Sets the path component for this URI.
@param [String, #] new_path The new path component.
# File lib/addressable/uri.rb, line 1136 1136: def path=(new_path) 1137: # Check for frozenness 1138: raise TypeError, "Can't modify frozen URI." if self.frozen? 1139: 1140: if new_path && !new_path.respond_to?(:to_str) 1141: raise TypeError, "Can't convert #{new_path.class} into String." 1142: end 1143: @path = (new_path || "").to_str 1144: if @path != "" && @path[0..0] != "/" && host != nil 1145: @path = "/#{@path}" 1146: end 1147: 1148: # Reset dependant values 1149: @normalized_path = nil 1150: @uri_string = nil 1151: end
Sets the port component for this URI.
@param [String, Integer, #] new_port The new port component.
# File lib/addressable/uri.rb, line 1050 1050: def port=(new_port) 1051: # Check for frozenness 1052: raise TypeError, "Can't modify frozen URI." if self.frozen? 1053: 1054: if new_port != nil && new_port.respond_to?(:to_str) 1055: new_port = Addressable::URI.unencode_component(new_port.to_str) 1056: end 1057: if new_port != nil && !(new_port.to_s =~ /^\d+$/) 1058: raise InvalidURIError, 1059: "Invalid port number: #{new_port.inspect}" 1060: end 1061: 1062: @port = new_port.to_s.to_i 1063: @port = nil if @port == 0 1064: 1065: # Reset dependant values 1066: @authority = nil 1067: @inferred_port = nil 1068: @normalized_port = nil 1069: @uri_string = nil 1070: 1071: # Ensure we haven't created an invalid URI 1072: validate() 1073: end
The query component for this URI.
@return [String] The query component.
# File lib/addressable/uri.rb, line 1176 1176: def query 1177: return @query ||= nil 1178: end
Sets the query component for this URI.
@param [String, #] new_query The new query component.
# File lib/addressable/uri.rb, line 1201 1201: def query=(new_query) 1202: # Check for frozenness 1203: raise TypeError, "Can't modify frozen URI." if self.frozen? 1204: 1205: if new_query && !new_query.respond_to?(:to_str) 1206: raise TypeError, "Can't convert #{new_query.class} into String." 1207: end 1208: @query = new_query ? new_query.to_str : nil 1209: 1210: # Reset dependant values 1211: @normalized_query = nil 1212: @uri_string = nil 1213: end
Converts the query component to a Hash value.
@option [Symbol] notation
May be one of <tt>:flat</tt>, <tt>:dot</tt>, or <tt>:subscript</tt>.
The :dot notation is not supported for assignment. Default value is :subscript.
@return [Hash] The query string parsed as a Hash object.
@example
Addressable::URI.parse("?one=1&two=2&three=3").query_values #=> {"one" => "1", "two" => "2", "three" => "3"} Addressable::URI.parse("?one[two][three]=four").query_values #=> {"one" => {"two" => {"three" => "four"}}} Addressable::URI.parse("?one.two.three=four").query_values( :notation => :dot ) #=> {"one" => {"two" => {"three" => "four"}}} Addressable::URI.parse("?one[two][three]=four").query_values( :notation => :flat ) #=> {"one[two][three]" => "four"} Addressable::URI.parse("?one.two.three=four").query_values( :notation => :flat ) #=> {"one.two.three" => "four"} Addressable::URI.parse( "?one[two][three][]=four&one[two][three][]=five" ).query_values #=> {"one" => {"two" => {"three" => ["four", "five"]}}}
# File lib/addressable/uri.rb, line 1246 1246: def query_values(options={}) 1247: defaults = {:notation => :subscript} 1248: options = defaults.merge(options) 1249: if ![:flat, :dot, :subscript].include?(options[:notation]) 1250: raise ArgumentError, 1251: "Invalid notation. Must be one of: [:flat, :dot, :subscript]." 1252: end 1253: dehash = lambda do |hash| 1254: hash.each do |(key, value)| 1255: if value.kind_of?(Hash) 1256: hash[key] = dehash.call(value) 1257: end 1258: end 1259: if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ } 1260: hash.sort.inject([]) do |accu, (key, value)| 1261: accu << value; accu 1262: end 1263: else 1264: hash 1265: end 1266: end 1267: return nil if self.query == nil 1268: return ((self.query.split("&").map do |pair| 1269: pair.split("=") 1270: end).inject({}) do |accumulator, (key, value)| 1271: value = true if value.nil? 1272: key = self.class.unencode_component(key) 1273: if value != true 1274: value = self.class.unencode_component(value).gsub(/\+/, " ") 1275: end 1276: if options[:notation] == :flat 1277: if accumulator[key] 1278: raise ArgumentError, "Key was repeated: #{key.inspect}" 1279: end 1280: accumulator[key] = value 1281: else 1282: if options[:notation] == :dot 1283: array_value = false 1284: subkeys = key.split(".") 1285: elsif options[:notation] == :subscript 1286: array_value = !!(key =~ /\[\]$/) 1287: subkeys = key.split(/[\[\]]+/) 1288: end 1289: current_hash = accumulator 1290: for i in 0...(subkeys.size - 1) 1291: subkey = subkeys[i] 1292: current_hash[subkey] = {} unless current_hash[subkey] 1293: current_hash = current_hash[subkey] 1294: end 1295: if array_value 1296: current_hash[subkeys.last] = [] unless current_hash[subkeys.last] 1297: current_hash[subkeys.last] << value 1298: else 1299: current_hash[subkeys.last] = value 1300: end 1301: end 1302: accumulator 1303: end).inject({}) do |accumulator, (key, value)| 1304: accumulator[key] = value.kind_of?(Hash) ? dehash.call(value) : value 1305: accumulator 1306: end 1307: end
Sets the query component for this URI from a Hash object. This method produces a query string using the :subscript notation.
@param [Hash, #] new_query_values The new query values.
# File lib/addressable/uri.rb, line 1314 1314: def query_values=(new_query_values) 1315: # Check for frozenness 1316: raise TypeError, "Can't modify frozen URI." if self.frozen? 1317: if !new_query_values.respond_to?(:to_hash) 1318: raise TypeError, "Can't convert #{new_query_values.class} into Hash." 1319: end 1320: new_query_values = new_query_values.to_hash 1321: 1322: # Algorithm shamelessly stolen from Julien Genestoux, slightly modified 1323: buffer = "" 1324: stack = [] 1325: e = lambda do |component| 1326: component = component.to_s if component.kind_of?(Symbol) 1327: self.class.encode_component(component, CharacterClasses::UNRESERVED) 1328: end 1329: new_query_values.each do |key, value| 1330: if value.kind_of?(Hash) 1331: stack << [key, value] 1332: elsif value.kind_of?(Array) 1333: stack << [ 1334: key, 1335: value.inject({}) { |accu, x| accu[accu.size.to_s] = x; accu } 1336: ] 1337: elsif value == true 1338: buffer << "#{e.call(key)}&" 1339: else 1340: buffer << "#{e.call(key)}=#{e.call(value)}&" 1341: end 1342: end 1343: stack.each do |(parent, hash)| 1344: (hash.sort_by { |key| key.to_s }).each do |(key, value)| 1345: if value.kind_of?(Hash) 1346: stack << ["#{parent}[#{key}]", value] 1347: elsif value == true 1348: buffer << "#{parent}[#{e.call(key)}]&" 1349: else 1350: buffer << "#{parent}[#{e.call(key)}]=#{e.call(value)}&" 1351: end 1352: end 1353: end 1354: @query = buffer.chop 1355: 1356: # Reset dependant values 1357: @normalized_query = nil 1358: @uri_string = nil 1359: end
The HTTP request URI for this URI. This is the path and the query string.
@return [String] The request URI required for an HTTP request.
# File lib/addressable/uri.rb, line 1366 1366: def request_uri 1367: return nil if self.absolute? && self.scheme !~ /^https?$/ 1368: return ( 1369: (self.path != "" ? self.path : "/") + 1370: (self.query ? "?#{self.query}" : "") 1371: ) 1372: end
Sets the HTTP request URI for this URI.
@param [String, #] new_request_uri The new HTTP request URI.
# File lib/addressable/uri.rb, line 1378 1378: def request_uri=(new_request_uri) 1379: if !new_request_uri.respond_to?(:to_str) 1380: raise TypeError, "Can't convert #{new_request_uri.class} into String." 1381: end 1382: if self.absolute? && self.scheme !~ /^https?$/ 1383: raise InvalidURIError, 1384: "Cannot set an HTTP request URI for a non-HTTP URI." 1385: end 1386: new_request_uri = new_request_uri.to_str 1387: path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1] 1388: query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] 1389: path_component = path_component.to_s 1390: path_component = (path_component != "" ? path_component : "/") 1391: self.path = path_component 1392: self.query = query_component 1393: 1394: # Reset dependant values 1395: @uri_string = nil 1396: end
Returns the shortest normalized relative form of this URI that uses the supplied URI as a base for resolution. Returns an absolute URI if necessary. This is effectively the opposite of route_to.
@param [String, Addressable::URI, #] uri The URI to route from.
@return [Addressable::URI]
The normalized relative URI that is equivalent to the original URI.
# File lib/addressable/uri.rb, line 1678 1678: def route_from(uri) 1679: uri = self.class.parse(uri).normalize 1680: normalized_self = self.normalize 1681: if normalized_self.relative? 1682: raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" 1683: end 1684: if uri.relative? 1685: raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" 1686: end 1687: if normalized_self == uri 1688: return Addressable::URI.parse("##{normalized_self.fragment}") 1689: end 1690: components = normalized_self.to_hash 1691: if normalized_self.scheme == uri.scheme 1692: components[:scheme] = nil 1693: if normalized_self.authority == uri.authority 1694: components[:user] = nil 1695: components[:password] = nil 1696: components[:host] = nil 1697: components[:port] = nil 1698: if normalized_self.path == uri.path 1699: components[:path] = nil 1700: if normalized_self.query == uri.query 1701: components[:query] = nil 1702: end 1703: else 1704: if uri.path != "/" 1705: components[:path].gsub!( 1706: Regexp.new("^" + Regexp.escape(uri.path)), "") 1707: end 1708: end 1709: end 1710: end 1711: # Avoid network-path references. 1712: if components[:host] != nil 1713: components[:scheme] = normalized_self.scheme 1714: end 1715: return Addressable::URI.new( 1716: :scheme => components[:scheme], 1717: :user => components[:user], 1718: :password => components[:password], 1719: :host => components[:host], 1720: :port => components[:port], 1721: :path => components[:path], 1722: :query => components[:query], 1723: :fragment => components[:fragment] 1724: ) 1725: end
Returns the shortest normalized relative form of the supplied URI that uses this URI as a base for resolution. Returns an absolute URI if necessary. This is effectively the opposite of route_from.
@param [String, Addressable::URI, #] uri The URI to route to.
@return [Addressable::URI]
The normalized relative URI that is equivalent to the supplied URI.
# File lib/addressable/uri.rb, line 1736 1736: def route_to(uri) 1737: return self.class.parse(uri).route_from(self) 1738: end
The scheme component for this URI.
@return [String] The scheme component.
# File lib/addressable/uri.rb, line 617 617: def scheme 618: return @scheme ||= nil 619: end
Sets the scheme component for this URI.
@param [String, #] new_scheme The new scheme component.
# File lib/addressable/uri.rb, line 646 646: def scheme=(new_scheme) 647: # Check for frozenness 648: raise TypeError, "Can't modify frozen URI." if self.frozen? 649: 650: if new_scheme && !new_scheme.respond_to?(:to_str) 651: raise TypeError, "Can't convert #{new_scheme.class} into String." 652: end 653: @scheme = new_scheme ? new_scheme.to_str : nil 654: @scheme = nil if @scheme.to_s.strip == "" 655: 656: # Reset dependant values 657: @normalized_scheme = nil 658: @uri_string = nil 659: 660: # Ensure we haven't created an invalid URI 661: validate() 662: end
Returns a Hash of the URI components.
@return [Hash] The URI as a Hash of components.
# File lib/addressable/uri.rb, line 1960 1960: def to_hash 1961: return { 1962: :scheme => self.scheme, 1963: :user => self.user, 1964: :password => self.password, 1965: :host => self.host, 1966: :port => self.port, 1967: :path => self.path, 1968: :query => self.query, 1969: :fragment => self.fragment 1970: } 1971: end
Converts the URI to a String.
@return [String] The URI’s String representation.
# File lib/addressable/uri.rb, line 1937 1937: def to_s 1938: @uri_string ||= (begin 1939: uri_string = "" 1940: uri_string << "#{self.scheme}:" if self.scheme != nil 1941: uri_string << "//#{self.authority}" if self.authority != nil 1942: uri_string << self.path.to_s 1943: uri_string << "?#{self.query}" if self.query != nil 1944: uri_string << "##{self.fragment}" if self.fragment != nil 1945: if uri_string.respond_to?(:force_encoding) 1946: uri_string.force_encoding(Encoding::UTF_8) 1947: end 1948: uri_string 1949: end) 1950: end
URI’s are glorified Strings. Allow implicit conversion.
The user component for this URI.
@return [String] The user component.
# File lib/addressable/uri.rb, line 668 668: def user 669: return @user ||= nil 670: end
Sets the user component for this URI.
@param [String, #] new_user The new user component.
# File lib/addressable/uri.rb, line 698 698: def user=(new_user) 699: # Check for frozenness 700: raise TypeError, "Can't modify frozen URI." if self.frozen? 701: 702: if new_user && !new_user.respond_to?(:to_str) 703: raise TypeError, "Can't convert #{new_user.class} into String." 704: end 705: @user = new_user ? new_user.to_str : nil 706: 707: # You can't have a nil user with a non-nil password 708: @password ||= nil 709: if @password != nil 710: @user = "" if @user.nil? 711: end 712: 713: # Reset dependant values 714: @userinfo = nil 715: @normalized_userinfo = nil 716: @authority = nil 717: @normalized_user = nil 718: @uri_string = nil 719: 720: # Ensure we haven't created an invalid URI 721: validate() 722: end
The userinfo component for this URI. Combines the user and password components.
@return [String] The userinfo component.
# File lib/addressable/uri.rb, line 790 790: def userinfo 791: @userinfo ||= (begin 792: current_user = self.user 793: current_password = self.password 794: if !current_user && !current_password 795: nil 796: elsif current_user && current_password 797: "#{current_user}:#{current_password}" 798: elsif current_user && !current_password 799: "#{current_user}" 800: end 801: end) 802: end
Sets the userinfo component for this URI.
@param [String, #] new_userinfo The new userinfo component.
# File lib/addressable/uri.rb, line 826 826: def userinfo=(new_userinfo) 827: # Check for frozenness 828: raise TypeError, "Can't modify frozen URI." if self.frozen? 829: 830: if new_userinfo && !new_userinfo.respond_to?(:to_str) 831: raise TypeError, "Can't convert #{new_userinfo.class} into String." 832: end 833: new_user, new_password = if new_userinfo 834: [ 835: new_userinfo.to_str.strip[/^(.*):/, 1], 836: new_userinfo.to_str.strip[/:(.*)$/, 1] 837: ] 838: else 839: [nil, nil] 840: end 841: 842: # Password assigned first to ensure validity in case of nil 843: self.password = new_password 844: self.user = new_user 845: 846: # Reset dependant values 847: @authority = nil 848: @uri_string = nil 849: 850: # Ensure we haven't created an invalid URI 851: validate() 852: end
Replaces the internal state of self with the specified URI’s state. Used in destructive operations to avoid massive code repetition.
@param [Addressable::URI] uri The URI to replace self with.
@return [Addressable::URI] self.
# File lib/addressable/uri.rb, line 2061 2061: def replace_self(uri) 2062: # Reset dependant values 2063: instance_variables.each do |var| 2064: instance_variable_set(var, nil) 2065: end 2066: 2067: @scheme = uri.scheme 2068: @user = uri.user 2069: @password = uri.password 2070: @host = uri.host 2071: @port = uri.port 2072: @path = uri.path 2073: @query = uri.query 2074: @fragment = uri.fragment 2075: return self 2076: end
Ensures that the URI is valid.
# File lib/addressable/uri.rb, line 2031 2031: def validate 2032: return if !!@validation_deferred 2033: if self.scheme != nil && 2034: (self.host == nil || self.host == "") && 2035: (self.path == nil || self.path == "") 2036: raise InvalidURIError, 2037: "Absolute URI missing hierarchical segment: '#{self.to_s}'" 2038: end 2039: if self.host == nil 2040: if self.port != nil || 2041: self.user != nil || 2042: self.password != nil 2043: raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" 2044: end 2045: end 2046: if self.path != nil && self.path != "" && self.path[0..0] != "/" && 2047: self.authority != nil 2048: raise InvalidURIError, 2049: "Cannot have a relative path with an authority set: '#{self.to_s}'" 2050: end 2051: return nil 2052: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.