Module: Async::HTTP::Protocol::HTTP2::Connection
Overview
Provides shared connection behaviour for HTTP/2 client and server connections.
Instance Attribute Summary collapse
-
#count ⇒ Object
readonly
Returns the value of attribute count.
-
#promises ⇒ Object
readonly
Returns the value of attribute promises.
-
#stream ⇒ Object
readonly
Returns the value of attribute stream.
Instance Method Summary collapse
- #as_json ⇒ Object
-
#close(error = nil) ⇒ Object
Close the connection and stop the background reader.
-
#close_if_drained! ⇒ Object
The connection has finished draining the streams which the remote peer accepted before its graceful GOAWAY.
- #concurrency ⇒ Object
- #http1? ⇒ Boolean
- #http2? ⇒ Boolean
-
#initialize ⇒ Object
Initialize the connection state.
- #peer ⇒ Object
-
#read_in_background(parent: Task.current) ⇒ Object
Start a transient background task that reads frames from the connection.
-
#reusable? ⇒ Boolean
Once the remote peer has sent a GOAWAY frame, it will not process any new streams on this connection, so it must not be handed out for another request, even while the streams it accepted are still being drained.
-
#start_connection ⇒ Object
Start the background reader task if it is not already running.
-
#synchronize(&block) ⇒ Object
Synchronize write access to the connection.
- #to_json ⇒ Object
- #to_s ⇒ Object
- #version ⇒ Object
-
#viable? ⇒ Boolean
Can we use this connection to make requests?.
-
#write_frame(frame) ⇒ Object
Write a single frame, deferring stop until the frame is written.
-
#write_frames ⇒ Object
Write multiple frames, deferring stop until the frames are written.
Instance Attribute Details
#count ⇒ Object (readonly)
Returns the value of attribute count.
148 149 150 |
# File 'lib/async/http/protocol/http2/connection.rb', line 148 def count @count end |
#promises ⇒ Object (readonly)
Returns the value of attribute promises.
141 142 143 |
# File 'lib/async/http/protocol/http2/connection.rb', line 141 def promises @promises end |
#stream ⇒ Object (readonly)
Returns the value of attribute stream.
73 74 75 |
# File 'lib/async/http/protocol/http2/connection.rb', line 73 def stream @stream end |
Instance Method Details
#as_json ⇒ Object
64 65 66 |
# File 'lib/async/http/protocol/http2/connection.rb', line 64 def as_json(...) to_s end |
#close(error = nil) ⇒ Object
Close the connection and stop the background reader.
91 92 93 94 95 96 97 98 99 100 |
# File 'lib/async/http/protocol/http2/connection.rb', line 91 def close(error = nil) if reader = @reader @reader = nil # The reader task can close the connection itself, e.g. when the last stream completes and the connection is released back to the pool. Stopping it here would cancel the current task in the middle of this method, leaving the underlying stream open, so we let it unwind by itself: `closed?` is now true, so the read loop exits. reader.stop unless reader.current? end super end |
#close_if_drained! ⇒ Object
The connection has finished draining the streams which the remote peer accepted before its graceful GOAWAY.
The last of those streams can complete on the sending side, in a task other than the background reader - the response arrived first and the request body was still being written. The reader is then parked in a blocking read and will never notice that the connection is closed, so we stop it and let its ensure close the connection.
105 106 107 108 109 110 111 |
# File 'lib/async/http/protocol/http2/connection.rb', line 105 def close_if_drained! super if self.closed? and (reader = @reader) and !reader.current? reader.stop end end |
#concurrency ⇒ Object
151 152 153 |
# File 'lib/async/http/protocol/http2/connection.rb', line 151 def concurrency self.maximum_concurrent_streams end |
#http1? ⇒ Boolean
76 77 78 |
# File 'lib/async/http/protocol/http2/connection.rb', line 76 def http1? false end |
#http2? ⇒ Boolean
81 82 83 |
# File 'lib/async/http/protocol/http2/connection.rb', line 81 def http2? true end |
#initialize ⇒ Object
Initialize the connection state.
33 34 35 36 37 38 39 40 |
# File 'lib/async/http/protocol/http2/connection.rb', line 33 def initialize(...) super @reader = nil # Writing multiple frames at the same time can cause odd problems if frames are only partially written. So we use a semaphore to ensure frames are written in their entirety. @write_frame_guard = Async::Semaphore.new(1) end |
#peer ⇒ Object
144 145 146 |
# File 'lib/async/http/protocol/http2/connection.rb', line 144 def peer @peer ||= ::Protocol::HTTP::Peer.for(@stream.io) end |
#read_in_background(parent: Task.current) ⇒ Object
Start a transient background task that reads frames from the connection.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/async/http/protocol/http2/connection.rb', line 114 def read_in_background(parent: Task.current) raise RuntimeError, "Connection is closed!" if closed? parent.async(transient: true) do |task| @reader = task task.annotate("#{version} reading data for #{self.class}.") # We don't need to defer stop here as this is already a transient task (ignores stop): begin while !self.closed? self.consume_window self.read_frame end rescue => error # Close with error. ensure # Don't call #close twice. if @reader @reader = nil self.close(error) end end end end |
#reusable? ⇒ Boolean
Once the remote peer has sent a GOAWAY frame, it will not process any new streams on this connection, so it must not be handed out for another request, even while the streams it accepted are still being drained.
163 164 165 |
# File 'lib/async/http/protocol/http2/connection.rb', line 163 def reusable? !self.closed? && !self.goaway_received? end |
#start_connection ⇒ Object
Start the background reader task if it is not already running.
86 87 88 |
# File 'lib/async/http/protocol/http2/connection.rb', line 86 def start_connection @reader || read_in_background end |
#synchronize(&block) ⇒ Object
Synchronize write access to the connection.
44 45 46 |
# File 'lib/async/http/protocol/http2/connection.rb', line 44 def synchronize(&block) @write_frame_guard.acquire(&block) end |
#to_json ⇒ Object
69 70 71 |
# File 'lib/async/http/protocol/http2/connection.rb', line 69 def to_json(...) as_json.to_json(...) end |
#to_s ⇒ Object
59 60 61 |
# File 'lib/async/http/protocol/http2/connection.rb', line 59 def to_s "\#<#{self.class} #{@streams.count} active streams>" end |
#version ⇒ Object
168 169 170 |
# File 'lib/async/http/protocol/http2/connection.rb', line 168 def version VERSION end |
#viable? ⇒ Boolean
Can we use this connection to make requests?
156 157 158 |
# File 'lib/async/http/protocol/http2/connection.rb', line 156 def viable? !self.goaway_received? && @stream&.readable? end |
#write_frame(frame) ⇒ Object
Write a single frame, deferring stop until the frame is written.
49 50 51 |
# File 'lib/async/http/protocol/http2/connection.rb', line 49 def write_frame(frame) Task.current.defer_stop{super} end |
#write_frames ⇒ Object
Write multiple frames, deferring stop until the frames are written.
54 55 56 |
# File 'lib/async/http/protocol/http2/connection.rb', line 54 def write_frames Task.current.defer_stop{super} end |