Protocol::HTTP2SourceProtocolHTTP2Continued

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