PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/whois/server/adapters/base.rb

http://github.com/weppos/whois
Ruby | 192 lines | 79 code | 30 blank | 83 comment | 13 complexity | b6a9eca05e900a5b6a500fa7fcbb1f71 MD5 | raw file
Possible License(s): MIT
  1. # frozen_string_literal: true
  2. #--
  3. # Ruby Whois
  4. #
  5. # An intelligent pure Ruby WHOIS client and parser.
  6. #
  7. # Copyright (c) 2009-2021 Simone Carletti <weppos@weppos.net>
  8. #++
  9. require 'whois/record/part'
  10. require 'whois/record'
  11. require 'whois/server/socket_handler'
  12. module Whois
  13. class Server
  14. module Adapters
  15. class Base
  16. class << self
  17. def query_handler
  18. @query_handler ||= SocketHandler.new
  19. end
  20. attr_writer :query_handler
  21. end
  22. # Default WHOIS request port.
  23. DEFAULT_WHOIS_PORT = 43
  24. # Default bind hostname.
  25. DEFAULT_BIND_HOST = "0.0.0.0"
  26. # @return [Symbol] The type of WHOIS server.
  27. attr_reader :type
  28. # @return [String] The allocation this server is responsible for.
  29. attr_reader :allocation
  30. # @return [String, nil] The server hostname.
  31. attr_reader :host
  32. # @return [Hash] Optional adapter properties.
  33. attr_reader :options
  34. # Temporary internal response buffer.
  35. #
  36. # @api private
  37. # @return [Array]
  38. attr_reader :buffer
  39. # @param [Symbol] type
  40. # The type of WHOIS adapter to define.
  41. # Known values are :tld, :ipv4, :ipv6.
  42. # @param [String] allocation
  43. # The allocation, range or hostname, this server is responsible for.
  44. # @param [String, nil] host
  45. # The server hostname. Use nil if unknown or not available.
  46. # @param [Hash] options Optional adapter properties.
  47. #
  48. def initialize(type, allocation, host, options = {})
  49. @type = type
  50. @allocation = allocation
  51. @host = host
  52. @options = options || {}
  53. end
  54. # Checks self and other for equality.
  55. #
  56. # @param [The Whois::Server::Adapters::Base] other
  57. # @return [Boolean] Returns true if the other is the same object,
  58. # or <tt>other</tt> attributes matches this object attributes.
  59. #
  60. def ==(other)
  61. (
  62. self.equal?(other)
  63. ) || (
  64. other.is_a?(self.class) &&
  65. self.type == other.type &&
  66. self.allocation == other.allocation &&
  67. self.host == other.host &&
  68. self.options == other.options
  69. )
  70. end
  71. alias_method :eql?, :==
  72. # Merges given +settings+ into current {#options}.
  73. #
  74. # @param [Hash] settings
  75. # @return [Hash] The updated options for this object.
  76. #
  77. def configure(settings)
  78. @host = settings[:host] if settings[:host]
  79. options.merge!(settings)
  80. end
  81. # Performs a Whois lookup for <tt>string</tt>
  82. # using the current server adapter.
  83. #
  84. # Internally, this method calls {#request}
  85. # using the Template Method design pattern.
  86. #
  87. # server.lookup("google.com")
  88. # # => Whois::Record
  89. #
  90. # @param [String] string The string to be sent as query parameter.
  91. # @return [Whois::Record]
  92. #
  93. def lookup(string)
  94. buffer_start do |buffer|
  95. request(string)
  96. Whois::Record.new(self, buffer.dup)
  97. end
  98. end
  99. # Performs the real WHOIS request.
  100. #
  101. # This method is not implemented in {Whois::Server::Adapters::Base} class,
  102. # it is intended to be overwritten in the concrete subclasses.
  103. # This is the heart of the Template Method design pattern.
  104. #
  105. # @param [String] string The string to be sent as query parameter.
  106. # @return [void]
  107. # @raise [NotImplementedError]
  108. # @abstract
  109. #
  110. def request(string)
  111. raise NotImplementedError
  112. end
  113. # Gets the current query handler for this class.
  114. #
  115. # @see Whois::Servers::Adapters::Base.query_handler
  116. #
  117. # @return [Object] the query handler
  118. def query_handler
  119. self.class.query_handler
  120. end
  121. private
  122. def buffer_append(body, host)
  123. @buffer << Whois::Record::Part.new(body: body, host: host)
  124. end
  125. def buffer_start
  126. @buffer ||= []
  127. yield(@buffer)
  128. ensure
  129. @buffer.clear
  130. end
  131. # Prepares and passes the query to the {#query_handler}.
  132. #
  133. # @param [String] query
  134. # @param [String] host
  135. # @param [String] port
  136. # @return [String]
  137. #
  138. def query(query, host, port = nil)
  139. args = []
  140. args.push(host)
  141. args.push(port || options[:port] || DEFAULT_WHOIS_PORT)
  142. # This is a hack to prevent +TCPSocket.new+ to crash
  143. # when resolv-replace.rb file is required.
  144. #
  145. # +TCPSocket.new+ defaults +local_host+ and +local_port+ to nil
  146. # but when you require resolv-replace.rb, +local_host+
  147. # is resolved when you pass any local parameter and in case of nil
  148. # it raises the following error
  149. #
  150. # ArgumentError: cannot interpret as DNS name: nil
  151. #
  152. if options[:bind_host] || options[:bind_port]
  153. args.push(options[:bind_host] || DEFAULT_BIND_HOST)
  154. args.push(options[:bind_port]) if options[:bind_port]
  155. end
  156. self.class.query_handler.call(query, *args)
  157. end
  158. alias :query_the_socket :query
  159. end
  160. end
  161. end
  162. end