main
1# frozen_string_literal: true
2
3require 'base64'
4require 'json'
5require 'logger'
6require 'monitor'
7require 'net/http'
8require 'openssl'
9require 'resolv'
10require 'timeout'
11
12require 'net/hippie/version'
13require 'net/hippie/client'
14require 'net/hippie/connection'
15require 'net/hippie/connection_pool'
16require 'net/hippie/content_type_mapper'
17
18module Net
19 # High-performance HTTP client with connection pooling and DNS caching.
20 module Hippie
21 CONNECTION_ERRORS = [
22 EOFError,
23 Errno::ECONNREFUSED,
24 Errno::ECONNRESET,
25 Errno::EHOSTUNREACH,
26 Errno::EINVAL,
27 Errno::EPIPE,
28 Errno::ECONNABORTED,
29 Errno::ETIMEDOUT,
30 IOError,
31 Net::OpenTimeout,
32 Net::ProtocolError,
33 Net::ReadTimeout,
34 Net::WriteTimeout,
35 OpenSSL::OpenSSLError,
36 OpenSSL::SSL::SSLError,
37 SocketError,
38 Timeout::Error
39 ].freeze
40
41 BASIC_PREFIX = 'Basic '
42 BEARER_PREFIX = 'Bearer '
43
44 class << self
45 attr_writer :logger, :verify_mode
46
47 def logger
48 @logger ||= Logger.new(nil)
49 end
50
51 def verify_mode
52 @verify_mode ||= OpenSSL::SSL::VERIFY_PEER
53 end
54
55 def basic_auth(username, password)
56 BASIC_PREFIX + ::Base64.strict_encode64("#{username}:#{password}")
57 end
58
59 def bearer_auth(token)
60 BEARER_PREFIX + token
61 end
62
63 def default_client
64 @default_client ||= Client.new(follow_redirects: 3, logger: logger)
65 end
66
67 def reset_default_client!
68 @default_client = nil
69 end
70
71 %i[get post put patch delete head options].each do |method|
72 define_method(method) do |*args, **kwargs, &block|
73 default_client.with_retry(retries: 3) { |c| c.public_send(method, *args, **kwargs, &block) }
74 end
75 end
76
77 def resolve(hostname, timeout: 5)
78 Timeout.timeout(timeout) do
79 addresses = Resolv.getaddresses(hostname)
80 addresses.find { |a| a.match?(/^\d+\.\d+\.\d+\.\d+$/) } || addresses.first
81 end
82 end
83 end
84 end
85end