class HTTPX::Options

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

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

Classes and Modules

  1. HTTPX::Options::Timeouts

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 => Timeouts.new, :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  
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
37 def freeze
38   @options_names.freeze
39   super
40 end
inherited(klass)
[show source]
   # File lib/httpx/options.rb
24 def inherited(klass)
25   super
26   klass.instance_variable_set(:@options_names, @options_names.dup)
27 end
method_added(meth)
[show source]
   # File lib/httpx/options.rb
42 def method_added(meth)
43   super
44 
45   return unless meth =~ /^option_(.+)$/
46 
47   optname = Regexp.last_match(1) #: String
48 
49   if optname =~ /^(.+[^_])_+with/
50     # ignore alias method chain generated methods.
51     # this is the case with RBS runtime tests.
52     # it relies on the "_with/_without" separator, which is the most used convention,
53     # however it shouldn't be used in practice in httpx given the plugin architecture
54     # as the main extension API.
55     orig_name = Regexp.last_match(1) #: String
56 
57     return if @options_names.include?(orig_name.to_sym)
58   end
59 
60   optname = optname.to_sym
61 
62   attr_reader(optname) unless method_defined?(optname)
63 
64   @options_names << optname unless @options_names.include?(optname)
65 end
new(options = {})
[show source]
   # File lib/httpx/options.rb
29 def new(options = {})
30   # let enhanced options go through
31   return options if self == Options && options.class < self
32   return options if options.is_a?(self)
33 
34   super
35 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
127 def initialize(options = EMPTY_HASH)
128   options_names = self.class.options_names
129 
130   defaults =
131     case options
132     when Options
133       unknown_options = options.class.options_names - options_names
134 
135       raise Error, "unknown option: `:#{unknown_options.first}`" unless unknown_options.empty?
136 
137       DEFAULT_OPTIONS.merge(options)
138     else
139       options.each_key do |k|
140         raise Error, "unknown option: `:#{k}`" unless options_names.include?(k)
141       end
142 
143       options.empty? ? DEFAULT_OPTIONS : DEFAULT_OPTIONS.merge(options)
144     end
145 
146   options_names.each do |k|
147     v = defaults[k]
148 
149     if v.nil?
150       instance_variable_set(:"@#{k}", v)
151 
152       next
153     end
154 
155     value = __send__(:"option_#{k}", v)
156     instance_variable_set(:"@#{k}", value)
157   end
158 
159   do_initialize
160   freeze
161 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
211 def connection_options_match?(other, ignore_ivars = nil)
212   return true if self == other
213 
214   # headers and other request options do not play a role, as they are
215   # relevant only for the request.
216   ivars = self.class.options_names.reject { |iv| REQUEST_BODY_IVARS.include?(iv) }
217   ivars = ivars.reject { |iv| ignore_ivars.include?(iv) } if ignore_ivars
218 
219   other_ivars = other.class.options_names.reject { |iv| REQUEST_BODY_IVARS.include?(iv) }
220   other_ivars = other_ivars.reject { |iv| ignore_ivars.include?(iv) } if ignore_ivars
221 
222   return false if ivars.size != other_ivars.size
223 
224   return false if ivars != other_ivars
225 
226   ivars.all? do |ivar|
227     send(ivar) == other.send(ivar)
228   end
229 end
extend_with_plugin_classes(pl)
[show source]
    # File lib/httpx/options.rb
310 def extend_with_plugin_classes(pl)
311   # extend request class
312   if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
313     @request_class = @request_class.dup
314     SET_TEMPORARY_NAME[@request_class, pl]
315     @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
316     @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
317   end
318   # extend response class
319   if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
320     @response_class = @response_class.dup
321     SET_TEMPORARY_NAME[@response_class, pl]
322     @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
323     @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
324   end
325   # extend headers class
326   if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
327     @headers_class = @headers_class.dup
328     SET_TEMPORARY_NAME[@headers_class, pl]
329     @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
330     @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
331   end
332   # extend request body class
333   if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
334     @request_body_class = @request_body_class.dup
335     SET_TEMPORARY_NAME[@request_body_class, pl]
336     @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
337     @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
338   end
339   # extend response body class
340   if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
341     @response_body_class = @response_body_class.dup
342     SET_TEMPORARY_NAME[@response_body_class, pl]
343     @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
344     @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
345   end
346   # extend connection pool class
347   if defined?(pl::PoolMethods)
348     @pool_class = @pool_class.dup
349     SET_TEMPORARY_NAME[@pool_class, pl]
350     @pool_class.__send__(:include, pl::PoolMethods)
351   end
352   # extend connection class
353   if defined?(pl::ConnectionMethods)
354     @connection_class = @connection_class.dup
355     SET_TEMPORARY_NAME[@connection_class, pl]
356     @connection_class.__send__(:include, pl::ConnectionMethods)
357   end
358   # extend http1 class
359   if defined?(pl::HTTP1Methods)
360     @http1_class = @http1_class.dup
361     SET_TEMPORARY_NAME[@http1_class, pl]
362     @http1_class.__send__(:include, pl::HTTP1Methods)
363   end
364   # extend http2 class
365   if defined?(pl::HTTP2Methods)
366     @http2_class = @http2_class.dup
367     SET_TEMPORARY_NAME[@http2_class, pl]
368     @http2_class.__send__(:include, pl::HTTP2Methods)
369   end
370   # extend native resolver class
371   if defined?(pl::ResolverNativeMethods)
372     @resolver_native_class = @resolver_native_class.dup
373     SET_TEMPORARY_NAME[@resolver_native_class, pl]
374     @resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
375   end
376   # extend system resolver class
377   if defined?(pl::ResolverSystemMethods)
378     @resolver_system_class = @resolver_system_class.dup
379     SET_TEMPORARY_NAME[@resolver_system_class, pl]
380     @resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
381   end
382   # extend https resolver class
383   if defined?(pl::ResolverHTTPSMethods)
384     @resolver_https_class = @resolver_https_class.dup
385     SET_TEMPORARY_NAME[@resolver_https_class, pl]
386     @resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
387   end
388 
389   return unless defined?(pl::OptionsMethods)
390 
391   # extend option class
392   # works around lack of initialize_dup callback
393   @options_class = @options_class.dup
394   # (self.class.options_names)
395   @options_class.__send__(:include, pl::OptionsMethods)
396 end
freeze()
[show source]
    # File lib/httpx/options.rb
193 def freeze
194   self.class.options_names.each do |ivar|
195     # avoid freezing debug option, as when it's set, it's usually an
196     # object which cannot be frozen, like stderr or stdout. It's a
197     # documented exception then, and still does not defeat the purpose
198     # here, which is to make option objects shareable across ractors,
199     # and in most cases debug should be nil, or one of the objects
200     # which will eventually be shareable, like STDOUT or STDERR.
201     next if %i[debug io].include?(ivar)
202 
203     send(ivar).freeze
204   end
205   super
206 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
246 def merge(other)
247   if (is_options = other.is_a?(Options))
248 
249     return self if eql?(other)
250 
251     opts_names = other.class.options_names
252 
253     return self if opts_names.all? { |opt| public_send(opt) == other.public_send(opt) }
254 
255     other_opts = opts_names
256   else
257     other_opts = other #: Hash[Symbol, untyped]
258     other_opts = Hash[other] unless other.is_a?(Hash)
259 
260     return self if other_opts.empty?
261 
262     return self if other_opts.all? do |opt, v|
263       unless respond_to?(opt)
264         # TODO: do this instead in a major or minor version bump
265         # raise Error, "unknown option: #{opt}" unless respond_to?(opt)
266         warn "DEPRECATION WARNING: unknown option: `:#{opt}`. an exception will be raised in a future version."
267         next(true)
268       end
269 
270       !respond_to?(opt) || public_send(opt) == v
271     end
272   end
273 
274   opts = dup
275 
276   other_opts.each do |opt, v|
277     next unless respond_to?(opt)
278 
279     v = other.public_send(opt) if is_options
280     ivar = :"@#{opt}"
281 
282     unless v
283       opts.instance_variable_set(ivar, v)
284       next
285     end
286 
287     v = opts.__send__(:"option_#{opt}", v)
288 
289     orig_v = public_send(opt)
290 
291     v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
292 
293     opts.instance_variable_set(ivar, v)
294   end
295 
296   opts.freeze
297   opts
298 end
resolver_cache()
[show source]
    # File lib/httpx/options.rb
173 def resolver_cache
174   cache_type = @resolver_cache
175 
176   case cache_type
177   when :memory
178     Resolver::Cache::Memory.cache(cache_type)
179   when :file
180     Resolver::Cache::File.cache(cache_type)
181   else
182     unless cache_type.respond_to?(:resolve) &&
183            cache_type.respond_to?(:get) &&
184            cache_type.respond_to?(:set) &&
185            cache_type.respond_to?(:evict)
186       raise TypeError, "`:resolver_cache` must be a compatible resolver cache and implement `#get`, `#set` and `#evict`"
187     end
188 
189     cache_type #: Object & Resolver::_Cache
190   end
191 end
resolver_class()

returns the class with which to instantiate the DNS resolver.

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

checks whether other matches the same resolver-level options

[show source]
    # File lib/httpx/options.rb
237 def resolver_options_match?(other)
238   self == other ||
239     RESOLVER_IVARS.all? do |ivar|
240       instance_variable_get(ivar) == other.instance_variable_get(ivar)
241     end
242 end
to_hash()
[show source]
    # File lib/httpx/options.rb
300 def to_hash
301   instance_variables.each_with_object({}) do |ivar, hs|
302     val = instance_variable_get(ivar)
303 
304     next if val.nil?
305 
306     hs[ivar[1..-1].to_sym] = val
307   end
308 end