plum 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +35 -6
- data/bin/plum +7 -0
- data/examples/rack.ru +22 -0
- data/lib/plum/binary_string.rb +5 -5
- data/lib/plum/connection.rb +24 -25
- data/lib/plum/connection_utils.rb +1 -4
- data/lib/plum/errors.rb +1 -1
- data/lib/plum/event_emitter.rb +7 -5
- data/lib/plum/flow_control.rb +19 -12
- data/lib/plum/frame.rb +60 -50
- data/lib/plum/frame_factory.rb +39 -5
- data/lib/plum/frame_utils.rb +0 -3
- data/lib/plum/hpack/constants.rb +49 -49
- data/lib/plum/hpack/context.rb +4 -3
- data/lib/plum/hpack/decoder.rb +55 -45
- data/lib/plum/hpack/encoder.rb +15 -20
- data/lib/plum/http_connection.rb +19 -3
- data/lib/plum/https_connection.rb +21 -5
- data/lib/plum/rack/cli.rb +130 -0
- data/lib/plum/rack/config.rb +28 -0
- data/lib/plum/rack/connection.rb +169 -0
- data/lib/plum/rack/dsl.rb +44 -0
- data/lib/plum/rack/listener.rb +122 -0
- data/lib/plum/rack/server.rb +68 -0
- data/lib/plum/rack.rb +10 -0
- data/lib/plum/stream.rb +35 -25
- data/lib/plum/stream_utils.rb +0 -4
- data/lib/plum/version.rb +1 -1
- data/lib/plum.rb +1 -0
- data/lib/rack/handler/plum.rb +49 -0
- data/plum.gemspec +1 -0
- data/test/plum/hpack/test_decoder.rb +8 -8
- data/test/plum/hpack/test_encoder.rb +3 -3
- data/test/plum/stream/test_handle_frame.rb +6 -6
- data/test/plum/test_frame.rb +4 -1
- data/test/plum/test_http_connection.rb +1 -3
- data/test/plum/test_https_connection.rb +9 -12
- data/test/utils/server.rb +3 -3
- metadata +28 -3
data/lib/plum/stream.rb
CHANGED
@@ -9,25 +9,21 @@ module Plum
|
|
9
9
|
attr_reader :id, :state, :connection
|
10
10
|
attr_reader :weight, :exclusive
|
11
11
|
attr_accessor :parent
|
12
|
+
# The child (depending on this stream) streams.
|
13
|
+
attr_reader :children
|
12
14
|
|
13
15
|
def initialize(con, id, state: :idle, weight: 16, parent: nil, exclusive: false)
|
14
16
|
@connection = con
|
15
17
|
@id = id
|
16
18
|
@state = state
|
17
19
|
@continuation = []
|
20
|
+
@children = Set.new
|
18
21
|
|
19
22
|
initialize_flow_control(send: @connection.remote_settings[:initial_window_size],
|
20
23
|
recv: @connection.local_settings[:initial_window_size])
|
21
24
|
update_dependency(weight: weight, parent: parent, exclusive: exclusive)
|
22
25
|
end
|
23
26
|
|
24
|
-
# Returns the child (depending on this stream) streams.
|
25
|
-
#
|
26
|
-
# @return [Array<Stream>] The child streams.
|
27
|
-
def children
|
28
|
-
@connection.streams.values.select {|c| c.parent == self }.freeze
|
29
|
-
end
|
30
|
-
|
31
27
|
# Processes received frames for this stream. Internal use.
|
32
28
|
# @private
|
33
29
|
def receive_frame(frame)
|
@@ -58,7 +54,6 @@ module Plum
|
|
58
54
|
end
|
59
55
|
|
60
56
|
# Closes this stream. Sends RST_STREAM frame to the peer.
|
61
|
-
#
|
62
57
|
# @param error_type [Symbol] The error type to be contained in the RST_STREAM frame.
|
63
58
|
def close(error_type = :no_error)
|
64
59
|
@state = :closed
|
@@ -67,20 +62,30 @@ module Plum
|
|
67
62
|
|
68
63
|
private
|
69
64
|
def send_immediately(frame)
|
70
|
-
callback(:send_frame, frame)
|
71
65
|
@connection.send(frame)
|
72
66
|
end
|
73
67
|
|
74
68
|
def update_dependency(weight: nil, parent: nil, exclusive: nil)
|
75
69
|
raise StreamError.new(:protocol_error, "A stream cannot depend on itself.") if parent == self
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
70
|
+
|
71
|
+
if weight
|
72
|
+
@weight = weight
|
73
|
+
end
|
74
|
+
|
75
|
+
if parent
|
76
|
+
@parent = parent
|
77
|
+
@parent.children << self
|
78
|
+
end
|
79
|
+
|
80
|
+
if exclusive != nil
|
81
|
+
@exclusive = exclusive
|
82
|
+
if @parent && exclusive
|
83
|
+
@parent.children.to_a.each do |child|
|
84
|
+
next if child == self
|
85
|
+
@parent.children.delete(child)
|
86
|
+
child.parent = self
|
87
|
+
@children << child
|
88
|
+
end
|
84
89
|
end
|
85
90
|
end
|
86
91
|
end
|
@@ -105,7 +110,7 @@ module Plum
|
|
105
110
|
raise StreamError.new(:stream_closed)
|
106
111
|
end
|
107
112
|
|
108
|
-
if frame.
|
113
|
+
if frame.padded?
|
109
114
|
padding_length = frame.payload.uint8(0)
|
110
115
|
if padding_length >= frame.length
|
111
116
|
raise ConnectionError.new(:protocol_error, "padding is too long")
|
@@ -116,18 +121,17 @@ module Plum
|
|
116
121
|
end
|
117
122
|
callback(:data, body)
|
118
123
|
|
119
|
-
receive_end_stream if frame.
|
124
|
+
receive_end_stream if frame.end_stream?
|
120
125
|
end
|
121
126
|
|
122
127
|
def receive_complete_headers(frames)
|
123
|
-
frames = frames.dup
|
124
128
|
first = frames.shift
|
125
129
|
|
126
130
|
payload = first.payload
|
127
131
|
first_length = first.length
|
128
132
|
padding_length = 0
|
129
133
|
|
130
|
-
if first.
|
134
|
+
if first.padded?
|
131
135
|
padding_length = payload.uint8
|
132
136
|
first_length -= 1 + padding_length
|
133
137
|
payload = payload.byteslice(1, first_length)
|
@@ -135,7 +139,7 @@ module Plum
|
|
135
139
|
payload = payload.dup
|
136
140
|
end
|
137
141
|
|
138
|
-
if first.
|
142
|
+
if first.priority?
|
139
143
|
receive_priority_payload(payload.byteshift(5))
|
140
144
|
first_length -= 5
|
141
145
|
end
|
@@ -156,7 +160,7 @@ module Plum
|
|
156
160
|
|
157
161
|
callback(:headers, decoded_headers)
|
158
162
|
|
159
|
-
receive_end_stream if first.
|
163
|
+
receive_end_stream if first.end_stream?
|
160
164
|
end
|
161
165
|
|
162
166
|
def receive_headers(frame)
|
@@ -171,7 +175,7 @@ module Plum
|
|
171
175
|
@state = :open
|
172
176
|
callback(:open)
|
173
177
|
|
174
|
-
if frame.
|
178
|
+
if frame.end_headers?
|
175
179
|
receive_complete_headers([frame])
|
176
180
|
else
|
177
181
|
@continuation << frame
|
@@ -182,7 +186,7 @@ module Plum
|
|
182
186
|
# state error mustn't happen: server_connection validates
|
183
187
|
@continuation << frame
|
184
188
|
|
185
|
-
if frame.
|
189
|
+
if frame.end_headers?
|
186
190
|
receive_complete_headers(@continuation)
|
187
191
|
@continuation.clear
|
188
192
|
end
|
@@ -214,5 +218,11 @@ module Plum
|
|
214
218
|
callback(:rst_stream, frame)
|
215
219
|
@state = :closed # MUST NOT send RST_STREAM
|
216
220
|
end
|
221
|
+
|
222
|
+
# override EventEmitter
|
223
|
+
def callback(name, *args)
|
224
|
+
super(name, *args)
|
225
|
+
@connection.callback(name, self, *args)
|
226
|
+
end
|
217
227
|
end
|
218
228
|
end
|
data/lib/plum/stream_utils.rb
CHANGED
@@ -3,7 +3,6 @@ using Plum::BinaryString
|
|
3
3
|
module Plum
|
4
4
|
module StreamUtils
|
5
5
|
# Responds to a HTTP request.
|
6
|
-
#
|
7
6
|
# @param headers [Enumerable<String, String>] The response headers.
|
8
7
|
# @param body [String, IO] The response body.
|
9
8
|
def respond(headers, body = nil, end_stream: true) # TODO: priority, padding
|
@@ -16,7 +15,6 @@ module Plum
|
|
16
15
|
end
|
17
16
|
|
18
17
|
# Reserves a stream to server push. Sends PUSH_PROMISE and create new stream.
|
19
|
-
#
|
20
18
|
# @param headers [Enumerable<String, String>] The *request* headers. It must contain all of them: ':authority', ':method', ':scheme' and ':path'.
|
21
19
|
# @return [Stream] The stream to send push response.
|
22
20
|
def promise(headers)
|
@@ -30,7 +28,6 @@ module Plum
|
|
30
28
|
end
|
31
29
|
|
32
30
|
# Sends response headers. If the encoded frame is larger than MAX_FRAME_SIZE, the headers will be splitted into HEADERS frame and CONTINUATION frame(s).
|
33
|
-
#
|
34
31
|
# @param headers [Enumerable<String, String>] The response headers.
|
35
32
|
# @param end_stream [Boolean] Set END_STREAM flag or not.
|
36
33
|
def send_headers(headers, end_stream:)
|
@@ -44,7 +41,6 @@ module Plum
|
|
44
41
|
end
|
45
42
|
|
46
43
|
# Sends DATA frame. If the data is larger than MAX_FRAME_SIZE, DATA frame will be splitted.
|
47
|
-
#
|
48
44
|
# @param data [String, IO] The data to send.
|
49
45
|
# @param end_stream [Boolean] Set END_STREAM flag or not.
|
50
46
|
def send_data(data, end_stream: true)
|
data/lib/plum/version.rb
CHANGED
data/lib/plum.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Rack
|
2
|
+
module Handler
|
3
|
+
class Plum
|
4
|
+
def self.run(app, options = {})
|
5
|
+
opts = default_options.merge(options)
|
6
|
+
|
7
|
+
config = ::Plum::Rack::Config.new(
|
8
|
+
listeners: [
|
9
|
+
{
|
10
|
+
listener: ::Plum::Rack::TLSListener,
|
11
|
+
hostname: opts[:Host],
|
12
|
+
port: opts[:Port].to_i
|
13
|
+
}
|
14
|
+
],
|
15
|
+
debug: !!opts[:Debug]
|
16
|
+
)
|
17
|
+
|
18
|
+
@server = ::Plum::Rack::Server.new(app, config)
|
19
|
+
yield @server if block_given? # TODO
|
20
|
+
@server.start
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.shutdown
|
24
|
+
@server.stop if @server
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.valid_options
|
28
|
+
{
|
29
|
+
"Host=HOST" => "Hostname to listen on (default: #{default_options[:Host]})",
|
30
|
+
"Port=PORT" => "Port to listen on (default: #{default_options[:Port]})",
|
31
|
+
"Debug" => "Turn on debug mode (default: #{default_options[:Debug]})",
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def self.default_options
|
37
|
+
rack_env = ENV["RACK_ENV"] || "development"
|
38
|
+
dev = rack_env == "development"
|
39
|
+
default_options = {
|
40
|
+
Host: dev ? "localhost" : "0.0.0.0",
|
41
|
+
Port: 8080,
|
42
|
+
Debug: dev,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
register(:plum, ::Rack::Handler::Plum)
|
48
|
+
end
|
49
|
+
end
|
data/plum.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.10"
|
22
22
|
spec.add_development_dependency "http_parser.rb"
|
23
|
+
spec.add_development_dependency "rack"
|
23
24
|
spec.add_development_dependency "rake"
|
24
25
|
spec.add_development_dependency "yard"
|
25
26
|
spec.add_development_dependency "minitest", "~> 5.7.0"
|
@@ -4,38 +4,38 @@ class HPACKDecoderTest < Minitest::Test
|
|
4
4
|
# C.1.1
|
5
5
|
def test_hpack_read_integer_small
|
6
6
|
buf = [0b11001010, 0b00001111].pack("C*")
|
7
|
-
result = new_decoder.__send__(:read_integer
|
7
|
+
result, succ = new_decoder.__send__(:read_integer, buf, 0, 5)
|
8
8
|
assert_equal(10, result)
|
9
|
-
assert_equal(
|
9
|
+
assert_equal(1, succ)
|
10
10
|
end
|
11
11
|
|
12
12
|
# C.1.2
|
13
13
|
def test_hpack_read_integer_big
|
14
14
|
buf = [0b11011111, 0b10011010, 0b00001010, 0b00001111].pack("C*")
|
15
|
-
result = new_decoder.__send__(:read_integer
|
15
|
+
result, succ = new_decoder.__send__(:read_integer, buf, 0, 5)
|
16
16
|
assert_equal(1337, result)
|
17
|
-
assert_equal(
|
17
|
+
assert_equal(3, succ)
|
18
18
|
end
|
19
19
|
|
20
20
|
# C.1.3
|
21
21
|
def test_hpack_read_integer_8prefix
|
22
22
|
buf = [0b00101010, 0b00001111].pack("C*")
|
23
|
-
result = new_decoder.__send__(:read_integer
|
23
|
+
result, succ = new_decoder.__send__(:read_integer, buf, 0, 8)
|
24
24
|
assert_equal(42, result)
|
25
|
-
assert_equal(
|
25
|
+
assert_equal(1, succ)
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_hpack_read_integer_too_big
|
29
29
|
buf = [0b11011111, 0b10011010, 0b10001010, 0b10001111, 0b11111111, 0b00000011].pack("C*")
|
30
30
|
assert_raises(HPACKError) {
|
31
|
-
new_decoder.__send__(:read_integer
|
31
|
+
new_decoder.__send__(:read_integer, buf, 0, 5)
|
32
32
|
}
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_hpack_read_integer_incomplete
|
36
36
|
buf = [0b11011111, 0b10011010].pack("C*")
|
37
37
|
assert_raises(HPACKError) {
|
38
|
-
new_decoder.__send__(:read_integer
|
38
|
+
new_decoder.__send__(:read_integer, buf, 0, 5)
|
39
39
|
}
|
40
40
|
end
|
41
41
|
|
@@ -3,19 +3,19 @@ require "test_helper"
|
|
3
3
|
class HPACKEncoderTest < Minitest::Test
|
4
4
|
# C.1.1
|
5
5
|
def test_hpack_encode_integer_small
|
6
|
-
result = new_encoder(1 << 31).__send__(:encode_integer, 10, 5)
|
6
|
+
result = new_encoder(1 << 31).__send__(:encode_integer, 10, 5, 0b00000000)
|
7
7
|
assert_equal([0b00001010].pack("C*"), result)
|
8
8
|
end
|
9
9
|
|
10
10
|
# C.1.2
|
11
11
|
def test_hpack_encode_integer_big
|
12
|
-
result = new_encoder(1 << 31).__send__(:encode_integer, 1337, 5)
|
12
|
+
result = new_encoder(1 << 31).__send__(:encode_integer, 1337, 5, 0b000000)
|
13
13
|
assert_equal([0b00011111, 0b10011010, 0b00001010].pack("C*"), result)
|
14
14
|
end
|
15
15
|
|
16
16
|
# C.1.3
|
17
17
|
def test_hpack_encode_integer_8prefix
|
18
|
-
result = new_encoder(1 << 31).__send__(:encode_integer, 42, 8)
|
18
|
+
result = new_encoder(1 << 31).__send__(:encode_integer, 42, 8, 0b000000)
|
19
19
|
assert_equal([0b00101010].pack("C*"), result)
|
20
20
|
end
|
21
21
|
|
@@ -8,7 +8,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
8
8
|
payload = "ABC" * 5
|
9
9
|
open_new_stream(state: :open) {|stream|
|
10
10
|
data = nil
|
11
|
-
stream.on(:data) {|_data| data = _data }
|
11
|
+
stream.connection.on(:data) {|_, _data| data = _data }
|
12
12
|
stream.receive_frame(Frame.new(type: :data, stream_id: stream.id,
|
13
13
|
flags: [], payload: payload))
|
14
14
|
assert_equal(payload, data)
|
@@ -19,7 +19,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
19
19
|
payload = "ABC" * 5
|
20
20
|
open_new_stream(state: :open) {|stream|
|
21
21
|
data = nil
|
22
|
-
stream.on(:data) {|_data| data = _data }
|
22
|
+
stream.connection.on(:data) {|_, _data| data = _data }
|
23
23
|
stream.receive_frame(Frame.new(type: :data, stream_id: stream.id,
|
24
24
|
flags: [:padded], payload: "".push_uint8(6).push(payload).push("\x00"*6)))
|
25
25
|
assert_equal(payload, data)
|
@@ -59,7 +59,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
59
59
|
def test_stream_handle_headers_single
|
60
60
|
open_new_stream {|stream|
|
61
61
|
headers = nil
|
62
|
-
stream.on(:headers) {|_headers|
|
62
|
+
stream.connection.on(:headers) {|_, _headers|
|
63
63
|
headers = _headers
|
64
64
|
}
|
65
65
|
stream.receive_frame(Frame.new(type: :headers,
|
@@ -75,7 +75,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
75
75
|
open_new_stream {|stream|
|
76
76
|
payload = HPACK::Encoder.new(0).encode([[":path", "/"]])
|
77
77
|
headers = nil
|
78
|
-
stream.on(:headers) {|_headers|
|
78
|
+
stream.connection.on(:headers) {|_, _headers|
|
79
79
|
headers = _headers
|
80
80
|
}
|
81
81
|
stream.receive_frame(Frame.new(type: :headers,
|
@@ -96,7 +96,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
96
96
|
open_new_stream {|stream|
|
97
97
|
payload = HPACK::Encoder.new(0).encode([[":path", "/"]])
|
98
98
|
headers = nil
|
99
|
-
stream.on(:headers) {|_headers|
|
99
|
+
stream.connection.on(:headers) {|_, _headers|
|
100
100
|
headers = _headers
|
101
101
|
}
|
102
102
|
stream.receive_frame(Frame.new(type: :headers,
|
@@ -156,7 +156,7 @@ class StreamHandleFrameTest < Minitest::Test
|
|
156
156
|
stream = open_new_stream(con)
|
157
157
|
|
158
158
|
headers = nil
|
159
|
-
stream.on(:headers) {|_headers| headers = _headers }
|
159
|
+
stream.connection.on(:headers) {|_, _headers| headers = _headers }
|
160
160
|
header_block = HPACK::Encoder.new(0).encode([[":path", "/"]])
|
161
161
|
payload = "".push_uint32((1 << 31) | parent.id)
|
162
162
|
.push_uint8(50)
|
data/test/plum/test_frame.rb
CHANGED
@@ -4,6 +4,7 @@ class FrameTest < Minitest::Test
|
|
4
4
|
# Frame.parse!
|
5
5
|
def test_parse_header_uncomplete
|
6
6
|
buffer = "\x00\x00\x00" << "\x00" << "\x00"
|
7
|
+
buffer.force_encoding(Encoding::BINARY)
|
7
8
|
buffer_orig = buffer.dup
|
8
9
|
assert_nil(Plum::Frame.parse!(buffer))
|
9
10
|
assert_equal(buffer_orig, buffer)
|
@@ -11,6 +12,7 @@ class FrameTest < Minitest::Test
|
|
11
12
|
|
12
13
|
def test_parse_body_uncomplete
|
13
14
|
buffer = "\x00\x00\x03" << "\x00" << "\x00" << "\x00\x00\x00\x00" << "ab"
|
15
|
+
buffer.force_encoding(Encoding::BINARY)
|
14
16
|
buffer_orig = buffer.dup
|
15
17
|
assert_nil(Plum::Frame.parse!(buffer))
|
16
18
|
assert_equal(buffer_orig, buffer)
|
@@ -18,7 +20,8 @@ class FrameTest < Minitest::Test
|
|
18
20
|
|
19
21
|
def test_parse
|
20
22
|
# R 0x1, stream_id 0x4, body "abc"
|
21
|
-
buffer = "\x00\x00\x03" << "\x00" << "\x09" << "\
|
23
|
+
buffer = "\x00\x00\x03" << "\x00" << "\x09" << "\x00\x00\x00\x04" << "abc" << "next_frame_data"
|
24
|
+
buffer.force_encoding(Encoding::BINARY)
|
22
25
|
frame = Plum::Frame.parse!(buffer)
|
23
26
|
assert_equal(3, frame.length)
|
24
27
|
assert_equal(:data, frame.type)
|
@@ -27,9 +27,7 @@ class HTTPConnectionNegotiationTest < Minitest::Test
|
|
27
27
|
io = StringIO.new
|
28
28
|
con = HTTPConnection.new(io)
|
29
29
|
heads = nil
|
30
|
-
con.on(:
|
31
|
-
stream.on(:headers) {|_h| heads = _h.to_h }
|
32
|
-
}
|
30
|
+
con.on(:headers) {|_, _h| heads = _h.to_h }
|
33
31
|
req = "GET / HTTP/1.1\r\n" <<
|
34
32
|
"Host: rhe.jp\r\n" <<
|
35
33
|
"User-Agent: nya\r\n" <<
|
@@ -64,24 +64,21 @@ class HTTPSConnectionNegotiationTest < Minitest::Test
|
|
64
64
|
client_thread = Thread.new {
|
65
65
|
sock = TCPSocket.new("127.0.0.1", LISTEN_PORT)
|
66
66
|
begin
|
67
|
-
|
68
|
-
ctx =
|
69
|
-
|
70
|
-
ctx.ciphers = "AES256-GCM-SHA384"
|
71
|
-
}
|
72
|
-
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
|
73
|
-
ssl.connect
|
74
|
-
ssl.write Connection::CLIENT_CONNECTION_PREFACE
|
75
|
-
ssl.write Frame.settings.assemble
|
67
|
+
ctx = OpenSSL::SSL::SSLContext.new.tap {|ctx|
|
68
|
+
ctx.alpn_protocols = ["h2"]
|
69
|
+
ctx.ciphers = "AES256-GCM-SHA384"
|
76
70
|
}
|
77
|
-
|
78
|
-
|
71
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
|
72
|
+
ssl.connect
|
73
|
+
ssl.write Connection::CLIENT_CONNECTION_PREFACE
|
74
|
+
ssl.write Frame.settings.assemble
|
75
|
+
sleep
|
79
76
|
ensure
|
80
77
|
sock.close
|
81
78
|
end
|
82
79
|
}
|
83
|
-
client_thread.join
|
84
80
|
server_thread.join
|
81
|
+
client_thread.kill
|
85
82
|
|
86
83
|
flunk "test not run" unless run
|
87
84
|
end
|
data/test/utils/server.rb
CHANGED
@@ -31,7 +31,7 @@ module ServerUtils
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def sent_frames(con = nil)
|
34
|
-
resp = (con || @_con).
|
34
|
+
resp = (con || @_con).sock.string.dup.force_encoding(Encoding::BINARY)
|
35
35
|
frames = []
|
36
36
|
while f = Frame.parse!(resp)
|
37
37
|
frames << f
|
@@ -40,10 +40,10 @@ module ServerUtils
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def capture_frames(con = nil, &blk)
|
43
|
-
io = (con || @_con).
|
43
|
+
io = (con || @_con).sock
|
44
44
|
pos = io.string.bytesize
|
45
45
|
blk.call
|
46
|
-
resp = io.string.byteslice(pos, io.string.bytesize - pos)
|
46
|
+
resp = io.string.byteslice(pos, io.string.bytesize - pos).force_encoding(Encoding::BINARY)
|
47
47
|
frames = []
|
48
48
|
while f = Frame.parse!(resp)
|
49
49
|
frames << f
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rhenium
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,7 +153,8 @@ dependencies:
|
|
139
153
|
description: A minimal implementation of HTTP/2 server.
|
140
154
|
email:
|
141
155
|
- k@rhe.jp
|
142
|
-
executables:
|
156
|
+
executables:
|
157
|
+
- plum
|
143
158
|
extensions: []
|
144
159
|
extra_rdoc_files: []
|
145
160
|
files:
|
@@ -151,7 +166,9 @@ files:
|
|
151
166
|
- README.md
|
152
167
|
- Rakefile
|
153
168
|
- bin/.gitkeep
|
169
|
+
- bin/plum
|
154
170
|
- examples/non_tls_server.rb
|
171
|
+
- examples/rack.ru
|
155
172
|
- examples/static_server.rb
|
156
173
|
- lib/plum.rb
|
157
174
|
- lib/plum/binary_string.rb
|
@@ -170,9 +187,17 @@ files:
|
|
170
187
|
- lib/plum/hpack/huffman.rb
|
171
188
|
- lib/plum/http_connection.rb
|
172
189
|
- lib/plum/https_connection.rb
|
190
|
+
- lib/plum/rack.rb
|
191
|
+
- lib/plum/rack/cli.rb
|
192
|
+
- lib/plum/rack/config.rb
|
193
|
+
- lib/plum/rack/connection.rb
|
194
|
+
- lib/plum/rack/dsl.rb
|
195
|
+
- lib/plum/rack/listener.rb
|
196
|
+
- lib/plum/rack/server.rb
|
173
197
|
- lib/plum/stream.rb
|
174
198
|
- lib/plum/stream_utils.rb
|
175
199
|
- lib/plum/version.rb
|
200
|
+
- lib/rack/handler/plum.rb
|
176
201
|
- plum.gemspec
|
177
202
|
- test/plum/connection/test_handle_frame.rb
|
178
203
|
- test/plum/hpack/test_context.rb
|