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
argumentsArray 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
streamIO The stream to read from.
-
parameter
maximum_frame_sizeInteger Maximum allowed frame size.
-
parameter
limitInteger 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
streamIO 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
dataString The data to pack.
-
parameter
optionsHash 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