Class: HTTPX::Session

Inherits:
Object
  • Object
show all
Includes:
Chainable, Loggable, ForkTracker
Defined in:
lib/httpx/session.rb,
sig/session.rbs

Overview

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

Defined Under Namespace

Modules: ForkTracker

Constant Summary collapse

INSTANCES =

Returns:

nil
EMPTY_HASH =

Returns:

  • (Hash[untyped, untyped])

Constants included from Loggable

Loggable::COLORS, Loggable::USE_DEBUG_LOG

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Chainable

#accept, #branch, #default_options, #plugin, #with

Methods included from Loggable

#log, #log_exception, log_identifiers, #log_redact, #log_redact_body, #log_redact_headers

Methods included from ForkTracker

#_fork

Constructor Details

#initialize(arg0) ⇒ void #initialize(arg0) ⇒ void

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.

Overloads:

  • #initialize(arg0) ⇒ void

    Parameters:

    • arg0 (options)
  • #initialize(arg0) ⇒ void

    Parameters:

    • arg0 (options)

Yields:

Yield Parameters:

  • arg0 (self)

Yield Returns:

  • (void)


16
17
18
19
20
21
22
23
24
# File 'lib/httpx/session.rb', line 16

def initialize(options = EMPTY_HASH, &blk)
  @options = self.class.default_options.merge(options)
  @persistent = @options.persistent
  @pool = @options.pool_class.new(@options.pool_options)
  @wrapped = false
  @closing = false
  INSTANCES[self] = self if @persistent && @options.close_on_fork && INSTANCES
  wrap(&blk) if blk
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class HTTPX::Chainable

Class Attribute Details

.default_optionsOptions (readonly)

Returns the value of attribute default_options.

Returns:



483
484
485
# File 'lib/httpx/session.rb', line 483

def default_options
  @default_options
end

Class Method Details

.after_forkvoid

This method returns an undefined value.



577
578
579
580
# File 'lib/httpx/session.rb', line 577

def self.after_fork
  INSTANCES.each_value(&:close)
  nil
end

.inherited(klass) ⇒ Object



485
486
487
488
489
490
# File 'lib/httpx/session.rb', line 485

def inherited(klass)
  super
  klass.instance_variable_set(:@default_options, @default_options)
  klass.instance_variable_set(:@plugins, @plugins.dup)
  klass.instance_variable_set(:@callbacks, @callbacks.dup)
end

.plugin(pl, options = nil, &block) ⇒ void

This method returns an undefined value.

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)

Parameters:

  • plugin (Symbol, Module)
  • options (options, nil) (defaults to: nil)

Raises:

  • (ArgumentError)


497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/httpx/session.rb', line 497

def plugin(pl, options = nil, &block)
  label = pl
  pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
  raise ArgumentError, "Invalid plugin type: #{pl.class.inspect}" unless pl.is_a?(Module)

  if !@plugins.include?(pl)
    @plugins << pl
    pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)

    @default_options = @default_options.dup

    include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
    extend(pl::ClassMethods) if defined?(pl::ClassMethods)

    opts = @default_options
    opts.extend_with_plugin_classes(pl)

    if defined?(pl::OptionsMethods)
      # when a class gets dup'ed, the #initialize_dup callbacks isn't triggered.
      # moreover, and because #method_added does not get triggered on mixin include,
      # the callback is also forcefully manually called here.
      opts.options_class.instance_variable_set(:@options_names, opts.options_class.options_names.dup)
      (pl::OptionsMethods.instance_methods + pl::OptionsMethods.private_instance_methods - Object.instance_methods).each do |meth|
        opts.options_class.method_added(meth)
      end
      @default_options = opts.options_class.new(opts)
    end

    @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
    @default_options = @default_options.merge(options) if options

    if pl.respond_to?(:subplugins)
      pl.subplugins.transform_keys(&Plugins.method(:load_plugin)).each do |main_pl, sub_pl|
        # in case the main plugin has already been loaded, then apply subplugin functionality
        # immediately
        next unless @plugins.include?(main_pl)

        plugin(sub_pl, options, &block)
      end
    end

    pl.configure(self, &block) if pl.respond_to?(:configure)

    if label.is_a?(Symbol)
      # in case an already-loaded plugin complements functionality of
      # the plugin currently being loaded, loaded it now
      @plugins.each do |registered_pl|
        next if registered_pl == pl

        next unless registered_pl.respond_to?(:subplugins)

        sub_pl = registered_pl.subplugins[label]

        next unless sub_pl

        plugin(sub_pl, options, &block)
      end
    end

    @default_options.freeze
    set_temporary_name("#{superclass}/#{pl}") if respond_to?(:set_temporary_name) # ruby 3.4 only
  elsif options
    # this can happen when two plugins are loaded, an one of them calls the other under the hood,
    # albeit changing some default.
    @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
    @default_options = @default_options.merge(options) if options

    @default_options.freeze
  end

  self
end

Instance Method Details

#build_request(verb, uri, params = EMPTY_HASH, options = @options) ⇒ Request

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)

Parameters:

  • verb (verb)
  • uri (generic_uri)
  • params (request_params) (defaults to: EMPTY_HASH)
  • options (Options) (defaults to: @options)

Returns:



114
115
116
117
118
119
120
# File 'lib/httpx/session.rb', line 114

def build_request(verb, uri, params = EMPTY_HASH, options = @options)
  rklass = options.request_class
  request = rklass.new(verb, uri, options, params)
  request.persistent = @persistent
  set_request_callbacks(request)
  request
end

#build_requests(arg0, arg1, arg2) ⇒ Array[Request] #build_requests(arg0, arg1) ⇒ Array[Request] #build_requests(arg0, arg1, arg2) ⇒ Array[Request]

returns a set of HTTPX::Request objects built from the given args and options.

Overloads:

  • #build_requests(arg0, arg1, arg2) ⇒ Array[Request]

    Parameters:

    • arg0 (verb)
    • arg1 (uri)
    • arg2 (request_params)

    Returns:

  • #build_requests(arg0, arg1) ⇒ Array[Request]

    Parameters:

    • arg0 (Array[[verb, uri] | [verb, uri, request_params]])
    • arg1 (request_params)

    Returns:

  • #build_requests(arg0, arg1, arg2) ⇒ Array[Request]

    Parameters:

    • arg0 (verb)
    • arg1 (_Each[[uri] | [uri, request_params]])
    • arg2 (request_params)

    Returns:

Raises:

  • (ArgumentError)


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/httpx/session.rb', line 266

def build_requests(*args, params)
  requests = if args.size == 1
    reqs = args.first
    reqs.map do |verb, uri, ps = EMPTY_HASH|
      request_params = params
      request_params = request_params.merge(ps) unless ps.empty?
      build_request(verb, uri, request_params)
    end
  else
    verb, uris = args
    if uris.respond_to?(:each)
      uris.enum_for(:each).map do |uri, ps = EMPTY_HASH|
        request_params = params
        request_params = request_params.merge(ps) unless ps.empty?
        build_request(verb, uri, request_params)
      end
    else
      [build_request(verb, uris, params)]
    end
  end
  raise ArgumentError, "wrong number of URIs (given 0, expect 1..+1)" if requests.empty?

  requests
end

#close(selector = Selector.new) ⇒ void

This method returns an undefined value.

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.

Parameters:

  • selector (Selector) (defaults to: Selector.new)


64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/httpx/session.rb', line 64

def close(selector = Selector.new)
  # throw resolvers away from the pool
  @pool.reset_resolvers

  # preparing to throw away connections
  while (connection = @pool.pop_connection)
    next if connection.state == :closed

    select_connection(connection, selector)
  end

  selector_close(selector)
end

#coalesce_connections(conn1, conn2, selector, from_pool) ⇒ void

This method returns an undefined value.

coalesces conn2 into conn1. if conn1 was loaded from the connection pool (it is known via from_pool), then it adds its to the selector.

Parameters:



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/httpx/session.rb', line 434

def coalesce_connections(conn1, conn2, selector, from_pool)
  unless conn1.coalescable?(conn2)
    conn2.log(level: 2) { "not coalescing with conn##{conn1.object_id}[#{conn1.origin}])" }
    select_connection(conn2, selector)
    if from_pool
      conn1.log(level: 2) { "check-in connection##{conn1.object_id}(#{conn1.state}) in pool##{@pool.object_id}" }
      @pool.checkin_connection(conn1)
    end
    return
  end

  conn2.log(level: 2) { "coalescing with connection##{conn1.object_id}[#{conn1.origin}])" }
  select_connection(conn1, selector) if from_pool
  conn2.coalesce!(conn1)
  conn2.disconnect
end

#deactivate(selector) ⇒ void

This method returns an undefined value.

tries deactivating connections in the selector, deregistering the ones that have been deactivated.

Parameters:



224
225
226
# File 'lib/httpx/session.rb', line 224

def deactivate(selector)
  selector.each_connection.to_a.each(&:deactivate)
end

#deselect_connection(connection, selector, cloned = false) ⇒ void

This method returns an undefined value.

Parameters:



137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/httpx/session.rb', line 137

def deselect_connection(connection, selector, cloned = false)
  connection.log(level: 2) do
    "deregistering connection##{connection.object_id}(#{connection.state}) from selector##{selector.object_id}"
  end
  selector.deregister(connection)

  # do not check-in connections only created for Happy Eyeballs
  return if cloned

  return if @closing && connection.state == :closed && !connection.used?

  connection.log(level: 2) { "check-in connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
  @pool.checkin_connection(connection)
end

#deselect_resolver(resolver, selector) ⇒ void

This method returns an undefined value.

Parameters:



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/httpx/session.rb', line 152

def deselect_resolver(resolver, selector)
  resolver.log(level: 2) do
    "deregistering resolver##{resolver.object_id}(#{resolver.state}) from selector##{selector.object_id}"
  end
  selector.deregister(resolver)

  return if @closing && resolver.closed?

  resolver.log(level: 2) { "check-in resolver##{resolver.object_id}(#{resolver.state}) in pool##{@pool.object_id}" }
  @pool.checkin_resolver(resolver)
end

#do_init_connection(connection, selector) ⇒ void

This method returns an undefined value.

Parameters:



295
296
297
# File 'lib/httpx/session.rb', line 295

def do_init_connection(connection, selector)
  resolve_connection(connection, selector) unless connection.family
end

#early_resolve(resolver, connection) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


395
396
397
# File 'lib/httpx/session.rb', line 395

def early_resolve(resolver, connection)
  resolver.early_resolve(connection)
end

#fetch_response(request, _selector, _options) ⇒ response?

returns the corresponding HTTP::Response to the given request if it has been received.

Parameters:

Returns:

  • (response, nil)


235
236
237
238
239
240
241
242
243
# File 'lib/httpx/session.rb', line 235

def fetch_response(request, _selector, _options)
  response = request.response

  return unless response && response.finished?

  request.log(level: 2) { "response##{response.object_id} fetched" }

  response
end

#find_connection(request_uri, selector, options) ⇒ Connection

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

Parameters:

Returns:



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/httpx/session.rb', line 180

def find_connection(request_uri, selector, options)
  if (connection = selector.find_connection(request_uri, options))
    connection.idling if connection.state == :closed
    log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" }
    return connection
  end

  connection = @pool.checkout_connection(request_uri, options)

  log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }

  case connection.state
  when :idle
    do_init_connection(connection, selector)
  when :open
    # external io
    select_connection(connection, selector)
  when :closing, :closed
    connection.idling
    if connection.addresses?
      select_connection(connection, selector)
    else
      # if addresses expired, resolve again
      resolve_connection(connection, selector)
    end
  else
    pin(connection, selector)
  end

  connection
end

#find_resolver_for(connection, selector) ⇒ resolver

Parameters:

Returns:

  • (resolver)


419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/httpx/session.rb', line 419

def find_resolver_for(connection, selector)
  if (resolver = selector.find_resolver(connection.options))
    resolver.log(level: 2) { "found resolver##{resolver.object_id}(#{resolver.state}) in selector##{selector.object_id}" }
    return resolver
  end

  resolver = @pool.checkout_resolver(connection.options)
  resolver.log(level: 2) { "found resolver##{resolver.object_id}(#{resolver.state}) in pool##{@pool.object_id}" }
  pin(resolver, selector)

  resolver
end

#get_current_selectorSelector? #get_current_selectorSelector

Overloads:

Yields:

Yield Returns:



451
452
453
# File 'lib/httpx/session.rb', line 451

def get_current_selector
  selector_store[self] || (yield if block_given?)
end

#on_promise(_, stream) ⇒ void

This method returns an undefined value.

callback executed when an HTTP/2 promise frame has been received.

Parameters:

  • (Object)
  • (Object)


229
230
231
232
# File 'lib/httpx/session.rb', line 229

def on_promise(_, stream)
  log(level: 2) { "#{stream.id}: refusing stream!" }
  stream.refuse
end

#on_resolver_closevoid

This method returns an undefined value.

Parameters:



73
# File 'sig/session.rbs', line 73

def on_resolver_close: (Resolver::Resolver resolver, Selector selector) -> void

#on_resolver_connection(connection, selector) ⇒ void

This method returns an undefined value.

Parameters:



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/httpx/session.rb', line 399

def on_resolver_connection(connection, selector)
  from_pool = false
  found_connection = selector.find_mergeable_connection(connection) || begin
    from_pool = true
    connection.log(level: 2) do
      "try finding a mergeable connection in pool##{@pool.object_id}"
    end
    @pool.checkout_mergeable_connection(connection)
  end

  return select_connection(connection, selector) unless found_connection

  connection.log(level: 2) do
    "try coalescing from #{from_pool ? "pool##{@pool.object_id}" : "selector##{selector.object_id}"} " \
      "(connection##{found_connection.object_id}[#{found_connection.origin}])"
  end

  coalesce_connections(found_connection, connection, selector, from_pool)
end

#pin(conn_or_resolver, selector) ⇒ void

This method returns an undefined value.

Parameters:



130
131
132
133
# File 'lib/httpx/session.rb', line 130

def pin(conn_or_resolver, selector)
  conn_or_resolver.current_session = self
  conn_or_resolver.current_selector = selector
end

#receive_requests(requests, selector) ⇒ Array[response]

returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request requests.

Parameters:

Returns:

  • (Array[response])

Raises:



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/httpx/session.rb', line 316

def receive_requests(requests, selector)
  pending_idxs = [] #: Array[Integer]
  pending = 0

  waiting = false

  requests.each do |request|
    send_request(request, selector)
  end

  # do work first
  selector.initial_call

  responses = requests.each_with_index.map do |request, idx|
    fetch_response(request, selector, request.options).tap do |response|
      if response.nil?
        pending += 1
        request.on_response_arrived = lambda do
          pending_idxs << idx if waiting
        end
      end
    end
  end

  log(level: 2) { "waiting to receive #{pending} pending requests..." }

  until pending.zero? || selector.empty?
    # loop on selector until at least one response has been received.
    waiting = true
    catch(:coalesced) { selector.next_tick }
    waiting = false

    while (idx = pending_idxs.shift)
      request = requests[idx]

      response = fetch_response(request, selector, request.options)

      # stop on first pending response. this avoids traversing pending idxs all the way
      # (which is more expensive in the beginning, when the array is larger and N) while
      # making the next loop cheaper (because we're dropping).
      next unless response

      request.complete!(response)
      responses[idx] = response
      request.on_response_arrived = nil
      pending -= 1
    end
  end

  raise Error, "something went wrong, #{pending} responses not found " \
               "and requests not resent" unless pending.zero?

  responses
end

#request(*args, **params) ⇒ Object

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&quot;) resp1, resp2 = session.request("GET", ["https://server.org/a&quot;, "https://server.org/b&quot;]) resp1, resp2 = session.request(["GET", "https://server.org/a&quot;], ["GET", "https://server.org/b&quot;]) resp1 = session.request("POST", "https://server.org/a&quot;, form: { "foo" => "bar" }) resp1, resp2 = session.request(["POST", "https://server.org/a&quot;, form: { "foo" => "bar" }], ["GET", "https://server.org/b&quot;]) resp1, resp2 = session.request("GET", ["https://server.org/a&quot;, "https://server.org/b&quot;], headers: { "x-api-token" => "TOKEN" })

Raises:

  • (ArgumentError)


98
99
100
101
102
103
104
105
106
# File 'lib/httpx/session.rb', line 98

def request(*args, **params)
  raise ArgumentError, "must perform at least one request" if args.empty?

  requests = args.first.is_a?(Request) ? args : build_requests(*args, params)
  responses = send_requests(*requests)
  return responses.first if responses.size == 1

  responses
end

#resolve_connection(connection, selector) ⇒ void

This method returns an undefined value.

Parameters:



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/httpx/session.rb', line 371

def resolve_connection(connection, selector)
  if connection.addresses? || connection.open?
    #
    # there are two cases in which we want to activate initialization of
    # connection immediately:
    #
    # 1. when the connection already has addresses, i.e. it doesn't need to
    #    resolve a name (not the same as name being an IP, yet)
    # 2. when the connection is initialized with an external already open IO.
    #
    on_resolver_connection(connection, selector)
    return
  end

  resolver = find_resolver_for(connection, selector)

  pin(connection, selector)
  if early_resolve(resolver, connection)
    @pool.checkin_resolver(resolver)
  else
    resolver.lazy_resolve(connection)
  end
end

#select_connection(connection, selector) ⇒ void Also known as: select_resolver

This method returns an undefined value.

Parameters:



122
123
124
125
126
127
128
# File 'lib/httpx/session.rb', line 122

def select_connection(connection, selector)
  pin(connection, selector)
  connection.log(level: 2) do
    "registering into selector##{selector.object_id}"
  end
  selector.register(connection)
end

#selector_close(selector) ⇒ void

This method returns an undefined value.

Parameters:



214
215
216
217
218
219
220
221
# File 'lib/httpx/session.rb', line 214

def selector_close(selector)
  begin
    @closing = true
    selector.terminate
  ensure
    @closing = false
  end
end

#selector_storeHash[instance, Selector]

Returns:



463
464
465
466
467
468
469
470
471
# File 'lib/httpx/session.rb', line 463

def selector_store
  th_current = Thread.current

  thread_selector_store(th_current) || begin
    {}.compare_by_identity.tap do |store|
      th_current.thread_variable_set(:httpx_persistent_selector_store, store)
    end
  end
end

#send_request(request, selector, options = request.options) ⇒ void

This method returns an undefined value.

sends the request to the corresponding HTTPX::Connection

Parameters:



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/httpx/session.rb', line 246

def send_request(request, selector, options = request.options)
  error = begin
    catch(:resolve_error) do
      log(level: 2) { "finding connection for request##{request.object_id}..." }
      connection = find_connection(request.uri, selector, options)
      connection.send(request)
    end
  rescue StandardError => e
    e
  end
  return unless error && error.is_a?(Exception)

  raise error unless error.is_a?(Error)

  response = ErrorResponse.new(request, error)
  request.response = response
  request.emit_response(response)
end

#send_requests(*requests) ⇒ Array[response]

sends an array of HTTPX::Request requests, returns the respective array of HTTPX::Response objects.

Parameters:

Returns:

  • (Array[response])


300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/httpx/session.rb', line 300

def send_requests(*requests)
  selector = get_current_selector { Selector.new }
  begin
    receive_requests(requests, selector)
  ensure
    unless @wrapped
      if @persistent
        deactivate(selector)
      else
        close(selector)
      end
    end
  end
end

#set_current_selector(selector) ⇒ void

This method returns an undefined value.

Parameters:



455
456
457
458
459
460
461
# File 'lib/httpx/session.rb', line 455

def set_current_selector(selector)
  if selector
    selector_store[self] = selector
  else
    selector_store.delete(self)
  end
end

#set_request_callbacks(request) ⇒ void

This method returns an undefined value.

Parameters:



291
292
293
# File 'lib/httpx/session.rb', line 291

def set_request_callbacks(request)
  request.on(:promise, &method(:on_promise))
end

#thread_selector_store(th) ⇒ Hash[instance, Selector]?

Parameters:

  • th (Thread)

Returns:



473
474
475
# File 'lib/httpx/session.rb', line 473

def thread_selector_store(th)
  th.thread_variable_get(:httpx_persistent_selector_store)
end

#try_clone_connection(connection, selector, family) ⇒ Connection

Parameters:

Returns:



164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/httpx/session.rb', line 164

def try_clone_connection(connection, selector, family)
  connection.family ||= family

  return connection if connection.family == family

  new_connection = connection.class.new(connection.origin, connection.options)

  new_connection.family = family

  connection.sibling = new_connection

  do_init_connection(new_connection, selector)
  new_connection
end

#wrap {|arg0| ... } ⇒ void

This method returns an undefined value.

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

Yields:

Yield Parameters:

  • arg0 (instance)

Yield Returns:

  • (void)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/httpx/session.rb', line 31

def wrap
  prev_wrapped = @wrapped
  @wrapped = true
  was_initialized = false
  current_selector = get_current_selector do
    selector = Selector.new

    set_current_selector(selector)

    was_initialized = true

    selector
  end
  begin
    yield self
  ensure
    unless prev_wrapped
      if @persistent
        deactivate(current_selector)
      else
        close(current_selector)
      end
    end
    @wrapped = prev_wrapped
    set_current_selector(nil) if was_initialized
  end
end