h2 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2ce1f4f619d3bd9eb680ad49ad0181ef4a5e81b0a9fa07f0b8e544b85b77028
4
- data.tar.gz: 34de290127df74e156b02e595f2b1ea91ab3da6edf38cfff263a4734e16297cc
3
+ metadata.gz: e62e384940a1e408102e4e518942c1245ce374f82007c858d9de5a0b286c2301
4
+ data.tar.gz: d3fc7f3d111b3786cb50c58f862b32dad713557ae69cf18233cd1eda7ca0d5be
5
5
  SHA512:
6
- metadata.gz: 2a89223df4da4f8effb784628e711bd9341b63b096ecfa5d1bb970f2d9a447c59e51871167c7da1f48eb3fc70436970fe64a84400ab93ab7e835e7d165cc203b
7
- data.tar.gz: 81cd03234bc8eff7a0acc6d69105ba5cf9599b8ad9b8193c28679d6c1fb504a612cb9c5062bba7f4c3ebe5448636908c8c87e75666de0575b78bb28d9a4b0e8f
6
+ metadata.gz: 907a28fb440862cbc3a6a9dbb80db39408f3635f4aa4983358bba508617ddbb8fcb9da0a30b3601a614f4ea7a79ff4cceece1b7d1c687b6afc3e663ad5d4459d
7
+ data.tar.gz: 317f75c090f2f54526a2bff4b2e8b7d298ab7f6bf8f4653e9bd5ac2916f333133e26a7b47d357c447a7a0a6741468b99733e1212c71ee018f4698c51b0ea5eaf
data/CHANGELOG.md CHANGED
@@ -1,7 +1,17 @@
1
1
  h2 changelog
2
2
  ============
3
3
 
4
- ### 0.4.1 16 jun 2017
4
+ ### 0.6.0 25 jul 2018
5
+
6
+ * update server API - kwargs
7
+ * update client API - addr: -> host:
8
+ * add rubydoc, update readme
9
+
10
+ ### 0.5.0 21 jul 2018
11
+
12
+ * add server
13
+
14
+ ### 0.4.1 17 jul 2018
5
15
 
6
16
  * update .travis.yml for latest supported versions
7
17
  * add CLI flags for threading model
data/README.md CHANGED
@@ -20,7 +20,7 @@ require 'h2/server'
20
20
 
21
21
  server = H2::Server::HTTP.new host: addr, port: port do |connection|
22
22
  connection.each_stream do |stream|
23
- stream.respond :ok, "hello, world!\n"
23
+ stream.respond status: 200, body: "hello, world!\n"
24
24
  stream.connection.goaway
25
25
  end
26
26
  end
@@ -29,7 +29,7 @@ stream = H2.get url: "http://#{addr}:#{port}", tls: false
29
29
  stream.body #=> "hello, world!\n"
30
30
  ```
31
31
 
32
- See [examples](https://github.com/kenichi/h2/tree/master/examples/server/)
32
+ See [examples](https://github.com/kenichi/h2/tree/master/examples/server/).
33
33
 
34
34
  ## Client Usage
35
35
 
@@ -55,7 +55,7 @@ client.closed? #=> true
55
55
  # --- normal connection
56
56
  #
57
57
 
58
- client = H2::Client.new addr: 'example.com', port: 443
58
+ client = H2::Client.new host: 'example.com', port: 443
59
59
 
60
60
  stream = client.get path: '/'
61
61
 
@@ -103,7 +103,7 @@ If you're running on macOS and using Homebrew's openssl package, you may need to
103
103
  specify the CA file in the TLS options:
104
104
 
105
105
  ```ruby
106
- client = H2::Client.new addr: 'example.com', port: 443, tls: { ca_file: '/usr/local/etc/openssl/cert.pem' }
106
+ client = H2::Client.new host: 'example.com', port: 443, tls: { ca_file: '/usr/local/etc/openssl/cert.pem' }
107
107
  ```
108
108
 
109
109
  or when using the CLI:
@@ -12,7 +12,7 @@ addr, port = '127.0.0.1', 1234
12
12
  puts "*** Starting server on http://#{addr}:#{port}"
13
13
  s = H2::Server::HTTP.new host: addr, port: port do |connection|
14
14
  connection.each_stream do |stream|
15
- stream.respond :ok, "hello, world!\n"
15
+ stream.respond status: 200, body: "hello, world!\n"
16
16
  stream.connection.goaway
17
17
  end
18
18
  end
@@ -21,9 +21,9 @@ s = H2::Server::HTTPS.new host: addr, port: port, **tls do |connection|
21
21
  stream.goaway_on_complete
22
22
 
23
23
  if stream.request.path == '/favicon.ico'
24
- stream.respond :not_found
24
+ stream.respond status: 404
25
25
  else
26
- stream.respond :ok, "hello, world!\n"
26
+ stream.respond status: 200, body: "hello, world!\n"
27
27
  end
28
28
  end
29
29
  end
@@ -11,7 +11,7 @@ port = 1234
11
11
  addr = Socket.getaddrinfo('localhost', port).first[3]
12
12
  certs_dir = File.expand_path '../../../tmp/certs', __FILE__
13
13
  dog_png = File.read File.expand_path '../dog.png', __FILE__
14
- push_promise = '<html>wait for it...<img src="/dog.png"/><script src="/pushed.js"></script></html>'
14
+ push_promise = '<html><body>wait for it...<img src="/dog.png"/><script src="/pushed.js"></script></body></html>'
15
15
  pushed_js = '(()=>{ alert("hello h2 push promise!"); })();'
16
16
 
17
17
  sni = {
@@ -27,17 +27,21 @@ s = H2::Server::HTTPS.new host: addr, port: port, sni: sni do |connection|
27
27
  connection.each_stream do |stream|
28
28
 
29
29
  if stream.request.path == '/favicon.ico'
30
- stream.respond :not_found
30
+ stream.respond status: 404
31
31
 
32
32
  else
33
33
  stream.goaway_on_complete
34
34
 
35
- stream.push_promise '/dog.png', { 'content-type' => 'image/png' }, dog_png
35
+ # one-line convenience with async "keep" handler
36
+ stream.push_promise path: '/dog.png', headers: { 'content-type' => 'image/png' }, body: dog_png
36
37
 
37
- js_promise = stream.push_promise_for '/pushed.js', { 'content-type' => 'application/javascript' }, pushed_js
38
+ # more control over when promises are "kept"...
39
+ js_promise = stream.push_promise_for path: '/pushed.js',
40
+ headers: { 'content-type' => 'application/javascript' },
41
+ body: pushed_js
38
42
  js_promise.make_on stream
39
43
 
40
- stream.respond :ok, push_promise
44
+ stream.respond status: 200, body: push_promise
41
45
 
42
46
  js_promise.keep
43
47
  end
data/exe/h2 CHANGED
@@ -8,9 +8,8 @@
8
8
  require 'colored'
9
9
  require 'optparse'
10
10
 
11
- $: << File.expand_path('../../../http-2/lib', __FILE__)
12
-
13
11
  begin # {{{
12
+ raise LoadError if ARGV.include?('--dev')
14
13
  require 'h2'
15
14
  rescue LoadError
16
15
  $: << File.expand_path('../../lib', __FILE__)
@@ -60,6 +59,10 @@ OptionParser.new do |o|
60
59
  options[:debug] = true
61
60
  end
62
61
 
62
+ o.on '--dev', 'load lib from source tree' do
63
+ # handled above for reasons
64
+ end
65
+
63
66
  o.on '-g', '--goaway', 'send GOAWAY frame when stream is complete' do
64
67
  options[:goaway] = true
65
68
  end
data/h2.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.required_ruby_version = '>= 2.2'
19
19
 
20
- spec.add_dependency 'http-2', '~> 0.9', '>= 0.9.1'
20
+ spec.add_dependency 'http-2', '~> 0.10', '>= 0.10.0'
21
21
  spec.add_dependency 'colored', '1.2'
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.15"
data/lib/h2.rb CHANGED
@@ -30,6 +30,10 @@ module H2
30
30
 
31
31
  class << self
32
32
 
33
+ # convenience wrappers to make requests with HTTP methods
34
+ #
35
+ # @see H2.request
36
+ #
33
37
  REQUEST_METHODS.each do |m|
34
38
  define_method m do |**args, &block|
35
39
  request method: m, **args, &block
@@ -38,25 +42,43 @@ module H2
38
42
 
39
43
  private
40
44
 
41
- def request addr: nil,
45
+ # creates a +H2::Client+ and initiates a +H2::Stream+ by making a request
46
+ # with the given HTTP method
47
+ #
48
+ # @param [String] host IP address or hostname
49
+ # @param [Integer] port TCP port
50
+ # @param [String,URI] url full URL to parse (optional: existing +URI+ instance)
51
+ # @param [Symbol] method HTTP request method
52
+ # @param [String] path request path
53
+ # @param [Hash] headers request headers
54
+ # @param [Hash] params request query string parameters
55
+ # @param [String] body request body
56
+ # @param [Hash,FalseClass] tls TLS options (optional: +false+ do not use TLS)
57
+ # @option tls [String] :cafile path to CA file
58
+ #
59
+ # @yield [H2::Stream]
60
+ #
61
+ # @return [H2::Stream]
62
+ #
63
+ def request host: nil,
42
64
  port: nil,
65
+ url: nil,
43
66
  method:,
44
67
  path: '/',
45
68
  headers: {},
46
69
  params: {},
47
70
  body: nil,
48
- url: nil,
49
71
  tls: {},
50
72
  &block
51
73
 
52
- raise ArgumentError if url.nil? && (addr.nil? || port.nil?)
74
+ raise ArgumentError if url.nil? && (host.nil? || port.nil?)
53
75
  if url
54
76
  url = URI.parse url unless URI === url
55
- addr = url.host
77
+ host = url.host
56
78
  port = url.port
57
79
  path = url.request_uri
58
80
  end
59
- c = Client.new addr: addr, port: port, tls: tls
81
+ c = Client.new host: host, port: port, tls: tls
60
82
  c.__send__ method, path: path, headers: headers, params: params, body: body, &block
61
83
  end
62
84
  end
data/lib/h2/client.rb CHANGED
@@ -21,24 +21,34 @@ module H2
21
21
  attr_accessor :last_stream
22
22
  attr_reader :client, :reader, :scheme, :socket, :streams
23
23
 
24
- def initialize addr: nil, port: nil, url: nil, tls: {}
25
- raise ArgumentError if url.nil? && (addr.nil? || port.nil?)
24
+ # create a new h2 client
25
+ #
26
+ # @param [String] host IP address or hostname
27
+ # @param [Integer] port TCP port
28
+ # @param [String,URI] url full URL to parse (optional: existing +URI+ instance)
29
+ # @param [Hash,FalseClass] tls TLS options (optional: +false+ do not use TLS)
30
+ # @option tls [String] :cafile path to CA file
31
+ #
32
+ # @return [H2::Client]
33
+ #
34
+ def initialize host: nil, port: nil, url: nil, tls: {}
35
+ raise ArgumentError if url.nil? && (host.nil? || port.nil?)
26
36
 
27
37
  if url
28
38
  url = URI.parse url unless URI === url
29
- @addr = url.host
39
+ @host = url.host
30
40
  @port = url.port
31
41
  @scheme = url.scheme
32
42
  tls = false if 'http' == @scheme
33
43
  else
34
- @addr = addr
44
+ @host = host
35
45
  @port = port
36
46
  @scheme = tls ? 'https' : 'http'
37
47
  end
38
48
 
39
49
  @tls = tls
40
50
  @streams = {}
41
- @socket = TCPSocket.new(@addr, @port)
51
+ @socket = TCPSocket.new(@host, @port)
42
52
  @socket = tls_socket @socket if @tls
43
53
  @client = HTTP2::Client.new
44
54
 
@@ -49,10 +59,14 @@ module H2
49
59
  read
50
60
  end
51
61
 
62
+ # @return true if the connection is closed
63
+ #
52
64
  def closed?
53
65
  @socket.closed?
54
66
  end
55
67
 
68
+ # close the connection
69
+ #
56
70
  def close
57
71
  unblock!
58
72
  @socket.close unless closed?
@@ -62,28 +76,55 @@ module H2
62
76
  @socket.eof?
63
77
  end
64
78
 
79
+ # send a goaway frame and wait until the connection is closed
80
+ #
65
81
  def goaway!
66
82
  goaway block: true
67
83
  end
68
84
 
85
+ # send a goaway frame and optionally wait for the connection to be closed
86
+ #
87
+ # @param [Boolean] block waits for close if +true+, returns immediately otherwise
88
+ #
89
+ # @return +false+ if already closed
90
+ # @return +nil+
91
+ #
69
92
  def goaway block: false
70
93
  return false if closed?
71
94
  @client.goaway
72
95
  block! if block
73
96
  end
74
97
 
98
+ # binds all connection events to their respective on_ handlers
99
+ #
75
100
  def bind_events
76
101
  CONNECTION_EVENTS.each do |e|
77
102
  @client.on(e){|*a| __send__ "on_#{e}", *a}
78
103
  end
79
104
  end
80
105
 
106
+ # convenience wrappers to make requests with HTTP methods
107
+ #
108
+ # @see Client#request
109
+ #
81
110
  REQUEST_METHODS.each do |m|
82
111
  define_method m do |**args, &block|
83
112
  request method: m, **args, &block
84
113
  end
85
114
  end
86
115
 
116
+ # initiate a +Stream+ by making a request with the given HTTP method
117
+ #
118
+ # @param [Symbol] method HTTP request method
119
+ # @param [String] path request path
120
+ # @param [Hash] headers request headers
121
+ # @param [Hash] params request query string parameters
122
+ # @param [String] body request body
123
+ #
124
+ # @yield [H2::Stream]
125
+ #
126
+ # @return [H2::Stream]
127
+ #
87
128
  def request method:, path:, headers: {}, params: {}, body: nil, &block
88
129
  s = @client.new_stream
89
130
  stream = add_stream method: method, path: path, stream: s, &block
@@ -95,6 +136,10 @@ module H2
95
136
  stream
96
137
  end
97
138
 
139
+ # mutates the given hash into +String+ keys and values
140
+ #
141
+ # @param [Hash] hash the headers +Hash+ to stringify
142
+ #
98
143
  def stringify_headers hash
99
144
  hash.keys.each do |key|
100
145
  hash[key] = hash[key].to_s unless String === hash[key]
@@ -103,9 +148,14 @@ module H2
103
148
  hash
104
149
  end
105
150
 
151
+ # builds headers +Hash+ with appropriate ordering
152
+ #
153
+ # @see https://http2.github.io/http2-spec/#rfc.section.8.1.2.1
154
+ # @see https://github.com/igrigorik/http-2/pull/136
155
+ #
106
156
  def build_headers method:, path:, headers:
107
157
  h = {
108
- AUTHORITY_KEY => [@addr, @port.to_s].join(':'),
158
+ AUTHORITY_KEY => [@host, @port.to_s].join(':'),
109
159
  METHOD_KEY => method.to_s.upcase,
110
160
  PATH_KEY => path,
111
161
  SCHEME_KEY => @scheme
@@ -113,6 +163,9 @@ module H2
113
163
  h.merge! stringify_headers(headers)
114
164
  end
115
165
 
166
+ # creates a new stream and adds it to the +@streams+ +Hash+ keyed at both
167
+ # the method +Symbol+ and request path as well as the ID of the stream.
168
+ #
116
169
  def add_stream method:, path:, stream:, &block
117
170
  @streams[method] ||= {}
118
171
  @streams[method][path] ||= []
@@ -122,6 +175,8 @@ module H2
122
175
  stream
123
176
  end
124
177
 
178
+ # add query string parameters the given request path +String+
179
+ #
125
180
  def add_params params, path
126
181
  appendage = path.index('?') ? '&' : '?'
127
182
  path << appendage
@@ -130,10 +185,20 @@ module H2
130
185
 
131
186
  # ---
132
187
 
188
+ # maintain a ivar for the +Array+ to send to +IO.select+
189
+ #
133
190
  def selector
134
191
  @selector ||= [@socket]
135
192
  end
136
193
 
194
+ # creates a new +Thread+ to read the given number of bytes each loop from
195
+ # the current +@socket+
196
+ #
197
+ # NOTE: this is the override point for celluloid actor pool or concurrent
198
+ # ruby threadpool support
199
+ #
200
+ # @param [Integer] maxlen maximum number of bytes to read
201
+ #
137
202
  def read maxlen = DEFAULT_MAXLEN
138
203
  main = Thread.current
139
204
  @reader = Thread.new do
@@ -145,6 +210,11 @@ module H2
145
210
  end
146
211
  end
147
212
 
213
+ # underyling read loop implementation, handling returned +Symbol+ values
214
+ # and shovelling data into the client parser
215
+ #
216
+ # @param [Integer] maxlen maximum number of bytes to read
217
+ #
148
218
  def _read maxlen = DEFAULT_MAXLEN
149
219
  begin
150
220
  data = nil
@@ -173,6 +243,10 @@ module H2
173
243
  end
174
244
  end
175
245
 
246
+ # fake exceptionless IO for reading on older ruby versions
247
+ #
248
+ # @param [Integer] maxlen maximum number of bytes to read
249
+ #
176
250
  def read_from_socket maxlen
177
251
  @socket.read_nonblock maxlen
178
252
  rescue IO::WaitReadable
@@ -181,11 +255,18 @@ module H2
181
255
 
182
256
  # ---
183
257
 
258
+ # close callback for parser: calls custom handler, then closes connection
259
+ #
184
260
  def on_close
185
261
  on :close
186
262
  close
187
263
  end
188
264
 
265
+ # frame callback for parser: writes bytes to the +@socket+, and slicing
266
+ # appropriately for given return values
267
+ #
268
+ # @param [String] bytes
269
+ #
189
270
  def on_frame bytes
190
271
  on :frame, bytes
191
272
 
@@ -207,17 +288,26 @@ module H2
207
288
  @socket.flush
208
289
  end
209
290
 
291
+ # fake exceptionless IO for writing on older ruby versions
292
+ #
293
+ # @param [String] bytes
294
+ #
210
295
  def write_to_socket bytes
211
296
  @socket.write_nonblock bytes
212
297
  rescue IO::WaitWritable
213
298
  :wait_writable
214
299
  end
215
300
 
301
+ # goaway callback for parser: calls custom handler, then closes connection
302
+ #
216
303
  def on_goaway *args
217
304
  on :goaway, *args
218
305
  close
219
306
  end
220
307
 
308
+ # push promise callback for parser: creates new +Stream+ with appropriate
309
+ # parent, binds close event, calls custom handler
310
+ #
221
311
  def on_promise promise
222
312
  push_promise = Stream.new client: self,
223
313
  parent: @streams[promise.parent.id],
@@ -235,10 +325,14 @@ module H2
235
325
 
236
326
  # ---
237
327
 
328
+ # build, configure, and return TLS socket
329
+ #
330
+ # @param [TCPSocket] socket unencrypted socket
331
+ #
238
332
  def tls_socket socket
239
333
  socket = OpenSSL::SSL::SSLSocket.new socket, create_ssl_context
240
334
  socket.sync_close = true
241
- socket.hostname = @addr unless RE_IP_ADDR.match(@addr)
335
+ socket.hostname = @host unless RE_IP_ADDR.match(@host)
242
336
  socket.connect
243
337
  socket
244
338
  end
@@ -261,6 +355,8 @@ module H2
261
355
  ctx
262
356
  end
263
357
 
358
+ # handle protocol negotiation for older ruby/openssl versions
359
+ #
264
360
  if H2.alpn?
265
361
  def set_ssl_context_protocols ctx
266
362
  ctx.alpn_protocols = ALPN_PROTOCOLS
@@ -273,6 +369,8 @@ module H2
273
369
 
274
370
  # ---
275
371
 
372
+ # use exceptionless IO if this ruby version supports it
373
+ #
276
374
  module ExceptionlessIO
277
375
 
278
376
  def read_from_socket maxlen
@@ -40,32 +40,13 @@ module H2
40
40
  bind_events
41
41
  end
42
42
 
43
- # mimicing Reel::Connection#respond
43
+ # write status, headers, and body to +@stream+
44
44
  #
45
- # write status, headers, and data to +@stream+
46
- #
47
- def respond response, body_or_headers = nil, body = nil
48
-
49
- # :/
50
- #
51
- if Hash === body_or_headers
52
- headers = body_or_headers
53
- body ||= ''
54
- else
55
- headers = {}
56
- body = body_or_headers ||= ''
57
- end
58
-
59
- @response = case response
60
- when Symbol, Integer
61
- response = Response.new stream: self,
62
- status: response,
63
- headers: headers,
64
- body: body
65
- when Response
66
- response
67
- else raise TypeError, "invalid response: #{response.inspect}"
68
- end
45
+ def respond status:, headers: {}, body: ''
46
+ response = Response.new stream: self,
47
+ status: status,
48
+ headers: headers,
49
+ body: body
69
50
 
70
51
  if @closed
71
52
  log :warn, 'stream closed before response sent'
@@ -85,20 +66,9 @@ module H2
85
66
  @connection.server.async.handle_push_promise pp
86
67
  end
87
68
 
88
- # create a push promise - mimicing Reel::Connection#respond
69
+ # create a push promise
89
70
  #
90
- def push_promise_for path, body_or_headers = {}, body = nil
91
-
92
- # :/
93
- #
94
- case body_or_headers
95
- when Hash
96
- headers = body_or_headers
97
- else
98
- headers = {}
99
- body = body_or_headers
100
- end
101
-
71
+ def push_promise_for path:, headers: {}, body: nil
102
72
  headers.merge! AUTHORITY_KEY => @request.authority,
103
73
  SCHEME_KEY => @request.scheme
104
74
 
@@ -55,8 +55,8 @@ module H2
55
55
 
56
56
  # respond to this request on its stream
57
57
  #
58
- def respond response, body_or_headers = nil, body = nil
59
- @stream.respond response, body_or_headers, body
58
+ def respond status:, headers: {}, body: ''
59
+ @stream.respond status: status, headers: headers, body: body
60
60
  end
61
61
 
62
62
  end
data/lib/h2/stream.rb CHANGED
@@ -13,6 +13,15 @@ module H2
13
13
 
14
14
  attr_reader :body, :client, :headers, :parent, :pushes, :stream
15
15
 
16
+ # create a new h2 stream
17
+ #
18
+ # @param [H2::Client] client the +Client+ bind this +Stream+ to
19
+ # @param [HTTP2::Stream] stream protocol library +HTTP2::Stream+ instance
20
+ # @param [Boolean] push true if a push promise stream, false otherwise
21
+ # @param [H2::Stream] parent the parent stream of this, if push promise stream
22
+ #
23
+ # @return [H2::Stream]
24
+ #
16
25
  def initialize client:, stream:, push: false, parent: nil
17
26
  @body = ''
18
27
  @client = client
@@ -28,46 +37,66 @@ module H2
28
37
  bind_events
29
38
  end
30
39
 
40
+ # @return [Integer] stream ID
41
+ #
31
42
  def id
32
43
  @stream.id
33
44
  end
34
45
 
46
+ # @return [Boolean] true if response status is 200
47
+ #
35
48
  def ok?
36
49
  headers[STATUS_KEY] == '200'
37
50
  end
38
51
 
52
+ # @return [Boolean] true if this +Stream+ is closed
53
+ #
39
54
  def closed?
40
55
  @closed
41
56
  end
42
57
 
58
+ # @return [Boolean] true if this +Stream+ is a push promise
59
+ #
43
60
  def push?
44
61
  @push
45
62
  end
46
63
 
64
+ # add a push promise +Stream+ to this +Stream+'s list of "child" pushes
65
+ #
47
66
  def add_push stream
48
67
  @pushes << stream
49
68
  end
50
69
 
70
+ # call cancel and unblock this +Stream+
71
+ #
51
72
  def cancel!
52
73
  @stream.cancel
53
74
  unblock!
54
75
  end
55
76
 
77
+ # block this stream until unblocked or timeout
78
+ #
56
79
  def block! timeout = nil
57
80
  @pushes.each {|p| p.block! timeout}
58
81
  super
59
82
  end
60
83
 
84
+ # @return [Hash] response headers (blocks)
85
+ #
61
86
  def headers
62
87
  block!
63
88
  @headers
64
89
  end
65
90
 
91
+ # @return [String] response headers (blocks)
92
+ #
66
93
  def body
67
94
  block!
68
95
  @body
69
96
  end
70
97
 
98
+ # binds all stream events to their respective on_ handlers
99
+ #
71
100
  def bind_events
72
101
  @stream.on(:close) do
73
102
  @parent.add_push self if @parent && push?
@@ -87,6 +116,8 @@ module H2
87
116
  end
88
117
  end
89
118
 
119
+ # builds +Hash+ from associative array, merges into response headers
120
+ #
90
121
  def add_headers h
91
122
  h = Hash[h]
92
123
  on :headers, h
@@ -94,6 +125,8 @@ module H2
94
125
  @headers
95
126
  end
96
127
 
128
+ # @return [Hash] a simple +Hash+ with +:headers+ and +:body+ keys/values
129
+ #
97
130
  def to_h
98
131
  { headers: headers, body: body }
99
132
  end
data/lib/h2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module H2
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
3
3
 
4
4
  class << self
5
5
 
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.5.0
4
+ version: 0.6.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: 2018-07-21 00:00:00.000000000 Z
11
+ date: 2018-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.9'
19
+ version: '0.10'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.9.1
22
+ version: 0.10.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '0.9'
29
+ version: '0.10'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.9.1
32
+ version: 0.10.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: colored
35
35
  requirement: !ruby/object:Gem::Requirement