diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2016-05-08 22:41:53 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2016-05-08 22:41:53 +0900 |
commit | ef9daa152ecf2e3f9fe0f2c5eb083379a5077c3b (patch) | |
tree | b9e2afa99c7912ffca4dc0a24c1ccd886348f91b /lib/plum/frame.rb | |
parent | 85f218f35d2e9f1332701d908d9570c698708620 (diff) | |
parent | 89c73779d0eab2d9aae1e524245beebd589bf15d (diff) | |
download | plum-ef9daa152ecf2e3f9fe0f2c5eb083379a5077c3b.tar.gz |
Merge branch 'topic/refactor-for-0.3'
* topic/refactor-for-0.3:
examples: static_server: use test certificate in test/
style: prefer "".b over String.new
frame: settings: add Frame::Settings.ack
avoid Frame#type if possible
client: decoders: unfreeze Client::Decoders::DECODERS
frame: create subclasses for each frame type
merge *_{utils,factory}
Diffstat (limited to 'lib/plum/frame.rb')
-rw-r--r-- | lib/plum/frame.rb | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/lib/plum/frame.rb b/lib/plum/frame.rb index bf61629..1a4b402 100644 --- a/lib/plum/frame.rb +++ b/lib/plum/frame.rb @@ -1,12 +1,8 @@ # frozen-string-literal: true using Plum::BinaryString - module Plum class Frame - extend FrameFactory - include FrameUtils - FRAME_TYPES = { data: 0x00, headers: 0x01, @@ -56,14 +52,10 @@ module Plum # @!visibility private FRAME_FLAGS_MAP = FRAME_FLAGS.values.inject(:merge).freeze - SETTINGS_TYPE = { - header_table_size: 0x01, - enable_push: 0x02, - max_concurrent_streams: 0x03, - initial_window_size: 0x04, - max_frame_size: 0x05, - max_header_list_size: 0x06 - }.freeze + # type_value = 0x00 - 0x09 are known, but these classes aren't defined yet... + # Frame.register_subclass adds them. + SUB_CLASSES = [] + private_constant :SUB_CLASSES # RFC7540: 4.1 Frame format # +-----------------------------------------------+ @@ -85,12 +77,29 @@ module Plum # [String] The payload. Value is frozen. attr_reader :payload - def initialize(type: nil, type_value: nil, flags: nil, flags_value: nil, stream_id: nil, payload: nil) + # @private + protected def initialize_base(type: nil, type_value: nil, flags: nil, flags_value: nil, stream_id: nil, payload: nil) @payload = payload || "" @length = @payload.bytesize - @type_value = type_value or self.type = type + @type_value = type_value || FRAME_TYPES[type] or raise ArgumentError.new("unknown frame type: #{type}") @flags_value = flags_value or self.flags = flags @stream_id = stream_id or raise ArgumentError.new("stream_id is necessary") + self + end + + # @private + def initialize(*, **) + raise ArgumentError, "can't instantiate abstract class" + end + + # Creates a new instance of Frame or an subclass of Frame. + # @private + def self.craft(type: nil, type_value: nil, **args) + type_value ||= type && FRAME_TYPES[type] or (raise ArgumentError, "unknown frame type") + klass = SUB_CLASSES[type_value] || Frame::Unknown + instance = klass.allocate + instance.send(:initialize_base, type_value: type_value, **args) + instance end # Returns the length of payload. @@ -105,12 +114,6 @@ module Plum FRAME_TYPES_INVERSE[@type_value] || ("unknown_%02x" % @type_value).to_sym end - # Sets the frame type. - # @param value [Symbol] The type. - def type=(value) - @type_value = FRAME_TYPES[value] or raise ArgumentError.new("unknown frame type: #{value}") - end - # Returns the set flags on the frame. # @return [Array<Symbol>] The flags. def flags @@ -150,26 +153,36 @@ module Plum # @private def inspect - "#<Plum::Frame:0x%04x} length=%d, type=%p, flags=%p, stream_id=0x%04x, payload=%p>" % [__id__, length, type, flags, stream_id, payload] + "#<%s:0x%04x length=%d, flags=%p, stream_id=0x%04x, payload=%p>" % [self.class, __id__, length, flags, stream_id, payload] end - # Parses a frame from given buffer. It changes given buffer. - # @param buffer [String] The buffer stored the data received from peer. Encoding must be Encoding::BINARY. - # @return [Frame, nil] The parsed frame or nil if the buffer is imcomplete. - def self.parse!(buffer) - return nil if buffer.bytesize < 9 # header: 9 bytes - length = buffer.uint24 - return nil if buffer.bytesize < 9 + length - - cur = buffer.byteshift(9 + length) - type_value, flags_value, r_sid = cur.byteslice(3, 6).unpack("CCN") - # r = r_sid >> 31 # currently not used - stream_id = r_sid # & ~(1 << 31) - - self.new(type_value: type_value, - flags_value: flags_value, - stream_id: stream_id, - payload: cur.byteslice(9, length)).freeze + class << self + # Parses a frame from given buffer. It changes given buffer. + # @param buffer [String] The buffer stored the data received from peer. Encoding must be Encoding::BINARY. + # @return [Frame, nil] The parsed frame or nil if the buffer is imcomplete. + def parse!(buffer) + return nil if buffer.bytesize < 9 # header: 9 bytes + length = buffer.uint24 + return nil if buffer.bytesize < 9 + length + + cur = buffer.byteshift(9 + length) + type_value, flags_value, r_sid = cur.byteslice(3, 6).unpack("CCN") + # r = r_sid >> 31 # currently not used + stream_id = r_sid # & ~(1 << 31) + + frame = (SUB_CLASSES[type_value] || Frame::Unknown).allocate + frame.send(:initialize_base, + type_value: type_value, + flags_value: flags_value, + stream_id: stream_id, + payload: cur.byteslice(9, length)) + frame.freeze + end + + # Sub classes must call this. + protected def register_subclass(type_value) + SUB_CLASSES[type_value] = self + end end end end |