aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/plum.rb11
-rw-r--r--lib/plum/connection.rb10
-rw-r--r--lib/plum/flow_control.rb3
-rw-r--r--lib/plum/frame.rb181
-rw-r--r--lib/plum/frame/continuation.rb16
-rw-r--r--lib/plum/frame/data.rb31
-rw-r--r--lib/plum/frame/goaway.rb20
-rw-r--r--lib/plum/frame/headers.rb32
-rw-r--r--lib/plum/frame/ping.rb24
-rw-r--r--lib/plum/frame/priority.rb12
-rw-r--r--lib/plum/frame/push_promise.rb33
-rw-r--r--lib/plum/frame/rst_stream.rb16
-rw-r--r--lib/plum/frame/settings.rb43
-rw-r--r--lib/plum/frame/unknown.rb12
-rw-r--r--lib/plum/frame/window_update.rb16
-rw-r--r--lib/plum/server/http_connection.rb6
-rw-r--r--lib/plum/stream.rb10
17 files changed, 313 insertions, 163 deletions
diff --git a/lib/plum.rb b/lib/plum.rb
index 3220bbc..fa70317 100644
--- a/lib/plum.rb
+++ b/lib/plum.rb
@@ -13,6 +13,17 @@ require "plum/hpack/context"
require "plum/hpack/decoder"
require "plum/hpack/encoder"
require "plum/frame"
+require "plum/frame/data"
+require "plum/frame/headers"
+require "plum/frame/priority"
+require "plum/frame/rst_stream"
+require "plum/frame/settings"
+require "plum/frame/push_promise"
+require "plum/frame/ping"
+require "plum/frame/goaway"
+require "plum/frame/window_update"
+require "plum/frame/continuation"
+require "plum/frame/unknown"
require "plum/flow_control"
require "plum/connection"
require "plum/stream"
diff --git a/lib/plum/connection.rb b/lib/plum/connection.rb
index 1eac16e..36faedd 100644
--- a/lib/plum/connection.rb
+++ b/lib/plum/connection.rb
@@ -85,7 +85,7 @@ module Plum
# Sends local settings to the peer.
# @param new_settings [Hash<Symbol, Integer>]
def settings(**new_settings)
- send_immediately Frame.settings(**new_settings)
+ send_immediately Frame::Settings.new(**new_settings)
old_settings = @local_settings.dup
@local_settings.merge!(new_settings)
@@ -98,14 +98,14 @@ module Plum
# @param data [String] Must be 8 octets.
# @raise [ArgumentError] If the data is not 8 octets.
def ping(data = "plum\x00\x00\x00\x00")
- send_immediately Frame.ping(data)
+ send_immediately Frame::Ping.new(data)
end
# Sends GOAWAY frame to the peer and closes the connection.
# @param error_type [Symbol] The error type to be contained in the GOAWAY frame.
def goaway(error_type = :no_error, message = "")
last_id = @max_stream_ids.max
- send_immediately Frame.goaway(last_id, error_type, message)
+ send_immediately Frame::Goaway.new(last_id, error_type, message)
end
# Returns whether peer enables server push or not
@@ -202,7 +202,7 @@ module Plum
callback(:remote_settings, @remote_settings, old_remote_settings)
- send_immediately Frame.settings(:ack) if send_ack
+ send_immediately Frame::Settings.new(:ack) if send_ack
if @state == :waiting_settings
@state = :open
@@ -223,7 +223,7 @@ module Plum
else
opaque_data = frame.payload
callback(:ping, opaque_data)
- send_immediately Frame.ping(:ack, opaque_data)
+ send_immediately Frame::Ping.new(:ack, opaque_data)
end
end
diff --git a/lib/plum/flow_control.rb b/lib/plum/flow_control.rb
index 9a2aa1d..f28fa3a 100644
--- a/lib/plum/flow_control.rb
+++ b/lib/plum/flow_control.rb
@@ -29,9 +29,8 @@ module Plum
# @param wsi [Integer] The amount to increase receiving window size. The legal range is 1 to 2^32-1.
def window_update(wsi)
@recv_remaining_window += wsi
- payload = String.new.push_uint32(wsi)
sid = (Stream === self) ? self.id : 0
- send_immediately Frame.new(type: :window_update, stream_id: sid, payload: payload)
+ send_immediately Frame::WindowUpdate.new(sid, wsi)
end
protected
diff --git a/lib/plum/frame.rb b/lib/plum/frame.rb
index 57b3061..4ac0596 100644
--- a/lib/plum/frame.rb
+++ b/lib/plum/frame.rb
@@ -1,7 +1,6 @@
# frozen-string-literal: true
using Plum::BinaryString
-
module Plum
class Frame
FRAME_TYPES = {
@@ -53,15 +52,6 @@ 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
-
# RFC7540: 4.1 Frame format
# +-----------------------------------------------+
# | Length (24) |
@@ -82,12 +72,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.
@@ -102,12 +109,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
@@ -147,44 +148,7 @@ 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]
- end
-
- # Splits this frame into multiple frames not to exceed MAX_FRAME_SIZE.
- # @param max [Integer] The maximum size of a frame payload.
- # @yield [Frame] The splitted frames.
- def split(max)
- return yield self if @length <= max
- first, *mid, last = @payload.chunk(max)
- case type
- when :data
- yield Frame.new(type_value: 0, stream_id: @stream_id, payload: first, flags_value: @flags_value & ~1)
- mid.each { |slice|
- yield Frame.new(type_value: 0, stream_id: @stream_id, payload: slice, flags_value: 0)
- }
- yield Frame.new(type_value: 0, stream_id: @stream_id, payload: last, flags_value: @flags_value & 1)
- when :headers, :push_promise
- yield Frame.new(type_value: @type_value, stream_id: @stream_id, payload: first, flags_value: @flags_value & ~4)
- mid.each { |slice|
- yield Frame.new(type: :continuation, stream_id: @stream_id, payload: slice, flags_value: 0)
- }
- yield Frame.new(type: :continuation, stream_id: @stream_id, payload: last, flags_value: @flags_value & 4)
- else
- raise NotImplementedError.new("frame split of frame with type #{type} is not supported")
- end
- end
-
- # Parses SETTINGS frame payload. Ignores unknown settings type (see RFC7540 6.5.2).
- # @return [Hash<Symbol, Integer>] The parsed strings.
- def parse_settings
- settings = {}
- payload.each_byteslice(6) do |param|
- id = param.uint16
- name = Frame::SETTINGS_TYPE.key(id)
- # ignore unknown settings type
- settings[name] = param.uint32(2) if name
- end
- settings
+ "#<%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.
@@ -200,100 +164,21 @@ module Plum
# 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
+ 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
- # Creates a RST_STREAM frame.
- # @param stream_id [Integer] The stream ID.
- # @param error_type [Symbol] The error type defined in RFC 7540 Section 7.
- def self.rst_stream(stream_id, error_type)
- payload = String.new.push_uint32(HTTPError::ERROR_CODES[error_type])
- Frame.new(type: :rst_stream, stream_id: stream_id, payload: payload)
- end
-
- # Creates a GOAWAY frame.
- # @param last_id [Integer] The biggest processed stream ID.
- # @param error_type [Symbol] The error type defined in RFC 7540 Section 7.
- # @param message [String] Additional debug data.
- # @see RFC 7540 Section 6.8
- def self.goaway(last_id, error_type, message = "")
- payload = String.new.push_uint32(last_id)
- .push_uint32(HTTPError::ERROR_CODES[error_type])
- .push(message)
- Frame.new(type: :goaway, stream_id: 0, payload: payload)
- end
-
- # Creates a SETTINGS frame.
- # @param ack [Symbol] Pass :ack to create an ACK frame.
- # @param args [Hash<Symbol, Integer>] The settings values to send.
- def self.settings(ack = nil, **args)
- payload = String.new
- args.each { |key, value|
- id = Frame::SETTINGS_TYPE[key] or raise ArgumentError.new("invalid settings type")
- payload.push_uint16(id)
- payload.push_uint32(value)
- }
- Frame.new(type: :settings, stream_id: 0, flags: [ack], payload: payload)
- end
-
- # Creates a PING frame.
- # @overload ping(ack, payload)
- # @param ack [Symbol] Pass :ack to create an ACK frame.
- # @param payload [String] 8 bytes length data to send.
- # @overload ping(payload = "plum\x00\x00\x00\x00")
- # @param payload [String] 8 bytes length data to send.
- def self.ping(arg1 = "plum\x00\x00\x00\x00".b, arg2 = nil)
- if !arg2
- raise ArgumentError.new("data must be 8 octets") if arg1.bytesize != 8
- arg1 = arg1.b if arg1.encoding != Encoding::BINARY
- Frame.new(type: :ping, stream_id: 0, payload: arg1)
- else
- Frame.new(type: :ping, stream_id: 0, flags: [:ack], payload: arg2)
- end
- end
-
- # Creates a DATA frame.
- # @param stream_id [Integer] The stream ID.
- # @param payload [String] Payload.
- # @param end_stream [Boolean] add END_STREAM flag
- def self.data(stream_id, payload = "", end_stream: false)
- payload = payload.b if payload&.encoding != Encoding::BINARY
- fval = end_stream ? 1 : 0
- Frame.new(type_value: 0, stream_id: stream_id, flags_value: fval, payload: payload)
- end
-
- # Creates a HEADERS frame.
- # @param stream_id [Integer] The stream ID.
- # @param encoded [String] Headers.
- # @param end_stream [Boolean] add END_STREAM flag
- # @param end_headers [Boolean] add END_HEADERS flag
- def self.headers(stream_id, encoded, end_stream: false, end_headers: false)
- fval = end_stream ? 1 : 0
- fval += 4 if end_headers
- Frame.new(type_value: 1, stream_id: stream_id, flags_value: fval, payload: encoded)
- end
-
- # Creates a PUSH_PROMISE frame.
- # @param stream_id [Integer] The stream ID.
- # @param new_id [Integer] The stream ID to create.
- # @param encoded [String] Request headers.
- # @param end_headers [Boolean] add END_HEADERS flag
- def self.push_promise(stream_id, new_id, encoded, end_headers: false)
- payload = String.new.push_uint32(new_id)
- .push(encoded)
- fval = end_headers ? 4 : 0
- Frame.new(type: :push_promise, stream_id: stream_id, flags_value: fval, payload: payload)
- end
-
- # Creates a CONTINUATION frame.
- # @param stream_id [Integer] The stream ID.
- # @param payload [String] Payload.
- # @param end_headers [Boolean] add END_HEADERS flag
- def self.continuation(stream_id, payload, end_headers: false)
- Frame.new(type: :continuation, stream_id: stream_id, flags_value: (end_headers ? 4 : 0), payload: payload)
+ # @private
+ # type_value = 0x00 - 0x09 are known, but these classes aren't defined yet...
+ SUB_CLASSES = []
+ private_constant :SUB_CLASSES
+ def self.register_subclass(type_value)
+ SUB_CLASSES[type_value] = self
end
end
end
diff --git a/lib/plum/frame/continuation.rb b/lib/plum/frame/continuation.rb
new file mode 100644
index 0000000..1c5232c
--- /dev/null
+++ b/lib/plum/frame/continuation.rb
@@ -0,0 +1,16 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Continuation < Frame
+ register_subclass 0x09
+
+ # Creates a CONTINUATION frame.
+ # @param stream_id [Integer] The stream ID.
+ # @param payload [String] Payload.
+ # @param end_headers [Boolean] add END_HEADERS flag
+ def initialize(stream_id, payload, end_headers: false)
+ initialize_base(type: :continuation, stream_id: stream_id, flags_value: (end_headers ? 4 : 0), payload: payload)
+ end
+ end
+end
diff --git a/lib/plum/frame/data.rb b/lib/plum/frame/data.rb
new file mode 100644
index 0000000..7c02029
--- /dev/null
+++ b/lib/plum/frame/data.rb
@@ -0,0 +1,31 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Data < Frame
+ register_subclass 0x00
+
+ # Creates a DATA frame.
+ # @param stream_id [Integer] The stream ID.
+ # @param payload [String] Payload.
+ # @param end_stream [Boolean] add END_STREAM flag
+ def initialize(stream_id, payload = "", end_stream: false)
+ payload = payload.b if payload&.encoding != Encoding::BINARY
+ fval = end_stream ? 1 : 0
+ initialize_base(type_value: 0, stream_id: stream_id, flags_value: fval, payload: payload)
+ end
+
+ # Splits this frame into multiple frames not to exceed MAX_FRAME_SIZE.
+ # @param max [Integer] The maximum size of a frame payload.
+ # @yield [Frame] The splitted frames.
+ def split(max)
+ return yield self if @length <= max
+ first, *mid, last = @payload.chunk(max)
+ yield Frame.craft(type_value: 0, stream_id: @stream_id, payload: first, flags_value: @flags_value & ~1)
+ mid.each { |slice|
+ yield Frame.craft(type_value: 0, stream_id: @stream_id, payload: slice, flags_value: 0)
+ }
+ yield Frame.craft(type_value: 0, stream_id: @stream_id, payload: last, flags_value: @flags_value & 1)
+ end
+ end
+end
diff --git a/lib/plum/frame/goaway.rb b/lib/plum/frame/goaway.rb
new file mode 100644
index 0000000..e1e0097
--- /dev/null
+++ b/lib/plum/frame/goaway.rb
@@ -0,0 +1,20 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Goaway < Frame
+ register_subclass 0x07
+
+ # Creates a GOAWAY frame.
+ # @param last_id [Integer] The biggest processed stream ID.
+ # @param error_type [Symbol] The error type defined in RFC 7540 Section 7.
+ # @param message [String] Additional debug data.
+ # @see RFC 7540 Section 6.8
+ def initialize(last_id, error_type, message = "")
+ payload = String.new.push_uint32(last_id)
+ .push_uint32(HTTPError::ERROR_CODES[error_type])
+ .push(message)
+ initialize_base(type: :goaway, stream_id: 0, payload: payload)
+ end
+ end
+end
diff --git a/lib/plum/frame/headers.rb b/lib/plum/frame/headers.rb
new file mode 100644
index 0000000..12d6a61
--- /dev/null
+++ b/lib/plum/frame/headers.rb
@@ -0,0 +1,32 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Headers < Frame
+ register_subclass 0x01
+
+ # Creates a HEADERS frame.
+ # @param stream_id [Integer] The stream ID.
+ # @param encoded [String] Headers.
+ # @param end_stream [Boolean] add END_STREAM flag
+ # @param end_headers [Boolean] add END_HEADERS flag
+ def initialize(stream_id, encoded, end_stream: false, end_headers: false)
+ fval = end_stream ? 1 : 0
+ fval += 4 if end_headers
+ initialize_base(type_value: 1, stream_id: stream_id, flags_value: fval, payload: encoded)
+ end
+
+ # Splits this frame into multiple frames not to exceed MAX_FRAME_SIZE.
+ # @param max [Integer] The maximum size of a frame payload.
+ # @yield [Frame] The splitted frames.
+ def split(max)
+ return yield self if @length <= max
+ first, *mid, last = @payload.chunk(max)
+ yield Frame.craft(type_value: @type_value, stream_id: @stream_id, payload: first, flags_value: @flags_value & ~4)
+ mid.each { |slice|
+ yield Frame.craft(type: :continuation, stream_id: @stream_id, payload: slice, flags_value: 0)
+ }
+ yield Frame.craft(type: :continuation, stream_id: @stream_id, payload: last, flags_value: @flags_value & 4)
+ end
+ end
+end
diff --git a/lib/plum/frame/ping.rb b/lib/plum/frame/ping.rb
new file mode 100644
index 0000000..b0b3804
--- /dev/null
+++ b/lib/plum/frame/ping.rb
@@ -0,0 +1,24 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Ping < Frame
+ register_subclass 0x06
+
+ # Creates a PING frame.
+ # @overload ping(ack, payload)
+ # @param ack [Symbol] Pass :ack to create an ACK frame.
+ # @param payload [String] 8 bytes length data to send.
+ # @overload ping(payload = "plum\x00\x00\x00\x00")
+ # @param payload [String] 8 bytes length data to send.
+ def initialize(arg1 = "plum\x00\x00\x00\x00".b, arg2 = nil)
+ if !arg2
+ raise ArgumentError.new("data must be 8 octets") if arg1.bytesize != 8
+ arg1 = arg1.b if arg1.encoding != Encoding::BINARY
+ initialize_base(type: :ping, stream_id: 0, payload: arg1)
+ else
+ initialize_base(type: :ping, stream_id: 0, flags: [:ack], payload: arg2)
+ end
+ end
+ end
+end
diff --git a/lib/plum/frame/priority.rb b/lib/plum/frame/priority.rb
new file mode 100644
index 0000000..2d081ce
--- /dev/null
+++ b/lib/plum/frame/priority.rb
@@ -0,0 +1,12 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Priority < Frame
+ register_subclass 0x02
+
+ # Creates a PRIORITY frame.
+ def initialize
+ end
+ end
+end
diff --git a/lib/plum/frame/push_promise.rb b/lib/plum/frame/push_promise.rb
new file mode 100644
index 0000000..e07b8e6
--- /dev/null
+++ b/lib/plum/frame/push_promise.rb
@@ -0,0 +1,33 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::PushPromise < Frame
+ register_subclass 0x05
+
+ # Creates a PUSH_PROMISE frame.
+ # @param stream_id [Integer] The stream ID.
+ # @param new_id [Integer] The stream ID to create.
+ # @param encoded [String] Request headers.
+ # @param end_headers [Boolean] add END_HEADERS flag
+ def initialize(stream_id, new_id, encoded, end_headers: false)
+ payload = String.new.push_uint32(new_id)
+ .push(encoded)
+ fval = end_headers ? 4 : 0
+ initialize_base(type: :push_promise, stream_id: stream_id, flags_value: fval, payload: payload)
+ end
+
+ # Splits this frame into multiple frames not to exceed MAX_FRAME_SIZE.
+ # @param max [Integer] The maximum size of a frame payload.
+ # @yield [Frame] The splitted frames.
+ def split(max)
+ return yield self if @length <= max
+ first, *mid, last = @payload.chunk(max)
+ yield Frame.craft(type_value: @type_value, stream_id: @stream_id, payload: first, flags_value: @flags_value & ~4)
+ mid.each { |slice|
+ yield Frame.craft(type: :continuation, stream_id: @stream_id, payload: slice, flags_value: 0)
+ }
+ yield Frame.craft(type: :continuation, stream_id: @stream_id, payload: last, flags_value: @flags_value & 4)
+ end
+ end
+end
diff --git a/lib/plum/frame/rst_stream.rb b/lib/plum/frame/rst_stream.rb
new file mode 100644
index 0000000..a8004d5
--- /dev/null
+++ b/lib/plum/frame/rst_stream.rb
@@ -0,0 +1,16 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::RstStream < Frame
+ register_subclass 0x03
+
+ # Creates a RST_STREAM frame.
+ # @param stream_id [Integer] The stream ID.
+ # @param error_type [Symbol] The error type defined in RFC 7540 Section 7.
+ def initialize(stream_id, error_type)
+ payload = String.new.push_uint32(HTTPError::ERROR_CODES[error_type])
+ initialize_base(type: :rst_stream, stream_id: stream_id, payload: payload)
+ end
+ end
+end
diff --git a/lib/plum/frame/settings.rb b/lib/plum/frame/settings.rb
new file mode 100644
index 0000000..3bd13d4
--- /dev/null
+++ b/lib/plum/frame/settings.rb
@@ -0,0 +1,43 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Settings < Frame
+ register_subclass 0x04
+
+ 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
+
+ # Creates a SETTINGS frame.
+ # @param ack [Symbol] Pass :ack to create an ACK frame.
+ # @param args [Hash<Symbol, Integer>] The settings values to send.
+ def initialize(ack = nil, **args)
+ payload = String.new
+ args.each { |key, value|
+ id = SETTINGS_TYPE[key] or raise ArgumentError.new("invalid settings type: #{key}")
+ payload.push_uint16(id)
+ payload.push_uint32(value)
+ }
+ initialize_base(type: :settings, stream_id: 0, flags: [ack], payload: payload)
+ end
+
+ # Parses SETTINGS frame payload. Ignores unknown settings type (see RFC7540 6.5.2).
+ # @return [Hash<Symbol, Integer>] The parsed strings.
+ def parse_settings
+ settings = {}
+ payload.each_byteslice(6) do |param|
+ id = param.uint16
+ name = SETTINGS_TYPE.key(id)
+ # ignore unknown settings type
+ settings[name] = param.uint32(2) if name
+ end
+ settings
+ end
+ end
+end
diff --git a/lib/plum/frame/unknown.rb b/lib/plum/frame/unknown.rb
new file mode 100644
index 0000000..6e9decb
--- /dev/null
+++ b/lib/plum/frame/unknown.rb
@@ -0,0 +1,12 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::Unknown < Frame
+ # Creates a frame with unknown type value.
+ def initialize(type_value, **args)
+ initialize_base(type_value: type_value, **args)
+ end
+ end
+end
+
diff --git a/lib/plum/frame/window_update.rb b/lib/plum/frame/window_update.rb
new file mode 100644
index 0000000..6e36b2c
--- /dev/null
+++ b/lib/plum/frame/window_update.rb
@@ -0,0 +1,16 @@
+# frozen-string-literal: true
+
+using Plum::BinaryString
+module Plum
+ class Frame::WindowUpdate < Frame
+ register_subclass 0x08
+
+ # Creates a WINDOW_UPDATE frame.
+ # @param stream_id [Integer] the stream ID or 0.
+ # @param wsi [Integer] the amount to increase
+ def initialize(stream_id, wsi)
+ payload = String.new.push_uint32(wsi)
+ initialize_base(type: :window_update, stream_id: stream_id, payload: payload)
+ end
+ end
+end
diff --git a/lib/plum/server/http_connection.rb b/lib/plum/server/http_connection.rb
index b257137..1cf80dc 100644
--- a/lib/plum/server/http_connection.rb
+++ b/lib/plum/server/http_connection.rb
@@ -49,7 +49,7 @@ module Plum
def switch_protocol(settings, parser, headers, data)
self.on(:negotiated) {
- _frame = Frame.new(type: :settings, stream_id: 0, payload: Base64.urlsafe_decode64(settings))
+ _frame = Frame.craft(type: :settings, stream_id: 0, payload: Base64.urlsafe_decode64(settings))
receive_settings(_frame, send_ack: false) # HTTP2-Settings
process_first_request(parser, headers, data)
}
@@ -71,8 +71,8 @@ module Plum
":authority" => headers["host"] })
.reject { |n, v| ["connection", "http2-settings", "upgrade", "host"].include?(n) }
- stream.receive_frame Frame.headers(1, encoder.encode(nheaders), end_headers: true)
- stream.receive_frame Frame.data(1, body, end_stream: true)
+ stream.receive_frame Frame::Headers.new(1, encoder.encode(nheaders), end_headers: true)
+ stream.receive_frame Frame::Data.new(1, body, end_stream: true)
end
end
end
diff --git a/lib/plum/stream.rb b/lib/plum/stream.rb
index 733aeaf..420ee23 100644
--- a/lib/plum/stream.rb
+++ b/lib/plum/stream.rb
@@ -53,7 +53,7 @@ module Plum
end
rescue RemoteStreamError => e
callback(:stream_error, e)
- send_immediately Frame.rst_stream(id, e.http2_error_type)
+ send_immediately Frame::RstStream.new(id, e.http2_error_type)
close
end
@@ -97,7 +97,7 @@ module Plum
def promise(headers)
stream = @connection.reserve_stream(weight: self.weight + 1, parent: self)
encoded = @connection.hpack_encoder.encode(headers)
- frame = Frame.push_promise(id, stream.id, encoded, end_headers: true)
+ frame = Frame::PushPromise.new(id, stream.id, encoded, end_headers: true)
send frame
stream
end
@@ -107,7 +107,7 @@ module Plum
# @param end_stream [Boolean] Set END_STREAM flag or not.
def send_headers(headers, end_stream:)
encoded = @connection.hpack_encoder.encode(headers)
- frame = Frame.headers(id, encoded, end_headers: true, end_stream: end_stream)
+ frame = Frame::Headers.new(id, encoded, end_headers: true, end_stream: end_stream)
send frame
@state = :half_closed_local if end_stream
end
@@ -120,10 +120,10 @@ module Plum
if data.is_a?(IO)
until data.eof?
fragment = data.readpartial(max)
- send Frame.data(id, fragment, end_stream: end_stream && data.eof?)
+ send Frame::Data.new(id, fragment, end_stream: end_stream && data.eof?)
end
else
- send Frame.data(id, data, end_stream: end_stream)
+ send Frame::Data.new(id, data, end_stream: end_stream)
end
@state = :half_closed_local if end_stream
end