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, :max_response_headers => 1000, :max_response_header_value_size => nil, :max_response_body_size => Float::INFINITY, :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, ping_timeout: PING_TIMEOUT, read_timeout: READ_TIMEOUT, write_timeout: WRITE_TIMEOUT, request_timeout: REQUEST_TIMEOUT, total_request_timeout: TOTAL_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  
PING_TIMEOUT = 2  
REQUEST_BODY_IVARS = %i[@headers].freeze  
REQUEST_TIMEOUT = OPERATION_TIMEOUT = TOTAL_REQUEST_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, :request_timeout, :total_request_timeout and :ping_timeout,

:headers

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

:max_response_body_size

maximum size (in bytes) that the response body can consume (no threshold by default), after which an error is raised.

:max_response_headers

maximum number of header fields that a response can receive, after which an error is raised.

:max_response_header_value_size

maximum size (in bytes) a header value can have (no threshold by default). for cases where the value is broken into multiple header fields (such as “cookie” or “set-cookie”), this is the total aggregated size.

: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
128 def initialize(options = EMPTY_HASH)
129   options_names = self.class.options_names
130 
131   defaults =
132     case options
133     when Options
134       unknown_options = options.class.options_names - options_names
135 
136       raise Error, "unknown option: #{unknown_options.first}" unless unknown_options.empty?
137 
138       DEFAULT_OPTIONS.merge(options)
139     else
140       options.each_key do |k|
141         raise Error, "unknown option: #{k}" unless options_names.include?(k)
142       end
143 
144       options.empty? ? DEFAULT_OPTIONS : DEFAULT_OPTIONS.merge(options)
145     end
146 
147   options_names.each do |k|
148     v = defaults[k]
149 
150     if v.nil?
151       instance_variable_set(:"@#{k}", v)
152 
153       next
154     end
155 
156     value = __send__(:"option_#{k}", v)
157     instance_variable_set(:"@#{k}", value)
158   end
159 
160   do_initialize
161   freeze
162 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
212 def connection_options_match?(other, ignore_ivars = nil)
213   return true if self == other
214 
215   # headers and other request options do not play a role, as they are
216   # relevant only for the request.
217   ivars = instance_variables
218   ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
219   ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
220 
221   other_ivars = other.instance_variables
222   other_ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
223   other_ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
224 
225   return false if ivars.size != other_ivars.size
226 
227   return false if ivars.sort != other_ivars.sort
228 
229   ivars.all? do |ivar|
230     instance_variable_get(ivar) == other.instance_variable_get(ivar)
231   end
232 end
extend_with_plugin_classes(pl)
[show source]
    # File lib/httpx/options.rb
303 def extend_with_plugin_classes(pl)
304   # extend request class
305   if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
306     @request_class = @request_class.dup
307     SET_TEMPORARY_NAME[@request_class, pl]
308     @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
309     @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
310   end
311   # extend response class
312   if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
313     @response_class = @response_class.dup
314     SET_TEMPORARY_NAME[@response_class, pl]
315     @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
316     @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
317   end
318   # extend headers class
319   if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
320     @headers_class = @headers_class.dup
321     SET_TEMPORARY_NAME[@headers_class, pl]
322     @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
323     @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
324   end
325   # extend request body class
326   if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
327     @request_body_class = @request_body_class.dup
328     SET_TEMPORARY_NAME[@request_body_class, pl]
329     @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
330     @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
331   end
332   # extend response body class
333   if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
334     @response_body_class = @response_body_class.dup
335     SET_TEMPORARY_NAME[@response_body_class, pl]
336     @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
337     @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
338   end
339   # extend connection pool class
340   if defined?(pl::PoolMethods)
341     @pool_class = @pool_class.dup
342     SET_TEMPORARY_NAME[@pool_class, pl]
343     @pool_class.__send__(:include, pl::PoolMethods)
344   end
345   # extend connection class
346   if defined?(pl::ConnectionMethods)
347     @connection_class = @connection_class.dup
348     SET_TEMPORARY_NAME[@connection_class, pl]
349     @connection_class.__send__(:include, pl::ConnectionMethods)
350   end
351   # extend http1 class
352   if defined?(pl::HTTP1Methods)
353     @http1_class = @http1_class.dup
354     SET_TEMPORARY_NAME[@http1_class, pl]
355     @http1_class.__send__(:include, pl::HTTP1Methods)
356   end
357   # extend http2 class
358   if defined?(pl::HTTP2Methods)
359     @http2_class = @http2_class.dup
360     SET_TEMPORARY_NAME[@http2_class, pl]
361     @http2_class.__send__(:include, pl::HTTP2Methods)
362   end
363   # extend native resolver class
364   if defined?(pl::ResolverNativeMethods)
365     @resolver_native_class = @resolver_native_class.dup
366     SET_TEMPORARY_NAME[@resolver_native_class, pl]
367     @resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
368   end
369   # extend system resolver class
370   if defined?(pl::ResolverSystemMethods)
371     @resolver_system_class = @resolver_system_class.dup
372     SET_TEMPORARY_NAME[@resolver_system_class, pl]
373     @resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
374   end
375   # extend https resolver class
376   if defined?(pl::ResolverHTTPSMethods)
377     @resolver_https_class = @resolver_https_class.dup
378     SET_TEMPORARY_NAME[@resolver_https_class, pl]
379     @resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
380   end
381 
382   return unless defined?(pl::OptionsMethods)
383 
384   # extend option class
385   # works around lack of initialize_dup callback
386   @options_class = @options_class.dup
387   # (self.class.options_names)
388   @options_class.__send__(:include, pl::OptionsMethods)
389 end
freeze()
[show source]
    # File lib/httpx/options.rb
194 def freeze
195   self.class.options_names.each do |ivar|
196     # avoid freezing debug option, as when it's set, it's usually an
197     # object which cannot be frozen, like stderr or stdout. It's a
198     # documented exception then, and still does not defeat the purpose
199     # here, which is to make option objects shareable across ractors,
200     # and in most cases debug should be nil, or one of the objects
201     # which will eventually be shareable, like STDOUT or STDERR.
202     next if ivar == :debug
203 
204     instance_variable_get(:"@#{ivar}").freeze
205   end
206   super
207 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
249 def merge(other)
250   if (is_options = other.is_a?(Options))
251 
252     return self if eql?(other)
253 
254     opts_names = other.class.options_names
255 
256     return self if opts_names.all? { |opt| public_send(opt) == other.public_send(opt) }
257 
258     other_opts = opts_names
259   else
260     other_opts = other # : Hash[Symbol, untyped]
261     other_opts = Hash[other] unless other.is_a?(Hash)
262 
263     return self if other_opts.empty?
264 
265     return self if other_opts.all? { |opt, v| !respond_to?(opt) || public_send(opt) == v }
266   end
267 
268   opts = dup
269 
270   other_opts.each do |opt, v|
271     next unless respond_to?(opt)
272 
273     v = other.public_send(opt) if is_options
274     ivar = :"@#{opt}"
275 
276     unless v
277       opts.instance_variable_set(ivar, v)
278       next
279     end
280 
281     v = opts.__send__(:"option_#{opt}", v)
282 
283     orig_v = public_send(opt)
284 
285     v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
286 
287     opts.instance_variable_set(ivar, v)
288   end
289 
290   opts
291 end
resolver_cache()
[show source]
    # File lib/httpx/options.rb
174 def resolver_cache
175   cache_type = @resolver_cache
176 
177   case cache_type
178   when :memory
179     Resolver::Cache::Memory.cache(cache_type)
180   when :file
181     Resolver::Cache::File.cache(cache_type)
182   else
183     unless cache_type.respond_to?(:resolve) &&
184            cache_type.respond_to?(:get) &&
185            cache_type.respond_to?(:set) &&
186            cache_type.respond_to?(:evict)
187       raise TypeError, ":resolver_cache must be a compatible resolver cache and implement #get, #set and #evict"
188     end
189 
190     cache_type #: Object & Resolver::_Cache
191   end
192 end
resolver_class()

returns the class with which to instantiate the DNS resolver.

[show source]
    # File lib/httpx/options.rb
165 def resolver_class
166   case @resolver_class
167   when Symbol
168     public_send(:"resolver_#{@resolver_class}_class")
169   else
170     @resolver_class
171   end
172 end
resolver_options_match?(other)

checks whether other matches the same resolver-level options

[show source]
    # File lib/httpx/options.rb
240 def resolver_options_match?(other)
241   self == other ||
242     RESOLVER_IVARS.all? do |ivar|
243       instance_variable_get(ivar) == other.instance_variable_get(ivar)
244     end
245 end
to_hash()
[show source]
    # File lib/httpx/options.rb
293 def to_hash
294   instance_variables.each_with_object({}) do |ivar, hs|
295     val = instance_variable_get(ivar)
296 
297     next if val.nil?
298 
299     hs[ivar[1..-1].to_sym] = val
300   end
301 end