module Continued
Module for frames that can be continued with CONTINUATION frames.
Definitions
LIMIT = 8
Signature
- constant
The maximum number of continuation frames to read to prevent resource exhaustion.
def initialize(*)
Initialize a continuable frame.
Signature
-
parameter
arguments
Array
Arguments passed to parent constructor.
Implementation
def initialize(*)
super
@continuation = nil
end
def continued?
Check if this frame has continuation frames.
Signature
-
returns
Boolean
True if there are continuation frames.
Implementation
def continued?
!!@continuation
end
def end_headers?
Check if this is the last header block fragment.
Signature
-
returns
Boolean
True if the END_HEADERS flag is set.
Implementation
def end_headers?
flag_set?(END_HEADERS)
end
def read(stream, maximum_frame_size, limit = LIMIT)
Read the frame and any continuation frames from the stream.
There is an upper limit to the number of continuation frames that can be read to prevent resource exhaustion. If the limit is 0, only one frame will be read (the initial frame). Otherwise, the limit decrements with each continuation frame read.
Signature
-
parameter
stream
IO
The stream to read from.
-
parameter
maximum_frame_size
Integer
Maximum allowed frame size.
-
parameter
limit
Integer
The maximum number of continuation frames to read.
Implementation
def read(stream, maximum_frame_size, limit = LIMIT)
super(stream, maximum_frame_size)
unless end_headers?
if limit.zero?
raise ProtocolError, "Too many continuation frames!"
end
continuation = ContinuationFrame.new
continuation.read_header(stream)
# We validate the frame type here:
unless continuation.valid_type?
raise ProtocolError, "Invalid frame type: #{@type}!"
end
if continuation.stream_id != @stream_id
raise ProtocolError, "Invalid stream id: #{continuation.stream_id} for continuation of stream id: #{@stream_id}!"
end
continuation.read(stream, maximum_frame_size, limit - 1)
@continuation = continuation
end
end
def write(stream)
Write the frame and any continuation frames to the stream.
Signature
-
parameter
stream
IO
The stream to write to.
Implementation
def write(stream)
super
if continuation = self.continuation
continuation.write(stream)
end
end
def pack(data, **options)
Pack data into this frame, creating continuation frames if needed.
Signature
-
parameter
data
String
The data to pack.
-
parameter
options
Hash
Options including maximum_size.
Implementation
def pack(data, **options)
maximum_size = options[:maximum_size]
if maximum_size and data.bytesize > maximum_size
clear_flags(END_HEADERS)
super(data.byteslice(0, maximum_size), **options)
remainder = data.byteslice(maximum_size, data.bytesize-maximum_size)
@continuation = ContinuationFrame.new
@continuation.pack(remainder, maximum_size: maximum_size)
else
set_flags(END_HEADERS)
super data, **options
@continuation = nil
end
end
def unpack
Unpack data from this frame and any continuation frames.
Signature
-
returns
String
The complete unpacked data.
Implementation
def unpack
if @continuation.nil?
super
else
super + @continuation.unpack
end
end