Class: HTTPX::Connection::HTTP2

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

Direct Known Subclasses

Plugins::H2C::H2CParser

Defined Under Namespace

Classes: Error, GoawayError

Constant Summary collapse

MAX_CONCURRENT_REQUESTS =
HTTP2Next::DEFAULT_MAX_CONCURRENT_STREAMS

Constants included from Loggable

Loggable::COLORS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Loggable

#log, #log_exception

Methods included from HTTPX::Callbacks

#callbacks_for?, #emit, #on, #once, #only

Constructor Details

#initialize(buffer, options) ⇒ HTTP2

Returns a new instance of HTTP2.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/httpx/connection/http2.rb', line 27

def initialize(buffer, options)
  @options = Options.new(options)
  @settings = @options.http2_settings
  @pending = []
  @streams = {}
  @drains  = {}
  @pings = []
  @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

#pendingObject (readonly)

Returns the value of attribute pending.



25
26
27
# File 'lib/httpx/connection/http2.rb', line 25

def pending
  @pending
end

#streamsObject (readonly)

Returns the value of attribute streams.



25
26
27
# File 'lib/httpx/connection/http2.rb', line 25

def streams
  @streams
end

Instance Method Details

#<<(data) ⇒ Object



91
92
93
# File 'lib/httpx/connection/http2.rb', line 91

def <<(data)
  @connection << data
end

#can_buffer_more_requests?Boolean

Returns:

  • (Boolean)


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

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

#closeObject



75
76
77
78
79
80
81
# File 'lib/httpx/connection/http2.rb', line 75

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

#consumeObject



118
119
120
121
122
123
124
# File 'lib/httpx/connection/http2.rb', line 118

def consume
  @streams.each do |request, stream|
    next if request.state == :done

    handle(request, stream)
  end
end

#empty?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/httpx/connection/http2.rb', line 83

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

#exhausted?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/httpx/connection/http2.rb', line 87

def exhausted?
  !@max_requests.positive?
end

#handle_error(ex) ⇒ Object



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

def handle_error(ex)
  if ex.instance_of?(TimeoutError) && !@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
  @streams.each_key do |request|
    emit(:error, request, ex)
  end
  @pending.each do |request|
    emit(:error, request, ex)
  end
end

#interestsObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/httpx/connection/http2.rb', line 48

def interests
  # waiting for WINDOW_UPDATE frames
  return :r if @buffer.full?

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

    return :w
  end

  unless @connection.state == :connected && @handshake_completed
    return @buffer.empty? ? :r : :rw
  end

  return :w if !@pending.empty? && can_buffer_more_requests?

  return :w unless @drains.empty?

  if @buffer.empty?
    return if @streams.empty? && @pings.empty?

    return :r
  end

  :rw
end

#pingObject



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

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

#send(request) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/httpx/connection/http2.rb', line 101

def send(request)
  unless can_buffer_more_requests?
    @pending << request
    return
  end
  unless (stream = @streams[request])
    stream = @connection.new_stream
    handle_stream(stream, request)
    @streams[request] = stream
    @max_requests -= 1
  end
  handle(request, stream)
  true
rescue HTTP2Next::Error::StreamLimitExceeded
  @pending.unshift(request)
end

#timeoutObject



42
43
44
45
46
# File 'lib/httpx/connection/http2.rb', line 42

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

  @options.timeout[:settings_timeout]
end