Class: HTTPX::Connection::HTTP2

Inherits:
Object
  • Object
show all
Includes:
HTTPX::Callbacks, Loggable
Defined in:
lib/httpx/connection/http2.rb,
sig/connection/http2.rbs

Defined Under Namespace

Classes: Error, GoawayError, PingError

Constant Summary collapse

MAX_CONCURRENT_REQUESTS =

Returns:

  • (Integer)
::HTTP2::DEFAULT_MAX_CONCURRENT_STREAMS

Constants included from Loggable

Loggable::COLORS, Loggable::USE_DEBUG_LOG

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Loggable

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

Methods included from HTTPX::Callbacks

#callbacks, #callbacks_for?, #emit, #on, #once

Constructor Details

#initialize(buffer, options) ⇒ HTTP2

Returns a new instance of HTTP2.

Parameters:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/httpx/connection/http2.rb', line 33

def initialize(buffer, options)
  @options = options
  @settings = @options.http2_settings
  @pending = []
  @streams = {}
  @drains = {}
  @pings = []
  @streams_to_close_after_receive = []
  @buffer = buffer
  @handshake_completed = false
  @wait_for_handshake = @settings.key?(:wait_for_handshake) ? @settings.delete(:wait_for_handshake) : true
  @max_concurrent_requests = @options.max_concurrent_requests || MAX_CONCURRENT_REQUESTS
  @max_requests = @options.max_requests
  init_connection
end

Instance Attribute Details

#pendingArray[Request] (readonly)

Returns the value of attribute pending.

Returns:



31
32
33
# File 'lib/httpx/connection/http2.rb', line 31

def pending
  @pending
end

#streamsHash[Request, ::HTTP2::Stream] (readonly)

Returns the value of attribute streams.

Returns:



31
32
33
# File 'lib/httpx/connection/http2.rb', line 31

def streams
  @streams
end

Instance Method Details

#<<(data) ⇒ void

This method returns an undefined value.

Parameters:

  • (string)


112
113
114
115
116
117
118
119
120
# File 'lib/httpx/connection/http2.rb', line 112

def <<(data)
  @connection << data

  while (stream, request, error = @streams_to_close_after_receive.shift)
    # these streams were marked for cancellation due to errors found while processing the
    # data received by the peer.
    emit_stream_error(stream, request, error)
  end
end

#can_buffer_more_requests?Boolean

Returns:

  • (Boolean)


185
186
187
188
189
# File 'lib/httpx/connection/http2.rb', line 185

def can_buffer_more_requests?
  (@handshake_completed || !@wait_for_handshake) &&
    @streams.size < @max_concurrent_requests &&
    @streams.size < @max_requests
end

#closevoid

This method returns an undefined value.



96
97
98
99
100
101
102
# File 'lib/httpx/connection/http2.rb', line 96

def close
  unless @connection.state == :closed
    @connection.goaway
    emit(:timeout, @options.timeout[:close_handshake_timeout])
  end
  emit(:close)
end

#consumevoid

This method returns an undefined value.



142
143
144
145
146
147
148
# File 'lib/httpx/connection/http2.rb', line 142

def consume
  @streams.each do |request, stream|
    next unless request.can_buffer?

    handle(request, stream)
  end
end

#emit_stream_error(stream, request, error) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (HTTP2::Stream)
  • request (Request)
  • error (StandardError)


533
534
535
536
537
# File 'lib/httpx/connection/http2.rb', line 533

def emit_stream_error(stream, request, error)
  teardown(request)
  stream.close
  emit(:error, request, error)
end

#empty?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/httpx/connection/http2.rb', line 104

def empty?
  @connection.state == :closed || @streams.empty?
end

#end_stream?(request, next_chunk) ⇒ Boolean

Parameters:

  • request (Request)
  • next_chunk (String, nil)

Returns:

  • (Boolean)


303
304
305
# File 'lib/httpx/connection/http2.rb', line 303

def end_stream?(request, next_chunk)
  !(next_chunk || request.trailers? || request.callbacks_for?(:trailers))
end

#exhausted?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/httpx/connection/http2.rb', line 108

def exhausted?
  !@max_requests.positive?
end

#frame_with_extra_info(frame) ⇒ Hash[Symbol, untyped]

Parameters:

  • frame (::HTTP2::frame)

Returns:

  • (Hash[Symbol, untyped])


467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/httpx/connection/http2.rb', line 467

def frame_with_extra_info(frame)
  flags_bits = frame.fetch(:flags, 0)
  case frame[:type]
  when :data
    flags = [] #: Array[Symbol]
    flags << :end_stream if flags_bits.anybits?(0b0001)
    flags << :padded if flags_bits.anybits?(0b1000)
    frame.merge(payload: frame[:payload].bytesize, flags: flags)
  when :push_promise, :headers
    flags = [] #: Array[Symbol]
    flags << :end_stream if flags_bits.anybits?(0b0001)
    flags << :priority if flags_bits.anybits?(0b0010)
    flags << :end_headers if flags_bits.anybits?(0b0100)
    flags << :padded if flags_bits.anybits?(0b1000)
    frame.merge(payload: log_redact_headers(frame[:payload]), flags: flags)
  when :ping
    flags = [] #: Array[Symbol]
    flags << :ack if flags_bits.anybits?(0b0001)
    frame.merge(payload: log_redact_headers(frame[:payload]), flags: flags)
  when :settings
    flags = [] #: Array[Symbol]
    flags << :ack if flags_bits.anybits?(0b0001)
    frame.merge(flags: flags)
  when :window_update
    connection_or_stream = if (id = frame[:stream]).zero?
      @connection
    else
      @streams.each_value.find { |s| s.id == id }
    end
    if connection_or_stream
      frame.merge(
        local_window: connection_or_stream.local_window,
        remote_window: connection_or_stream.remote_window,
        buffered_amount: connection_or_stream.buffered_amount,
        stream_state: connection_or_stream.state,
      )
    else
      frame
    end
  else
    frame
  end.merge(connection_state: @connection.state)
end

#handle(request, stream) ⇒ void

This method returns an undefined value.

Parameters:

  • request (Request)
  • stream (::HTTP2::Stream)


197
198
199
200
201
202
203
204
205
206
207
# File 'lib/httpx/connection/http2.rb', line 197

def handle(request, stream)
  catch(:buffer_full) do
    request.transition(:headers)
    join_headers(stream, request) if request.state == :headers
    request.transition(:body)
    join_body(stream, request) if request.state == :body
    request.transition(:trailers)
    join_trailers(stream, request) if request.state == :trailers && !request.body.empty?
    request.transition(:done)
  end
end

#handle_error(ex, request = nil) ⇒ void

This method returns an undefined value.

Parameters:

  • ex (StandardError)
  • request (Request, nil) (defaults to: nil)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/httpx/connection/http2.rb', line 150

def handle_error(ex, request = nil)
  if ex.is_a?(OperationTimeoutError) && !@handshake_completed && @connection.state != :closed
    @connection.goaway(:settings_timeout, "closing due to settings timeout")
    emit(:close_handshake)
    settings_ex = SettingsTimeoutError.new(ex.timeout, ex.message)
    settings_ex.set_backtrace(ex.backtrace)
    ex = settings_ex
  end
  while (req, _ = @streams.shift)
    next if request && request == req

    emit(:error, req, ex)
  end
  while (req = @pending.shift)
    next if request && request == req

    emit(:error, req, ex)
  end
end

#handle_stream(stream, request) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)


232
233
234
235
236
237
238
239
# File 'lib/httpx/connection/http2.rb', line 232

def handle_stream(stream, request)
  request.on(:refuse, &method(:on_stream_refuse).curry(3)[stream, request])
  stream.on(:close, &method(:on_stream_close).curry(3)[stream, request])
  stream.on(:half_close) { on_stream_half_close(stream, request) }
  stream.on(:altsvc, &method(:on_altsvc).curry(2)[request.origin])
  stream.on(:headers, &method(:on_stream_headers).curry(3)[stream, request])
  stream.on(:data, &method(:on_stream_data).curry(3)[stream, request])
end

#init_connectionvoid Also known as: reset

This method returns an undefined value.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/httpx/connection/http2.rb', line 209

def init_connection
  @connection = ::HTTP2::Client.new(@settings)
  @connection.on(:frame, &method(:on_frame))
  @connection.on(:frame_sent, &method(:on_frame_sent))
  @connection.on(:frame_received, &method(:on_frame_received))
  @connection.on(:origin, &method(:on_origin))
  @connection.on(:promise, &method(:on_promise))
  @connection.on(:altsvc) { |frame| on_altsvc(frame[:origin], frame) }
  @connection.on(:settings_ack, &method(:on_settings))
  @connection.on(:ack, &method(:on_pong))
  @connection.on(:goaway, &method(:on_close))
  #
  # Some servers initiate HTTP/2 negotiation right away, some don't.
  # As such, we have to check the socket buffer. If there is something
  # to read, the server initiated the negotiation. If not, we have to
  # initiate it.
  #
  @connection.send_connection_preface
end

#interestsio_interests?

Returns:

  • (io_interests, nil)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/httpx/connection/http2.rb', line 55

def interests
  if @connection.state == :closed
    return unless @handshake_completed

    return if @buffer.empty?

    # HTTP/2 GOAWAY frame buffered.
    return :w
  end

  unless @connection.state == :connected && @handshake_completed
    # HTTP/2 in intermediate state or still completing initialization-
    return @buffer.empty? ? :r : :rw
  end

  unless @connection.send_buffer.empty?
    # HTTP/2 connection is buffering data chunks and failing to emit DATA frames,
    # most likely because the flow control window is exhausted.
    return :rw unless @buffer.empty?

    # waiting for WINDOW_UPDATE frames
    return :r
  end

  # there are pending bufferable requests
  return :w if !@pending.empty? && can_buffer_more_requests?

  # there are pending frames from the last run
  return :w unless @drains.empty?

  if @buffer.empty?
    # skip if no more requests or pings to process
    return if @streams.empty? && @pings.empty?

    :r
  else
    # buffered frames
    :w
  end
end

#join_body(stream, request) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)


276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/httpx/connection/http2.rb', line 276

def join_body(stream, request)
  return if request.body.empty?

  chunk = @drains.delete(request) || request.drain_body
  while chunk
    next_chunk = request.drain_body
    send_chunk(request, stream, chunk, next_chunk)

    if next_chunk && (@buffer.full? || request.body.unbounded_body?)
      @drains[request] = next_chunk
      throw(:buffer_full)
    end

    chunk = next_chunk
  end

  return unless (error = request.drain_error)

  on_stream_refuse(stream, request, error)
end

#join_headers(stream, request) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)


250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/httpx/connection/http2.rb', line 250

def join_headers(stream, request)
  extra_headers = set_protocol_headers(request)

  if request.headers.key?("host")
    request.log { "forbidden \"host\" header found (#{log_redact_headers(request.headers["host"])}), will use it as authority..." }
    extra_headers[":authority"] = request.headers["host"]
  end

  request.log(level: 1, color: :yellow) do
    "\n#{request.headers.merge(extra_headers).each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact_headers(v)}" }.join("\n")}"
  end
  stream.headers(request.headers.each(extra_headers), end_stream: request.body.empty?)
end

#join_headlineString

Parameters:

Returns:

  • (String)


66
# File 'sig/connection/http2.rbs', line 66

def join_headline: (Request request) -> String

#join_trailers(stream, request) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)


264
265
266
267
268
269
270
271
272
273
274
# File 'lib/httpx/connection/http2.rb', line 264

def join_trailers(stream, request)
  unless request.trailers?
    stream.data("", end_stream: true) if request.callbacks_for?(:trailers)
    return
  end

  request.log(level: 1, color: :yellow) do
    request.trailers.each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact_headers(v)}" }.join("\n")
  end
  stream.headers(request.trailers.each, end_stream: true)
end

#on_altsvc(origin, frame) ⇒ void

This method returns an undefined value.

Parameters:

  • origin (String)
  • frame (::HTTP2::frame)


511
512
513
514
515
516
517
# File 'lib/httpx/connection/http2.rb', line 511

def on_altsvc(origin, frame)
  log(level: 2) { "#{frame[:stream]}: altsvc frame was received" }
  log(level: 2) { "#{frame[:stream]}: #{log_redact_headers(frame.inspect)}" }
  alt_origin = URI.parse("#{frame[:proto]}://#{frame[:host]}:#{frame[:port]}")
  params = { "ma" => frame[:max_age] }
  emit(:altsvc, origin, alt_origin, origin, params)
end

#on_close(_last_frame, error, _payload) ⇒ void

This method returns an undefined value.

Parameters:

  • last_frame (Integer)
  • error (Symbol, nil)
  • payload (String, nil)


434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# File 'lib/httpx/connection/http2.rb', line 434

def on_close(_last_frame, error, _payload)
  is_connection_closed = @connection.state == :closed
  if error
    @buffer.clear if is_connection_closed
    case error
    when :http_1_1_required
      while (request = @pending.shift)
        emit(:error, request, error)
      end
    else
      ex = GoawayError.new(error)
      ex.set_backtrace(caller)

      handle_error(ex)
      teardown

    end
  end
  return unless is_connection_closed && @streams.empty?

  emit(:close) if is_connection_closed
end

#on_frame(bytes) ⇒ void

This method returns an undefined value.

Parameters:

  • bytes (string)


423
424
425
# File 'lib/httpx/connection/http2.rb', line 423

def on_frame(bytes)
  @buffer << bytes
end

#on_frame_received(frame) ⇒ void

This method returns an undefined value.

Parameters:

  • frame (::HTTP2::frame)


462
463
464
465
# File 'lib/httpx/connection/http2.rb', line 462

def on_frame_received(frame)
  log(level: 2) { "#{frame[:stream]}: frame was received!" }
  log(level: 2, color: :magenta) { "#{frame[:stream]}: #{frame_with_extra_info(frame)}" }
end

#on_frame_sent(frame) ⇒ void

This method returns an undefined value.

Parameters:

  • frame (::HTTP2::frame)


457
458
459
460
# File 'lib/httpx/connection/http2.rb', line 457

def on_frame_sent(frame)
  log(level: 2) { "#{frame[:stream]}: frame was sent!" }
  log(level: 2, color: :blue) { "#{frame[:stream]}: #{frame_with_extra_info(frame)}" }
end

#on_origin(origin) ⇒ void

This method returns an undefined value.

Parameters:

  • (String)


523
524
525
# File 'lib/httpx/connection/http2.rb', line 523

def on_origin(origin)
  emit(:origin, origin)
end

#on_pong(ping) ⇒ void

This method returns an undefined value.

Parameters:

  • ping (string)

Raises:



527
528
529
530
531
# File 'lib/httpx/connection/http2.rb', line 527

def on_pong(ping)
  raise PingError unless @pings.delete(ping.to_s)

  emit(:pong)
end

#on_promise(stream) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)


519
520
521
# File 'lib/httpx/connection/http2.rb', line 519

def on_promise(stream)
  emit(:promise, @streams.key(stream.parent), stream)
end

#on_settingsvoid

This method returns an undefined value.

Parameters:

  • (Object)


427
428
429
430
431
432
# File 'lib/httpx/connection/http2.rb', line 427

def on_settings(*)
  @handshake_completed = true
  emit(:current_timeout)
  @max_concurrent_requests = [@max_concurrent_requests, @connection.remote_settings[:settings_max_concurrent_streams]].min
  send_pending
end

#on_stream_close(stream, request, error) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)
  • error (Symbol, StandardError, nil)


386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/httpx/connection/http2.rb', line 386

def on_stream_close(stream, request, error)
  return if error == :stream_closed && !@streams.key?(request)

  log(level: 2) { "#{stream.id}: closing stream" }
  teardown(request)

  if error
    case error
    when :http_1_1_required
      emit(:error, request, error)
    else
      ex = Error.new(stream.id, error)
      ex.set_backtrace(caller)
      response = ErrorResponse.new(request, ex)
      request.response = response
      emit(:response, request, response)
    end
  else
    if (response = request.response)
      if response.is_a?(Response) && response.status == 421
        emit(:error, request, :http_1_1_required)
      else
        emit(:response, request, response)
      end
    end
  end
  send(@pending.shift) unless @pending.empty?

  return unless @streams.empty? && exhausted?

  if @pending.empty?
    close
  else
    emit(:exhausted)
  end
end

#on_stream_data(stream, request, data) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)
  • data (String)


354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/httpx/connection/http2.rb', line 354

def on_stream_data(stream, request, data)
  request.log(level: 1, color: :green) { "#{stream.id}: <- DATA: #{data.bytesize} bytes..." }
  request.log(level: 2, color: :green) { "#{stream.id}: <- #{log_redact_body(data.inspect)}" }

  return unless request.response

  request.response << data
rescue HTTPX::Error => e
  if stream.state == :closing
    # there won't be any more chunks to process after this one.
    emit_stream_error(stream, request, e)
  else
    # defer until the last chunk from the payload is processed.
    @streams_to_close_after_receive << [stream, request, e]
  end
end

#on_stream_half_close(stream, request) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)


376
377
378
379
380
381
382
383
384
# File 'lib/httpx/connection/http2.rb', line 376

def on_stream_half_close(stream, request)
  unless stream.send_buffer.empty?
    stream.send_buffer.clear
    stream.data("", end_stream: true)
  end

  # TODO: omit log line if response already here
  request.log(level: 2) { "#{stream.id}: waiting for response..." }
end

#on_stream_headers(stream, request, h) ⇒ void

This method returns an undefined value.

HTTP/2 Callbacks

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)
  • headers (Array[[String, String]])


311
312
313
314
315
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
# File 'lib/httpx/connection/http2.rb', line 311

def on_stream_headers(stream, request, h)
  response = request.response

  if response.is_a?(Response) && response.version == "2.0"
    on_stream_trailers(stream, request, response, h)
    return
  end

  request.log(color: :yellow) do
    h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{k == ":status" ? v : log_redact_headers(v)}" }.join("\n")
  end
  _, status = h.shift
  headers = request.options.headers_class.new(h)

  raise HTTPX::Error, "maximum number of response headers exceeded" if h.size > @options.max_response_headers

  if (max_header_value_size = @options.max_response_header_value_size)
    headers.each do |_, v| # rubocop:disable Style/HashEachMethods
      raise HTTPX::Error, "maximum header value size exceeded" if v.size > max_header_value_size
    end
  end

  response = request.options.response_class.new(request, status, "2.0", headers)

  if response.content_length && response.content_length > request.options.max_response_body_size
    raise HTTPX::Error.new, "maximum response body size exceeded"
  end

  request.response = response
  @streams[request] = stream

  handle(request, stream) if request.expects?
rescue HTTPX::Error => e
  @streams_to_close_after_receive << [stream, request, e]
end

#on_stream_refuse(stream, request, error) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)
  • error (StandardError)


371
372
373
374
# File 'lib/httpx/connection/http2.rb', line 371

def on_stream_refuse(stream, request, error)
  on_stream_close(stream, request, error)
  stream.close
end

#on_stream_trailers(stream, request, response, h) ⇒ void

This method returns an undefined value.

Parameters:

  • stream (::HTTP2::Stream)
  • request (Request)
  • response (Response)
  • headers (Array[[String, String]])


347
348
349
350
351
352
# File 'lib/httpx/connection/http2.rb', line 347

def on_stream_trailers(stream, request, response, h)
  request.log(color: :yellow) do
    h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{log_redact_headers(v)}" }.join("\n")
  end
  response.merge_headers(h)
end

#pingvoid

This method returns an undefined value.



170
171
172
173
174
175
# File 'lib/httpx/connection/http2.rb', line 170

def ping
  ping = SecureRandom.gen_random(8)
  @connection.ping(ping.dup)
ensure
  @pings << ping
end

#reset_requestsvoid

This method returns an undefined value.



181
# File 'lib/httpx/connection/http2.rb', line 181

def reset_requests; end

#send(request, head = false) ⇒ Boolean

Parameters:

  • request (Request)
  • head (Boolean) (defaults to: false)

Returns:

  • (Boolean)


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/httpx/connection/http2.rb', line 122

def send(request, head = false)
  unless can_buffer_more_requests?
    head ? @pending.unshift(request) : @pending << request
    return false
  end
  unless (stream = @streams[request])
    stream = @connection.new_stream(**request.http2_stream_options)
    handle_stream(stream, request)
    @streams[request] = stream
    @max_requests -= 1
  end
  handle(request, stream)
  true
rescue ::HTTP2::Error::StreamLimitExceeded
  @pending.unshift(request)
  false
rescue ::HTTP2::Error::Error, ArgumentError => e
  emit(:error, request, e)
end

#send_chunk(request, stream, chunk, next_chunk) ⇒ void

This method returns an undefined value.

Parameters:

  • request (Request)
  • stream (::HTTP2::Stream)
  • chunk (String)
  • next_chunk (String, nil)


297
298
299
300
301
# File 'lib/httpx/connection/http2.rb', line 297

def send_chunk(request, stream, chunk, next_chunk)
  request.log(level: 1, color: :green) { "#{stream.id}: -> DATA: #{chunk.bytesize} bytes..." }
  request.log(level: 2, color: :green) { "#{stream.id}: -> #{log_redact_body(chunk.inspect)}" }
  stream.data(chunk, end_stream: end_stream?(request, next_chunk))
end

#send_pendingvoid

This method returns an undefined value.



191
192
193
194
195
# File 'lib/httpx/connection/http2.rb', line 191

def send_pending
  while (request = @pending.shift)
    break unless send(request, true)
  end
end

#set_protocol_headers(request) ⇒ _Each[[String, String]]

Parameters:

Returns:

  • (_Each[[String, String]])


241
242
243
244
245
246
247
248
# File 'lib/httpx/connection/http2.rb', line 241

def set_protocol_headers(request)
  {
    ":scheme" => request.scheme,
    ":method" => request.verb,
    ":path" => request.path,
    ":authority" => request.authority,
  }
end

#teardown(request = nil) ⇒ void

This method returns an undefined value.

Parameters:

  • request (Request, nil) (defaults to: nil)


539
540
541
542
543
544
545
546
547
# File 'lib/httpx/connection/http2.rb', line 539

def teardown(request = nil)
  if request
    @drains.delete(request)
    @streams.delete(request)
  else
    @drains.clear
    @streams.clear
  end
end

#timeoutinterval?

Returns:

  • (interval, nil)


49
50
51
52
53
# File 'lib/httpx/connection/http2.rb', line 49

def timeout
  return @options.timeout[:operation_timeout] if @handshake_completed

  @options.timeout[:settings_timeout]
end

#waiting_for_ping?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/httpx/connection/http2.rb', line 177

def waiting_for_ping?
  @pings.any?
end