PageRenderTime 64ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ruby/jruby/addressable-2.2.4/lib/addressable/uri.rb

https://github.com/iverson2329/FireApp
Ruby | 2291 lines | 1618 code | 109 blank | 564 comment | 224 complexity | 1c5b61f7719f8760a51a73e3e229840b MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, Apache-2.0, BSD-3-Clause, MIT, GPL-2.0, WTFPL
  1. # encoding:utf-8
  2. #--
  3. # Addressable, Copyright (c) 2006-2010 Bob Aman
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining
  6. # a copy of this software and associated documentation files (the
  7. # "Software"), to deal in the Software without restriction, including
  8. # without limitation the rights to use, copy, modify, merge, publish,
  9. # distribute, sublicense, and/or sell copies of the Software, and to
  10. # permit persons to whom the Software is furnished to do so, subject to
  11. # the following conditions:
  12. #
  13. # The above copyright notice and this permission notice shall be
  14. # included in all copies or substantial portions of the Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. #++
  24. require "addressable/version"
  25. require "addressable/idna"
  26. module Addressable
  27. ##
  28. # This is an implementation of a URI parser based on
  29. # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
  30. # <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>.
  31. class URI
  32. ##
  33. # Raised if something other than a uri is supplied.
  34. class InvalidURIError < StandardError
  35. end
  36. ##
  37. # Container for the character classes specified in
  38. # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
  39. module CharacterClasses
  40. ALPHA = "a-zA-Z"
  41. DIGIT = "0-9"
  42. GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
  43. SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
  44. RESERVED = GEN_DELIMS + SUB_DELIMS
  45. UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
  46. PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
  47. SCHEME = ALPHA + DIGIT + "\\-\\+\\."
  48. AUTHORITY = PCHAR
  49. PATH = PCHAR + "\\/"
  50. QUERY = PCHAR + "\\/\\?"
  51. FRAGMENT = PCHAR + "\\/\\?"
  52. end
  53. ##
  54. # Returns a URI object based on the parsed string.
  55. #
  56. # @param [String, Addressable::URI, #to_str] uri
  57. # The URI string to parse.
  58. # No parsing is performed if the object is already an
  59. # <code>Addressable::URI</code>.
  60. #
  61. # @return [Addressable::URI] The parsed URI.
  62. def self.parse(uri)
  63. # If we were given nil, return nil.
  64. return nil unless uri
  65. # If a URI object is passed, just return itself.
  66. return uri if uri.kind_of?(self)
  67. # If a URI object of the Ruby standard library variety is passed,
  68. # convert it to a string, then parse the string.
  69. # We do the check this way because we don't want to accidentally
  70. # cause a missing constant exception to be thrown.
  71. if uri.class.name =~ /^URI\b/
  72. uri = uri.to_s
  73. end
  74. if !uri.respond_to?(:to_str)
  75. raise TypeError, "Can't convert #{uri.class} into String."
  76. end
  77. # Otherwise, convert to a String
  78. uri = uri.to_str
  79. # This Regexp supplied as an example in RFC 3986, and it works great.
  80. uri_regex =
  81. /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
  82. scan = uri.scan(uri_regex)
  83. fragments = scan[0]
  84. scheme = fragments[1]
  85. authority = fragments[3]
  86. path = fragments[4]
  87. query = fragments[6]
  88. fragment = fragments[8]
  89. user = nil
  90. password = nil
  91. host = nil
  92. port = nil
  93. if authority != nil
  94. # The Regexp above doesn't split apart the authority.
  95. userinfo = authority[/^([^\[\]]*)@/, 1]
  96. if userinfo != nil
  97. user = userinfo.strip[/^([^:]*):?/, 1]
  98. password = userinfo.strip[/:(.*)$/, 1]
  99. end
  100. host = authority.gsub(/^([^\[\]]*)@/, "").gsub(/:([^:@\[\]]*?)$/, "")
  101. port = authority[/:([^:@\[\]]*?)$/, 1]
  102. end
  103. if port == ""
  104. port = nil
  105. end
  106. return Addressable::URI.new(
  107. :scheme => scheme,
  108. :user => user,
  109. :password => password,
  110. :host => host,
  111. :port => port,
  112. :path => path,
  113. :query => query,
  114. :fragment => fragment
  115. )
  116. end
  117. ##
  118. # Converts an input to a URI. The input does not have to be a valid
  119. # URI — the method will use heuristics to guess what URI was intended.
  120. # This is not standards-compliant, merely user-friendly.
  121. #
  122. # @param [String, Addressable::URI, #to_str] uri
  123. # The URI string to parse.
  124. # No parsing is performed if the object is already an
  125. # <code>Addressable::URI</code>.
  126. # @param [Hash] hints
  127. # A <code>Hash</code> of hints to the heuristic parser.
  128. # Defaults to <code>{:scheme => "http"}</code>.
  129. #
  130. # @return [Addressable::URI] The parsed URI.
  131. def self.heuristic_parse(uri, hints={})
  132. # If we were given nil, return nil.
  133. return nil unless uri
  134. # If a URI object is passed, just return itself.
  135. return uri if uri.kind_of?(self)
  136. if !uri.respond_to?(:to_str)
  137. raise TypeError, "Can't convert #{uri.class} into String."
  138. end
  139. # Otherwise, convert to a String
  140. uri = uri.to_str.dup
  141. hints = {
  142. :scheme => "http"
  143. }.merge(hints)
  144. case uri
  145. when /^http:\/+/
  146. uri.gsub!(/^http:\/+/, "http://")
  147. when /^feed:\/+http:\/+/
  148. uri.gsub!(/^feed:\/+http:\/+/, "feed:http://")
  149. when /^feed:\/+/
  150. uri.gsub!(/^feed:\/+/, "feed://")
  151. when /^file:\/+/
  152. uri.gsub!(/^file:\/+/, "file:///")
  153. end
  154. parsed = self.parse(uri)
  155. if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/
  156. parsed = self.parse(hints[:scheme] + "://" + uri)
  157. end
  158. if parsed.path.include?(".")
  159. new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
  160. if new_host
  161. parsed.defer_validation do
  162. new_path = parsed.path.gsub(
  163. Regexp.new("^" + Regexp.escape(new_host)), "")
  164. parsed.host = new_host
  165. parsed.path = new_path
  166. parsed.scheme = hints[:scheme] unless parsed.scheme
  167. end
  168. end
  169. end
  170. return parsed
  171. end
  172. ##
  173. # Converts a path to a file scheme URI. If the path supplied is
  174. # relative, it will be returned as a relative URI. If the path supplied
  175. # is actually a non-file URI, it will parse the URI as if it had been
  176. # parsed with <code>Addressable::URI.parse</code>. Handles all of the
  177. # various Microsoft-specific formats for specifying paths.
  178. #
  179. # @param [String, Addressable::URI, #to_str] path
  180. # Typically a <code>String</code> path to a file or directory, but
  181. # will return a sensible return value if an absolute URI is supplied
  182. # instead.
  183. #
  184. # @return [Addressable::URI]
  185. # The parsed file scheme URI or the original URI if some other URI
  186. # scheme was provided.
  187. #
  188. # @example
  189. # base = Addressable::URI.convert_path("/absolute/path/")
  190. # uri = Addressable::URI.convert_path("relative/path")
  191. # (base + uri).to_s
  192. # #=> "file:///absolute/path/relative/path"
  193. #
  194. # Addressable::URI.convert_path(
  195. # "c:\\windows\\My Documents 100%20\\foo.txt"
  196. # ).to_s
  197. # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt"
  198. #
  199. # Addressable::URI.convert_path("http://example.com/").to_s
  200. # #=> "http://example.com/"
  201. def self.convert_path(path)
  202. # If we were given nil, return nil.
  203. return nil unless path
  204. # If a URI object is passed, just return itself.
  205. return path if path.kind_of?(self)
  206. if !path.respond_to?(:to_str)
  207. raise TypeError, "Can't convert #{path.class} into String."
  208. end
  209. # Otherwise, convert to a String
  210. path = path.to_str.strip
  211. path.gsub!(/^file:\/?\/?/, "") if path =~ /^file:\/?\/?/
  212. path = "/" + path if path =~ /^([a-zA-Z])[\|:]/
  213. uri = self.parse(path)
  214. if uri.scheme == nil
  215. # Adjust windows-style uris
  216. uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
  217. "/#{$1.downcase}:/"
  218. end
  219. uri.path.gsub!(/\\/, "/")
  220. if File.exists?(uri.path) &&
  221. File.stat(uri.path).directory?
  222. uri.path.gsub!(/\/$/, "")
  223. uri.path = uri.path + '/'
  224. end
  225. # If the path is absolute, set the scheme and host.
  226. if uri.path =~ /^\//
  227. uri.scheme = "file"
  228. uri.host = ""
  229. end
  230. uri.normalize!
  231. end
  232. return uri
  233. end
  234. ##
  235. # Joins several URIs together.
  236. #
  237. # @param [String, Addressable::URI, #to_str] *uris
  238. # The URIs to join.
  239. #
  240. # @return [Addressable::URI] The joined URI.
  241. #
  242. # @example
  243. # base = "http://example.com/"
  244. # uri = Addressable::URI.parse("relative/path")
  245. # Addressable::URI.join(base, uri)
  246. # #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
  247. def self.join(*uris)
  248. uri_objects = uris.collect do |uri|
  249. if !uri.respond_to?(:to_str)
  250. raise TypeError, "Can't convert #{uri.class} into String."
  251. end
  252. uri.kind_of?(self) ? uri : self.parse(uri.to_str)
  253. end
  254. result = uri_objects.shift.dup
  255. for uri in uri_objects
  256. result.join!(uri)
  257. end
  258. return result
  259. end
  260. ##
  261. # Percent encodes a URI component.
  262. #
  263. # @param [String, #to_str] component The URI component to encode.
  264. #
  265. # @param [String, Regexp] character_class
  266. # The characters which are not percent encoded. If a <code>String</code>
  267. # is passed, the <code>String</code> must be formatted as a regular
  268. # expression character class. (Do not include the surrounding square
  269. # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
  270. # everything but the letters 'b' through 'z' and the numbers '0' through
  271. # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
  272. # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
  273. # useful <code>String</code> values may be found in the
  274. # <code>Addressable::URI::CharacterClasses</code> module. The default
  275. # value is the reserved plus unreserved character classes specified in
  276. # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
  277. #
  278. # @return [String] The encoded component.
  279. #
  280. # @example
  281. # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9")
  282. # => "simple%2Fex%61mple"
  283. # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/)
  284. # => "simple%2Fex%61mple"
  285. # Addressable::URI.encode_component(
  286. # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED
  287. # )
  288. # => "simple%2Fexample"
  289. def self.encode_component(component, character_class=
  290. CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
  291. return nil if component.nil?
  292. if !component.respond_to?(:to_str)
  293. raise TypeError, "Can't convert #{component.class} into String."
  294. end
  295. component = component.to_str
  296. if ![String, Regexp].include?(character_class.class)
  297. raise TypeError,
  298. "Expected String or Regexp, got #{character_class.inspect}"
  299. end
  300. if character_class.kind_of?(String)
  301. character_class = /[^#{character_class}]/
  302. end
  303. if component.respond_to?(:force_encoding)
  304. # We can't perform regexps on invalid UTF sequences, but
  305. # here we need to, so switch to ASCII.
  306. component = component.dup
  307. component.force_encoding(Encoding::ASCII_8BIT)
  308. end
  309. return component.gsub(character_class) do |sequence|
  310. (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join("")
  311. end
  312. end
  313. class << self
  314. alias_method :encode_component, :encode_component
  315. end
  316. ##
  317. # Unencodes any percent encoded characters within a URI component.
  318. # This method may be used for unencoding either components or full URIs,
  319. # however, it is recommended to use the <code>unencode_component</code>
  320. # alias when unencoding components.
  321. #
  322. # @param [String, Addressable::URI, #to_str] uri
  323. # The URI or component to unencode.
  324. #
  325. # @param [Class] returning
  326. # The type of object to return.
  327. # This value may only be set to <code>String</code> or
  328. # <code>Addressable::URI</code>. All other values are invalid. Defaults
  329. # to <code>String</code>.
  330. #
  331. # @return [String, Addressable::URI]
  332. # The unencoded component or URI.
  333. # The return type is determined by the <code>returning</code> parameter.
  334. def self.unencode(uri, returning=String)
  335. return nil if uri.nil?
  336. if !uri.respond_to?(:to_str)
  337. raise TypeError, "Can't convert #{uri.class} into String."
  338. end
  339. if ![String, ::Addressable::URI].include?(returning)
  340. raise TypeError,
  341. "Expected Class (String or Addressable::URI), " +
  342. "got #{returning.inspect}"
  343. end
  344. result = uri.to_str.gsub(/%[0-9a-f]{2}/i) do |sequence|
  345. sequence[1..3].to_i(16).chr
  346. end
  347. result.force_encoding("utf-8") if result.respond_to?(:force_encoding)
  348. if returning == String
  349. return result
  350. elsif returning == ::Addressable::URI
  351. return ::Addressable::URI.parse(result)
  352. end
  353. end
  354. class << self
  355. alias_method :unescape, :unencode
  356. alias_method :unencode_component, :unencode
  357. alias_method :unescape_component, :unencode
  358. end
  359. ##
  360. # Normalizes the encoding of a URI component.
  361. #
  362. # @param [String, #to_str] component The URI component to encode.
  363. #
  364. # @param [String, Regexp] character_class
  365. # The characters which are not percent encoded. If a <code>String</code>
  366. # is passed, the <code>String</code> must be formatted as a regular
  367. # expression character class. (Do not include the surrounding square
  368. # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
  369. # everything but the letters 'b' through 'z' and the numbers '0' through
  370. # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
  371. # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
  372. # useful <code>String</code> values may be found in the
  373. # <code>Addressable::URI::CharacterClasses</code> module. The default
  374. # value is the reserved plus unreserved character classes specified in
  375. # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
  376. #
  377. # @return [String] The normalized component.
  378. #
  379. # @example
  380. # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z")
  381. # => "simple%2Fex%61mple"
  382. # Addressable::URI.normalize_component(
  383. # "simpl%65/%65xampl%65", /[^b-zB-Z]/
  384. # )
  385. # => "simple%2Fex%61mple"
  386. # Addressable::URI.normalize_component(
  387. # "simpl%65/%65xampl%65",
  388. # Addressable::URI::CharacterClasses::UNRESERVED
  389. # )
  390. # => "simple%2Fexample"
  391. def self.normalize_component(component, character_class=
  392. CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
  393. return nil if component.nil?
  394. if !component.respond_to?(:to_str)
  395. raise TypeError, "Can't convert #{component.class} into String."
  396. end
  397. component = component.to_str
  398. if ![String, Regexp].include?(character_class.class)
  399. raise TypeError,
  400. "Expected String or Regexp, got #{character_class.inspect}"
  401. end
  402. if character_class.kind_of?(String)
  403. character_class = /[^#{character_class}]/
  404. end
  405. if component.respond_to?(:force_encoding)
  406. # We can't perform regexps on invalid UTF sequences, but
  407. # here we need to, so switch to ASCII.
  408. component = component.dup
  409. component.force_encoding(Encoding::ASCII_8BIT)
  410. end
  411. unencoded = self.unencode_component(component)
  412. begin
  413. encoded = self.encode_component(
  414. Addressable::IDNA.unicode_normalize_kc(unencoded),
  415. character_class
  416. )
  417. rescue ArgumentError
  418. encoded = self.encode_component(unencoded)
  419. end
  420. return encoded
  421. end
  422. ##
  423. # Percent encodes any special characters in the URI.
  424. #
  425. # @param [String, Addressable::URI, #to_str] uri
  426. # The URI to encode.
  427. #
  428. # @param [Class] returning
  429. # The type of object to return.
  430. # This value may only be set to <code>String</code> or
  431. # <code>Addressable::URI</code>. All other values are invalid. Defaults
  432. # to <code>String</code>.
  433. #
  434. # @return [String, Addressable::URI]
  435. # The encoded URI.
  436. # The return type is determined by the <code>returning</code> parameter.
  437. def self.encode(uri, returning=String)
  438. return nil if uri.nil?
  439. if !uri.respond_to?(:to_str)
  440. raise TypeError, "Can't convert #{uri.class} into String."
  441. end
  442. if ![String, ::Addressable::URI].include?(returning)
  443. raise TypeError,
  444. "Expected Class (String or Addressable::URI), " +
  445. "got #{returning.inspect}"
  446. end
  447. uri_object = uri.kind_of?(self) ? uri : self.parse(uri.to_str)
  448. encoded_uri = Addressable::URI.new(
  449. :scheme => self.encode_component(uri_object.scheme,
  450. Addressable::URI::CharacterClasses::SCHEME),
  451. :authority => self.encode_component(uri_object.authority,
  452. Addressable::URI::CharacterClasses::AUTHORITY),
  453. :path => self.encode_component(uri_object.path,
  454. Addressable::URI::CharacterClasses::PATH),
  455. :query => self.encode_component(uri_object.query,
  456. Addressable::URI::CharacterClasses::QUERY),
  457. :fragment => self.encode_component(uri_object.fragment,
  458. Addressable::URI::CharacterClasses::FRAGMENT)
  459. )
  460. if returning == String
  461. return encoded_uri.to_s
  462. elsif returning == ::Addressable::URI
  463. return encoded_uri
  464. end
  465. end
  466. class << self
  467. alias_method :escape, :encode
  468. end
  469. ##
  470. # Normalizes the encoding of a URI. Characters within a hostname are
  471. # not percent encoded to allow for internationalized domain names.
  472. #
  473. # @param [String, Addressable::URI, #to_str] uri
  474. # The URI to encode.
  475. #
  476. # @param [Class] returning
  477. # The type of object to return.
  478. # This value may only be set to <code>String</code> or
  479. # <code>Addressable::URI</code>. All other values are invalid. Defaults
  480. # to <code>String</code>.
  481. #
  482. # @return [String, Addressable::URI]
  483. # The encoded URI.
  484. # The return type is determined by the <code>returning</code> parameter.
  485. def self.normalized_encode(uri, returning=String)
  486. if !uri.respond_to?(:to_str)
  487. raise TypeError, "Can't convert #{uri.class} into String."
  488. end
  489. if ![String, ::Addressable::URI].include?(returning)
  490. raise TypeError,
  491. "Expected Class (String or Addressable::URI), " +
  492. "got #{returning.inspect}"
  493. end
  494. uri_object = uri.kind_of?(self) ? uri : self.parse(uri.to_str)
  495. components = {
  496. :scheme => self.unencode_component(uri_object.scheme),
  497. :user => self.unencode_component(uri_object.user),
  498. :password => self.unencode_component(uri_object.password),
  499. :host => self.unencode_component(uri_object.host),
  500. :port => uri_object.port,
  501. :path => self.unencode_component(uri_object.path),
  502. :query => self.unencode_component(uri_object.query),
  503. :fragment => self.unencode_component(uri_object.fragment)
  504. }
  505. components.each do |key, value|
  506. if value != nil
  507. begin
  508. components[key] =
  509. Addressable::IDNA.unicode_normalize_kc(value.to_str)
  510. rescue ArgumentError
  511. # Likely a malformed UTF-8 character, skip unicode normalization
  512. components[key] = value.to_str
  513. end
  514. end
  515. end
  516. encoded_uri = Addressable::URI.new(
  517. :scheme => self.encode_component(components[:scheme],
  518. Addressable::URI::CharacterClasses::SCHEME),
  519. :user => self.encode_component(components[:user],
  520. Addressable::URI::CharacterClasses::UNRESERVED),
  521. :password => self.encode_component(components[:password],
  522. Addressable::URI::CharacterClasses::UNRESERVED),
  523. :host => components[:host],
  524. :port => components[:port],
  525. :path => self.encode_component(components[:path],
  526. Addressable::URI::CharacterClasses::PATH),
  527. :query => self.encode_component(components[:query],
  528. Addressable::URI::CharacterClasses::QUERY),
  529. :fragment => self.encode_component(components[:fragment],
  530. Addressable::URI::CharacterClasses::FRAGMENT)
  531. )
  532. if returning == String
  533. return encoded_uri.to_s
  534. elsif returning == ::Addressable::URI
  535. return encoded_uri
  536. end
  537. end
  538. ##
  539. # Encodes a set of key/value pairs according to the rules for the
  540. # <code>application/x-www-form-urlencoded</code> MIME type.
  541. #
  542. # @param [#to_hash, #to_ary] form_values
  543. # The form values to encode.
  544. #
  545. # @param [TrueClass, FalseClass] sort
  546. # Sort the key/value pairs prior to encoding.
  547. # Defaults to <code>false</code>.
  548. #
  549. # @return [String]
  550. # The encoded value.
  551. def self.form_encode(form_values, sort=false)
  552. if form_values.respond_to?(:to_hash)
  553. form_values = form_values.to_hash.to_a
  554. elsif form_values.respond_to?(:to_ary)
  555. form_values = form_values.to_ary
  556. else
  557. raise TypeError, "Can't convert #{form_values.class} into Array."
  558. end
  559. form_values = form_values.map do |(key, value)|
  560. [key.to_s, value.to_s]
  561. end
  562. if sort
  563. # Useful for OAuth and optimizing caching systems
  564. form_values = form_values.sort
  565. end
  566. escaped_form_values = form_values.map do |(key, value)|
  567. # Line breaks are CRLF pairs
  568. [
  569. self.encode_component(
  570. key.gsub(/(\r\n|\n|\r)/, "\r\n"),
  571. CharacterClasses::UNRESERVED
  572. ).gsub("%20", "+"),
  573. self.encode_component(
  574. value.gsub(/(\r\n|\n|\r)/, "\r\n"),
  575. CharacterClasses::UNRESERVED
  576. ).gsub("%20", "+")
  577. ]
  578. end
  579. return (escaped_form_values.map do |(key, value)|
  580. "#{key}=#{value}"
  581. end).join("&")
  582. end
  583. ##
  584. # Decodes a <code>String</code> according to the rules for the
  585. # <code>application/x-www-form-urlencoded</code> MIME type.
  586. #
  587. # @param [String, #to_str] encoded_value
  588. # The form values to decode.
  589. #
  590. # @return [Array]
  591. # The decoded values.
  592. # This is not a <code>Hash</code> because of the possibility for
  593. # duplicate keys.
  594. def self.form_unencode(encoded_value)
  595. if !encoded_value.respond_to?(:to_str)
  596. raise TypeError, "Can't convert #{encoded_value.class} into String."
  597. end
  598. encoded_value = encoded_value.to_str
  599. split_values = encoded_value.split("&").map do |pair|
  600. pair.split("=", 2)
  601. end
  602. return split_values.map do |(key, value)|
  603. [
  604. key ? self.unencode_component(
  605. key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil,
  606. value ? (self.unencode_component(
  607. value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil
  608. ]
  609. end
  610. end
  611. ##
  612. # Creates a new uri object from component parts.
  613. #
  614. # @option [String, #to_str] scheme The scheme component.
  615. # @option [String, #to_str] user The user component.
  616. # @option [String, #to_str] password The password component.
  617. # @option [String, #to_str] userinfo
  618. # The userinfo component. If this is supplied, the user and password
  619. # components must be omitted.
  620. # @option [String, #to_str] host The host component.
  621. # @option [String, #to_str] port The port component.
  622. # @option [String, #to_str] authority
  623. # The authority component. If this is supplied, the user, password,
  624. # userinfo, host, and port components must be omitted.
  625. # @option [String, #to_str] path The path component.
  626. # @option [String, #to_str] query The query component.
  627. # @option [String, #to_str] fragment The fragment component.
  628. #
  629. # @return [Addressable::URI] The constructed URI object.
  630. def initialize(options={})
  631. if options.has_key?(:authority)
  632. if (options.keys & [:userinfo, :user, :password, :host, :port]).any?
  633. raise ArgumentError,
  634. "Cannot specify both an authority and any of the components " +
  635. "within the authority."
  636. end
  637. end
  638. if options.has_key?(:userinfo)
  639. if (options.keys & [:user, :password]).any?
  640. raise ArgumentError,
  641. "Cannot specify both a userinfo and either the user or password."
  642. end
  643. end
  644. self.defer_validation do
  645. # Bunch of crazy logic required because of the composite components
  646. # like userinfo and authority.
  647. self.scheme = options[:scheme] if options[:scheme]
  648. self.user = options[:user] if options[:user]
  649. self.password = options[:password] if options[:password]
  650. self.userinfo = options[:userinfo] if options[:userinfo]
  651. self.host = options[:host] if options[:host]
  652. self.port = options[:port] if options[:port]
  653. self.authority = options[:authority] if options[:authority]
  654. self.path = options[:path] if options[:path]
  655. self.query = options[:query] if options[:query]
  656. self.fragment = options[:fragment] if options[:fragment]
  657. end
  658. end
  659. ##
  660. # The scheme component for this URI.
  661. #
  662. # @return [String] The scheme component.
  663. def scheme
  664. return @scheme ||= nil
  665. end
  666. ##
  667. # The scheme component for this URI, normalized.
  668. #
  669. # @return [String] The scheme component, normalized.
  670. def normalized_scheme
  671. @normalized_scheme ||= (begin
  672. if self.scheme != nil
  673. if self.scheme =~ /^\s*ssh\+svn\s*$/i
  674. "svn+ssh"
  675. else
  676. Addressable::URI.normalize_component(
  677. self.scheme.strip.downcase,
  678. Addressable::URI::CharacterClasses::SCHEME
  679. )
  680. end
  681. else
  682. nil
  683. end
  684. end)
  685. end
  686. ##
  687. # Sets the scheme component for this URI.
  688. #
  689. # @param [String, #to_str] new_scheme The new scheme component.
  690. def scheme=(new_scheme)
  691. # Check for frozenness
  692. raise TypeError, "Can't modify frozen URI." if self.frozen?
  693. if new_scheme && !new_scheme.respond_to?(:to_str)
  694. raise TypeError, "Can't convert #{new_scheme.class} into String."
  695. elsif new_scheme
  696. new_scheme = new_scheme.to_str
  697. end
  698. if new_scheme && new_scheme !~ /[a-z][a-z0-9\.\+\-]*/i
  699. raise InvalidURIError, "Invalid scheme format."
  700. end
  701. @scheme = new_scheme
  702. @scheme = nil if @scheme.to_s.strip == ""
  703. # Reset dependant values
  704. @normalized_scheme = nil
  705. @uri_string = nil
  706. @hash = nil
  707. # Ensure we haven't created an invalid URI
  708. validate()
  709. end
  710. ##
  711. # The user component for this URI.
  712. #
  713. # @return [String] The user component.
  714. def user
  715. return @user ||= nil
  716. end
  717. ##
  718. # The user component for this URI, normalized.
  719. #
  720. # @return [String] The user component, normalized.
  721. def normalized_user
  722. @normalized_user ||= (begin
  723. if self.user
  724. if normalized_scheme =~ /https?/ && self.user.strip == "" &&
  725. (!self.password || self.password.strip == "")
  726. nil
  727. else
  728. Addressable::URI.normalize_component(
  729. self.user.strip,
  730. Addressable::URI::CharacterClasses::UNRESERVED
  731. )
  732. end
  733. else
  734. nil
  735. end
  736. end)
  737. end
  738. ##
  739. # Sets the user component for this URI.
  740. #
  741. # @param [String, #to_str] new_user The new user component.
  742. def user=(new_user)
  743. # Check for frozenness
  744. raise TypeError, "Can't modify frozen URI." if self.frozen?
  745. if new_user && !new_user.respond_to?(:to_str)
  746. raise TypeError, "Can't convert #{new_user.class} into String."
  747. end
  748. @user = new_user ? new_user.to_str : nil
  749. # You can't have a nil user with a non-nil password
  750. @password ||= nil
  751. if @password != nil
  752. @user = "" if @user.nil?
  753. end
  754. # Reset dependant values
  755. @userinfo = nil
  756. @normalized_userinfo = nil
  757. @authority = nil
  758. @normalized_user = nil
  759. @uri_string = nil
  760. @hash = nil
  761. # Ensure we haven't created an invalid URI
  762. validate()
  763. end
  764. ##
  765. # The password component for this URI.
  766. #
  767. # @return [String] The password component.
  768. def password
  769. return @password ||= nil
  770. end
  771. ##
  772. # The password component for this URI, normalized.
  773. #
  774. # @return [String] The password component, normalized.
  775. def normalized_password
  776. @normalized_password ||= (begin
  777. if self.password
  778. if normalized_scheme =~ /https?/ && self.password.strip == "" &&
  779. (!self.user || self.user.strip == "")
  780. nil
  781. else
  782. Addressable::URI.normalize_component(
  783. self.password.strip,
  784. Addressable::URI::CharacterClasses::UNRESERVED
  785. )
  786. end
  787. else
  788. nil
  789. end
  790. end)
  791. end
  792. ##
  793. # Sets the password component for this URI.
  794. #
  795. # @param [String, #to_str] new_password The new password component.
  796. def password=(new_password)
  797. # Check for frozenness
  798. raise TypeError, "Can't modify frozen URI." if self.frozen?
  799. if new_password && !new_password.respond_to?(:to_str)
  800. raise TypeError, "Can't convert #{new_password.class} into String."
  801. end
  802. @password = new_password ? new_password.to_str : nil
  803. # You can't have a nil user with a non-nil password
  804. @password ||= nil
  805. @user ||= nil
  806. if @password != nil
  807. @user = "" if @user.nil?
  808. end
  809. # Reset dependant values
  810. @userinfo = nil
  811. @normalized_userinfo = nil
  812. @authority = nil
  813. @normalized_password = nil
  814. @uri_string = nil
  815. @hash = nil
  816. # Ensure we haven't created an invalid URI
  817. validate()
  818. end
  819. ##
  820. # The userinfo component for this URI.
  821. # Combines the user and password components.
  822. #
  823. # @return [String] The userinfo component.
  824. def userinfo
  825. @userinfo ||= (begin
  826. current_user = self.user
  827. current_password = self.password
  828. if !current_user && !current_password
  829. nil
  830. elsif current_user && current_password
  831. "#{current_user}:#{current_password}"
  832. elsif current_user && !current_password
  833. "#{current_user}"
  834. end
  835. end)
  836. end
  837. ##
  838. # The userinfo component for this URI, normalized.
  839. #
  840. # @return [String] The userinfo component, normalized.
  841. def normalized_userinfo
  842. @normalized_userinfo ||= (begin
  843. current_user = self.normalized_user
  844. current_password = self.normalized_password
  845. if !current_user && !current_password
  846. nil
  847. elsif current_user && current_password
  848. "#{current_user}:#{current_password}"
  849. elsif current_user && !current_password
  850. "#{current_user}"
  851. end
  852. end)
  853. end
  854. ##
  855. # Sets the userinfo component for this URI.
  856. #
  857. # @param [String, #to_str] new_userinfo The new userinfo component.
  858. def userinfo=(new_userinfo)
  859. # Check for frozenness
  860. raise TypeError, "Can't modify frozen URI." if self.frozen?
  861. if new_userinfo && !new_userinfo.respond_to?(:to_str)
  862. raise TypeError, "Can't convert #{new_userinfo.class} into String."
  863. end
  864. new_user, new_password = if new_userinfo
  865. [
  866. new_userinfo.to_str.strip[/^(.*):/, 1],
  867. new_userinfo.to_str.strip[/:(.*)$/, 1]
  868. ]
  869. else
  870. [nil, nil]
  871. end
  872. # Password assigned first to ensure validity in case of nil
  873. self.password = new_password
  874. self.user = new_user
  875. # Reset dependant values
  876. @authority = nil
  877. @uri_string = nil
  878. @hash = nil
  879. # Ensure we haven't created an invalid URI
  880. validate()
  881. end
  882. ##
  883. # The host component for this URI.
  884. #
  885. # @return [String] The host component.
  886. def host
  887. return @host ||= nil
  888. end
  889. ##
  890. # The host component for this URI, normalized.
  891. #
  892. # @return [String] The host component, normalized.
  893. def normalized_host
  894. @normalized_host ||= (begin
  895. if self.host != nil
  896. if self.host.strip != ""
  897. result = ::Addressable::IDNA.to_ascii(
  898. self.class.unencode_component(self.host.strip.downcase)
  899. )
  900. if result[-1..-1] == "."
  901. # Trailing dots are unnecessary
  902. result = result[0...-1]
  903. end
  904. result
  905. else
  906. ""
  907. end
  908. else
  909. nil
  910. end
  911. end)
  912. end
  913. ##
  914. # Sets the host component for this URI.
  915. #
  916. # @param [String, #to_str] new_host The new host component.
  917. def host=(new_host)
  918. # Check for frozenness
  919. raise TypeError, "Can't modify frozen URI." if self.frozen?
  920. if new_host && !new_host.respond_to?(:to_str)
  921. raise TypeError, "Can't convert #{new_host.class} into String."
  922. end
  923. @host = new_host ? new_host.to_str : nil
  924. # Reset dependant values
  925. @authority = nil
  926. @normalized_host = nil
  927. @uri_string = nil
  928. @hash = nil
  929. # Ensure we haven't created an invalid URI
  930. validate()
  931. end
  932. ##
  933. # The authority component for this URI.
  934. # Combines the user, password, host, and port components.
  935. #
  936. # @return [String] The authority component.
  937. def authority
  938. @authority ||= (begin
  939. if self.host.nil?
  940. nil
  941. else
  942. authority = ""
  943. if self.userinfo != nil
  944. authority << "#{self.userinfo}@"
  945. end
  946. authority << self.host
  947. if self.port != nil
  948. authority << ":#{self.port}"
  949. end
  950. authority
  951. end
  952. end)
  953. end
  954. ##
  955. # The authority component for this URI, normalized.
  956. #
  957. # @return [String] The authority component, normalized.
  958. def normalized_authority
  959. @normalized_authority ||= (begin
  960. if self.normalized_host.nil?
  961. nil
  962. else
  963. authority = ""
  964. if self.normalized_userinfo != nil
  965. authority << "#{self.normalized_userinfo}@"
  966. end
  967. authority << self.normalized_host
  968. if self.normalized_port != nil
  969. authority << ":#{self.normalized_port}"
  970. end
  971. authority
  972. end
  973. end)
  974. end
  975. ##
  976. # Sets the authority component for this URI.
  977. #
  978. # @param [String, #to_str] new_authority The new authority component.
  979. def authority=(new_authority)
  980. # Check for frozenness
  981. raise TypeError, "Can't modify frozen URI." if self.frozen?
  982. if new_authority
  983. if !new_authority.respond_to?(:to_str)
  984. raise TypeError, "Can't convert #{new_authority.class} into String."
  985. end
  986. new_authority = new_authority.to_str
  987. new_userinfo = new_authority[/^([^\[\]]*)@/, 1]
  988. if new_userinfo
  989. new_user = new_userinfo.strip[/^([^:]*):?/, 1]
  990. new_password = new_userinfo.strip[/:(.*)$/, 1]
  991. end
  992. new_host =
  993. new_authority.gsub(/^([^\[\]]*)@/, "").gsub(/:([^:@\[\]]*?)$/, "")
  994. new_port =
  995. new_authority[/:([^:@\[\]]*?)$/, 1]
  996. end
  997. # Password assigned first to ensure validity in case of nil
  998. self.password = defined?(new_password) ? new_password : nil
  999. self.user = defined?(new_user) ? new_user : nil
  1000. self.host = defined?(new_host) ? new_host : nil
  1001. self.port = defined?(new_port) ? new_port : nil
  1002. # Reset dependant values
  1003. @inferred_port = nil
  1004. @userinfo = nil
  1005. @normalized_userinfo = nil
  1006. @uri_string = nil
  1007. @hash = nil
  1008. # Ensure we haven't created an invalid URI
  1009. validate()
  1010. end
  1011. ##
  1012. # The origin for this URI, serialized to ASCII, as per
  1013. # draft-ietf-websec-origin-00, section 5.2.
  1014. #
  1015. # @return [String] The serialized origin.
  1016. def origin
  1017. return (if self.scheme && self.authority
  1018. if self.normalized_port
  1019. (
  1020. "#{self.normalized_scheme}://#{self.normalized_host}" +
  1021. ":#{self.normalized_port}"
  1022. )
  1023. else
  1024. "#{self.normalized_scheme}://#{self.normalized_host}"
  1025. end
  1026. else
  1027. "null"
  1028. end)
  1029. end
  1030. # Returns an array of known ip-based schemes. These schemes typically
  1031. # use a similar URI form:
  1032. # <code>//<user>:<password>@<host>:<port>/<url-path></code>
  1033. def self.ip_based_schemes
  1034. return self.port_mapping.keys
  1035. end
  1036. # Returns a hash of common IP-based schemes and their default port
  1037. # numbers. Adding new schemes to this hash, as necessary, will allow
  1038. # for better URI normalization.
  1039. def self.port_mapping
  1040. @port_mapping ||= {
  1041. "http" => 80,
  1042. "https" => 443,
  1043. "ftp" => 21,
  1044. "tftp" => 69,
  1045. "sftp" => 22,
  1046. "ssh" => 22,
  1047. "svn+ssh" => 22,
  1048. "telnet" => 23,
  1049. "nntp" => 119,
  1050. "gopher" => 70,
  1051. "wais" => 210,
  1052. "ldap" => 389,
  1053. "prospero" => 1525
  1054. }
  1055. end
  1056. ##
  1057. # The port component for this URI.
  1058. # This is the port number actually given in the URI. This does not
  1059. # infer port numbers from default values.
  1060. #
  1061. # @return [Integer] The port component.
  1062. def port
  1063. return @port ||= nil
  1064. end
  1065. ##
  1066. # The port component for this URI, normalized.
  1067. #
  1068. # @return [Integer] The port component, normalized.
  1069. def normalized_port
  1070. @normalized_port ||= (begin
  1071. if self.class.port_mapping[normalized_scheme] == self.port
  1072. nil
  1073. else
  1074. self.port
  1075. end
  1076. end)
  1077. end
  1078. ##
  1079. # Sets the port component for this URI.
  1080. #
  1081. # @param [String, Integer, #to_s] new_port The new port component.
  1082. def port=(new_port)
  1083. # Check for frozenness
  1084. raise TypeError, "Can't modify frozen URI." if self.frozen?
  1085. if new_port != nil && new_port.respond_to?(:to_str)
  1086. new_port = Addressable::URI.unencode_component(new_port.to_str)
  1087. end
  1088. if new_port != nil && !(new_port.to_s =~ /^\d+$/)
  1089. raise InvalidURIError,
  1090. "Invalid port number: #{new_port.inspect}"
  1091. end
  1092. @port = new_port.to_s.to_i
  1093. @port = nil if @port == 0
  1094. # Reset dependant values
  1095. @authority = nil
  1096. @inferred_port = nil
  1097. @normalized_port = nil
  1098. @uri_string = nil
  1099. @hash = nil
  1100. # Ensure we haven't created an invalid URI
  1101. validate()
  1102. end
  1103. ##
  1104. # The inferred port component for this URI.
  1105. # This method will normalize to the default port for the URI's scheme if
  1106. # the port isn't explicitly specified in the URI.
  1107. #
  1108. # @return [Integer] The inferred port component.
  1109. def inferred_port
  1110. @inferred_port ||= (begin
  1111. if port.to_i == 0
  1112. if scheme
  1113. self.class.port_mapping[scheme.strip.downcase]
  1114. else
  1115. nil
  1116. end
  1117. else
  1118. port.to_i
  1119. end
  1120. end)
  1121. end
  1122. ##
  1123. # The combination of components that represent a site.
  1124. # Combines the scheme, user, password, host, and port components.
  1125. # Primarily useful for HTTP and HTTPS.
  1126. #
  1127. # For example, <code>"http://example.com/path?query"</code> would have a
  1128. # <code>site</code> value of <code>"http://example.com"</code>.
  1129. #
  1130. # @return [String] The components that identify a site.
  1131. def site
  1132. @site ||= (begin
  1133. if self.scheme || self.authority
  1134. site_string = ""
  1135. site_string << "#{self.scheme}:" if self.scheme != nil
  1136. site_string << "//#{self.authority}" if self.authority != nil
  1137. site_string
  1138. else
  1139. nil
  1140. end
  1141. end)
  1142. end
  1143. ##
  1144. # The normalized combination of components that represent a site.
  1145. # Combines the scheme, user, password, host, and port components.
  1146. # Primarily useful for HTTP and HTTPS.
  1147. #
  1148. # For example, <code>"http://example.com/path?query"</code> would have a
  1149. # <code>site</code> value of <code>"http://example.com"</code>.
  1150. #
  1151. # @return [String] The normalized components that identify a site.
  1152. def normalized_site
  1153. @site ||= (begin
  1154. if self.normalized_scheme || self.normalized_authority
  1155. site_string = ""
  1156. if self.normalized_scheme != nil
  1157. site_string << "#{self.normalized_scheme}:"
  1158. end
  1159. if self.normalized_authority != nil
  1160. site_string << "//#{self.normalized_authority}"
  1161. end
  1162. site_string
  1163. else
  1164. nil
  1165. end
  1166. end)
  1167. end
  1168. ##
  1169. # Sets the site value for this URI.
  1170. #
  1171. # @param [String, #to_str] new_site The new site value.
  1172. def site=(new_site)
  1173. if new_site
  1174. if !new_site.respond_to?(:to_str)
  1175. raise TypeError, "Can't convert #{new_site.class} into String."
  1176. end
  1177. new_site = new_site.to_str
  1178. # These two regular expressions derived from the primary parsing
  1179. # expression
  1180. self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1]
  1181. self.authority = new_site[
  1182. /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1
  1183. ]
  1184. else
  1185. self.scheme = nil
  1186. self.authority = nil
  1187. end
  1188. end
  1189. ##
  1190. # The path component for this URI.
  1191. #
  1192. # @return [String] The path component.
  1193. def path
  1194. @path ||= ""
  1195. return @path
  1196. end
  1197. ##
  1198. # The path component for this URI, normalized.
  1199. #
  1200. # @return [String] The path component, normalized.
  1201. def normalized_path
  1202. @normalized_path ||= (begin
  1203. if self.scheme == nil && self.path != nil && self.path != "" &&
  1204. self.path =~ /^(?!\/)[^\/:]*:.*$/
  1205. # Relative paths with colons in the first segment are ambiguous.
  1206. self.path.sub!(":", "%2F")
  1207. end
  1208. # String#split(delimeter, -1) uses the more strict splitting behavior
  1209. # found by default in Python.
  1210. result = (self.path.strip.split("/", -1).map do |segment|
  1211. Addressable::URI.normalize_component(
  1212. segment,
  1213. Addressable::URI::CharacterClasses::PCHAR
  1214. )
  1215. end).join("/")
  1216. result = self.class.normalize_path(result)
  1217. if result == "" &&
  1218. ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme)
  1219. result = "/"
  1220. end
  1221. result
  1222. end)
  1223. end
  1224. ##
  1225. # Sets the path component for this URI.
  1226. #
  1227. # @param [String, #to_str] new_path The new path component.
  1228. def path=(new_path)
  1229. # Check for frozenness
  1230. raise TypeError, "Can't modify frozen URI." if self.frozen?
  1231. if new_path && !new_path.respond_to?(:to_str)
  1232. raise TypeError, "Can't convert #{new_path.class} into String."
  1233. end
  1234. @path = (new_path || "").to_str
  1235. if @path != "" && @path[0..0] != "/" && host != nil
  1236. @path = "/#{@path}"
  1237. end
  1238. # Reset dependant values
  1239. @normalized_path = nil
  1240. @uri_string = nil
  1241. @hash = nil
  1242. end
  1243. ##
  1244. # The basename, if any, of the file in the path component.
  1245. #
  1246. # @return [String] The path's basename.
  1247. def basename
  1248. # Path cannot be nil
  1249. return File.basename(self.path).gsub(/;[^\/]*$/, "")
  1250. end
  1251. ##
  1252. # The extname, if any, of the file in the path component.
  1253. # Empty string if there is no extension.
  1254. #
  1255. # @return [String] The path's extname.
  1256. def extname
  1257. return nil unless self.path
  1258. return File.extname(self.basename)
  1259. end
  1260. ##
  1261. # The query component for this URI.
  1262. #
  1263. # @return [String] The query component.
  1264. def query
  1265. return @query ||= nil
  1266. end
  1267. ##
  1268. # The query component for this URI, normalized.
  1269. #
  1270. # @return [String] The query component, normalized.
  1271. def normalized_query
  1272. @normalized_query ||= (begin
  1273. if self.query
  1274. Addressable::URI.normalize_component(
  1275. self.query.strip,
  1276. Addressable::URI::CharacterClasses::QUERY
  1277. )
  1278. else
  1279. nil
  1280. end
  1281. end)
  1282. end
  1283. ##
  1284. # Sets the query component for this URI.
  1285. #
  1286. # @param [String, #to_str] new_query The new query component.
  1287. def query=(new_query)
  1288. # Check for frozenness
  1289. raise TypeError, "Can't modify frozen URI." if self.frozen?
  1290. if new_query && !new_query.respond_to?(:to_str)
  1291. raise TypeError, "Can't convert #{new_query.class} into String."
  1292. end
  1293. @query = new_query ? new_query.to_str : nil
  1294. # Reset dependant values
  1295. @normalized_query = nil
  1296. @uri_string = nil
  1297. @hash = nil
  1298. end
  1299. ##
  1300. # Converts the query component to a Hash value.
  1301. #
  1302. # @option [Symbol] notation
  1303. # May be one of <code>:flat</code>, <code>:dot</code>, or
  1304. # <code>:subscript</code>. The <code>:dot</code> notation is not
  1305. # supported for assignment. Default value is <code>:subscript</code>.
  1306. #
  1307. # @return [Hash, Array] The query string parsed as a Hash or Array object.
  1308. #
  1309. # @example
  1310. # Addressable::URI.parse("?one=1&two=2&three=3").query_values
  1311. # #=> {"one" => "1", "two" => "2", "three" => "3"}
  1312. # Addressable::URI.parse("?one[two][three]=four").query_values
  1313. # #=> {"one" => {"two" => {"three" => "four"}}}
  1314. # Addressable::URI.parse("?one.two.three=four").query_values(
  1315. # :notation => :dot
  1316. # )
  1317. # #=> {"one" => {"two" => {"three" => "four"}}}
  1318. # Addressable::URI.parse("?one[two][three]=four").query_values(
  1319. # :notation => :flat
  1320. # )
  1321. # #=> {"one[two][three]" => "four"}
  1322. # Addressable::URI.parse("?one.two.three=four").query_values(
  1323. # :notation => :flat
  1324. # )
  1325. # #=> {"one.two.three" => "four"}
  1326. # Addressable::URI.parse(
  1327. # "?one[two][three][]=four&one[two][three][]=five"
  1328. # ).query_values
  1329. # #=> {"one" => {"two" => {"three" => ["four", "five"]}}}
  1330. # Addressable::URI.parse(
  1331. # "?one=two&one=three").query_values(:notation => :flat_array)
  1332. # #=> [['one', 'two'], ['one', 'three']]
  1333. def query_values(options={})
  1334. defaults = {:notation => :subscript}
  1335. options = defaults.merge(options)
  1336. if ![:flat, :dot, :subscript, :flat_array].include?(options[:notation])
  1337. raise ArgumentError,
  1338. "Invalid notation. Must be one of: " +
  1339. "[:flat, :dot, :subscript, :flat_array]."
  1340. end
  1341. dehash = lambda do |hash|
  1342. hash.each do |(key, value)|
  1343. if value.kind_of?(Hash)
  1344. hash[key] = dehash.call(value)
  1345. end
  1346. end
  1347. if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ }
  1348. hash.sort.inject([]) do |accu, (key, value)|
  1349. accu << value; accu
  1350. end
  1351. else
  1352. hash
  1353. end
  1354. end
  1355. return nil if self.query == nil
  1356. empty_accumulator = :flat_array == options[:notation] ? [] : {}
  1357. return ((self.query.split("&").map do |pair|
  1358. pair.split("=", 2) if pair && pair != ""
  1359. end).compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
  1360. value = true if value.nil?
  1361. key = self.class.unencode_component(key)
  1362. if value != true
  1363. value = self.class.unencode_component(value.gsub(/\+/, " "))
  1364. end
  1365. if options[:notation] == :flat
  1366. if accumulator[key]
  1367. raise ArgumentError, "Key was repeated: #{key.inspect}"
  1368. end
  1369. accumulator[key] = value
  1370. elsif options[:notation] == :flat_array
  1371. accumulator << [key, value]
  1372. else
  1373. if options[:notation] == :dot
  1374. array_value = false
  1375. subkeys = key.split(".")
  1376. elsif options[:notation] == :subscript
  1377. array_value = !!(key =~ /\[\]$/)
  1378. subkeys = key.split(/[\[\]]+/)
  1379. end
  1380. current_hash = accumulator
  1381. for i in 0...(subkeys.size - 1)
  1382. subkey = subkeys[i]
  1383. current_hash[subkey] = {} unless current_hash[subkey]
  1384. current_hash = current_hash[subkey]
  1385. end
  1386. if array_value
  1387. current_hash[subkeys.last] = [] unless current_hash[subkeys.last]
  1388. current_hash[subkeys.last] << value
  1389. else
  1390. current_hash[subkeys.last] = value
  1391. end
  1392. end
  1393. accumulator
  1394. end).inject(empty_accumulator.dup) do |accumulator, (key, value)|
  1395. if options[:notation] == :flat_array
  1396. accumulator << [key, value]
  1397. else
  1398. accumulator[key] = value.kind_of?(Hash) ? dehash.call(value) : value
  1399. end
  1400. accumulator
  1401. end
  1402. end
  1403. ##
  1404. # Sets the query component for this URI from a Hash object.
  1405. # This method produces a query string using the :subscript notation.
  1406. # An empty Hash will result in a nil query.
  1407. #
  1408. # @param [Hash, #to_hash, Array] new_query_values The new query values.
  1409. def query_values=(new_query_values)
  1410. # Check for frozenness
  1411. raise TypeError, "Can't modify frozen URI." if self.frozen?
  1412. if new_query_values == nil
  1413. self.query = nil
  1414. return nil
  1415. end
  1416. if !new_query_values.is_a?(Array)
  1417. if !new_query_values.respond_to?(:to_hash)
  1418. raise TypeError,
  1419. "Can't convert #{new_query_values.class} into Hash."
  1420. end
  1421. new_query_values = new_query_values.to_hash
  1422. new_query_values = new_query_values.map do |key, value|
  1423. key = key.to_s if key.kind_of?(Symbol)
  1424. [key, value]
  1425. end
  1426. # Useful default for OAuth and caching.
  1427. # Only to be used for non-Array inputs. Arrays should preserve order.
  1428. new_query_values.sort!
  1429. end
  1430. # new_query_values have form [['key1', 'value1'], ['key2', 'value2']]
  1431. # Algorithm shamelessly stolen from Julien Genestoux, slightly modified
  1432. buffer = ""
  1433. stack = []
  1434. e = lambda do |component|
  1435. component = component.to_s if component.kind_of?(Symbol)
  1436. self.class.encode_component(component, CharacterClasses::UNRESERVED)
  1437. end
  1438. new_query_values.each do |key, value|
  1439. if value.kind_of?(Hash)
  1440. stack << [key, value]
  1441. elsif value.kind_of?(Array)
  1442. stack << [
  1443. key,
  1444. value.inject({}) { |accu, x| accu[accu.size.to_s] = x; accu }
  1445. ]
  1446. elsif value == true
  1447. buffer << "#{e.call(key)}&"
  1448. else
  1449. buffer << "#{e.call(key)}=#{e.call(value)}&"
  1450. end
  1451. end
  1452. stack.each do |(parent, hash)|
  1453. (hash.sort_by { |key| key.to_s }).each do |(key, value)|
  1454. if value.kind_of?(Hash)
  1455. stack << ["#{parent}[#{key}]", value]
  1456. elsif value == true
  1457. buffer << "#{parent}[#{e.call(key)}]&"
  1458. else
  1459. buffer << "#{parent}[#{e.call(key)}]=#{e.call(value)}&"
  1460. end
  1461. end
  1462. end
  1463. self.query = buffer.chop
  1464. end
  1465. ##
  1466. # The HTTP request URI for this URI. This is the path and the
  1467. # query string.
  1468. #
  1469. # @return [String] The request URI required for an HTTP request.
  1470. def request_uri
  1471. return nil if self.absolute? && self.scheme !~ /^https?$/
  1472. return (
  1473. (self.path != "" ? self.path : "/") +
  1474. (self.query ? "?#{self.query}" : "")
  1475. )
  1476. end
  1477. ##
  1478. # Sets the HTTP request URI for this URI.
  1479. #
  1480. # @param [String, #to_str] new_request_uri The new HTTP request URI.
  1481. def request_uri=(new_request_uri)
  1482. if !new_request_uri.respond_to?(:to_str)
  1483. raise TypeError, "Can't convert #{new_request_uri.class} into String."
  1484. end
  1485. if self.absolute? && self.scheme !~ /^https?$/
  1486. raise InvalidURIError,
  1487. "Cannot set an HTTP request URI for a non-HTTP URI."
  1488. end
  1489. new_request_uri = new_request_uri.to_str
  1490. path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1]
  1491. query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1]
  1492. path_component = path_component.to_s
  1493. path_component = (path_component != "" ? path_component : "/")
  1494. self.path = path_component
  1495. self.query = query_component
  1496. # Reset dependant values
  1497. @uri_string = nil
  1498. @hash = nil
  1499. end
  1500. ##
  1501. # The fragment component for this URI.
  1502. #
  1503. # @return [String] The fragment component.
  1504. def fragment
  1505. return @fragment ||= nil
  1506. end
  1507. ##
  1508. # The fragment component for this URI, normalized.
  1509. #
  1510. # @return [String] The fragment component, normalized.
  1511. def normalized_fragment
  1512. @normalized_fragment ||= (begin
  1513. if self.fragment
  1514. Addressable::URI.normalize_component(
  1515. self.fragment.strip,
  1516. Addressable::URI::CharacterClasses::FRAGMENT
  1517. )
  1518. else
  1519. nil
  1520. end
  1521. end)
  1522. end
  1523. ##
  1524. # Sets the fragment component for this URI.
  1525. #
  1526. # @param [String, #to_str] new_fragment The new fragment component.
  1527. def fragment=(new_fragment)
  1528. # Check for frozenness
  1529. raise TypeError, "Can't modify frozen URI." if self.frozen?
  1530. if new_fragment && !new_fragment.respond_to?(:to_str)
  1531. raise TypeError, "Can't convert #{new_fragment.class} into String."
  1532. end
  1533. @fragment = new_fragment ? new_fragment.to_str : nil
  1534. # Reset dependant values
  1535. @normalized_fragment = nil
  1536. @uri_string = nil
  1537. @hash = nil
  1538. # Ensure we haven't created an invalid URI
  1539. validate()
  1540. end
  1541. ##
  1542. # Determines if the scheme indicates an IP-based protocol.
  1543. #
  1544. # @return [TrueClass, FalseClass]
  1545. # <code>true</code> if the scheme indicates an IP-based protocol.
  1546. # <code>false</code> otherwise.
  1547. def ip_based?
  1548. if self.scheme
  1549. return self.class.ip_based_schemes.include?(
  1550. self.scheme.strip.downcase)
  1551. end
  1552. return false
  1553. end
  1554. ##
  1555. # Determines if the URI is relative.
  1556. #
  1557. # @return [TrueClass, FalseClass]
  1558. # <code>true</code> if the URI is relative. <code>false</code>
  1559. # otherwise.
  1560. def relative?
  1561. return self.scheme.nil?
  1562. end
  1563. ##
  1564. # Determines if the URI is absolute.
  1565. #
  1566. # @return [TrueClass, FalseClass]
  1567. # <code>true</code> if the URI is absolute. <code>false</code>
  1568. # otherwise.
  1569. def absolute?
  1570. return !relative?
  1571. end
  1572. ##
  1573. # Joins two URIs together.
  1574. #
  1575. # @param [String, Addressable::URI, #to_str] The URI to join with.
  1576. #
  1577. # @return [Addressable::URI] The joined URI.
  1578. def join(uri)
  1579. if !uri.respond_to?(:to_str)
  1580. raise TypeError, "Can't convert #{uri.class} into String."
  1581. end
  1582. if !uri.kind_of?(self.class)
  1583. # Otherwise, convert to a String, then parse.
  1584. uri = self.class.parse(uri.to_str)
  1585. end
  1586. if uri.to_s == ""
  1587. return self.dup
  1588. end
  1589. joined_scheme = nil
  1590. joined_user = nil
  1591. joined_password = nil
  1592. joined_host = nil
  1593. joined_port = nil
  1594. joined_path = nil
  1595. joined_query = nil
  1596. joined_fragment = nil
  1597. # Section 5.2.2 of RFC 3986
  1598. if uri.scheme != nil
  1599. joined_scheme = uri.scheme
  1600. joined_user = uri.user
  1601. joined_password = uri.password
  1602. joined_host = uri.host
  1603. joined_port = uri.port
  1604. joined_path = self.class.normalize_path(uri.path)
  1605. joined_query = uri.query
  1606. else
  1607. if uri.authority != nil
  1608. joined_user = uri.user
  1609. joined_password = uri.password
  1610. joined_host = uri.host
  1611. joined_port = uri.port
  1612. joined_path = self.class.normalize_path(uri.path)
  1613. joined_query = uri.query
  1614. else
  1615. if uri.path == nil || uri.path == ""
  1616. joined_path = self.path
  1617. if uri.query != nil
  1618. joined_query = uri.query
  1619. else
  1620. joined_query = self.query
  1621. end
  1622. else
  1623. if uri.path[0..0] == "/"
  1624. joined_path = self.class.normalize_path(uri.path)
  1625. else
  1626. base_path = self.path.dup
  1627. base_path = "" if base_path == nil
  1628. base_path = self.class.normalize_path(base_path)
  1629. # Section 5.2.3 of RFC 3986
  1630. #
  1631. # Removes the right-most path segment from the base path.
  1632. if base_path =~ /\//
  1633. base_path.gsub!(/\/[^\/]+$/, "/")
  1634. else
  1635. base_path = ""
  1636. end
  1637. # If the base path is empty and an authority segment has been
  1638. # defined, use a base path of "/"
  1639. if base_path == "" && self.authority != nil
  1640. base_path = "/"
  1641. end
  1642. joined_path = self.class.normalize_path(base_path + uri.path)
  1643. end
  1644. joined_query = uri.query
  1645. end
  1646. joined_user = self.user
  1647. joined_password = self.password
  1648. joined_host = self.host
  1649. joined_port = self.port
  1650. end
  1651. joined_scheme = self.scheme
  1652. end
  1653. joined_fragment = uri.fragment
  1654. return Addressable::URI.new(
  1655. :scheme => joined_scheme,
  1656. :user => joined_user,
  1657. :password => joined_password,
  1658. :host => joined_host,
  1659. :port => joined_port,
  1660. :path => joined_path,
  1661. :query => joined_query,
  1662. :fragment => joined_fragment
  1663. )
  1664. end
  1665. alias_method :+, :join
  1666. ##
  1667. # Destructive form of <code>join</code>.
  1668. #
  1669. # @param [String, Addressable::URI, #to_str] The URI to join with.
  1670. #
  1671. # @return [Addressable::URI] The joined URI.
  1672. #
  1673. # @see Addressable::URI#join
  1674. def join!(uri)
  1675. replace_self(self.join(uri))
  1676. end
  1677. ##
  1678. # Merges a URI with a <code>Hash</code> of components.
  1679. # This method has different behavior from <code>join</code>. Any
  1680. # components present in the <code>hash</code> parameter will override the
  1681. # original components. The path component is not treated specially.
  1682. #
  1683. # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
  1684. #
  1685. # @return [Addressable::URI] The merged URI.
  1686. #
  1687. # @see Hash#merge
  1688. def merge(hash)
  1689. if !hash.respond_to?(:to_hash)
  1690. raise TypeError, "Can't convert #{hash.class} into Hash."
  1691. end
  1692. hash = hash.to_hash
  1693. if hash.has_key?(:authority)
  1694. if (hash.keys & [:userinfo, :user, :password, :host, :port]).any?
  1695. raise ArgumentError,
  1696. "Cannot specify both an authority and any of the components " +
  1697. "within the authority."
  1698. end
  1699. end
  1700. if hash.has_key?(:userinfo)
  1701. if (hash.keys & [:user, :password]).any?
  1702. raise ArgumentError,
  1703. "Cannot specify both a userinfo and either the user or password."
  1704. end
  1705. end
  1706. uri = Addressable::URI.new
  1707. uri.defer_validation do
  1708. # Bunch of crazy logic required because of the composite components
  1709. # like userinfo and authority.
  1710. uri.scheme =
  1711. hash.has_key?(:scheme) ? hash[:scheme] : self.scheme
  1712. if hash.has_key?(:authority)
  1713. uri.authority =
  1714. hash.has_key?(:authority) ? hash[:authority] : self.authority
  1715. end
  1716. if hash.has_key?(:userinfo)
  1717. uri.userinfo =
  1718. hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo
  1719. end
  1720. if !hash.has_key?(:userinfo) && !hash.has_key?(:authority)
  1721. uri.user =
  1722. hash.has_key?(:user) ? hash[:user] : self.user
  1723. uri.password =
  1724. hash.has_key?(:password) ? hash[:password] : self.password
  1725. end
  1726. if !hash.has_key?(:authority)
  1727. uri.host =
  1728. hash.has_key?(:host) ? hash[:host] : self.host
  1729. uri.port =
  1730. hash.has_key?(:port) ? hash[:port] : self.port
  1731. end
  1732. uri.path =
  1733. hash.has_key?(:path) ? hash[:path] : self.path
  1734. uri.query =
  1735. hash.has_key?(:query) ? hash[:query] : self.query
  1736. uri.fragment =
  1737. hash.has_key?(:fragment) ? hash[:fragment] : self.fragment
  1738. end
  1739. return uri
  1740. end
  1741. ##
  1742. # Destructive form of <code>merge</code>.
  1743. #
  1744. # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
  1745. #
  1746. # @return [Addressable::URI] The merged URI.
  1747. #
  1748. # @see Addressable::URI#merge
  1749. def merge!(uri)
  1750. replace_self(self.merge(uri))
  1751. end
  1752. ##
  1753. # Returns the shortest normalized relative form of this URI that uses the
  1754. # supplied URI as a base for resolution. Returns an absolute URI if
  1755. # necessary. This is effectively the opposite of <code>route_to</code>.
  1756. #
  1757. # @param [String, Addressable::URI, #to_str] uri The URI to route from.
  1758. #
  1759. # @return [Addressable::URI]
  1760. # The normalized relative URI that is equivalent to the original URI.
  1761. def route_from(uri)
  1762. uri = self.class.parse(uri).normalize
  1763. normalized_self = self.normalize
  1764. if normalized_self.relative?
  1765. raise ArgumentError, "Expected absolute URI, got: #{self.to_s}"
  1766. end
  1767. if uri.relative?
  1768. raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}"
  1769. end
  1770. if normalized_self == uri
  1771. return Addressable::URI.parse("##{normalized_self.fragment}")
  1772. end
  1773. components = normalized_self.to_hash
  1774. if normalized_self.scheme == uri.scheme
  1775. components[:scheme] = nil
  1776. if normalized_self.authority == uri.authority
  1777. components[:user] = nil
  1778. components[:password] = nil
  1779. components[:host] = nil
  1780. components[:port] = nil
  1781. if normalized_self.path == uri.path
  1782. components[:path] = nil
  1783. if normalized_self.query == uri.query
  1784. components[:query] = nil
  1785. end
  1786. else
  1787. if uri.path != "/"
  1788. components[:path].gsub!(
  1789. Regexp.new("^" + Regexp.escape(uri.path)), "")
  1790. end
  1791. end
  1792. end
  1793. end
  1794. # Avoid network-path references.
  1795. if components[:host] != nil
  1796. components[:scheme] = normalized_self.scheme
  1797. end
  1798. return Addressable::URI.new(
  1799. :scheme => components[:scheme],
  1800. :user => components[:user],
  1801. :password => components[:password],
  1802. :host => components[:host],
  1803. :port => components[:port],
  1804. :path => components[:path],
  1805. :query => components[:query],
  1806. :fragment => components[:fragment]
  1807. )
  1808. end
  1809. ##
  1810. # Returns the shortest normalized relative form of the supplied URI that
  1811. # uses this URI as a base for resolution. Returns an absolute URI if
  1812. # necessary. This is effectively the opposite of <code>route_from</code>.
  1813. #
  1814. # @param [String, Addressable::URI, #to_str] uri The URI to route to.
  1815. #
  1816. # @return [Addressable::URI]
  1817. # The normalized relative URI that is equivalent to the supplied URI.
  1818. def route_to(uri)
  1819. return self.class.parse(uri).route_from(self)
  1820. end
  1821. ##
  1822. # Returns a normalized URI object.
  1823. #
  1824. # NOTE: This method does not attempt to fully conform to specifications.
  1825. # It exists largely to correct other people's failures to read the
  1826. # specifications, and also to deal with caching issues since several
  1827. # different URIs may represent the same resource and should not be
  1828. # cached multiple times.
  1829. #
  1830. # @return [Addressable::URI] The normalized URI.
  1831. def normalize
  1832. # This is a special exception for the frequently misused feed
  1833. # URI scheme.
  1834. if normalized_scheme == "feed"
  1835. if self.to_s =~ /^feed:\/*http:\/*/
  1836. return self.class.parse(
  1837. self.to_s[/^feed:\/*(http:\/*.*)/, 1]
  1838. ).normalize
  1839. end
  1840. end
  1841. return Addressable::URI.new(
  1842. :scheme => normalized_scheme,
  1843. :authority => normalized_authority,
  1844. :path => normalized_path,
  1845. :query => normalized_query,
  1846. :fragment => normalized_fragment
  1847. )
  1848. end
  1849. ##
  1850. # Destructively normalizes this URI object.
  1851. #
  1852. # @return [Addressable::URI] The normalized URI.
  1853. #
  1854. # @see Addressable::URI#normalize
  1855. def normalize!
  1856. replace_self(self.normalize)
  1857. end
  1858. ##
  1859. # Creates a URI suitable for display to users. If semantic attacks are
  1860. # likely, the application should try to detect these and warn the user.
  1861. # See <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
  1862. # section 7.6 for more information.
  1863. #
  1864. # @return [Addressable::URI] A URI suitable for display purposes.
  1865. def display_uri
  1866. display_uri = self.normalize
  1867. display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host)
  1868. return display_uri
  1869. end
  1870. ##
  1871. # Returns <code>true</code> if the URI objects are equal. This method
  1872. # normalizes both URIs before doing the comparison, and allows comparison
  1873. # against <code>Strings</code>.
  1874. #
  1875. # @param [Object] uri The URI to compare.
  1876. #
  1877. # @return [TrueClass, FalseClass]
  1878. # <code>true</code> if the URIs are equivalent, <code>false</code>
  1879. # otherwise.
  1880. def ===(uri)
  1881. if uri.respond_to?(:normalize)
  1882. uri_string = uri.normalize.to_s
  1883. else
  1884. begin
  1885. uri_string = ::Addressable::URI.parse(uri).normalize.to_s
  1886. rescue InvalidURIError, TypeError
  1887. return false
  1888. end
  1889. end
  1890. return self.normalize.to_s == uri_string
  1891. end
  1892. ##
  1893. # Returns <code>true</code> if the URI objects are equal. This method
  1894. # normalizes both URIs before doing the comparison.
  1895. #
  1896. # @param [Object] uri The URI to compare.
  1897. #
  1898. # @return [TrueClass, FalseClass]
  1899. # <code>true</code> if the URIs are equivalent, <code>false</code>
  1900. # otherwise.
  1901. def ==(uri)
  1902. return false unless uri.kind_of?(self.class)
  1903. return self.normalize.to_s == uri.normalize.to_s
  1904. end
  1905. ##
  1906. # Returns <code>true</code> if the URI objects are equal. This method
  1907. # does NOT normalize either URI before doing the comparison.
  1908. #
  1909. # @param [Object] uri The URI to compare.
  1910. #
  1911. # @return [TrueClass, FalseClass]
  1912. # <code>true</code> if the URIs are equivalent, <code>false</code>
  1913. # otherwise.
  1914. def eql?(uri)
  1915. return false unless uri.kind_of?(self.class)
  1916. return self.to_s == uri.to_s
  1917. end
  1918. ##
  1919. # A hash value that will make a URI equivalent to its normalized
  1920. # form.
  1921. #
  1922. # @return [Integer] A hash of the URI.
  1923. def hash
  1924. return @hash ||= (self.to_s.hash * -1)
  1925. end
  1926. ##
  1927. # Clones the URI object.
  1928. #
  1929. # @return [Addressable::URI] The cloned URI.
  1930. def dup
  1931. duplicated_uri = Addressable::URI.new(
  1932. :scheme => self.scheme ? self.scheme.dup : nil,
  1933. :user => self.user ? self.user.dup : nil,
  1934. :password => self.password ? self.password.dup : nil,
  1935. :host => self.host ? self.host.dup : nil,
  1936. :port => self.port,
  1937. :path => self.path ? self.path.dup : nil,
  1938. :query => self.query ? self.query.dup : nil,
  1939. :fragment => self.fragment ? self.fragment.dup : nil
  1940. )
  1941. return duplicated_uri
  1942. end
  1943. ##
  1944. # Freezes the URI object.
  1945. #
  1946. # @return [Addressable::URI] The frozen URI.
  1947. def freeze
  1948. # Unfortunately, because of the memoized implementation of many of the
  1949. # URI methods, the default freeze method will cause unexpected errors.
  1950. # As an alternative, we freeze the string representation of the URI
  1951. # instead. This should generally produce the desired effect.
  1952. self.to_s.freeze
  1953. return self
  1954. end
  1955. ##
  1956. # Determines if the URI is frozen.
  1957. #
  1958. # @return [TrueClass, FalseClass]
  1959. # <code>true</code> if the URI is frozen, <code>false</code> otherwise.
  1960. def frozen?
  1961. self.to_s.frozen?
  1962. end
  1963. ##
  1964. # Omits components from a URI.
  1965. #
  1966. # @param [Symbol] *components The components to be omitted.
  1967. #
  1968. # @return [Addressable::URI] The URI with components omitted.
  1969. #
  1970. # @example
  1971. # uri = Addressable::URI.parse("http://example.com/path?query")
  1972. # #=> #<Addressable::URI:0xcc5e7a URI:http://example.com/path?query>
  1973. # uri.omit(:scheme, :authority)
  1974. # #=> #<Addressable::URI:0xcc4d86 URI:/path?query>
  1975. def omit(*components)
  1976. invalid_components = components - [
  1977. :scheme, :user, :password, :userinfo, :host, :port, :authority,
  1978. :path, :query, :fragment
  1979. ]
  1980. unless invalid_components.empty?
  1981. raise ArgumentError,
  1982. "Invalid component names: #{invalid_components.inspect}."
  1983. end
  1984. duplicated_uri = self.dup
  1985. duplicated_uri.defer_validation do
  1986. components.each do |component|
  1987. duplicated_uri.send((component.to_s + "=").to_sym, nil)
  1988. end
  1989. duplicated_uri.user = duplicated_uri.normalized_user
  1990. end
  1991. duplicated_uri
  1992. end
  1993. ##
  1994. # Destructive form of omit.
  1995. #
  1996. # @param [Symbol] *components The components to be omitted.
  1997. #
  1998. # @return [Addressable::URI] The URI with components omitted.
  1999. #
  2000. # @see Addressable::URI#omit
  2001. def omit!(*components)
  2002. replace_self(self.omit(*components))
  2003. end
  2004. ##
  2005. # Converts the URI to a <code>String</code>.
  2006. #
  2007. # @return [String] The URI's <code>String</code> representation.
  2008. def to_s
  2009. @uri_string ||= (begin
  2010. uri_string = ""
  2011. uri_string << "#{self.scheme}:" if self.scheme != nil
  2012. uri_string << "//#{self.authority}" if self.authority != nil
  2013. uri_string << self.path.to_s
  2014. uri_string << "?#{self.query}" if self.query != nil
  2015. uri_string << "##{self.fragment}" if self.fragment != nil
  2016. if uri_string.respond_to?(:force_encoding)
  2017. uri_string.force_encoding(Encoding::UTF_8)
  2018. end
  2019. uri_string
  2020. end)
  2021. end
  2022. ##
  2023. # URI's are glorified <code>Strings</code>. Allow implicit conversion.
  2024. alias_method :to_str, :to_s
  2025. ##
  2026. # Returns a Hash of the URI components.
  2027. #
  2028. # @return [Hash] The URI as a <code>Hash</code> of components.
  2029. def to_hash
  2030. return {
  2031. :scheme => self.scheme,
  2032. :user => self.user,
  2033. :password => self.password,
  2034. :host => self.host,
  2035. :port => self.port,
  2036. :path => self.path,
  2037. :query => self.query,
  2038. :fragment => self.fragment
  2039. }
  2040. end
  2041. ##
  2042. # Returns a <code>String</code> representation of the URI object's state.
  2043. #
  2044. # @return [String] The URI object's state, as a <code>String</code>.
  2045. def inspect
  2046. sprintf("#<%s:%#0x URI:%s>", self.class.to_s, self.object_id, self.to_s)
  2047. end
  2048. ##
  2049. # This method allows you to make several changes to a URI simultaneously,
  2050. # which separately would cause validation errors, but in conjunction,
  2051. # are valid. The URI will be revalidated as soon as the entire block has
  2052. # been executed.
  2053. #
  2054. # @param [Proc] block
  2055. # A set of operations to perform on a given URI.
  2056. def defer_validation(&block)
  2057. raise LocalJumpError, "No block given." unless block
  2058. @validation_deferred = true
  2059. block.call()
  2060. @validation_deferred = false
  2061. validate
  2062. return nil
  2063. end
  2064. private
  2065. ##
  2066. # Resolves paths to their simplest form.
  2067. #
  2068. # @param [String] path The path to normalize.
  2069. #
  2070. # @return [String] The normalized path.
  2071. def self.normalize_path(path)
  2072. # Section 5.2.4 of RFC 3986
  2073. return nil if path.nil?
  2074. normalized_path = path.dup
  2075. previous_state = normalized_path.dup
  2076. begin
  2077. previous_state = normalized_path.dup
  2078. normalized_path.gsub!(/\/\.\//, "/")
  2079. normalized_path.gsub!(/\/\.$/, "/")
  2080. parent = normalized_path[/\/([^\/]+)\/\.\.\//, 1]
  2081. if parent != "." && parent != ".."
  2082. normalized_path.gsub!(/\/#{parent}\/\.\.\//, "/")
  2083. end
  2084. parent = normalized_path[/\/([^\/]+)\/\.\.$/, 1]
  2085. if parent != "." && parent != ".."
  2086. normalized_path.gsub!(/\/#{parent}\/\.\.$/, "/")
  2087. end
  2088. normalized_path.gsub!(/^\.\.?\/?/, "")
  2089. normalized_path.gsub!(/^\/\.\.?\//, "/")
  2090. # Non-standard
  2091. normalized_path.gsub!(/^(\/\.\.?)+\/?$/, "/")
  2092. end until previous_state == normalized_path
  2093. return normalized_path
  2094. end
  2095. ##
  2096. # Ensures that the URI is valid.
  2097. def validate
  2098. return if !!@validation_deferred
  2099. if self.scheme != nil &&
  2100. (self.host == nil || self.host == "") &&
  2101. (self.path == nil || self.path == "")
  2102. raise InvalidURIError,
  2103. "Absolute URI missing hierarchical segment: '#{self.to_s}'"
  2104. end
  2105. if self.host == nil
  2106. if self.port != nil ||
  2107. self.user != nil ||
  2108. self.password != nil
  2109. raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
  2110. end
  2111. end
  2112. if self.path != nil && self.path != "" && self.path[0..0] != "/" &&
  2113. self.authority != nil
  2114. raise InvalidURIError,
  2115. "Cannot have a relative path with an authority set: '#{self.to_s}'"
  2116. end
  2117. return nil
  2118. end
  2119. ##
  2120. # Replaces the internal state of self with the specified URI's state.
  2121. # Used in destructive operations to avoid massive code repetition.
  2122. #
  2123. # @param [Addressable::URI] uri The URI to replace <code>self</code> with.
  2124. #
  2125. # @return [Addressable::URI] <code>self</code>.
  2126. def replace_self(uri)
  2127. # Reset dependant values
  2128. instance_variables.each do |var|
  2129. instance_variable_set(var, nil)
  2130. end
  2131. @scheme = uri.scheme
  2132. @user = uri.user
  2133. @password = uri.password
  2134. @host = uri.host
  2135. @port = uri.port
  2136. @path = uri.path
  2137. @query = uri.query
  2138. @fragment = uri.fragment
  2139. return self
  2140. end
  2141. end
  2142. end