class HTTPX::Options

  1. lib/httpx/options.rb
  2. lib/httpx/transcoder/utils/deflater.rb
  3. 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_options => { cache: true }.freeze, :pool_options => EMPTY_HASH, :ip_families => nil, :close_on_fork => false, }.freeze  
KEEP_ALIVE_TIMEOUT = 20  
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112  
REQUEST_BODY_IVARS = %i[@headers].freeze  
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil  
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  
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)
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)
56 
57     return if @options_names.include?(orig_name.to_sym)
58   end
59 
60   optname = optname.to_sym
61 
62   attr_reader(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 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)

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

Public Instance methods

==(other)
[show source]
    # File lib/httpx/options.rb
171 def ==(other)
172   super || options_equals?(other)
173 end
extend_with_plugin_classes(pl)
[show source]
    # File lib/httpx/options.rb
237 def extend_with_plugin_classes(pl)
238   # extend request class
239   if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
240     @request_class = @request_class.dup
241     SET_TEMPORARY_NAME[@request_class, pl]
242     @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
243     @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
244   end
245   # extend response class
246   if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
247     @response_class = @response_class.dup
248     SET_TEMPORARY_NAME[@response_class, pl]
249     @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
250     @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
251   end
252   # extend headers class
253   if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
254     @headers_class = @headers_class.dup
255     SET_TEMPORARY_NAME[@headers_class, pl]
256     @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
257     @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
258   end
259   # extend request body class
260   if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
261     @request_body_class = @request_body_class.dup
262     SET_TEMPORARY_NAME[@request_body_class, pl]
263     @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
264     @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
265   end
266   # extend response body class
267   if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
268     @response_body_class = @response_body_class.dup
269     SET_TEMPORARY_NAME[@response_body_class, pl]
270     @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
271     @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
272   end
273   # extend connection pool class
274   if defined?(pl::PoolMethods)
275     @pool_class = @pool_class.dup
276     SET_TEMPORARY_NAME[@pool_class, pl]
277     @pool_class.__send__(:include, pl::PoolMethods)
278   end
279   # extend connection class
280   if defined?(pl::ConnectionMethods)
281     @connection_class = @connection_class.dup
282     SET_TEMPORARY_NAME[@connection_class, pl]
283     @connection_class.__send__(:include, pl::ConnectionMethods)
284   end
285   # extend http1 class
286   if defined?(pl::HTTP1Methods)
287     @http1_class = @http1_class.dup
288     SET_TEMPORARY_NAME[@http1_class, pl]
289     @http1_class.__send__(:include, pl::HTTP1Methods)
290   end
291   # extend http2 class
292   if defined?(pl::HTTP2Methods)
293     @http2_class = @http2_class.dup
294     SET_TEMPORARY_NAME[@http2_class, pl]
295     @http2_class.__send__(:include, pl::HTTP2Methods)
296   end
297   # extend native resolver class
298   if defined?(pl::ResolverNativeMethods)
299     @resolver_native_class = @resolver_native_class.dup
300     SET_TEMPORARY_NAME[@resolver_native_class, pl]
301     @resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
302   end
303   # extend system resolver class
304   if defined?(pl::ResolverSystemMethods)
305     @resolver_system_class = @resolver_system_class.dup
306     SET_TEMPORARY_NAME[@resolver_system_class, pl]
307     @resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
308   end
309   # extend https resolver class
310   if defined?(pl::ResolverHTTPSMethods)
311     @resolver_https_class = @resolver_https_class.dup
312     SET_TEMPORARY_NAME[@resolver_https_class, pl]
313     @resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
314   end
315 
316   return unless defined?(pl::OptionsMethods)
317 
318   # extend option class
319   # works around lack of initialize_dup callback
320   @options_class = @options_class.dup
321   # (self.class.options_names)
322   @options_class.__send__(:include, pl::OptionsMethods)
323 end
freeze()
[show source]
    # File lib/httpx/options.rb
154 def freeze
155   self.class.options_names.each do |ivar|
156     # avoid freezing debug option, as when it's set, it's usually an
157     # object which cannot be frozen, like stderr or stdout. It's a
158     # documented exception then, and still does not defeat the purpose
159     # here, which is to make option objects shareable across ractors,
160     # and in most cases debug should be nil, or one of the objects
161     # which will eventually be shareable, like STDOUT or STDERR.
162     next if ivar == :debug
163 
164     instance_variable_get(:"@#{ivar}").freeze
165   end
166   super
167 end
merge(other)
[show source]
    # File lib/httpx/options.rb
190 def merge(other)
191   ivar_map = nil
192   other_ivars = case other
193                 when Options
194                   other.instance_variables
195                 else
196                   other = Hash[other] unless other.is_a?(Hash)
197                   ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
198                   ivar_map.keys
199   end
200 
201   return self if other_ivars.empty?
202 
203   return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == access_option(other, ivar, ivar_map) }
204 
205   opts = dup
206 
207   other_ivars.each do |ivar|
208     v = access_option(other, ivar, ivar_map)
209 
210     unless v
211       opts.instance_variable_set(ivar, v)
212       next
213     end
214 
215     v = opts.__send__(:"option_#{ivar[1..-1]}", v)
216 
217     orig_v = instance_variable_get(ivar)
218 
219     v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
220 
221     opts.instance_variable_set(ivar, v)
222   end
223 
224   opts
225 end
options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
[show source]
    # File lib/httpx/options.rb
175 def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
176   # headers and other request options do not play a role, as they are
177   # relevant only for the request.
178   ivars = instance_variables - ignore_ivars
179   other_ivars = other.instance_variables - ignore_ivars
180 
181   return false if ivars.size != other_ivars.size
182 
183   return false if ivars.sort != other_ivars.sort
184 
185   ivars.all? do |ivar|
186     instance_variable_get(ivar) == other.instance_variable_get(ivar)
187   end
188 end
to_hash()
[show source]
    # File lib/httpx/options.rb
227 def to_hash
228   instance_variables.each_with_object({}) do |ivar, hs|
229     val = instance_variable_get(ivar)
230 
231     next if val.nil?
232 
233     hs[ivar[1..-1].to_sym] = val
234   end
235 end