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
523 def self.after_fork
524   INSTANCES.each_value(&:close)
525   nil
526 end
inherited(klass)
[show source]
    # File lib/httpx/session.rb
436 def inherited(klass)
437   super
438   klass.instance_variable_set(:@default_options, @default_options)
439   klass.instance_variable_set(:@plugins, @plugins.dup)
440   klass.instance_variable_set(:@callbacks, @callbacks.dup)
441 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
448 def plugin(pl, options = nil, &block)
449   label = pl
450   # raise Error, "Cannot add a plugin to a frozen config" if frozen?
451   pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
452   if !@plugins.include?(pl)
453     @plugins << pl
454     pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
455 
456     @default_options = @default_options.dup
457 
458     include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
459     extend(pl::ClassMethods) if defined?(pl::ClassMethods)
460 
461     opts = @default_options
462     opts.extend_with_plugin_classes(pl)
463     if defined?(pl::OptionsMethods)
464 
465       (pl::OptionsMethods.instance_methods - Object.instance_methods).each do |meth|
466         opts.options_class.method_added(meth)
467       end
468       @default_options = opts.options_class.new(opts)
469     end
470 
471     @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
472     @default_options = @default_options.merge(options) if options
473 
474     if pl.respond_to?(:subplugins)
475       pl.subplugins.transform_keys(&Plugins.method(:load_plugin)).each do |main_pl, sub_pl|
476         # in case the main plugin has already been loaded, then apply subplugin functionality
477         # immediately
478         next unless @plugins.include?(main_pl)
479 
480         plugin(sub_pl, options, &block)
481       end
482     end
483 
484     pl.configure(self, &block) if pl.respond_to?(:configure)
485 
486     if label.is_a?(Symbol)
487       # in case an already-loaded plugin complements functionality of
488       # the plugin currently being loaded, loaded it now
489       @plugins.each do |registered_pl|
490         next if registered_pl == pl
491 
492         next unless registered_pl.respond_to?(:subplugins)
493 
494         sub_pl = registered_pl.subplugins[label]
495 
496         next unless sub_pl
497 
498         plugin(sub_pl, options, &block)
499       end
500     end
501 
502     @default_options.freeze
503     set_temporary_name("#{superclass}/#{pl}") if respond_to?(:set_temporary_name) # ruby 3.4 only
504   elsif options
505     # this can happen when two plugins are loaded, an one of them calls the other under the hood,
506     # albeit changing some default.
507     @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
508     @default_options = @default_options.merge(options) if options
509 
510     @default_options.freeze
511   end
512 
513   self
514 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     return connection
178   end
179 
180   connection = @pool.checkout_connection(request_uri, options)
181 
182   case connection.state
183   when :idle
184     do_init_connection(connection, selector)
185   when :open
186     if options.io
187       select_connection(connection, selector)
188     else
189       pin_connection(connection, selector)
190     end
191   when :closing, :closed
192     connection.idling
193     select_connection(connection, selector)
194   else
195     pin_connection(connection, selector)
196   end
197 
198   connection
199 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