plum 0.1.3 → 0.2.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +84 -12
  3. data/circle.yml +27 -0
  4. data/examples/client/large.rb +20 -0
  5. data/examples/client/twitter.rb +51 -0
  6. data/examples/non_tls_server.rb +15 -9
  7. data/examples/static_server.rb +30 -23
  8. data/lib/plum.rb +9 -2
  9. data/lib/plum/client.rb +198 -0
  10. data/lib/plum/client/client_session.rb +91 -0
  11. data/lib/plum/client/connection.rb +19 -0
  12. data/lib/plum/client/legacy_client_session.rb +118 -0
  13. data/lib/plum/client/response.rb +100 -0
  14. data/lib/plum/client/upgrade_client_session.rb +46 -0
  15. data/lib/plum/connection.rb +58 -65
  16. data/lib/plum/connection_utils.rb +1 -1
  17. data/lib/plum/errors.rb +7 -3
  18. data/lib/plum/flow_control.rb +3 -3
  19. data/lib/plum/rack/listener.rb +3 -3
  20. data/lib/plum/rack/server.rb +1 -0
  21. data/lib/plum/rack/session.rb +5 -2
  22. data/lib/plum/server/connection.rb +42 -0
  23. data/lib/plum/{http_connection.rb → server/http_connection.rb} +7 -14
  24. data/lib/plum/{https_connection.rb → server/https_connection.rb} +2 -9
  25. data/lib/plum/stream.rb +54 -24
  26. data/lib/plum/stream_utils.rb +0 -12
  27. data/lib/plum/version.rb +1 -1
  28. data/plum.gemspec +2 -2
  29. data/test/plum/client/test_client.rb +152 -0
  30. data/test/plum/client/test_connection.rb +11 -0
  31. data/test/plum/client/test_legacy_client_session.rb +90 -0
  32. data/test/plum/client/test_response.rb +74 -0
  33. data/test/plum/client/test_upgrade_client_session.rb +45 -0
  34. data/test/plum/connection/test_handle_frame.rb +4 -1
  35. data/test/plum/{test_http_connection.rb → server/test_http_connection.rb} +4 -4
  36. data/test/plum/{test_https_connection.rb → server/test_https_connection.rb} +14 -8
  37. data/test/plum/test_connection.rb +9 -2
  38. data/test/plum/test_connection_utils.rb +9 -0
  39. data/test/plum/test_error.rb +1 -2
  40. data/test/plum/test_frame_factory.rb +37 -0
  41. data/test/plum/test_stream.rb +24 -4
  42. data/test/plum/test_stream_utils.rb +0 -1
  43. data/test/test_helper.rb +5 -2
  44. data/test/utils/assertions.rb +9 -9
  45. data/test/utils/client.rb +19 -0
  46. data/test/utils/server.rb +6 -6
  47. data/test/utils/string_socket.rb +15 -0
  48. metadata +36 -12
@@ -23,7 +23,6 @@ class ConnectionTest < Minitest::Test
23
23
  con << Frame.new(type: :settings, stream_id: 0, payload: _settings * (limit / 6 + 1)).assemble
24
24
  }
25
25
  }
26
-
27
26
  new_con.call {|con|
28
27
  assert_connection_error(:frame_size_error) {
29
28
  con << Frame.new(type: :headers, stream_id: 3, payload: "\x00" * (limit + 1)).assemble
@@ -89,8 +88,16 @@ class ConnectionTest < Minitest::Test
89
88
  }
90
89
  prepare.call {|con|
91
90
  assert_equal(:waiting_continuation, con.state)
92
- con << Frame.new(type: :continuation, flags: [:end_headers], stream_id: 3, payload: "hello").assemble
91
+ con << Frame.new(type: :continuation, flags: [:end_headers], stream_id: 3, payload: "").assemble
93
92
  assert_equal(:open, con.state)
94
93
  }
95
94
  end
95
+
96
+ def test_connection_local_error
97
+ open_server_connection { |con|
98
+ assert_raises(LocalConnectionError) {
99
+ con << Frame.goaway(0, :frame_size_error).assemble
100
+ }
101
+ }
102
+ end
96
103
  end
@@ -26,4 +26,13 @@ class ServerConnectionUtilsTest < Minitest::Test
26
26
  assert_equal(HTTPError::ERROR_CODES[:stream_closed], last.payload.uint32(4))
27
27
  }
28
28
  end
29
+
30
+ def test_push_enabled
31
+ open_server_connection {|con|
32
+ con << Frame.settings(enable_push: 0).assemble
33
+ assert_equal(false, con.push_enabled?)
34
+ con << Frame.settings(enable_push: 1).assemble
35
+ assert_equal(true, con.push_enabled?)
36
+ }
37
+ end
29
38
  end
@@ -7,7 +7,6 @@ class ErrorTest < Minitest::Test
7
7
  assert_equal(0x08, e.http2_error_code)
8
8
  }
9
9
 
10
- test.call ConnectionError
11
- test.call StreamError
10
+ test.call HTTPError
12
11
  end
13
12
  end
@@ -53,4 +53,41 @@ class FrameFactoryTest < Minitest::Test
53
53
  flags: [:ack],
54
54
  payload: "12345678")
55
55
  end
56
+
57
+ def test_continuation
58
+ frame = Frame.continuation(123, "abc", :end_headers)
59
+ assert_frame(frame,
60
+ type: :continuation,
61
+ stream_id: 123,
62
+ flags: [:end_headers],
63
+ payload: "abc")
64
+ end
65
+
66
+ def test_data
67
+ frame = Frame.data(123, "abc".force_encoding("UTF-8"))
68
+ assert_frame(frame,
69
+ type: :data,
70
+ stream_id: 123,
71
+ flags: [],
72
+ payload: "abc")
73
+ assert_equal(Encoding::BINARY, frame.payload.encoding)
74
+ end
75
+
76
+ def test_headers
77
+ frame = Frame.headers(123, "abc", :end_stream)
78
+ assert_frame(frame,
79
+ type: :headers,
80
+ stream_id: 123,
81
+ flags: [:end_stream],
82
+ payload: "abc")
83
+ end
84
+
85
+ def test_push_promise
86
+ frame = Frame.push_promise(345, 2, "abc", :end_headers)
87
+ assert_frame(frame,
88
+ type: :push_promise,
89
+ stream_id: 345,
90
+ flags: [:end_headers],
91
+ payload: "\x00\x00\x00\x02abc")
92
+ end
56
93
  end
@@ -19,14 +19,34 @@ class StreamTest < Minitest::Test
19
19
  }
20
20
  end
21
21
 
22
- def test_stream_close
23
- open_new_stream(state: :half_closed_local) {|stream|
24
- stream.close(:frame_size_error)
22
+ def test_stream_remote_error
23
+ open_server_connection { |con|
24
+ stream = nil
25
+ con.on(:headers) { |s|
26
+ stream = s
27
+ raise RemoteStreamError.new(:frame_size_error)
28
+ }
29
+
30
+ assert_stream_error(:frame_size_error) {
31
+ con << Frame.headers(1, "", :end_headers).assemble
32
+ }
25
33
 
26
34
  last = sent_frames.last
27
35
  assert_equal(:rst_stream, last.type)
28
- assert_equal(StreamError.new(:frame_size_error).http2_error_code, last.payload.uint32)
36
+ assert_equal(HTTPError::ERROR_CODES[:frame_size_error], last.payload.uint32)
29
37
  assert_equal(:closed, stream.state)
30
38
  }
31
39
  end
40
+
41
+ def test_stream_local_error
42
+ open_server_connection { |con|
43
+ stream = nil
44
+ con.on(:headers) { |s| stream = s }
45
+
46
+ con << Frame.headers(1, "", :end_headers).assemble
47
+ assert_raises(LocalStreamError) {
48
+ con << Frame.rst_stream(1, :frame_size_error).assemble
49
+ }
50
+ }
51
+ end
32
52
  end
@@ -1,7 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
3
  using BinaryString
4
-
5
4
  class StreamUtilsTest < Minitest::Test
6
5
  def test_stream_promise
7
6
  open_new_stream {|stream|
@@ -1,5 +1,3 @@
1
- LISTEN_PORT = ENV["PLUM_LISTEN_PORT"] || 40444
2
-
3
1
  unless ENV["SKIP_COVERAGE"]
4
2
  begin
5
3
  require "simplecov"
@@ -26,3 +24,8 @@ include Plum
26
24
  Dir.glob(File.expand_path("../utils/*.rb", __FILE__)).each do |file|
27
25
  require file
28
26
  end
27
+
28
+ LISTEN_PORT = ENV["PLUM_LISTEN_PORT"] || 40444
29
+ TLS_CERT = OpenSSL::X509::Certificate.new File.read(File.expand_path("../server.crt", __FILE__))
30
+ TLS_KEY = OpenSSL::PKey::RSA.new File.read(File.expand_path("../server.key", __FILE__))
31
+ ExampleError = Class.new(RuntimeError)
@@ -1,21 +1,21 @@
1
1
  module CustomAssertions
2
2
  def assert_connection_error(type, &blk)
3
- assert_http_error(Plum::ConnectionError, type, &blk)
3
+ assert_http_error(Plum::RemoteConnectionError, type, &blk)
4
4
  end
5
5
 
6
6
  def assert_stream_error(type, &blk)
7
- assert_http_error(Plum::StreamError, type, &blk)
7
+ assert_http_error(Plum::RemoteStreamError, type, &blk)
8
8
  end
9
9
 
10
10
  def assert_no_error(stream: nil, connection: nil, &blk)
11
- Plum::ConnectionError.reset
12
- Plum::StreamError.reset
11
+ Plum::RemoteConnectionError.reset
12
+ Plum::RemoteStreamError.reset
13
13
  begin
14
14
  blk.call
15
- rescue Plum::HTTPError
15
+ rescue Plum::RemoteHTTPError
16
16
  end
17
- assert_nil(Plum::StreamError.last, "No stream error expected but raised: #{Plum::StreamError.last}")
18
- assert_nil(Plum::ConnectionError.last, "No connection error expected but raised: #{Plum::ConnectionError.last}")
17
+ assert_nil(Plum::RemoteStreamError.last, "No stream error expected but raised: #{Plum::RemoteStreamError.last}")
18
+ assert_nil(Plum::RemoteConnectionError.last, "No connection error expected but raised: #{Plum::RemoteConnectionError.last}")
19
19
  end
20
20
 
21
21
  def assert_frame(frame, **args)
@@ -56,5 +56,5 @@ module LastErrorExtension
56
56
  base.reset
57
57
  end
58
58
  end
59
- Plum::ConnectionError.__send__(:prepend, LastErrorExtension)
60
- Plum::StreamError.__send__(:prepend, LastErrorExtension)
59
+ Plum::RemoteConnectionError.__send__(:prepend, LastErrorExtension)
60
+ Plum::RemoteStreamError.__send__(:prepend, LastErrorExtension)
@@ -0,0 +1,19 @@
1
+ require "timeout"
2
+
3
+ module ServerUtils
4
+ def open_client_connection(scheme = :https)
5
+ io = StringIO.new
6
+ @_ccon = ClientConnection.new(io.method(:write))
7
+ @_ccon << Frame.new(type: :settings, stream_id: 0, flags: [:ack]).assemble
8
+ @_ccon << Frame.new(type: :settings, stream_id: 0).assemble
9
+ if block_given?
10
+ yield @_ccon
11
+ else
12
+ @_ccon
13
+ end
14
+ end
15
+ end
16
+
17
+ class Minitest::Test
18
+ include ServerUtils
19
+ end
@@ -3,7 +3,7 @@ require "timeout"
3
3
  module ServerUtils
4
4
  def open_server_connection(scheme = :https)
5
5
  io = StringIO.new
6
- @_con = (scheme == :https ? HTTPSConnection : HTTPConnection).new(io)
6
+ @_con = (scheme == :https ? HTTPSServerConnection : HTTPServerConnection).new(io)
7
7
  @_con << Connection::CLIENT_CONNECTION_PREFACE
8
8
  @_con << Frame.new(type: :settings, stream_id: 0).assemble
9
9
  if block_given?
@@ -13,16 +13,16 @@ module ServerUtils
13
13
  end
14
14
  end
15
15
 
16
- def open_new_stream(arg1 = nil, **kwargs)
17
- if arg1.is_a?(Connection)
16
+ def open_new_stream(arg1 = nil, state: :idle, **kwargs)
17
+ if arg1.is_a?(ServerConnection)
18
18
  con = arg1
19
19
  else
20
20
  con = open_server_connection
21
21
  end
22
22
 
23
- @_stream = con.instance_eval {
24
- new_stream((con.streams.keys.last||0/2)*2+1, **kwargs)
25
- }
23
+ @_stream = con.instance_eval { stream(((@max_stream_id+1)/2)*2+1) }
24
+ @_stream.set_state(state)
25
+ @_stream.update_dependency(**kwargs)
26
26
  if block_given?
27
27
  yield @_stream
28
28
  else
@@ -0,0 +1,15 @@
1
+ class StringSocket < IO
2
+ # remove all methods
3
+ (IO.instance_methods - Object.instance_methods).each { |symbol| undef_method symbol }
4
+
5
+ extend Forwardable
6
+ def_delegators :@rio, :readpartial
7
+ def_delegators :@wio, :<<, :write
8
+
9
+ attr_reader :rio, :wio
10
+
11
+ def initialize(str = nil)
12
+ @rio = StringIO.new(str.to_s)
13
+ @wio = StringIO.new
14
+ end
15
+ end
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.1.3
4
+ version: 0.2.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-11-01 00:00:00.000000000 Z
11
+ date: 2015-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 5.7.0
89
+ version: 5.8.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 5.7.0
96
+ version: 5.8.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +150,7 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
- description: A minimal implementation of HTTP/2 server.
153
+ description: An HTTP/2 Library for Ruby
154
154
  email:
155
155
  - k@rhe.jp
156
156
  executables:
@@ -167,11 +167,20 @@ files:
167
167
  - Rakefile
168
168
  - bin/.gitkeep
169
169
  - bin/plum
170
+ - circle.yml
171
+ - examples/client/large.rb
172
+ - examples/client/twitter.rb
170
173
  - examples/non_tls_server.rb
171
174
  - examples/rack.ru
172
175
  - examples/static_server.rb
173
176
  - lib/plum.rb
174
177
  - lib/plum/binary_string.rb
178
+ - lib/plum/client.rb
179
+ - lib/plum/client/client_session.rb
180
+ - lib/plum/client/connection.rb
181
+ - lib/plum/client/legacy_client_session.rb
182
+ - lib/plum/client/response.rb
183
+ - lib/plum/client/upgrade_client_session.rb
175
184
  - lib/plum/connection.rb
176
185
  - lib/plum/connection_utils.rb
177
186
  - lib/plum/errors.rb
@@ -185,8 +194,6 @@ files:
185
194
  - lib/plum/hpack/decoder.rb
186
195
  - lib/plum/hpack/encoder.rb
187
196
  - lib/plum/hpack/huffman.rb
188
- - lib/plum/http_connection.rb
189
- - lib/plum/https_connection.rb
190
197
  - lib/plum/rack.rb
191
198
  - lib/plum/rack/cli.rb
192
199
  - lib/plum/rack/config.rb
@@ -194,16 +201,26 @@ files:
194
201
  - lib/plum/rack/listener.rb
195
202
  - lib/plum/rack/server.rb
196
203
  - lib/plum/rack/session.rb
204
+ - lib/plum/server/connection.rb
205
+ - lib/plum/server/http_connection.rb
206
+ - lib/plum/server/https_connection.rb
197
207
  - lib/plum/stream.rb
198
208
  - lib/plum/stream_utils.rb
199
209
  - lib/plum/version.rb
200
210
  - lib/rack/handler/plum.rb
201
211
  - plum.gemspec
212
+ - test/plum/client/test_client.rb
213
+ - test/plum/client/test_connection.rb
214
+ - test/plum/client/test_legacy_client_session.rb
215
+ - test/plum/client/test_response.rb
216
+ - test/plum/client/test_upgrade_client_session.rb
202
217
  - test/plum/connection/test_handle_frame.rb
203
218
  - test/plum/hpack/test_context.rb
204
219
  - test/plum/hpack/test_decoder.rb
205
220
  - test/plum/hpack/test_encoder.rb
206
221
  - test/plum/hpack/test_huffman.rb
222
+ - test/plum/server/test_http_connection.rb
223
+ - test/plum/server/test_https_connection.rb
207
224
  - test/plum/stream/test_handle_frame.rb
208
225
  - test/plum/test_binary_string.rb
209
226
  - test/plum/test_connection.rb
@@ -214,8 +231,6 @@ files:
214
231
  - test/plum/test_frame.rb
215
232
  - test/plum/test_frame_factory.rb
216
233
  - test/plum/test_frame_utils.rb
217
- - test/plum/test_http_connection.rb
218
- - test/plum/test_https_connection.rb
219
234
  - test/plum/test_stream.rb
220
235
  - test/plum/test_stream_utils.rb
221
236
  - test/server.crt
@@ -223,7 +238,9 @@ files:
223
238
  - test/server.key
224
239
  - test/test_helper.rb
225
240
  - test/utils/assertions.rb
241
+ - test/utils/client.rb
226
242
  - test/utils/server.rb
243
+ - test/utils/string_socket.rb
227
244
  homepage: https://github.com/rhenium/plum
228
245
  licenses:
229
246
  - MIT
@@ -247,13 +264,20 @@ rubyforge_project:
247
264
  rubygems_version: 2.4.5.1
248
265
  signing_key:
249
266
  specification_version: 4
250
- summary: A minimal implementation of HTTP/2 server.
267
+ summary: An HTTP/2 Library for Ruby
251
268
  test_files:
269
+ - test/plum/client/test_client.rb
270
+ - test/plum/client/test_connection.rb
271
+ - test/plum/client/test_legacy_client_session.rb
272
+ - test/plum/client/test_response.rb
273
+ - test/plum/client/test_upgrade_client_session.rb
252
274
  - test/plum/connection/test_handle_frame.rb
253
275
  - test/plum/hpack/test_context.rb
254
276
  - test/plum/hpack/test_decoder.rb
255
277
  - test/plum/hpack/test_encoder.rb
256
278
  - test/plum/hpack/test_huffman.rb
279
+ - test/plum/server/test_http_connection.rb
280
+ - test/plum/server/test_https_connection.rb
257
281
  - test/plum/stream/test_handle_frame.rb
258
282
  - test/plum/test_binary_string.rb
259
283
  - test/plum/test_connection.rb
@@ -264,8 +288,6 @@ test_files:
264
288
  - test/plum/test_frame.rb
265
289
  - test/plum/test_frame_factory.rb
266
290
  - test/plum/test_frame_utils.rb
267
- - test/plum/test_http_connection.rb
268
- - test/plum/test_https_connection.rb
269
291
  - test/plum/test_stream.rb
270
292
  - test/plum/test_stream_utils.rb
271
293
  - test/server.crt
@@ -273,5 +295,7 @@ test_files:
273
295
  - test/server.key
274
296
  - test/test_helper.rb
275
297
  - test/utils/assertions.rb
298
+ - test/utils/client.rb
276
299
  - test/utils/server.rb
300
+ - test/utils/string_socket.rb
277
301
  has_rdoc: