h2 0.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b533a3c1702ec83aad19b84c16dcb97badbc669b
4
- data.tar.gz: e8adb1f561a47a3970d1bed94b276b26220798e5
3
+ metadata.gz: 7026103d2e280847900dbd974196250ef62d1ba0
4
+ data.tar.gz: df6cd50fb58732f2256aa90c85d36a6d8d9cb6c3
5
5
  SHA512:
6
- metadata.gz: c948d743e1a8923c0cfc7e87564aedb6e16fbf27173859aa1fd6316e900adf05e661f223e243b2604c611685fc5280e9984c4d25a5f6053c17862af9d31db9e5
7
- data.tar.gz: bbd51fcf78448aeb6636dc55d0cc22f188c5a44517a4887e01db8d0936efa10133d65c6637237463413224f1d79fbc2c9b2c71b01f22d5ee188ef4c98055f1ae
6
+ metadata.gz: af9a7b61585c3b9a0dc9f4fca518dd7516a57db3ac7299969c95b9790c7e3de965a83b63391fcba731079ef88db30dacabb872e1c05573b2077dc0db3a660c0a
7
+ data.tar.gz: 54ad799634b7cc747cdfa0cf2cf9b42324f67464bcfd941bb86bd7b118d4d44975aab518ab4d558be0d0f54d79a76a4e63e55a9e0b86b7b2e520d3e84310d866
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ h2 changelog
2
+ ============
3
+
4
+ ### 0.2.0 7 mar 2017
5
+
6
+ * add concurrency alternates
7
+
8
+ ### 0.1.1 -
9
+
10
+ * removed extra rescue/ensure in H2::Client#read
11
+
12
+ ### 0.1.0 - 30 dec 2016
13
+
14
+ * initial release
15
+ * seems to work! :)
data/Gemfile CHANGED
@@ -1,9 +1,17 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'http-2', git: 'https://github.com/igrigorik/http-2'
3
+ gem 'http-2', git: 'https://github.com/kenichi/http-2', branch: 'stream_close_state'
4
4
 
5
5
  gemspec
6
6
 
7
+ group :concurrent_ruby do
8
+ gem 'concurrent-ruby'
9
+ end
10
+
11
+ group :celluloid do
12
+ gem 'celluloid'
13
+ end
14
+
7
15
  group :development, :test do
8
16
  gem 'awesome_print'
9
17
  gem 'pry-byebug'
data/README.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # H2
2
2
 
3
- [![Build Status](https://travis-ci.org/kenichi/h2.png?branch=master)](https://travis-ci.org/kenichi/h2)
3
+ [![Build Status](https://travis-ci.org/kenichi/h2.svg?branch=master)](https://travis-ci.org/kenichi/h2)
4
4
 
5
- H2 is a basic HTTP/2 client based on the [http-2](https://github.com/igrigorik/http-2) gem.
5
+ H2 is a basic, _experimental_ HTTP/2 client based on the [http-2](https://github.com/igrigorik/http-2) gem.
6
6
 
7
- H2 currently uses:
7
+ H2 uses:
8
8
 
9
- * one new thread per client (see [TODO](#TODO) item 3)
10
9
  * keyword arguments (>=2.0)
11
10
  * exception-less socket IO (>=2.3).
12
11
 
@@ -70,17 +69,65 @@ end
70
69
  client.goaway!
71
70
  ```
72
71
 
72
+ ## CLI
73
+
74
+ For more info on using the CLI `h2` installed with this gem:
75
+
76
+ `$ h2 --help`
77
+
78
+ ## Alternate Concurrency Models
79
+
80
+ Right now, h2 uses one new thread per connection. This is hardly ideal, so a
81
+ couple other models are tentatively supported out of the box:
82
+
83
+ * [celluloid](https://github.com/celluloid/celluloid)
84
+ * [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby)
85
+
86
+ Neither of these gems are hard dependencies. If you want to use either one, you must
87
+ have it available to your Ruby VM, most likely via Bundler, *and* require the
88
+ sub-component of h2 that will prepend and extend `H2::Client`. They are also intended
89
+ to be mutually exclusive: you can have both in your VM, but you can only use one at a
90
+ time with h2.
91
+
92
+ #### Celluloid Pool
93
+
94
+ To use a celluloid actor pool for reading from `H2::Client` connections:
95
+
96
+ ```ruby
97
+ require 'h2/client/celluloid'
98
+ ```
99
+
100
+ This will lazily fire up a celluloid pool, with defaults defined by Celluloid.
101
+
102
+ #### Concurrent-Ruby ThreadPoolExecutor
103
+
104
+ To use a concurrent-ruby thread pool executor for reading from `H2::Client` connections:
105
+
106
+ ```ruby
107
+ require 'h2/client/concurrent'
108
+ ```
109
+
110
+ This will lazily fire up a `Concurrent::ThreadPoolExecutor` with the following settings:
111
+
112
+ ```ruby
113
+ procs = ::Concurrent.processor_count
114
+
115
+ min_threads: 0,
116
+ max_threads: procs,
117
+ max_queue: procs * 5
118
+ ```
119
+
73
120
  ## TODO
74
121
 
75
122
  * [x] HTTPS / TLS
76
- * [ ] push promise cancellation
77
- * [ ] alternate concurrency models
123
+ * [x] push promise cancellation
124
+ * [x] alternate concurrency models
125
+ * [ ] fix up CLI to be more curlish
78
126
 
79
127
  ## Contributing
80
128
 
81
129
  Bug reports and pull requests are welcome on GitHub at https://github.com/kenichi/h2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
82
130
 
83
-
84
131
  ## License
85
132
 
86
133
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/bin/console CHANGED
@@ -4,5 +4,22 @@ require 'bundler/setup'
4
4
  require 'h2'
5
5
  require 'irb'
6
6
 
7
- Bundler.require :development
7
+ #Bundler.require :development
8
+
9
+ def trunc_payload f
10
+ x = f.dup
11
+ size = x[:payload]&.to_s&.bytesize || 0
12
+ x[:payload] = "#{size} redacted" if size > 64
13
+ x
14
+ end
15
+
16
+ def new_client
17
+ # H2::Client.new url: 'https://127.0.0.1:4430', tls: { ca_file: '/Users/ken/src/ruby/other_reel/tmp/certs/ca.crt' } do |client|
18
+ # H2::Client.new url: 'http://127.0.0.1:1234' do |client|
19
+ H2::Client.new url: 'https://vux.nakamura.io:4430', tls: { ca_file: '/usr/local/etc/cacert-201611290415.pem' } do |client|
20
+ client.client.on(:frame_sent){|f| STDERR.puts ">> #{trunc_payload(f).inspect}"}
21
+ client.client.on(:frame_received){|f| STDERR.puts "<< #{trunc_payload(f).inspect}"}
22
+ end
23
+ end
24
+
8
25
  IRB.start
data/exe/h2 CHANGED
@@ -22,6 +22,7 @@ end # }}}
22
22
  options = {
23
23
  body: nil,
24
24
  block: false,
25
+ debug: false,
25
26
  headers: {},
26
27
  goaway: false,
27
28
  method: nil,
@@ -52,7 +53,7 @@ OptionParser.new do |o|
52
53
  end
53
54
 
54
55
  o.on '-g', '--goaway', 'send GOAWAY frame when stream is complete' do
55
- options[:debug] = true
56
+ options[:goaway] = true
56
57
  end
57
58
 
58
59
  o.on '-v', '--verbose', 'turn on verbosity' do
@@ -65,6 +66,7 @@ OptionParser.new do |o|
65
66
  options[:method] = meth
66
67
  end
67
68
 
69
+
68
70
  end.parse!
69
71
 
70
72
  options[:method] ||= :get
@@ -0,0 +1,33 @@
1
+ require 'celluloid/current'
2
+ require 'h2'
3
+
4
+ module H2
5
+ class Client
6
+ module Celluloid
7
+
8
+ class Reader
9
+ include ::Celluloid
10
+
11
+ def read client, maxlen = DEFAULT_MAXLEN
12
+ client._read maxlen
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def thread_pool
18
+ @thread_pool ||= Reader.pool
19
+ end
20
+ end
21
+
22
+ def read maxlen = DEFAULT_MAXLEN
23
+ self.class.thread_pool.async.read self
24
+ end
25
+
26
+ end
27
+
28
+ extend H2::Client::Celluloid::ClassMethods
29
+ prepend H2::Client::Celluloid
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,34 @@
1
+ require 'concurrent'
2
+ require 'h2'
3
+
4
+ module H2
5
+ class Client
6
+ module Concurrent
7
+
8
+ module ClassMethods
9
+ def thread_pool
10
+ procs = ::Concurrent.processor_count
11
+ @thread_pool ||= ::Concurrent::ThreadPoolExecutor.new min_threads: 0,
12
+ max_threads: procs,
13
+ max_queue: procs * 5
14
+ end
15
+ end
16
+
17
+ def read maxlen = DEFAULT_MAXLEN
18
+ main = Thread.current
19
+ @reader = self.class.thread_pool.post do
20
+ begin
21
+ _read maxlen
22
+ rescue => e
23
+ main.raise e
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ extend H2::Client::Concurrent::ClassMethods
31
+ prepend H2::Client::Concurrent
32
+ end
33
+ end
34
+
data/lib/h2/client.rb CHANGED
@@ -13,11 +13,6 @@ module H2
13
13
  :promise
14
14
  ]
15
15
 
16
- PROMISE_EVENTS = [
17
- :headers,
18
- :data
19
- ]
20
-
21
16
  ALPN_PROTOCOLS = ['h2']
22
17
  DEFAULT_MAXLEN = 4096
23
18
 
@@ -112,17 +107,16 @@ module H2
112
107
  METHOD_KEY => method.to_s.upcase,
113
108
  PATH_KEY => path,
114
109
  SCHEME_KEY => @scheme
115
- }
110
+ }.merge USER_AGENT
116
111
  h.merge! stringify_headers(headers)
117
112
  end
118
113
 
119
114
  def add_stream method:, path:, stream:, &block
120
- stream_id = stream.id
121
115
  @streams[method] ||= {}
122
116
  @streams[method][path] ||= []
123
117
  stream = Stream.new client: self, stream: stream, &block unless Stream === stream
124
118
  @streams[method][path] << stream
125
- @streams[stream_id] = stream
119
+ @streams[stream.id] = stream
126
120
  stream
127
121
  end
128
122
 
@@ -143,12 +137,6 @@ module H2
143
137
  main.raise e
144
138
  end
145
139
  end
146
- rescue => e
147
- STDERR.puts "#{e.message} - closing socket"
148
- STDERR.puts e.backtrace.map {|l| "\t" + l}
149
- close
150
- ensure
151
- unblock!
152
140
  end
153
141
 
154
142
  def _read maxlen = DEFAULT_MAXLEN
@@ -214,18 +202,18 @@ module H2
214
202
  end
215
203
 
216
204
  def on_promise promise
217
- on :promise, promise
218
-
219
- Stream.new client: self,
220
- parent: @streams[promise.parent.id],
221
- push: true,
222
- stream: promise do |p|
205
+ push_promise = Stream.new client: self,
206
+ parent: @streams[promise.parent.id],
207
+ push: true,
208
+ stream: promise do |p|
223
209
  p.on :close do
224
210
  method = p.headers[METHOD_KEY].downcase.to_sym rescue :error
225
211
  path = p.headers[PATH_KEY]
226
212
  add_stream method: method, path: path, stream: p
227
213
  end
228
214
  end
215
+
216
+ on :promise, push_promise
229
217
  end
230
218
 
231
219
  # ---
data/lib/h2/stream.rb CHANGED
@@ -49,8 +49,8 @@ module H2
49
49
  end
50
50
 
51
51
  def cancel!
52
- unblock!
53
52
  @stream.cancel
53
+ unblock!
54
54
  end
55
55
 
56
56
  def block! timeout = nil
data/lib/h2/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module H2
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/h2.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require 'http/2'
4
4
  require 'uri'
5
5
 
6
+ require 'h2/version'
7
+
6
8
  module H2
7
9
 
8
10
  # http/2 psuedo-headers
@@ -13,6 +15,10 @@ module H2
13
15
  SCHEME_KEY = ':scheme'
14
16
  STATUS_KEY = ':status'
15
17
 
18
+ USER_AGENT = {
19
+ 'user-agent' => "h2/#{H2::VERSION} #{RUBY_ENGINE}-#{RUBY_VERSION}/#{RUBY_PLATFORM}"
20
+ }
21
+
16
22
  REQUEST_METHODS = [
17
23
  :get,
18
24
  :delete,
@@ -92,4 +98,3 @@ end
92
98
 
93
99
  require 'h2/client'
94
100
  require 'h2/stream'
95
- require 'h2/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: h2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenichi Nakamura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-31 00:00:00.000000000 Z
11
+ date: 2017-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2
@@ -96,6 +96,7 @@ extra_rdoc_files: []
96
96
  files:
97
97
  - ".gitignore"
98
98
  - ".travis.yml"
99
+ - CHANGELOG.md
99
100
  - CODE_OF_CONDUCT.md
100
101
  - Gemfile
101
102
  - LICENSE.txt
@@ -106,6 +107,8 @@ files:
106
107
  - h2.gemspec
107
108
  - lib/h2.rb
108
109
  - lib/h2/client.rb
110
+ - lib/h2/client/celluloid.rb
111
+ - lib/h2/client/concurrent.rb
109
112
  - lib/h2/client/tcp_socket.rb
110
113
  - lib/h2/stream.rb
111
114
  - lib/h2/version.rb
@@ -129,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
132
  version: '0'
130
133
  requirements: []
131
134
  rubyforge_project:
132
- rubygems_version: 2.6.8
135
+ rubygems_version: 2.6.10
133
136
  signing_key:
134
137
  specification_version: 4
135
138
  summary: an http/2 client based on http-2 and modern ruby