Module: HTTP2::FlowBuffer
- Includes:
- Error
- Included in:
- Connection, Stream
- Defined in:
- lib/http/2/flow_buffer.rb,
sig/flow_buffer.rbs
Overview
Implementation of stream and connection DATA flow control: frames may be split and / or may be buffered based on current flow control window.
Constant Summary collapse
- MAX_WINDOW_SIZE =
(2 << 30) - 1
Instance Attribute Summary collapse
-
#send_buffer ⇒ FrameBuffer
readonly
Returns the value of attribute send_buffer.
Instance Method Summary collapse
-
#buffered_amount ⇒ Integer
Amount of buffered data.
- #calculate_window_update(window_max_size) ⇒ void
- #flush ⇒ void
- #process_window_update(frame:, encode: false) ⇒ void
-
#send_data(frame = nil, encode = false) ⇒ void
Buffers outgoing DATA frames and applies flow control logic to split and emit DATA frames based on current flow control window.
- #send_frame(frame, encode) ⇒ void
- #update_local_window(frame) ⇒ void
Methods included from Error
Instance Attribute Details
#send_buffer ⇒ FrameBuffer (readonly)
Returns the value of attribute send_buffer.
10 11 12 |
# File 'lib/http/2/flow_buffer.rb', line 10 def send_buffer @send_buffer end |
Instance Method Details
#buffered_amount ⇒ Integer
Amount of buffered data. Only DATA payloads are subject to flow stream and connection flow control.
18 19 20 |
# File 'lib/http/2/flow_buffer.rb', line 18 def buffered_amount @send_buffer.bytesize end |
#calculate_window_update(window_max_size) ⇒ void
This method returns an undefined value.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/http/2/flow_buffer.rb', line 34 def calculate_window_update(window_max_size) # If DATA frame is received with length > 0 and # current received window size + delta length is strictly larger than # local window size, it throws a flow control error. # error(:flow_control_error) if @local_window < 0 # Send WINDOW_UPDATE if the received window size goes over # the local window size / 2. # # The HTTP/2 spec mandates that every DATA frame received # generates a WINDOW_UPDATE to send. In some cases however, # (ex: DATA frames with short payloads), # the noise generated by flow control frames creates enough # congestion for this to be deemed very inefficient. # # This heuristic was inherited from nghttp, which delays the # WINDOW_UPDATE until at least half the window is exhausted. # This works because the sender doesn't need those increments # until the receiver window is exhausted, after which he'll be # waiting for the WINDOW_UPDATE frame. return unless @local_window <= (window_max_size / 2) window_update(window_max_size - @local_window) end |
#flush ⇒ void
This method returns an undefined value.
22 23 24 |
# File 'lib/http/2/flow_buffer.rb', line 22 def flush send_data end |
#process_window_update(frame:, encode: false) ⇒ void
This method returns an undefined value.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/http/2/flow_buffer.rb', line 104 def process_window_update(frame:, encode: false) return if frame[:ignore] if (increment = frame[:increment]) raise ProtocolError, "increment MUST be higher than zero" if increment.zero? @remote_window += increment error(:flow_control_error, msg: "window size too large") if @remote_window > MAX_WINDOW_SIZE end send_data(nil, encode) end |
#send_data(frame = nil, encode = false) ⇒ void
This method returns an undefined value.
Buffers outgoing DATA frames and applies flow control logic to split and emit DATA frames based on current flow control window. If the window is large enough, the data is sent immediately. Otherwise, the data is buffered until the flow control window is updated.
Buffered DATA frames are emitted in FIFO order.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/http/2/flow_buffer.rb', line 69 def send_data(frame = nil, encode = false) if frame if @send_buffer.empty? frame_size = frame[:payload].bytesize end_stream = frame[:flags].anybits?(END_STREAM) # if buffer is empty, and frame is either end 0 length OR # is within available window size, skip buffering and send immediately. if @remote_window.positive? return send_frame(frame, encode) if frame_size <= @remote_window elsif frame_size.zero? && end_stream return send_frame(frame, encode) end end @send_buffer << frame end while (frame = @send_buffer.retrieve(@remote_window)) send_frame(frame, encode) end end |
#send_frame(frame, encode) ⇒ void
This method returns an undefined value.
91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/http/2/flow_buffer.rb', line 91 def send_frame(frame, encode) sent = frame[:payload].bytesize manage_state(frame) do if encode encode(frame) else emit(:frame, frame) end @remote_window -= sent end end |
#update_local_window(frame) ⇒ void
This method returns an undefined value.
28 29 30 31 32 |
# File 'lib/http/2/flow_buffer.rb', line 28 def update_local_window(frame) frame_size = frame[:payload].bytesize frame_size += frame.fetch(:padding, 0) @local_window -= frame_size end |