Contains a set of options which are passed and shared across from session to its requests or responses.
Methods
Public Class
Public Instance
Classes and Modules
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
| options_names | [R] |
Public Class methods
# File lib/httpx/options.rb 37 def freeze 38 @options_names.freeze 39 super 40 end
# File lib/httpx/options.rb 24 def inherited(klass) 25 super 26 klass.instance_variable_set(:@options_names, @options_names.dup) 27 end
# 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
# 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
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 |
| :ssl |
a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see |
| :http2_settings |
a hash of options to be passed to a HTTP2::Connection (ex: |
| :fallback_protocol |
version of HTTP protocol to use by default in the absence of protocol negotiation like ALPN (defaults to |
| :supported_compression_formats |
list of compressions supported by the transcoder layer (defaults to |
| :decompress_response_body |
whether to auto-decompress response body (defaults to |
| :compress_request_body |
whether to auto-decompress response body (defaults to |
| :timeout |
hash of timeout configurations (supports |
| :headers |
hash of HTTP headers (ex: |
| :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 |
| :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 |
| :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 |
| :resolver_class |
which resolver to use (defaults to |
| :resolver_cache |
strategy to cache DNS results, ignored by the |
| :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 |
This list of options are enhanced with each loaded plugin, see the plugin docs for details.
# 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
checks whether other matches the same connection-level options
# 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
# 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
# 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
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.
# 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
# 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
returns the class with which to instantiate the DNS resolver.
# 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
checks whether other matches the same resolver-level options
# 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
# 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