PageRenderTime 61ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/19/uri/generic.rb

http://github.com/rubinius/rubinius
Ruby | 1599 lines | 734 code | 155 blank | 710 comment | 174 complexity | 4d7e84805869163dfb8bb39219845e9f MD5 | raw file
Possible License(s): BSD-3-Clause, MPL-2.0-no-copyleft-exception, 0BSD, GPL-2.0, LGPL-2.1
  1. # = uri/generic.rb
  2. #
  3. # Author:: Akira Yamada <akira@ruby-lang.org>
  4. # License:: You can redistribute it and/or modify it under the same term as Ruby.
  5. # Revision:: $Id: generic.rb 32560 2011-07-15 21:32:02Z marcandre $
  6. #
  7. # See URI for general documentation
  8. #
  9. require 'uri/common'
  10. module URI
  11. #
  12. # Base class for all URI classes.
  13. # Implements generic URI syntax as per RFC 2396.
  14. #
  15. class Generic
  16. include URI
  17. #
  18. # A Default port of nil for URI::Generic
  19. #
  20. DEFAULT_PORT = nil
  21. #
  22. # Returns default port
  23. #
  24. def self.default_port
  25. self::DEFAULT_PORT
  26. end
  27. #
  28. # Returns default port
  29. #
  30. def default_port
  31. self.class.default_port
  32. end
  33. #
  34. # An Array of the available components for URI::Generic
  35. #
  36. COMPONENT = [
  37. :scheme,
  38. :userinfo, :host, :port, :registry,
  39. :path, :opaque,
  40. :query,
  41. :fragment
  42. ].freeze
  43. #
  44. # Components of the URI in the order.
  45. #
  46. def self.component
  47. self::COMPONENT
  48. end
  49. #
  50. # Default to not use the registry for a URI::Generic
  51. #
  52. USE_REGISTRY = false
  53. #
  54. # Returns whether a registry of naming
  55. # authorities are being used.
  56. #
  57. def self.use_registry
  58. self::USE_REGISTRY
  59. end
  60. #
  61. # == Synopsis
  62. #
  63. # See #new
  64. #
  65. # == Description
  66. #
  67. # At first, tries to create a new URI::Generic instance using
  68. # URI::Generic::build. But, if exception URI::InvalidComponentError is raised,
  69. # then it URI::Escape.escape all URI components and tries again.
  70. #
  71. #
  72. def self.build2(args)
  73. begin
  74. return self.build(args)
  75. rescue InvalidComponentError
  76. if args.kind_of?(Array)
  77. return self.build(args.collect{|x|
  78. if x
  79. parser.escape(x)
  80. else
  81. x
  82. end
  83. })
  84. elsif args.kind_of?(Hash)
  85. tmp = {}
  86. args.each do |key, value|
  87. tmp[key] = if value
  88. parser.escape(value)
  89. else
  90. value
  91. end
  92. end
  93. return self.build(tmp)
  94. end
  95. end
  96. end
  97. #
  98. # == Synopsis
  99. #
  100. # See #new
  101. #
  102. # == Description
  103. #
  104. # Creates a new URI::Generic instance from components of URI::Generic
  105. # with check. Components are: scheme, userinfo, host, port, registry, path,
  106. # opaque, query and fragment. You can provide arguments either by an Array or a Hash.
  107. # See #new for hash keys to use or for order of array items.
  108. #
  109. def self.build(args)
  110. if args.kind_of?(Array) &&
  111. args.size == ::URI::Generic::COMPONENT.size
  112. tmp = args
  113. elsif args.kind_of?(Hash)
  114. tmp = ::URI::Generic::COMPONENT.collect do |c|
  115. if args.include?(c)
  116. args[c]
  117. else
  118. nil
  119. end
  120. end
  121. else
  122. raise ArgumentError,
  123. "expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})"
  124. end
  125. tmp << nil
  126. tmp << true
  127. return self.new(*tmp)
  128. end
  129. #
  130. # == Args
  131. #
  132. # +scheme+::
  133. # Protocol scheme, i.e. 'http','ftp','mailto' and so on.
  134. # +userinfo+::
  135. # User name and password, i.e. 'sdmitry:bla'
  136. # +host+::
  137. # Server host name
  138. # +port+::
  139. # Server port
  140. # +registry+::
  141. # Registry of naming authorities.
  142. # +path+::
  143. # Path on server
  144. # +opaque+::
  145. # Opaque part
  146. # +query+::
  147. # Query data
  148. # +fragment+::
  149. # A part of URI after '#' sign
  150. # +parser+::
  151. # Parser for internal use [URI::DEFAULT_PARSER by default]
  152. # +arg_check+::
  153. # Check arguments [false by default]
  154. #
  155. # == Description
  156. #
  157. # Creates a new URI::Generic instance from ``generic'' components without check.
  158. #
  159. def initialize(scheme,
  160. userinfo, host, port, registry,
  161. path, opaque,
  162. query,
  163. fragment,
  164. parser = DEFAULT_PARSER,
  165. arg_check = false)
  166. @scheme = nil
  167. @user = nil
  168. @password = nil
  169. @host = nil
  170. @port = nil
  171. @path = nil
  172. @query = nil
  173. @opaque = nil
  174. @registry = nil
  175. @fragment = nil
  176. @parser = parser == DEFAULT_PARSER ? nil : parser
  177. if arg_check
  178. self.scheme = scheme
  179. self.userinfo = userinfo
  180. self.host = host
  181. self.port = port
  182. self.path = path
  183. self.query = query
  184. self.opaque = opaque
  185. self.registry = registry
  186. self.fragment = fragment
  187. else
  188. self.set_scheme(scheme)
  189. self.set_userinfo(userinfo)
  190. self.set_host(host)
  191. self.set_port(port)
  192. self.set_path(path)
  193. self.set_query(query)
  194. self.set_opaque(opaque)
  195. self.set_registry(registry)
  196. self.set_fragment(fragment)
  197. end
  198. if @registry && !self.class.use_registry
  199. raise InvalidURIError,
  200. "the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)"
  201. end
  202. @scheme.freeze if @scheme
  203. self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
  204. self.set_port(self.default_port) if self.default_port && !@port
  205. end
  206. #
  207. # returns the scheme component of the URI.
  208. #
  209. # URI("http://foo/bar/baz").scheme #=> "http"
  210. #
  211. attr_reader :scheme
  212. # returns the host component of the URI.
  213. #
  214. # URI("http://foo/bar/baz").host #=> "foo"
  215. #
  216. # It returns nil if no host component.
  217. #
  218. # URI("mailto:foo@example.org").host #=> nil
  219. #
  220. # The component doesn't contains the port number.
  221. #
  222. # URI("http://foo:8080/bar/baz").host #=> "foo"
  223. #
  224. # Since IPv6 addresses are wrapped by brackets in URIs,
  225. # this method returns IPv6 addresses wrapped by brackets.
  226. # This form is not appropriate to pass socket methods such as TCPSocket.open.
  227. # If unwrapped host names are required, use "hostname" method.
  228. #
  229. # URI("http://[::1]/bar/baz").host #=> "[::1]"
  230. # URI("http://[::1]/bar/baz").hostname #=> "::1"
  231. #
  232. attr_reader :host
  233. # returns the port component of the URI.
  234. #
  235. # URI("http://foo/bar/baz").port #=> "80"
  236. #
  237. # URI("http://foo:8080/bar/baz").port #=> "8080"
  238. #
  239. attr_reader :port
  240. # returns the registry component of the URI.
  241. #
  242. # (see RFC2396 Section 3.2)
  243. #
  244. attr_reader :registry
  245. # returns the path component of the URI.
  246. #
  247. # URI("http://foo/bar/baz").path #=> "/bar/baz"
  248. #
  249. attr_reader :path
  250. # returns the query component of the URI.
  251. #
  252. # URI("http://foo/bar/baz?search=FooBar").query #=> "search=FooBar"
  253. #
  254. attr_reader :query
  255. # returns the opaque part of the URI.
  256. #
  257. # URI("mailto:foo@example.org").opaque #=> "foo@example.org"
  258. #
  259. # Portion of the path that does make use of the slash '/'.
  260. # The path typically refers to the absolute path and the opaque part.
  261. # (see RFC2396 Section 3 and 5.2)
  262. #
  263. attr_reader :opaque
  264. # returns the fragment component of the URI.
  265. #
  266. # URI("http://foo/bar/baz?search=FooBar#ponies").fragment #=> "ponies"
  267. #
  268. attr_reader :fragment
  269. # returns the parser to be used.
  270. #
  271. # Unless a URI::Parser is defined, then DEFAULT_PARSER is used.
  272. #
  273. def parser
  274. if !defined?(@parser) || !@parser
  275. DEFAULT_PARSER
  276. else
  277. @parser || DEFAULT_PARSER
  278. end
  279. end
  280. # replace self by other URI object
  281. def replace!(oth)
  282. if self.class != oth.class
  283. raise ArgumentError, "expected #{self.class} object"
  284. end
  285. component.each do |c|
  286. self.__send__("#{c}=", oth.__send__(c))
  287. end
  288. end
  289. private :replace!
  290. #
  291. # Components of the URI in the order.
  292. #
  293. def component
  294. self.class.component
  295. end
  296. #
  297. # check the scheme +v+ component against the URI::Parser Regexp for :SCHEME
  298. #
  299. def check_scheme(v)
  300. if v && parser.regexp[:SCHEME] !~ v
  301. raise InvalidComponentError,
  302. "bad component(expected scheme component): #{v}"
  303. end
  304. return true
  305. end
  306. private :check_scheme
  307. # protected setter for the scheme component +v+
  308. #
  309. # see also URI::Generic.scheme=
  310. #
  311. def set_scheme(v)
  312. @scheme = v
  313. end
  314. protected :set_scheme
  315. #
  316. # == Args
  317. #
  318. # +v+::
  319. # String
  320. #
  321. # == Description
  322. #
  323. # public setter for the scheme component +v+.
  324. # (with validation)
  325. #
  326. # see also URI::Generic.check_scheme
  327. #
  328. # == Usage
  329. #
  330. # require 'uri'
  331. #
  332. # uri = URI.parse("http://my.example.com")
  333. # uri.scheme = "https"
  334. # # => "https"
  335. # uri
  336. # #=> #<URI::HTTP:0x000000008e89e8 URL:https://my.example.com>
  337. #
  338. def scheme=(v)
  339. check_scheme(v)
  340. set_scheme(v)
  341. v
  342. end
  343. #
  344. # check the +user+ and +password+.
  345. #
  346. # If +password+ is not provided, then +user+ is
  347. # split, using URI::Generic.split_userinfo, to
  348. # pull +user+ and +password.
  349. #
  350. # see also URI::Generic.check_user, URI::Generic.check_password
  351. #
  352. def check_userinfo(user, password = nil)
  353. if !password
  354. user, password = split_userinfo(user)
  355. end
  356. check_user(user)
  357. check_password(password, user)
  358. return true
  359. end
  360. private :check_userinfo
  361. #
  362. # check the user +v+ component for RFC2396 compliance
  363. # and against the URI::Parser Regexp for :USERINFO
  364. #
  365. # Can not have a registry or opaque component defined,
  366. # with a user component defined.
  367. #
  368. def check_user(v)
  369. if @registry || @opaque
  370. raise InvalidURIError,
  371. "can not set user with registry or opaque"
  372. end
  373. return v unless v
  374. if parser.regexp[:USERINFO] !~ v
  375. raise InvalidComponentError,
  376. "bad component(expected userinfo component or user component): #{v}"
  377. end
  378. return true
  379. end
  380. private :check_user
  381. #
  382. # check the password +v+ component for RFC2396 compliance
  383. # and against the URI::Parser Regexp for :USERINFO
  384. #
  385. # Can not have a registry or opaque component defined,
  386. # with a user component defined.
  387. #
  388. def check_password(v, user = @user)
  389. if @registry || @opaque
  390. raise InvalidURIError,
  391. "can not set password with registry or opaque"
  392. end
  393. return v unless v
  394. if !user
  395. raise InvalidURIError,
  396. "password component depends user component"
  397. end
  398. if parser.regexp[:USERINFO] !~ v
  399. raise InvalidComponentError,
  400. "bad component(expected user component): #{v}"
  401. end
  402. return true
  403. end
  404. private :check_password
  405. #
  406. # Sets userinfo, argument is string like 'name:pass'
  407. #
  408. def userinfo=(userinfo)
  409. if userinfo.nil?
  410. return nil
  411. end
  412. check_userinfo(*userinfo)
  413. set_userinfo(*userinfo)
  414. # returns userinfo
  415. end
  416. #
  417. # == Args
  418. #
  419. # +v+::
  420. # String
  421. #
  422. # == Description
  423. #
  424. # public setter for the +user+ component.
  425. # (with validation)
  426. #
  427. # see also URI::Generic.check_user
  428. #
  429. # == Usage
  430. #
  431. # require 'uri'
  432. #
  433. # uri = URI.parse("http://john:S3nsit1ve@my.example.com")
  434. # uri.user = "sam"
  435. # # => "sam"
  436. # uri
  437. # #=> #<URI::HTTP:0x00000000881d90 URL:http://sam:V3ry_S3nsit1ve@my.example.com>
  438. #
  439. def user=(user)
  440. check_user(user)
  441. set_user(user)
  442. # returns user
  443. end
  444. #
  445. # == Args
  446. #
  447. # +v+::
  448. # String
  449. #
  450. # == Description
  451. #
  452. # public setter for the +password+ component.
  453. # (with validation)
  454. #
  455. # see also URI::Generic.check_password
  456. #
  457. # == Usage
  458. #
  459. # require 'uri'
  460. #
  461. # uri = URI.parse("http://john:S3nsit1ve@my.example.com")
  462. # uri.password = "V3ry_S3nsit1ve"
  463. # # => "V3ry_S3nsit1ve"
  464. # uri
  465. # #=> #<URI::HTTP:0x00000000881d90 URL:http://john:V3ry_S3nsit1ve@my.example.com>
  466. #
  467. def password=(password)
  468. check_password(password)
  469. set_password(password)
  470. # returns password
  471. end
  472. # protect setter for the +user+ component, and +password+ if available.
  473. # (with validation)
  474. #
  475. # see also URI::Generic.userinfo=
  476. #
  477. def set_userinfo(user, password = nil)
  478. unless password
  479. user, password = split_userinfo(user)
  480. end
  481. @user = user
  482. @password = password if password
  483. [@user, @password]
  484. end
  485. protected :set_userinfo
  486. # protected setter for the user component +v+
  487. #
  488. # see also URI::Generic.user=
  489. #
  490. def set_user(v)
  491. set_userinfo(v, @password)
  492. v
  493. end
  494. protected :set_user
  495. # protected setter for the password component +v+
  496. #
  497. # see also URI::Generic.password=
  498. #
  499. def set_password(v)
  500. @password = v
  501. # returns v
  502. end
  503. protected :set_password
  504. # returns the userinfo +ui+ as user, password
  505. # if properly formated as 'user:password'
  506. def split_userinfo(ui)
  507. return nil, nil unless ui
  508. user, password = ui.split(/:/, 2)
  509. return user, password
  510. end
  511. private :split_userinfo
  512. # escapes 'user:password' +v+ based on RFC 1738 section 3.1
  513. def escape_userpass(v)
  514. v = parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
  515. end
  516. private :escape_userpass
  517. # returns the userinfo, either as 'user' or 'user:password'
  518. def userinfo
  519. if @user.nil?
  520. nil
  521. elsif @password.nil?
  522. @user
  523. else
  524. @user + ':' + @password
  525. end
  526. end
  527. # returns the user component
  528. def user
  529. @user
  530. end
  531. # returns the password component
  532. def password
  533. @password
  534. end
  535. #
  536. # check the host +v+ component for RFC2396 compliance
  537. # and against the URI::Parser Regexp for :HOST
  538. #
  539. # Can not have a registry or opaque component defined,
  540. # with a host component defined.
  541. #
  542. def check_host(v)
  543. return v unless v
  544. if @registry || @opaque
  545. raise InvalidURIError,
  546. "can not set host with registry or opaque"
  547. elsif parser.regexp[:HOST] !~ v
  548. raise InvalidComponentError,
  549. "bad component(expected host component): #{v}"
  550. end
  551. return true
  552. end
  553. private :check_host
  554. # protected setter for the host component +v+
  555. #
  556. # see also URI::Generic.host=
  557. #
  558. def set_host(v)
  559. @host = v
  560. end
  561. protected :set_host
  562. #
  563. # == Args
  564. #
  565. # +v+::
  566. # String
  567. #
  568. # == Description
  569. #
  570. # public setter for the host component +v+.
  571. # (with validation)
  572. #
  573. # see also URI::Generic.check_host
  574. #
  575. # == Usage
  576. #
  577. # require 'uri'
  578. #
  579. # uri = URI.parse("http://my.example.com")
  580. # uri.host = "foo.com"
  581. # # => "foo.com"
  582. # uri
  583. # #=> #<URI::HTTP:0x000000008e89e8 URL:http://foo.com>
  584. #
  585. def host=(v)
  586. check_host(v)
  587. set_host(v)
  588. v
  589. end
  590. # extract the host part of the URI and unwrap brackets for IPv6 addresses.
  591. #
  592. # This method is same as URI::Generic#host except
  593. # brackets for IPv6 (andn future IP) addresses are removed.
  594. #
  595. # u = URI("http://[::1]/bar")
  596. # p u.hostname #=> "::1"
  597. # p u.host #=> "[::1]"
  598. #
  599. def hostname
  600. v = self.host
  601. /\A\[(.*)\]\z/ =~ v ? $1 : v
  602. end
  603. # set the host part of the URI as the argument with brackets for IPv6 addresses.
  604. #
  605. # This method is same as URI::Generic#host= except
  606. # the argument can be bare IPv6 address.
  607. #
  608. # u = URI("http://foo/bar")
  609. # p u.to_s #=> "http://foo/bar"
  610. # u.hostname = "::1"
  611. # p u.to_s #=> "http://[::1]/bar"
  612. #
  613. # If the arugument seems IPv6 address,
  614. # it is wrapped by brackets.
  615. #
  616. def hostname=(v)
  617. v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v
  618. self.host = v
  619. end
  620. #
  621. # check the port +v+ component for RFC2396 compliance
  622. # and against the URI::Parser Regexp for :PORT
  623. #
  624. # Can not have a registry or opaque component defined,
  625. # with a port component defined.
  626. #
  627. def check_port(v)
  628. return v unless v
  629. if @registry || @opaque
  630. raise InvalidURIError,
  631. "can not set port with registry or opaque"
  632. elsif !v.kind_of?(Fixnum) && parser.regexp[:PORT] !~ v
  633. raise InvalidComponentError,
  634. "bad component(expected port component): #{v}"
  635. end
  636. return true
  637. end
  638. private :check_port
  639. # protected setter for the port component +v+
  640. #
  641. # see also URI::Generic.port=
  642. #
  643. def set_port(v)
  644. unless !v || v.kind_of?(Fixnum)
  645. if v.empty?
  646. v = nil
  647. else
  648. v = v.to_i
  649. end
  650. end
  651. @port = v
  652. end
  653. protected :set_port
  654. #
  655. # == Args
  656. #
  657. # +v+::
  658. # String
  659. #
  660. # == Description
  661. #
  662. # public setter for the port component +v+.
  663. # (with validation)
  664. #
  665. # see also URI::Generic.check_port
  666. #
  667. # == Usage
  668. #
  669. # require 'uri'
  670. #
  671. # uri = URI.parse("http://my.example.com")
  672. # uri.port = 8080
  673. # # => 8080
  674. # uri
  675. # #=> #<URI::HTTP:0x000000008e89e8 URL:http://my.example.com:8080>
  676. #
  677. def port=(v)
  678. check_port(v)
  679. set_port(v)
  680. port
  681. end
  682. #
  683. # check the registry +v+ component for RFC2396 compliance
  684. # and against the URI::Parser Regexp for :REGISTRY
  685. #
  686. # Can not have a host, port or user component defined,
  687. # with a registry component defined.
  688. #
  689. def check_registry(v)
  690. return v unless v
  691. # raise if both server and registry are not nil, because:
  692. # authority = server | reg_name
  693. # server = [ [ userinfo "@" ] hostport ]
  694. if @host || @port || @user # userinfo = @user + ':' + @password
  695. raise InvalidURIError,
  696. "can not set registry with host, port, or userinfo"
  697. elsif v && parser.regexp[:REGISTRY] !~ v
  698. raise InvalidComponentError,
  699. "bad component(expected registry component): #{v}"
  700. end
  701. return true
  702. end
  703. private :check_registry
  704. # protected setter for the registry component +v+
  705. #
  706. # see also URI::Generic.registry=
  707. #
  708. def set_registry(v)
  709. @registry = v
  710. end
  711. protected :set_registry
  712. #
  713. # == Args
  714. #
  715. # +v+::
  716. # String
  717. #
  718. # == Description
  719. #
  720. # public setter for the registry component +v+.
  721. # (with validation)
  722. #
  723. # see also URI::Generic.check_registry
  724. #
  725. def registry=(v)
  726. check_registry(v)
  727. set_registry(v)
  728. v
  729. end
  730. #
  731. # check the path +v+ component for RFC2396 compliance
  732. # and against the URI::Parser Regexp
  733. # for :ABS_PATH and :REL_PATH
  734. #
  735. # Can not have a opaque component defined,
  736. # with a path component defined.
  737. #
  738. def check_path(v)
  739. # raise if both hier and opaque are not nil, because:
  740. # absoluteURI = scheme ":" ( hier_part | opaque_part )
  741. # hier_part = ( net_path | abs_path ) [ "?" query ]
  742. if v && @opaque
  743. raise InvalidURIError,
  744. "path conflicts with opaque"
  745. end
  746. # If scheme is ftp, path may be relative.
  747. # See RFC 1738 section 3.2.2, and RFC 2396.
  748. if @scheme && @scheme != "ftp"
  749. if v && v != '' && parser.regexp[:ABS_PATH] !~ v
  750. raise InvalidComponentError,
  751. "bad component(expected absolute path component): #{v}"
  752. end
  753. else
  754. if v && v != '' && parser.regexp[:ABS_PATH] !~ v && parser.regexp[:REL_PATH] !~ v
  755. raise InvalidComponentError,
  756. "bad component(expected relative path component): #{v}"
  757. end
  758. end
  759. return true
  760. end
  761. private :check_path
  762. # protected setter for the path component +v+
  763. #
  764. # see also URI::Generic.path=
  765. #
  766. def set_path(v)
  767. @path = v
  768. end
  769. protected :set_path
  770. #
  771. # == Args
  772. #
  773. # +v+::
  774. # String
  775. #
  776. # == Description
  777. #
  778. # public setter for the path component +v+.
  779. # (with validation)
  780. #
  781. # see also URI::Generic.check_path
  782. #
  783. # == Usage
  784. #
  785. # require 'uri'
  786. #
  787. # uri = URI.parse("http://my.example.com/pub/files")
  788. # uri.path = "/faq/"
  789. # # => "/faq/"
  790. # uri
  791. # #=> #<URI::HTTP:0x000000008e89e8 URL:http://my.example.com/faq/>
  792. #
  793. def path=(v)
  794. check_path(v)
  795. set_path(v)
  796. v
  797. end
  798. #
  799. # check the query +v+ component for RFC2396 compliance
  800. # and against the URI::Parser Regexp for :QUERY
  801. #
  802. # Can not have a opaque component defined,
  803. # with a query component defined.
  804. #
  805. def check_query(v)
  806. return v unless v
  807. # raise if both hier and opaque are not nil, because:
  808. # absoluteURI = scheme ":" ( hier_part | opaque_part )
  809. # hier_part = ( net_path | abs_path ) [ "?" query ]
  810. if @opaque
  811. raise InvalidURIError,
  812. "query conflicts with opaque"
  813. end
  814. if v && v != '' && parser.regexp[:QUERY] !~ v
  815. raise InvalidComponentError,
  816. "bad component(expected query component): #{v}"
  817. end
  818. return true
  819. end
  820. private :check_query
  821. # protected setter for the query component +v+
  822. #
  823. # see also URI::Generic.query=
  824. #
  825. def set_query(v)
  826. @query = v
  827. end
  828. protected :set_query
  829. #
  830. # == Args
  831. #
  832. # +v+::
  833. # String
  834. #
  835. # == Description
  836. #
  837. # public setter for the query component +v+.
  838. # (with validation)
  839. #
  840. # see also URI::Generic.check_query
  841. #
  842. # == Usage
  843. #
  844. # require 'uri'
  845. #
  846. # uri = URI.parse("http://my.example.com/?id=25")
  847. # uri.query = "id=1"
  848. # # => "id=1"
  849. # uri
  850. # #=> #<URI::HTTP:0x000000008e89e8 URL:http://my.example.com/?id=1>
  851. #
  852. def query=(v)
  853. check_query(v)
  854. set_query(v)
  855. v
  856. end
  857. #
  858. # check the opaque +v+ component for RFC2396 compliance and
  859. # against the URI::Parser Regexp for :OPAQUE
  860. #
  861. # Can not have a host, port, user or path component defined,
  862. # with an opaque component defined.
  863. #
  864. def check_opaque(v)
  865. return v unless v
  866. # raise if both hier and opaque are not nil, because:
  867. # absoluteURI = scheme ":" ( hier_part | opaque_part )
  868. # hier_part = ( net_path | abs_path ) [ "?" query ]
  869. if @host || @port || @user || @path # userinfo = @user + ':' + @password
  870. raise InvalidURIError,
  871. "can not set opaque with host, port, userinfo or path"
  872. elsif v && parser.regexp[:OPAQUE] !~ v
  873. raise InvalidComponentError,
  874. "bad component(expected opaque component): #{v}"
  875. end
  876. return true
  877. end
  878. private :check_opaque
  879. # protected setter for the opaque component +v+
  880. #
  881. # see also URI::Generic.opaque=
  882. #
  883. def set_opaque(v)
  884. @opaque = v
  885. end
  886. protected :set_opaque
  887. #
  888. # == Args
  889. #
  890. # +v+::
  891. # String
  892. #
  893. # == Description
  894. #
  895. # public setter for the opaque component +v+.
  896. # (with validation)
  897. #
  898. # see also URI::Generic.check_opaque
  899. #
  900. def opaque=(v)
  901. check_opaque(v)
  902. set_opaque(v)
  903. v
  904. end
  905. #
  906. # check the fragment +v+ component against the URI::Parser Regexp for :FRAGMENT
  907. #
  908. def check_fragment(v)
  909. return v unless v
  910. if v && v != '' && parser.regexp[:FRAGMENT] !~ v
  911. raise InvalidComponentError,
  912. "bad component(expected fragment component): #{v}"
  913. end
  914. return true
  915. end
  916. private :check_fragment
  917. # protected setter for the fragment component +v+
  918. #
  919. # see also URI::Generic.fragment=
  920. #
  921. def set_fragment(v)
  922. @fragment = v
  923. end
  924. protected :set_fragment
  925. #
  926. # == Args
  927. #
  928. # +v+::
  929. # String
  930. #
  931. # == Description
  932. #
  933. # public setter for the fragment component +v+.
  934. # (with validation)
  935. #
  936. # see also URI::Generic.check_fragment
  937. #
  938. # == Usage
  939. #
  940. # require 'uri'
  941. #
  942. # uri = URI.parse("http://my.example.com/?id=25#time=1305212049")
  943. # uri.fragment = "time=1305212086"
  944. # # => "time=1305212086"
  945. # uri
  946. # #=> #<URI::HTTP:0x000000007a81f8 URL:http://my.example.com/?id=25#time=1305212086>
  947. #
  948. def fragment=(v)
  949. check_fragment(v)
  950. set_fragment(v)
  951. v
  952. end
  953. #
  954. # Checks if URI has a path
  955. #
  956. def hierarchical?
  957. if @path
  958. true
  959. else
  960. false
  961. end
  962. end
  963. #
  964. # Checks if URI is an absolute one
  965. #
  966. def absolute?
  967. if @scheme
  968. true
  969. else
  970. false
  971. end
  972. end
  973. alias absolute absolute?
  974. #
  975. # Checks if URI is relative
  976. #
  977. def relative?
  978. !absolute?
  979. end
  980. #
  981. # returns an Array of the path split on '/'
  982. #
  983. def split_path(path)
  984. path.split(%r{/+}, -1)
  985. end
  986. private :split_path
  987. #
  988. # Merges a base path +base+, with relative path +rel+,
  989. # returns a modified base path.
  990. #
  991. def merge_path(base, rel)
  992. # RFC2396, Section 5.2, 5)
  993. # RFC2396, Section 5.2, 6)
  994. base_path = split_path(base)
  995. rel_path = split_path(rel)
  996. # RFC2396, Section 5.2, 6), a)
  997. base_path << '' if base_path.last == '..'
  998. while i = base_path.index('..')
  999. base_path.slice!(i - 1, 2)
  1000. end
  1001. if (first = rel_path.first) and first.empty?
  1002. base_path.clear
  1003. rel_path.shift
  1004. end
  1005. # RFC2396, Section 5.2, 6), c)
  1006. # RFC2396, Section 5.2, 6), d)
  1007. rel_path.push('') if rel_path.last == '.' || rel_path.last == '..'
  1008. rel_path.delete('.')
  1009. # RFC2396, Section 5.2, 6), e)
  1010. tmp = []
  1011. rel_path.each do |x|
  1012. if x == '..' &&
  1013. !(tmp.empty? || tmp.last == '..')
  1014. tmp.pop
  1015. else
  1016. tmp << x
  1017. end
  1018. end
  1019. add_trailer_slash = !tmp.empty?
  1020. if base_path.empty?
  1021. base_path = [''] # keep '/' for root directory
  1022. elsif add_trailer_slash
  1023. base_path.pop
  1024. end
  1025. while x = tmp.shift
  1026. if x == '..'
  1027. # RFC2396, Section 4
  1028. # a .. or . in an absolute path has no special meaning
  1029. base_path.pop if base_path.size > 1
  1030. else
  1031. # if x == '..'
  1032. # valid absolute (but abnormal) path "/../..."
  1033. # else
  1034. # valid absolute path
  1035. # end
  1036. base_path << x
  1037. tmp.each {|t| base_path << t}
  1038. add_trailer_slash = false
  1039. break
  1040. end
  1041. end
  1042. base_path.push('') if add_trailer_slash
  1043. return base_path.join('/')
  1044. end
  1045. private :merge_path
  1046. #
  1047. # == Args
  1048. #
  1049. # +oth+::
  1050. # URI or String
  1051. #
  1052. # == Description
  1053. #
  1054. # Destructive form of #merge
  1055. #
  1056. # == Usage
  1057. #
  1058. # require 'uri'
  1059. #
  1060. # uri = URI.parse("http://my.example.com")
  1061. # uri.merge!("/main.rbx?page=1")
  1062. # p uri
  1063. # # => #<URI::HTTP:0x2021f3b0 URL:http://my.example.com/main.rbx?page=1>
  1064. #
  1065. def merge!(oth)
  1066. t = merge(oth)
  1067. if self == t
  1068. nil
  1069. else
  1070. replace!(t)
  1071. self
  1072. end
  1073. end
  1074. #
  1075. # == Args
  1076. #
  1077. # +oth+::
  1078. # URI or String
  1079. #
  1080. # == Description
  1081. #
  1082. # Merges two URI's.
  1083. #
  1084. # == Usage
  1085. #
  1086. # require 'uri'
  1087. #
  1088. # uri = URI.parse("http://my.example.com")
  1089. # p uri.merge("/main.rbx?page=1")
  1090. # # => #<URI::HTTP:0x2021f3b0 URL:http://my.example.com/main.rbx?page=1>
  1091. #
  1092. def merge(oth)
  1093. begin
  1094. base, rel = merge0(oth)
  1095. rescue
  1096. raise $!.class, $!.message
  1097. end
  1098. if base == rel
  1099. return base
  1100. end
  1101. authority = rel.userinfo || rel.host || rel.port
  1102. # RFC2396, Section 5.2, 2)
  1103. if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
  1104. base.set_fragment(rel.fragment) if rel.fragment
  1105. return base
  1106. end
  1107. base.set_query(nil)
  1108. base.set_fragment(nil)
  1109. # RFC2396, Section 5.2, 4)
  1110. if !authority
  1111. base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
  1112. else
  1113. # RFC2396, Section 5.2, 4)
  1114. base.set_path(rel.path) if rel.path
  1115. end
  1116. # RFC2396, Section 5.2, 7)
  1117. base.set_userinfo(rel.userinfo) if rel.userinfo
  1118. base.set_host(rel.host) if rel.host
  1119. base.set_port(rel.port) if rel.port
  1120. base.set_query(rel.query) if rel.query
  1121. base.set_fragment(rel.fragment) if rel.fragment
  1122. return base
  1123. end # merge
  1124. alias + merge
  1125. # return base and rel.
  1126. # you can modify `base', but can not `rel'.
  1127. def merge0(oth)
  1128. oth = parser.send(:convert_to_uri, oth)
  1129. if self.relative? && oth.relative?
  1130. raise BadURIError,
  1131. "both URI are relative"
  1132. end
  1133. if self.absolute? && oth.absolute?
  1134. #raise BadURIError,
  1135. # "both URI are absolute"
  1136. # hmm... should return oth for usability?
  1137. return oth, oth
  1138. end
  1139. if self.absolute?
  1140. return self.dup, oth
  1141. else
  1142. return oth, oth
  1143. end
  1144. end
  1145. private :merge0
  1146. # :stopdoc:
  1147. def route_from_path(src, dst)
  1148. case dst
  1149. when src
  1150. # RFC2396, Section 4.2
  1151. return ''
  1152. when %r{(?:\A|/)\.\.?(?:/|\z)}
  1153. # dst has abnormal absolute path,
  1154. # like "/./", "/../", "/x/../", ...
  1155. return dst.dup
  1156. end
  1157. src_path = src.scan(%r{(?:\A|[^/]+)/})
  1158. dst_path = dst.scan(%r{(?:\A|[^/]+)/?})
  1159. # discard same parts
  1160. while !dst_path.empty? && dst_path.first == src_path.first
  1161. src_path.shift
  1162. dst_path.shift
  1163. end
  1164. tmp = dst_path.join
  1165. # calculate
  1166. if src_path.empty?
  1167. if tmp.empty?
  1168. return './'
  1169. elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
  1170. return './' + tmp
  1171. else
  1172. return tmp
  1173. end
  1174. end
  1175. return '../' * src_path.size + tmp
  1176. end
  1177. private :route_from_path
  1178. # :startdoc:
  1179. # :stopdoc:
  1180. def route_from0(oth)
  1181. oth = parser.send(:convert_to_uri, oth)
  1182. if self.relative?
  1183. raise BadURIError,
  1184. "relative URI: #{self}"
  1185. end
  1186. if oth.relative?
  1187. raise BadURIError,
  1188. "relative URI: #{oth}"
  1189. end
  1190. if self.scheme != oth.scheme
  1191. return self, self.dup
  1192. end
  1193. rel = URI::Generic.new(nil, # it is relative URI
  1194. self.userinfo, self.host, self.port,
  1195. self.registry, self.path, self.opaque,
  1196. self.query, self.fragment, parser)
  1197. if rel.userinfo != oth.userinfo ||
  1198. rel.host.to_s.downcase != oth.host.to_s.downcase ||
  1199. rel.port != oth.port
  1200. if self.userinfo.nil? && self.host.nil?
  1201. return self, self.dup
  1202. end
  1203. rel.set_port(nil) if rel.port == oth.default_port
  1204. return rel, rel
  1205. end
  1206. rel.set_userinfo(nil)
  1207. rel.set_host(nil)
  1208. rel.set_port(nil)
  1209. if rel.path && rel.path == oth.path
  1210. rel.set_path('')
  1211. rel.set_query(nil) if rel.query == oth.query
  1212. return rel, rel
  1213. elsif rel.opaque && rel.opaque == oth.opaque
  1214. rel.set_opaque('')
  1215. rel.set_query(nil) if rel.query == oth.query
  1216. return rel, rel
  1217. end
  1218. # you can modify `rel', but can not `oth'.
  1219. return oth, rel
  1220. end
  1221. private :route_from0
  1222. # :startdoc:
  1223. #
  1224. # == Args
  1225. #
  1226. # +oth+::
  1227. # URI or String
  1228. #
  1229. # == Description
  1230. #
  1231. # Calculates relative path from oth to self
  1232. #
  1233. # == Usage
  1234. #
  1235. # require 'uri'
  1236. #
  1237. # uri = URI.parse('http://my.example.com/main.rbx?page=1')
  1238. # p uri.route_from('http://my.example.com')
  1239. # #=> #<URI::Generic:0x20218858 URL:/main.rbx?page=1>
  1240. #
  1241. def route_from(oth)
  1242. # you can modify `rel', but can not `oth'.
  1243. begin
  1244. oth, rel = route_from0(oth)
  1245. rescue
  1246. raise $!.class, $!.message
  1247. end
  1248. if oth == rel
  1249. return rel
  1250. end
  1251. rel.set_path(route_from_path(oth.path, self.path))
  1252. if rel.path == './' && self.query
  1253. # "./?foo" -> "?foo"
  1254. rel.set_path('')
  1255. end
  1256. return rel
  1257. end
  1258. alias - route_from
  1259. #
  1260. # == Args
  1261. #
  1262. # +oth+::
  1263. # URI or String
  1264. #
  1265. # == Description
  1266. #
  1267. # Calculates relative path to oth from self
  1268. #
  1269. # == Usage
  1270. #
  1271. # require 'uri'
  1272. #
  1273. # uri = URI.parse('http://my.example.com')
  1274. # p uri.route_to('http://my.example.com/main.rbx?page=1')
  1275. # #=> #<URI::Generic:0x2020c2f6 URL:/main.rbx?page=1>
  1276. #
  1277. def route_to(oth)
  1278. parser.send(:convert_to_uri, oth).route_from(self)
  1279. end
  1280. #
  1281. # Returns normalized URI
  1282. #
  1283. def normalize
  1284. uri = dup
  1285. uri.normalize!
  1286. uri
  1287. end
  1288. #
  1289. # Destructive version of #normalize
  1290. #
  1291. def normalize!
  1292. if path && path == ''
  1293. set_path('/')
  1294. end
  1295. if scheme && scheme != scheme.downcase
  1296. set_scheme(self.scheme.downcase)
  1297. end
  1298. if host && host != host.downcase
  1299. set_host(self.host.downcase)
  1300. end
  1301. end
  1302. # returns the assemble String with path and query components
  1303. def path_query
  1304. str = @path
  1305. if @query
  1306. str += '?' + @query
  1307. end
  1308. str
  1309. end
  1310. private :path_query
  1311. #
  1312. # Constructs String from URI
  1313. #
  1314. def to_s
  1315. str = ''
  1316. if @scheme
  1317. str << @scheme
  1318. str << ':'
  1319. end
  1320. if @opaque
  1321. str << @opaque
  1322. else
  1323. if @registry
  1324. str << @registry
  1325. else
  1326. if @host
  1327. str << '//'
  1328. end
  1329. if self.userinfo
  1330. str << self.userinfo
  1331. str << '@'
  1332. end
  1333. if @host
  1334. str << @host
  1335. end
  1336. if @port && @port != self.default_port
  1337. str << ':'
  1338. str << @port.to_s
  1339. end
  1340. end
  1341. str << path_query
  1342. end
  1343. if @fragment
  1344. str << '#'
  1345. str << @fragment
  1346. end
  1347. str
  1348. end
  1349. #
  1350. # Compares to URI's
  1351. #
  1352. def ==(oth)
  1353. if self.class == oth.class
  1354. self.normalize.component_ary == oth.normalize.component_ary
  1355. else
  1356. false
  1357. end
  1358. end
  1359. def hash
  1360. self.component_ary.hash
  1361. end
  1362. def eql?(oth)
  1363. self.class == oth.class &&
  1364. parser == oth.parser &&
  1365. self.component_ary.eql?(oth.component_ary)
  1366. end
  1367. =begin
  1368. --- URI::Generic#===(oth)
  1369. =end
  1370. # def ===(oth)
  1371. # raise NotImplementedError
  1372. # end
  1373. =begin
  1374. =end
  1375. # returns an Array of the components defined from the COMPONENT Array
  1376. def component_ary
  1377. component.collect do |x|
  1378. self.send(x)
  1379. end
  1380. end
  1381. protected :component_ary
  1382. # == Args
  1383. #
  1384. # +components+::
  1385. # Multiple Symbol arguments defined in URI::HTTP
  1386. #
  1387. # == Description
  1388. #
  1389. # Selects specified components from URI
  1390. #
  1391. # == Usage
  1392. #
  1393. # require 'uri'
  1394. #
  1395. # uri = URI.parse('http://myuser:mypass@my.example.com/test.rbx')
  1396. # p uri.select(:userinfo, :host, :path)
  1397. # # => ["myuser:mypass", "my.example.com", "/test.rbx"]
  1398. #
  1399. def select(*components)
  1400. components.collect do |c|
  1401. if component.include?(c)
  1402. self.send(c)
  1403. else
  1404. raise ArgumentError,
  1405. "expected of components of #{self.class} (#{self.class.component.join(', ')})"
  1406. end
  1407. end
  1408. end
  1409. @@to_s = Kernel.instance_method(:to_s)
  1410. def inspect
  1411. @@to_s.bind(self).call.sub!(/>\z/) {" URL:#{self}>"}
  1412. end
  1413. #
  1414. # == Args
  1415. #
  1416. # +v+::
  1417. # URI or String
  1418. #
  1419. # == Description
  1420. #
  1421. # attempt to parse other URI +oth+
  1422. # return [parsed_oth, self]
  1423. #
  1424. # == Usage
  1425. #
  1426. # require 'uri'
  1427. #
  1428. # uri = URI.parse("http://my.example.com")
  1429. # uri.coerce("http://foo.com")
  1430. # #=> [#<URI::HTTP:0x00000000bcb028 URL:http://foo.com/>, #<URI::HTTP:0x00000000d92178 URL:http://my.example.com>]
  1431. #
  1432. def coerce(oth)
  1433. case oth
  1434. when String
  1435. oth = parser.parse(oth)
  1436. else
  1437. super
  1438. end
  1439. return oth, self
  1440. end
  1441. end
  1442. end