summaryrefslogtreecommitdiff
path: root/lib/net/hippie.rb
blob: 79fe058453a055a3a9f7e458c42c9b36ae10e3c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# frozen_string_literal: true

require 'base64'
require 'json'
require 'logger'
require 'monitor'
require 'net/http'
require 'openssl'
require 'resolv'
require 'timeout'

require 'net/hippie/version'
require 'net/hippie/client'
require 'net/hippie/connection'
require 'net/hippie/connection_pool'
require 'net/hippie/content_type_mapper'

module Net
  # High-performance HTTP client with connection pooling and DNS caching.
  module Hippie
    CONNECTION_ERRORS = [
      EOFError,
      Errno::ECONNREFUSED,
      Errno::ECONNRESET,
      Errno::EHOSTUNREACH,
      Errno::EINVAL,
      Errno::EPIPE,
      Errno::ECONNABORTED,
      Errno::ETIMEDOUT,
      IOError,
      Net::OpenTimeout,
      Net::ProtocolError,
      Net::ReadTimeout,
      Net::WriteTimeout,
      OpenSSL::OpenSSLError,
      OpenSSL::SSL::SSLError,
      SocketError,
      Timeout::Error
    ].freeze

    BASIC_PREFIX = 'Basic '
    BEARER_PREFIX = 'Bearer '

    class << self
      attr_writer :logger, :verify_mode

      def logger
        @logger ||= Logger.new(nil)
      end

      def verify_mode
        @verify_mode ||= OpenSSL::SSL::VERIFY_PEER
      end

      def basic_auth(username, password)
        BASIC_PREFIX + ::Base64.strict_encode64("#{username}:#{password}")
      end

      def bearer_auth(token)
        BEARER_PREFIX + token
      end

      def default_client
        @default_client ||= Client.new(follow_redirects: 3, logger: logger)
      end

      def reset_default_client!
        @default_client = nil
      end

      %i[get post put patch delete head options].each do |method|
        define_method(method) do |*args, **kwargs, &block|
          default_client.with_retry(retries: 3) { |c| c.public_send(method, *args, **kwargs, &block) }
        end
      end

      def resolve(hostname, timeout: 5)
        Timeout.timeout(timeout) do
          addresses = Resolv.getaddresses(hostname)
          addresses.find { |a| a.match?(/^\d+\.\d+\.\d+\.\d+$/) } || addresses.first
        end
      end
    end
  end
end