class HTTPX::Options

  1. lib/httpx/options.rb
  2. lib/httpx/plugins/stream.rb
  3. lib/httpx/transcoder/utils/deflater.rb
  4. show all
Superclass: Object

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

Constants

BUFFER_SIZE = 1 << 14  
CLOSE_HANDSHAKE_TIMEOUT = 10  
CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60  
DEFAULT_OPTIONS = { :max_requests => Float::INFINITY, :debug => nil, :debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i, :debug_redact => ENV.key?("HTTPX_DEBUG_REDACT"), :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, }.freeze, :headers_class => Class.new(Headers, &SET_TEMPORARY_NAME), :headers => EMPTY_HASH, :window_size => WINDOW_SIZE, :buffer_size => BUFFER_SIZE, :body_threshold_size => MAX_BODY_THRESHOLD_SIZE, :request_class => Class.new(Request, &SET_TEMPORARY_NAME), :response_class => Class.new(Response, &SET_TEMPORARY_NAME), :request_body_class => Class.new(Request::Body, &SET_TEMPORARY_NAME), :response_body_class => Class.new(Response::Body, &SET_TEMPORARY_NAME), :pool_class => Class.new(Pool, &SET_TEMPORARY_NAME), :connection_class => Class.new(Connection, &SET_TEMPORARY_NAME), :http1_class => Class.new(Connection::HTTP1, &SET_TEMPORARY_NAME), :http2_class => Class.new(Connection::HTTP2, &SET_TEMPORARY_NAME), :resolver_native_class => Class.new(Resolver::Native, &SET_TEMPORARY_NAME), :resolver_system_class => Class.new(Resolver::System, &SET_TEMPORARY_NAME), :resolver_https_class => Class.new(Resolver::HTTPS, &SET_TEMPORARY_NAME), :options_class => Class.new(self, &SET_TEMPORARY_NAME), :transport => nil, :addresses => nil, :persistent => false, :resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym, :resolver_cache => (ENV["HTTPX_RESOLVER_CACHE"] || :memory).to_sym, :resolver_options => { cache: true }.freeze, :pool_options => EMPTY_HASH, :ip_families => nil, :close_on_fork => false, }.each_value(&:freeze).freeze  
KEEP_ALIVE_TIMEOUT = 20  
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112  
REQUEST_BODY_IVARS = %i[@headers].freeze  
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil  
RESOLVER_IVARS = %i[ @resolver_class @resolver_cache @resolver_options @resolver_native_class @resolver_system_class @resolver_https_class ].freeze  
RESOLVER_TYPES = %i[memory file].freeze  
SETTINGS_TIMEOUT = 10  
SET_TEMPORARY_NAME = ->(klass, pl = nil) do if klass.respond_to?(:set_temporary_name) # ruby 3.4 only name = klass.name || "#{klass.superclass.name}(plugin)" name = "#{name}/#{pl}" if pl klass.set_temporary_name(name) end end  

rubocop:disable Lint/UselessConstantScoping these really need to be defined at the end of the class

USER_AGENT = "httpx.rb/#{VERSION}".freeze  

default value used for “user-agent” header, when not overridden.

WINDOW_SIZE = 1 << 14  

Attributes

Public Class methods

freeze()
[show source]
   # File lib/httpx/options.rb
38 def freeze
39   @options_names.freeze
40   super
41 end
inherited(klass)
[show source]
   # File lib/httpx/options.rb
25 def inherited(klass)
26   super
27   klass.instance_variable_set(:@options_names, @options_names.dup)
28 end
method_added(meth)
[show source]
   # File lib/httpx/options.rb
43 def method_added(meth)
44   super
45 
46   return unless meth =~ /^option_(.+)$/
47 
48   optname = Regexp.last_match(1) #: String
49 
50   if optname =~ /^(.+[^_])_+with/
51     # ignore alias method chain generated methods.
52     # this is the case with RBS runtime tests.
53     # it relies on the "_with/_without" separator, which is the most used convention,
54     # however it shouldn't be used in practice in httpx given the plugin architecture
55     # as the main extension API.
56     orig_name = Regexp.last_match(1) #: String
57 
58     return if @options_names.include?(orig_name.to_sym)
59   end
60 
61   optname = optname.to_sym
62 
63   attr_reader(optname) unless method_defined?(optname)
64 
65   @options_names << optname unless @options_names.include?(optname)
66 end
new(options = {})
[show source]
   # File lib/httpx/options.rb
30 def new(options = {})
31   # let enhanced options go through
32   return options if self == Options && options.class < self
33   return options if options.is_a?(self)
34 
35   super
36 end
new(options = EMPTY_HASH)

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).

:debug_redact

whether header/body payload should be redacted (defaults to false).

:ssl

a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::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

:http1_class

class used to manage HTTP1 sessions

:http2_class

class used to imanage HTTP2 sessions

:resolver_native_class

class used to resolve names using pure ruby DNS implementation

:resolver_system_class

class used to resolve names using system-based (getaddrinfo) name resolution

:resolver_https_class

class used to resolve names using DoH

: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 inheriting from HTTPX::Resolver::Resolver)

:resolver_cache

strategy to cache DNS results, ignored by the :system resolver, can be set to <tt>:memory<tt> or an instance of a custom class inheriting from HTTPX::Resolver::Cache::Base

: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.

:close_on_fork

whether the session automatically closes when the process is fork (defaults to false). it only works if the session is persistent (and ruby 3.1 or higher is used).

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

[show source]
    # File lib/httpx/options.rb
122 def initialize(options = EMPTY_HASH)
123   options_names = self.class.options_names
124 
125   defaults =
126     case options
127     when Options
128       unknown_options = options.class.options_names - options_names
129 
130       raise Error, "unknown option: #{unknown_options.first}" unless unknown_options.empty?
131 
132       DEFAULT_OPTIONS.merge(options)
133     else
134       options.each_key do |k|
135         raise Error, "unknown option: #{k}" unless options_names.include?(k)
136       end
137 
138       options.empty? ? DEFAULT_OPTIONS : DEFAULT_OPTIONS.merge(options)
139     end
140 
141   options_names.each do |k|
142     v = defaults[k]
143 
144     if v.nil?
145       instance_variable_set(:"@#{k}", v)
146 
147       next
148     end
149 
150     value = __send__(:"option_#{k}", v)
151     instance_variable_set(:"@#{k}", value)
152   end
153 
154   do_initialize
155   freeze
156 end

Public Instance methods

connection_options_match?(other, ignore_ivars = nil)

checks whether other matches the same connection-level options

[show source]
    # File lib/httpx/options.rb
206 def connection_options_match?(other, ignore_ivars = nil)
207   return true if self == other
208 
209   # headers and other request options do not play a role, as they are
210   # relevant only for the request.
211   ivars = instance_variables
212   ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
213   ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
214 
215   other_ivars = other.instance_variables
216   other_ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
217   other_ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
218 
219   return false if ivars.size != other_ivars.size
220 
221   return false if ivars.sort != other_ivars.sort
222 
223   ivars.all? do |ivar|
224     instance_variable_get(ivar) == other.instance_variable_get(ivar)
225   end
226 end
extend_with_plugin_classes(pl)
[show source]
    # File lib/httpx/options.rb
297 def extend_with_plugin_classes(pl)
298   # extend request class
299   if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
300     @request_class = @request_class.dup
301     SET_TEMPORARY_NAME[@request_class, pl]
302     @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
303     @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
304   end
305   # extend response class
306   if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
307     @response_class = @response_class.dup
308     SET_TEMPORARY_NAME[@response_class, pl]
309     @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
310     @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
311   end
312   # extend headers class
313   if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
314     @headers_class = @headers_class.dup
315     SET_TEMPORARY_NAME[@headers_class, pl]
316     @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
317     @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
318   end
319   # extend request body class
320   if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
321     @request_body_class = @request_body_class.dup
322     SET_TEMPORARY_NAME[@request_body_class, pl]
323     @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
324     @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
325   end
326   # extend response body class
327   if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
328     @response_body_class = @response_body_class.dup
329     SET_TEMPORARY_NAME[@response_body_class, pl]
330     @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
331     @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
332   end
333   # extend connection pool class
334   if defined?(pl::PoolMethods)
335     @pool_class = @pool_class.dup
336     SET_TEMPORARY_NAME[@pool_class, pl]
337     @pool_class.__send__(:include, pl::PoolMethods)
338   end
339   # extend connection class
340   if defined?(pl::ConnectionMethods)
341     @connection_class = @connection_class.dup
342     SET_TEMPORARY_NAME[@connection_class, pl]
343     @connection_class.__send__(:include, pl::ConnectionMethods)
344   end
345   # extend http1 class
346   if defined?(pl::HTTP1Methods)
347     @http1_class = @http1_class.dup
348     SET_TEMPORARY_NAME[@http1_class, pl]
349     @http1_class.__send__(:include, pl::HTTP1Methods)
350   end
351   # extend http2 class
352   if defined?(pl::HTTP2Methods)
353     @http2_class = @http2_class.dup
354     SET_TEMPORARY_NAME[@http2_class, pl]
355     @http2_class.__send__(:include, pl::HTTP2Methods)
356   end
357   # extend native resolver class
358   if defined?(pl::ResolverNativeMethods)
359     @resolver_native_class = @resolver_native_class.dup
360     SET_TEMPORARY_NAME[@resolver_native_class, pl]
361     @resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
362   end
363   # extend system resolver class
364   if defined?(pl::ResolverSystemMethods)
365     @resolver_system_class = @resolver_system_class.dup
366     SET_TEMPORARY_NAME[@resolver_system_class, pl]
367     @resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
368   end
369   # extend https resolver class
370   if defined?(pl::ResolverHTTPSMethods)
371     @resolver_https_class = @resolver_https_class.dup
372     SET_TEMPORARY_NAME[@resolver_https_class, pl]
373     @resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
374   end
375 
376   return unless defined?(pl::OptionsMethods)
377 
378   # extend option class
379   # works around lack of initialize_dup callback
380   @options_class = @options_class.dup
381   # (self.class.options_names)
382   @options_class.__send__(:include, pl::OptionsMethods)
383 end
freeze()
[show source]
    # File lib/httpx/options.rb
188 def freeze
189   self.class.options_names.each do |ivar|
190     # avoid freezing debug option, as when it's set, it's usually an
191     # object which cannot be frozen, like stderr or stdout. It's a
192     # documented exception then, and still does not defeat the purpose
193     # here, which is to make option objects shareable across ractors,
194     # and in most cases debug should be nil, or one of the objects
195     # which will eventually be shareable, like STDOUT or STDERR.
196     next if ivar == :debug
197 
198     instance_variable_get(:"@#{ivar}").freeze
199   end
200   super
201 end
merge(other)

returns a HTTPX::Options instance resulting of the merging of other with self. it may return self if other is self or equal to self.

[show source]
    # File lib/httpx/options.rb
243 def merge(other)
244   if (is_options = other.is_a?(Options))
245 
246     return self if eql?(other)
247 
248     opts_names = other.class.options_names
249 
250     return self if opts_names.all? { |opt| public_send(opt) == other.public_send(opt) }
251 
252     other_opts = opts_names
253   else
254     other_opts = other # : Hash[Symbol, untyped]
255     other_opts = Hash[other] unless other.is_a?(Hash)
256 
257     return self if other_opts.empty?
258 
259     return self if other_opts.all? { |opt, v| !respond_to?(opt) || public_send(opt) == v }
260   end
261 
262   opts = dup
263 
264   other_opts.each do |opt, v|
265     next unless respond_to?(opt)
266 
267     v = other.public_send(opt) if is_options
268     ivar = :"@#{opt}"
269 
270     unless v
271       opts.instance_variable_set(ivar, v)
272       next
273     end
274 
275     v = opts.__send__(:"option_#{opt}", v)
276 
277     orig_v = public_send(opt)
278 
279     v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
280 
281     opts.instance_variable_set(ivar, v)
282   end
283 
284   opts
285 end
resolver_cache()
[show source]
    # File lib/httpx/options.rb
168 def resolver_cache
169   cache_type = @resolver_cache
170 
171   case cache_type
172   when :memory
173     Resolver::Cache::Memory.cache(cache_type)
174   when :file
175     Resolver::Cache::File.cache(cache_type)
176   else
177     unless cache_type.respond_to?(:resolve) &&
178            cache_type.respond_to?(:get) &&
179            cache_type.respond_to?(:set) &&
180            cache_type.respond_to?(:evict)
181       raise TypeError, ":resolver_cache must be a compatible resolver cache and implement #get, #set and #evict"
182     end
183 
184     cache_type #: Object & Resolver::_Cache
185   end
186 end
resolver_class()

returns the class with which to instantiate the DNS resolver.

[show source]
    # File lib/httpx/options.rb
159 def resolver_class
160   case @resolver_class
161   when Symbol
162     public_send(:"resolver_#{@resolver_class}_class")
163   else
164     @resolver_class
165   end
166 end
resolver_options_match?(other)

checks whether other matches the same resolver-level options

[show source]
    # File lib/httpx/options.rb
234 def resolver_options_match?(other)
235   self == other ||
236     RESOLVER_IVARS.all? do |ivar|
237       instance_variable_get(ivar) == other.instance_variable_get(ivar)
238     end
239 end
to_hash()
[show source]
    # File lib/httpx/options.rb
287 def to_hash
288   instance_variables.each_with_object({}) do |ivar, hs|
289     val = instance_variable_get(ivar)
290 
291     next if val.nil?
292 
293     hs[ivar[1..-1].to_sym] = val
294   end
295 end