Class: HTTPX::Options

Inherits:
Object
  • Object
show all
Defined in:
lib/httpx/options.rb

Overview

Contains a set of options which are passed and shared across from session to its requests or responses.

Constant Summary collapse

BUFFER_SIZE =
1 << 14
WINDOW_SIZE =

16K

1 << 14
MAX_BODY_THRESHOLD_SIZE =

112K

(1 << 10) * 112
KEEP_ALIVE_TIMEOUT =
20
SETTINGS_TIMEOUT =
10
CLOSE_HANDSHAKE_TIMEOUT =
10
CONNECT_TIMEOUT =
READ_TIMEOUT = WRITE_TIMEOUT = 60
REQUEST_TIMEOUT =
OPERATION_TIMEOUT = nil
DEFAULT_OPTIONS =
{
  :max_requests => Float::INFINITY,
  :debug => nil,
  :debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
  :ssl => EMPTY_HASH,
  :http2_settings => { settings_enable_push: 0 }.freeze,
  :fallback_protocol => "http/1.1",
  :supported_compression_formats => %w[gzip deflate],
  :decompress_response_body => true,
  :compress_request_body => true,
  :timeout => {
    connect_timeout: CONNECT_TIMEOUT,
    settings_timeout: SETTINGS_TIMEOUT,
    close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
    operation_timeout: OPERATION_TIMEOUT,
    keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
    read_timeout: READ_TIMEOUT,
    write_timeout: WRITE_TIMEOUT,
    request_timeout: REQUEST_TIMEOUT,
  },
  :headers_class => Class.new(Headers),
  :headers => {},
  :window_size => WINDOW_SIZE,
  :buffer_size => BUFFER_SIZE,
  :body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
  :request_class => Class.new(Request),
  :response_class => Class.new(Response),
  :request_body_class => Class.new(Request::Body),
  :response_body_class => Class.new(Response::Body),
  :pool_class => Class.new(Pool),
  :connection_class => Class.new(Connection),
  :options_class => Class.new(self),
  :transport => nil,
  :addresses => nil,
  :persistent => false,
  :resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
  :resolver_options => { cache: true }.freeze,
  :pool_options => EMPTY_HASH,
  :ip_families => ip_address_families,
}.freeze
REQUEST_BODY_IVARS =
%i[@headers].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Options

creates a new options instance from a given hash, which optionally define the following:

:debug

an object which log messages are written to (must respond to <<)

:debug_level

the log level of messages (can be 1, 2, or 3).

:ssl

a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::IO::SSL)

:http2_settings

a hash of options to be passed to a HTTP2::Connection (ex: { max_concurrent_streams: 2 })

:fallback_protocol

version of HTTP protocol to use by default in the absence of protocol negotiation like ALPN (defaults to "http/1.1")

:supported_compression_formats

list of compressions supported by the transcoder layer (defaults to %w[gzip deflate]).

:decompress_response_body

whether to auto-decompress response body (defaults to true).

:compress_request_body

whether to auto-decompress response body (defaults to true)

:timeout

hash of timeout configurations (supports :connect_timeout, :settings_timeout, :operation_timeout, :keep_alive_timeout, :read_timeout, :write_timeout and :request_timeout

:headers

hash of HTTP headers (ex: { "x-custom-foo" => "bar" })

:window_size

number of bytes to read from a socket

:buffer_size

internal read and write buffer size in bytes

:body_threshold_size

maximum size in bytes of response payload that is buffered in memory.

:request_class

class used to instantiate a request

:response_class

class used to instantiate a response

:headers_class

class used to instantiate headers

:request_body_class

class used to instantiate a request body

:response_body_class

class used to instantiate a response body

:connection_class

class used to instantiate connections

:pool_class

class used to instantiate the session connection pool

:options_class

class used to instantiate options

:transport

type of transport to use (set to “unix” for UNIX sockets)

:addresses

bucket of peer addresses (can be a list of IP addresses, a hash of domain to list of adddresses; paths should be used for UNIX sockets instead)

:io

open socket, or domain/ip-to-socket hash, which requests should be sent to

:persistent

whether to persist connections in between requests (defaults to true)

:resolver_class

which resolver to use (defaults to :native, can also be :system<tt> for using getaddrinfo or <tt>:https for DoH resolver, or a custom class)

:resolver_options

hash of options passed to the resolver. Accepted keys depend on the resolver type.

:pool_options

hash of options passed to the connection pool (See Pool#initialize).

:ip_families

which socket families are supported (system-dependent)

:origin

HTTP origin to set on requests with relative path (ex: “api.serv.com”)

:base_path

path to prefix given relative paths with (ex: “/v2”)

:max_concurrent_requests

max number of requests which can be set concurrently

:max_requests

max number of requests which can be made on socket before it reconnects.

This list of options are enhanced with each loaded plugin, see the plugin docs for details.



133
134
135
136
# File 'lib/httpx/options.rb', line 133

def initialize(options = {})
  do_initialize(options)
  freeze
end

Class Method Details

.method_added(meth) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/httpx/options.rb', line 80

def method_added(meth)
  super

  return unless meth =~ /^option_(.+)$/

  optname = Regexp.last_match(1).to_sym

  attr_reader(optname)
end

.new(options = {}) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/httpx/options.rb', line 72

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

Instance Method Details

#==(other) ⇒ Object



235
236
237
# File 'lib/httpx/options.rb', line 235

def ==(other)
  super || options_equals?(other)
end

#extend_with_plugin_classes(pl) ⇒ Object



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/httpx/options.rb', line 296

def extend_with_plugin_classes(pl)
  if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
    @request_class = @request_class.dup
    @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
    @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
  end
  if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
    @response_class = @response_class.dup
    @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
    @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
  end
  if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
    @headers_class = @headers_class.dup
    @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
    @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
  end
  if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
    @request_body_class = @request_body_class.dup
    @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
    @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
  end
  if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
    @response_body_class = @response_body_class.dup
    @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
    @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
  end
  if defined?(pl::PoolMethods)
    @pool_class = @pool_class.dup
    @pool_class.__send__(:include, pl::PoolMethods)
  end
  if defined?(pl::ConnectionMethods)
    @connection_class = @connection_class.dup
    @connection_class.__send__(:include, pl::ConnectionMethods)
  end
  return unless defined?(pl::OptionsMethods)

  @options_class = @options_class.dup
  @options_class.__send__(:include, pl::OptionsMethods)
end

#freezeObject



138
139
140
141
142
143
144
145
146
# File 'lib/httpx/options.rb', line 138

def freeze
  super
  @origin.freeze
  @base_path.freeze
  @timeout.freeze
  @headers.freeze
  @addresses.freeze
  @supported_compression_formats.freeze
end

#merge(other) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/httpx/options.rb', line 254

def merge(other)
  ivar_map = nil
  other_ivars = case other
                when Hash
                  ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
                  ivar_map.keys
                else
                  other.instance_variables
  end

  return self if other_ivars.empty?

  return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == access_option(other, ivar, ivar_map) }

  opts = dup

  other_ivars.each do |ivar|
    v = access_option(other, ivar, ivar_map)

    unless v
      opts.instance_variable_set(ivar, v)
      next
    end

    v = opts.__send__(:"option_#{ivar[1..-1]}", v)

    orig_v = instance_variable_get(ivar)

    v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)

    opts.instance_variable_set(ivar, v)
  end

  opts
end

#option_addresses(value) ⇒ Object



210
211
212
# File 'lib/httpx/options.rb', line 210

def option_addresses(value)
  Array(value)
end

#option_base_path(value) ⇒ Object



152
153
154
# File 'lib/httpx/options.rb', line 152

def option_base_path(value)
  String(value)
end

#option_body_threshold_size(value) ⇒ Object

Raises:

  • (TypeError)


196
197
198
199
200
201
# File 'lib/httpx/options.rb', line 196

def option_body_threshold_size(value)
  bytes = Integer(value)
  raise TypeError, ":body_threshold_size must be positive" unless bytes.positive?

  bytes
end

#option_buffer_size(value) ⇒ Object

Raises:

  • (TypeError)


188
189
190
191
192
193
194
# File 'lib/httpx/options.rb', line 188

def option_buffer_size(value)
  value = Integer(value)

  raise TypeError, ":buffer_size must be positive" unless value.positive?

  value
end

#option_headers(value) ⇒ Object



156
157
158
# File 'lib/httpx/options.rb', line 156

def option_headers(value)
  headers_class.new(value)
end

#option_ip_families(value) ⇒ Object



214
215
216
# File 'lib/httpx/options.rb', line 214

def option_ip_families(value)
  Array(value)
end

#option_max_concurrent_requests(value) ⇒ Object

Raises:

  • (TypeError)


168
169
170
171
172
# File 'lib/httpx/options.rb', line 168

def option_max_concurrent_requests(value)
  raise TypeError, ":max_concurrent_requests must be positive" unless value.positive?

  value
end

#option_max_requests(value) ⇒ Object

Raises:

  • (TypeError)


174
175
176
177
178
# File 'lib/httpx/options.rb', line 174

def option_max_requests(value)
  raise TypeError, ":max_requests must be positive" unless value.positive?

  value
end

#option_origin(value) ⇒ Object



148
149
150
# File 'lib/httpx/options.rb', line 148

def option_origin(value)
  URI(value)
end

#option_supported_compression_formats(value) ⇒ Object



164
165
166
# File 'lib/httpx/options.rb', line 164

def option_supported_compression_formats(value)
  Array(value).map(&:to_s)
end

#option_timeout(value) ⇒ Object



160
161
162
# File 'lib/httpx/options.rb', line 160

def option_timeout(value)
  Hash[value]
end

#option_transport(value) ⇒ Object

Raises:

  • (TypeError)


203
204
205
206
207
208
# File 'lib/httpx/options.rb', line 203

def option_transport(value)
  transport = value.to_s
  raise TypeError, "#{transport} is an unsupported transport type" unless %w[unix].include?(transport)

  transport
end

#option_window_size(value) ⇒ Object

Raises:

  • (TypeError)


180
181
182
183
184
185
186
# File 'lib/httpx/options.rb', line 180

def option_window_size(value)
  value = Integer(value)

  raise TypeError, ":window_size must be positive" unless value.positive?

  value
end

#options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS) ⇒ Boolean

Returns:

  • (Boolean)


239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/httpx/options.rb', line 239

def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
  # headers and other request options do not play a role, as they are
  # relevant only for the request.
  ivars = instance_variables - ignore_ivars
  other_ivars = other.instance_variables - ignore_ivars

  return false if ivars.size != other_ivars.size

  return false if ivars.sort != other_ivars.sort

  ivars.all? do |ivar|
    instance_variable_get(ivar) == other.instance_variable_get(ivar)
  end
end

#to_hashObject



290
291
292
293
294
# File 'lib/httpx/options.rb', line 290

def to_hash
  instance_variables.each_with_object({}) do |ivar, hs|
    hs[ivar[1..-1].to_sym] = instance_variable_get(ivar)
  end
end