aboutsummaryrefslogtreecommitdiffstats
path: root/lib/plum/frame.rb
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-05-08 22:41:53 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-05-08 22:41:53 +0900
commitef9daa152ecf2e3f9fe0f2c5eb083379a5077c3b (patch)
treeb9e2afa99c7912ffca4dc0a24c1ccd886348f91b /lib/plum/frame.rb
parent85f218f35d2e9f1332701d908d9570c698708620 (diff)
parent89c73779d0eab2d9aae1e524245beebd589bf15d (diff)
downloadplum-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.rb89
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