aboutsummaryrefslogtreecommitdiffstats
path: root/lib/plum/frame_utils.rb
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2015-08-09 01:19:40 +0900
committerKazuki Yamaguchi <k@rhe.jp>2015-08-09 01:19:40 +0900
commitb9f7f878793d043bfa49faf21e7b8e988a32f93f (patch)
tree3c9276b3466342e16ca397ae3a5c801af566d480 /lib/plum/frame_utils.rb
parent8b7f6ae897f1abc83c1b8b8585083ac5cde610f0 (diff)
downloadplum-b9f7f878793d043bfa49faf21e7b8e988a32f93f.tar.gz
extract Frame creation into FrameFactory
Diffstat (limited to 'lib/plum/frame_utils.rb')
-rw-r--r--lib/plum/frame_utils.rb64
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