httpx/lib/httpx/options.rb

137 lines
3.8 KiB
Ruby

# frozen_string_literal: true
module HTTPX
class Options
MAX_CONCURRENT_REQUESTS = 100
MAX_RETRIES = 3
WINDOW_SIZE = 1 << 14 # 16K
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
class << self
def inherited(klass)
super
klass.instance_variable_set(:@defined_options, @defined_options.dup)
end
def new(options = {})
# let enhanced options go through
return options if self == Options && options.class > self
return options if options.is_a?(self)
super
end
def defined_options
@defined_options ||= []
end
def def_option(name, &interpreter)
defined_options << name.to_sym
interpreter ||= lambda { |v| v }
attr_accessor name
protected :"#{name}="
define_method(:"with_#{name}") do |value|
dup { |opts| opts.send(:"#{name}=", instance_exec(value, &interpreter)) }
end
end
end
def initialize(options = {})
defaults = {
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
:ssl => { alpn_protocols: %w[h2 http/1.1] },
:http2_settings => { settings_enable_push: 0 },
:fallback_protocol => "http/1.1",
:timeout => Timeout.by(:per_operation),
:headers => {},
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
:max_retries => MAX_RETRIES,
:window_size => WINDOW_SIZE,
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
:request_class => Class.new(Request),
:response_class => Class.new(Response),
:headers_class => Class.new(Headers),
:response_body_class => Class.new(Response::Body),
}
defaults.merge!(options)
defaults[:headers] = Headers.new(defaults[:headers])
defaults.each { |(k, v)| self[k] = v }
end
def_option(:headers) do |headers|
self.headers.merge(headers)
end
def_option(:timeout) do |type, opts|
self.timeout = Timeout.by(type, opts)
end
def_option(:max_concurrent_requests) do |num|
max = Integer(num)
raise Error, ":max_concurrent_requests must be positive" unless max.positive?
self.max_concurrent_requests = max
end
def_option(:window_size) do |num|
self.window_size = Integer(num)
end
def_option(:body_threshold_size) do |num|
self.body_threshold_size = Integer(num)
end
%w[
params form json body
follow ssl http2_settings max_retries
request_class response_class headers_class response_body_class
io fallback_protocol debug debug_level
].each do |method_name|
def_option(method_name)
end
def merge(other)
h1 = to_hash
h2 = other.to_hash
merged = h1.merge(h2) do |k, v1, v2|
case k
when :headers, :ssl, :http2_settings
v1.merge(v2)
else
v2
end
end
self.class.new(merged)
end
def to_hash
hash_pairs = self.class.
defined_options.
flat_map { |opt_name| [opt_name, send(opt_name)] }
Hash[*hash_pairs]
end
def dup
dupped = super
dupped.headers = headers.dup
dupped.ssl = ssl.dup
dupped.request_class = request_class.dup
dupped.response_class = response_class.dup
dupped.headers_class = headers_class.dup
dupped.response_body_class = response_body_class.dup
yield(dupped) if block_given?
dupped
end
protected
def []=(option, val)
send(:"#{option}=", val)
end
end
end