class HTTPX::Session

  1. lib/httpx/session.rb
Superclass: Object

Class implementing the APIs being used publicly.

HTTPX.get(..) #=> delegating to an internal HTTPX::Session object.
HTTPX.plugin(..).get(..) #=> creating an intermediate HTTPX::Session with plugin, then sending the GET request

Included modules

  1. Loggable
  2. Chainable

Constants

INSTANCES = ObjectSpace::WeakMap.new  

Public Instance Aliases

select_resolver -> select_connection

Attributes

Public Class methods

after_fork()
[show source]
    # File lib/httpx/session.rb
526 def self.after_fork
527   INSTANCES.each_value(&:close)
528   nil
529 end
inherited(klass)
[show source]
    # File lib/httpx/session.rb
439 def inherited(klass)
440   super
441   klass.instance_variable_set(:@default_options, @default_options)
442   klass.instance_variable_set(:@plugins, @plugins.dup)
443   klass.instance_variable_set(:@callbacks, @callbacks.dup)
444 end
new(options = EMPTY_HASH, &blk)

initializes the session with a set of options, which will be shared by all requests sent from it.

When pass a block, it’ll yield itself to it, then closes after the block is evaluated.

[show source]
   # File lib/httpx/session.rb
16 def initialize(options = EMPTY_HASH, &blk)
17   @options = self.class.default_options.merge(options)
18   @persistent = @options.persistent
19   @pool = @options.pool_class.new(@options.pool_options)
20   @wrapped = false
21   @closing = false
22   INSTANCES[self] = self if @persistent && @options.close_on_fork && INSTANCES
23   wrap(&blk) if blk
24 end
plugin(pl, options = nil, &block)

returns a new HTTPX::Session instance, with the plugin pointed by pl loaded.

session_with_retries = session.plugin(:retries)
session_with_custom = session.plugin(CustomPlugin)
[show source]
    # File lib/httpx/session.rb
451 def plugin(pl, options = nil, &block)
452   label = pl
453   # raise Error, "Cannot add a plugin to a frozen config" if frozen?
454   pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
455   if !@plugins.include?(pl)
456     @plugins << pl
457     pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
458 
459     @default_options = @default_options.dup
460 
461     include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
462     extend(pl::ClassMethods) if defined?(pl::ClassMethods)
463 
464     opts = @default_options
465     opts.extend_with_plugin_classes(pl)
466     if defined?(pl::OptionsMethods)
467 
468       (pl::OptionsMethods.instance_methods - Object.instance_methods).each do |meth|
469         opts.options_class.method_added(meth)
470       end
471       @default_options = opts.options_class.new(opts)
472     end
473 
474     @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
475     @default_options = @default_options.merge(options) if options
476 
477     if pl.respond_to?(:subplugins)
478       pl.subplugins.transform_keys(&Plugins.method(:load_plugin)).each do |main_pl, sub_pl|
479         # in case the main plugin has already been loaded, then apply subplugin functionality
480         # immediately
481         next unless @plugins.include?(main_pl)
482 
483         plugin(sub_pl, options, &block)
484       end
485     end
486 
487     pl.configure(self, &block) if pl.respond_to?(:configure)
488 
489     if label.is_a?(Symbol)
490       # in case an already-loaded plugin complements functionality of
491       # the plugin currently being loaded, loaded it now
492       @plugins.each do |registered_pl|
493         next if registered_pl == pl
494 
495         next unless registered_pl.respond_to?(:subplugins)
496 
497         sub_pl = registered_pl.subplugins[label]
498 
499         next unless sub_pl
500 
501         plugin(sub_pl, options, &block)
502       end
503     end
504 
505     @default_options.freeze
506     set_temporary_name("#{superclass}/#{pl}") if respond_to?(:set_temporary_name) # ruby 3.4 only
507   elsif options
508     # this can happen when two plugins are loaded, an one of them calls the other under the hood,
509     # albeit changing some default.
510     @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
511     @default_options = @default_options.merge(options) if options
512 
513     @default_options.freeze
514   end
515 
516   self
517 end

Public Instance methods

build_request(verb, uri, params = EMPTY_HASH, options = @options)

returns a HTTP::Request instance built from the HTTP verb, the request uri, and the optional set of request-specific options. This request must be sent through the same session it was built from.

req = session.build_request("GET", "https://server.com")
resp = session.request(req)
[show source]
    # File lib/httpx/session.rb
118 def build_request(verb, uri, params = EMPTY_HASH, options = @options)
119   rklass = options.request_class
120   request = rklass.new(verb, uri, options, params)
121   request.persistent = @persistent
122   set_request_callbacks(request)
123   request
124 end
close(selector = Selector.new)

closes all the active connections from the session.

when called directly without specifying selector, all available connections will be picked up from the connection pool and closed. Connections in use by other sessions, or same session in a different thread, will not be reaped.

[show source]
   # File lib/httpx/session.rb
64 def close(selector = Selector.new)
65   # throw resolvers away from the pool
66   @pool.reset_resolvers
67 
68   # preparing to throw away connections
69   while (connection = @pool.pop_connection)
70     next if connection.state == :closed
71 
72     select_connection(connection, selector)
73   end
74   begin
75     @closing = true
76     selector.terminate
77   ensure
78     @closing = false
79   end
80 end
deselect_connection(connection, selector, cloned = false)
[show source]
    # File lib/httpx/session.rb
138 def deselect_connection(connection, selector, cloned = false)
139   selector.deregister(connection)
140 
141   # when connections coalesce
142   return if connection.state == :idle
143 
144   return if cloned
145 
146   return if @closing && connection.state == :closed
147 
148   @pool.checkin_connection(connection)
149 end
deselect_resolver(resolver, selector)
[show source]
    # File lib/httpx/session.rb
151 def deselect_resolver(resolver, selector)
152   selector.deregister(resolver)
153 
154   return if @closing && resolver.closed?
155 
156   @pool.checkin_resolver(resolver)
157 end
find_connection(request_uri, selector, options)

returns the HTTPX::Connection through which the request should be sent through.

[show source]
    # File lib/httpx/session.rb
175 def find_connection(request_uri, selector, options)
176   if (connection = selector.find_connection(request_uri, options))
177     connection.idling if connection.state == :closed
178     connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" }
179     return connection
180   end
181 
182   connection = @pool.checkout_connection(request_uri, options)
183 
184   connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
185 
186   case connection.state
187   when :idle
188     do_init_connection(connection, selector)
189   when :open
190     if options.io
191       select_connection(connection, selector)
192     else
193       pin_connection(connection, selector)
194     end
195   when :closing, :closed
196     connection.idling
197     select_connection(connection, selector)
198   else
199     pin_connection(connection, selector)
200   end
201 
202   connection
203 end
pin_connection(connection, selector)
[show source]
    # File lib/httpx/session.rb
131 def pin_connection(connection, selector)
132   connection.current_session = self
133   connection.current_selector = selector
134 end
request(*args, **params)

performs one, or multple requests; it accepts:

  1. one or multiple HTTPX::Request objects;

  2. an HTTP verb, then a sequence of URIs or URI/options tuples;

  3. one or multiple HTTP verb / uri / (optional) options tuples;

when present, the set of options kwargs is applied to all of the sent requests.

respectively returns a single HTTPX::Response response, or all of them in an Array, in the same order.

resp1 = session.request(req1)
resp1, resp2 = session.request(req1, req2)
resp1 = session.request("GET", "https://server.org/a")
resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"])
resp1, resp2 = session.request(["GET", "https://server.org/a"], ["GET", "https://server.org/b"])
resp1 = session.request("POST", "https://server.org/a", form: { "foo" => "bar" })
resp1, resp2 = session.request(["POST", "https://server.org/a", form: { "foo" => "bar" }], ["GET", "https://server.org/b"])
resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"], headers: { "x-api-token" => "TOKEN" })
[show source]
    # File lib/httpx/session.rb
102 def request(*args, **params)
103   raise ArgumentError, "must perform at least one request" if args.empty?
104 
105   requests = args.first.is_a?(Request) ? args : build_requests(*args, params)
106   responses = send_requests(*requests)
107   return responses.first if responses.size == 1
108 
109   responses
110 end
select_connection(connection, selector)
[show source]
    # File lib/httpx/session.rb
126 def select_connection(connection, selector)
127   pin_connection(connection, selector)
128   selector.register(connection)
129 end
try_clone_connection(connection, selector, family)
[show source]
    # File lib/httpx/session.rb
159 def try_clone_connection(connection, selector, family)
160   connection.family ||= family
161 
162   return connection if connection.family == family
163 
164   new_connection = connection.class.new(connection.origin, connection.options)
165 
166   new_connection.family = family
167 
168   connection.sibling = new_connection
169 
170   do_init_connection(new_connection, selector)
171   new_connection
172 end
wrap()

Yields itself the block, then closes it after the block is evaluated.

session.wrap do |http|
  http.get("https://wikipedia.com")
end # wikipedia connection closes here
[show source]
   # File lib/httpx/session.rb
31 def wrap
32   prev_wrapped = @wrapped
33   @wrapped = true
34   was_initialized = false
35   current_selector = get_current_selector do
36     selector = Selector.new
37 
38     set_current_selector(selector)
39 
40     was_initialized = true
41 
42     selector
43   end
44   begin
45     yield self
46   ensure
47     unless prev_wrapped
48       if @persistent
49         deactivate(current_selector)
50       else
51         close(current_selector)
52       end
53     end
54     @wrapped = prev_wrapped
55     set_current_selector(nil) if was_initialized
56   end
57 end