diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2015-08-09 01:19:40 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2015-08-09 01:19:40 +0900 |
commit | b9f7f878793d043bfa49faf21e7b8e988a32f93f (patch) | |
tree | 3c9276b3466342e16ca397ae3a5c801af566d480 /lib/plum/frame_utils.rb | |
parent | 8b7f6ae897f1abc83c1b8b8585083ac5cde610f0 (diff) | |
download | plum-b9f7f878793d043bfa49faf21e7b8e988a32f93f.tar.gz |
extract Frame creation into FrameFactory
Diffstat (limited to 'lib/plum/frame_utils.rb')
-rw-r--r-- | lib/plum/frame_utils.rb | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/lib/plum/frame_utils.rb b/lib/plum/frame_utils.rb new file mode 100644 index 0000000..2694f5a --- /dev/null +++ b/lib/plum/frame_utils.rb @@ -0,0 +1,64 @@ +using Plum::BinaryString + +module Plum + module FrameUtils + # Splits the frame into multiple frames if the payload size exceeds max size. + # + # @param max [Integer] The maximum size of a frame payload. + # @return [Array<Frame>] The splitted frames. + def split_data(max) + return [self] if self.length <= max + raise "Frame type must be DATA" unless self.type == :data + + fragments = [] + pos = 0 + while pos <= self.length # data may be empty + fragments << self.payload.byteslice(pos, max) + pos += max + end + + frames = [] + last = Frame.data(stream_id, fragments.pop, *(self.flags & [:end_stream])) + fragments.each do |fragment| + frames << Frame.data(stream_id, fragment, *(self.flags - [:end_stream])) + end + frames << last + frames + end + + def split_headers(max) + return [self] if self.length <= max + raise "Frame type must be DATA" unless [:headers, :push_promise].include?(self.type) + + fragments = [] + pos = 0 + while pos < self.length + fragments << self.payload.byteslice(pos, max) + pos += max + end + + frames = [] + frames << Frame.new(type_value: self.type_value, flags: self.flags - [:end_headers], stream_id: self.stream_id, payload: fragments.shift) + if fragments.size > 0 + last = Frame.continuation(stream_id, fragments.pop, *(self.flags & [:end_headers])) + fragments.each do |fragment| + frames << Frame.continuation(stream_id, fragment) + end + frames << last + end + frames + end + + # Parses SETTINGS frame payload. Ignores unknown settings type (see RFC7540 6.5.2). + # + # @return [Hash<Symbol, Integer>] The parsed strings. + def parse_settings + (self.length / 6).times.map {|i| + id = self.payload.uint16(6 * i) + val = self.payload.uint32(6 * i + 2) + name = Frame::SETTINGS_TYPE.key(id) or next nil + [name, val] + }.compact.to_h + end + end +end |