h2 0.6.0 → 0.6.1

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
  SHA256:
3
- metadata.gz: e62e384940a1e408102e4e518942c1245ce374f82007c858d9de5a0b286c2301
4
- data.tar.gz: d3fc7f3d111b3786cb50c58f862b32dad713557ae69cf18233cd1eda7ca0d5be
3
+ metadata.gz: 9a9868c3d9496207683352704cd152a9d5426ff42cd3aa30035a56981596e957
4
+ data.tar.gz: 43e60980d431d769835d4bb15de0cacbb5676c250b1e461c31e4f88c89734c48
5
5
  SHA512:
6
- metadata.gz: 907a28fb440862cbc3a6a9dbb80db39408f3635f4aa4983358bba508617ddbb8fcb9da0a30b3601a614f4ea7a79ff4cceece1b7d1c687b6afc3e663ad5d4459d
7
- data.tar.gz: 317f75c090f2f54526a2bff4b2e8b7d298ab7f6bf8f4653e9bd5ac2916f333133e26a7b47d357c447a7a0a6741468b99733e1212c71ee018f4698c51b0ea5eaf
6
+ metadata.gz: 19e4e75141869144f1ed7b6abf8b6faeb61d00db6466d02ec5264ec7d95ddada0de2914b071dc13a5293885189fea5cb9b235515fc8e282218244d19b5eea08a
7
+ data.tar.gz: 50a36bbc351d0dca3cc81750800e2a5085e403bc6019a8620cef8ec5d8977c4e227dcd994656365eb9d75ae03d4fdb0dd9d2e740f2eeccbdf636210f8952dd50
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  h2 changelog
2
2
  ============
3
3
 
4
+ ### 0.6.1 27 jul 2018
5
+
6
+ * fix race between reading and sending first frame
7
+ * make `port:` default to 443 for `H2::Client.new`
8
+
4
9
  ### 0.6.0 25 jul 2018
5
10
 
6
11
  * update server API - kwargs
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'http-2', path: '../http-2'
6
+
5
7
  group :concurrent_ruby do
6
8
  gem 'concurrent-ruby'
7
9
  end
data/exe/h2 CHANGED
@@ -9,7 +9,6 @@ require 'colored'
9
9
  require 'optparse'
10
10
 
11
11
  begin # {{{
12
- raise LoadError if ARGV.include?('--dev')
13
12
  require 'h2'
14
13
  rescue LoadError
15
14
  $: << File.expand_path('../../lib', __FILE__)
@@ -59,10 +58,6 @@ OptionParser.new do |o|
59
58
  options[:debug] = true
60
59
  end
61
60
 
62
- o.on '--dev', 'load lib from source tree' do
63
- # handled above for reasons
64
- end
65
-
66
61
  o.on '-g', '--goaway', 'send GOAWAY frame when stream is complete' do
67
62
  options[:goaway] = true
68
63
  end
@@ -142,8 +137,8 @@ end
142
137
 
143
138
  puts s.body
144
139
 
145
- c.goaway if options[:goaway]
146
140
  c.block! if options[:block]
141
+ c.goaway if options[:goaway]
147
142
  c.close
148
143
 
149
144
  # }}}
data/lib/h2.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'http/2'
4
+ require 'logger'
4
5
  require 'uri'
5
6
  require 'h2/version'
6
7
 
@@ -28,8 +29,21 @@ module H2
28
29
  :put
29
30
  ]
30
31
 
32
+ Logger = ::Logger.new STDOUT
33
+
31
34
  class << self
32
35
 
36
+ # turn on extra verbose debug logging
37
+ #
38
+ def verbose!
39
+ @verbose = true
40
+ end
41
+
42
+ def verbose?
43
+ @verbose = false unless defined?(@verbose)
44
+ @verbose
45
+ end
46
+
33
47
  # convenience wrappers to make requests with HTTP methods
34
48
  #
35
49
  # @see H2.request
@@ -120,6 +134,33 @@ module H2
120
134
 
121
135
  end
122
136
 
137
+ module FrameDebugger
138
+
139
+ def self.included base
140
+ H2.verbose!
141
+ base::PARSER_EVENTS.push :frame_sent, :frame_received
142
+ end
143
+
144
+ def on_frame_sent f
145
+ Logger.debug "Sent frame: #{truncate_frame(f).inspect}"
146
+ end
147
+
148
+ def on_frame_received f
149
+ Logger.debug "Received frame: #{truncate_frame(f).inspect}"
150
+ end
151
+
152
+ private
153
+
154
+ def truncate_string s
155
+ (String === s && s.length > 64) ? "#{s[0,64]}..." : s
156
+ end
157
+
158
+ def truncate_frame f
159
+ f.reduce({}) { |h, (k, v)| h[k] = truncate_string(v); h }
160
+ end
161
+
162
+ end
163
+
123
164
  end
124
165
 
125
166
  require 'h2/client'
data/lib/h2/client.rb CHANGED
@@ -7,16 +7,18 @@ module H2
7
7
  include Blockable
8
8
  include On
9
9
 
10
- CONNECTION_EVENTS = [
10
+ PARSER_EVENTS = [
11
11
  :close,
12
12
  :frame,
13
13
  :goaway,
14
14
  :promise
15
15
  ]
16
16
 
17
- ALPN_PROTOCOLS = ['h2']
18
- DEFAULT_MAXLEN = 4096
19
- RE_IP_ADDR = Regexp.union Resolv::IPv4::Regex, Resolv::IPv6::Regex
17
+ # include FrameDebugger
18
+
19
+ ALPN_PROTOCOLS = ['h2']
20
+ DEFAULT_MAXLEN = 4096
21
+ RE_IP_ADDR = Regexp.union Resolv::IPv4::Regex, Resolv::IPv6::Regex
20
22
 
21
23
  attr_accessor :last_stream
22
24
  attr_reader :client, :reader, :scheme, :socket, :streams
@@ -24,14 +26,14 @@ module H2
24
26
  # create a new h2 client
25
27
  #
26
28
  # @param [String] host IP address or hostname
27
- # @param [Integer] port TCP port
29
+ # @param [Integer] port TCP port (default: 443)
28
30
  # @param [String,URI] url full URL to parse (optional: existing +URI+ instance)
29
31
  # @param [Hash,FalseClass] tls TLS options (optional: +false+ do not use TLS)
30
32
  # @option tls [String] :cafile path to CA file
31
33
  #
32
34
  # @return [H2::Client]
33
35
  #
34
- def initialize host: nil, port: nil, url: nil, tls: {}
36
+ def initialize host: nil, port: 443, url: nil, tls: {}
35
37
  raise ArgumentError if url.nil? && (host.nil? || port.nil?)
36
38
 
37
39
  if url
@@ -52,11 +54,12 @@ module H2
52
54
  @socket = tls_socket @socket if @tls
53
55
  @client = HTTP2::Client.new
54
56
 
57
+ @first = true
58
+ @reading = false
59
+
55
60
  init_blocking
56
61
  yield self if block_given?
57
62
  bind_events
58
-
59
- read
60
63
  end
61
64
 
62
65
  # @return true if the connection is closed
@@ -76,6 +79,14 @@ module H2
76
79
  @socket.eof?
77
80
  end
78
81
 
82
+ def reading?
83
+ @mutex.synchronize { @reading }
84
+ end
85
+
86
+ def reading!
87
+ @mutex.synchronize { @reading = true }
88
+ end
89
+
79
90
  # send a goaway frame and wait until the connection is closed
80
91
  #
81
92
  def goaway!
@@ -98,7 +109,7 @@ module H2
98
109
  # binds all connection events to their respective on_ handlers
99
110
  #
100
111
  def bind_events
101
- CONNECTION_EVENTS.each do |e|
112
+ PARSER_EVENTS.each do |e|
102
113
  @client.on(e){|*a| __send__ "on_#{e}", *a}
103
114
  end
104
115
  end
@@ -194,6 +205,8 @@ module H2
194
205
  # creates a new +Thread+ to read the given number of bytes each loop from
195
206
  # the current +@socket+
196
207
  #
208
+ # NOTE: initial client frames (settings, etc) should be sent first!
209
+ #
197
210
  # NOTE: this is the override point for celluloid actor pool or concurrent
198
211
  # ruby threadpool support
199
212
  #
@@ -202,6 +215,7 @@ module H2
202
215
  def read maxlen = DEFAULT_MAXLEN
203
216
  main = Thread.current
204
217
  @reader = Thread.new do
218
+ reading!
205
219
  begin
206
220
  _read maxlen
207
221
  rescue => e
@@ -230,7 +244,7 @@ module H2
230
244
  begin
231
245
  @client << data
232
246
  rescue HTTP2::Error::ProtocolError => pe
233
- STDERR.puts 'mystery protocol error!'
247
+ STDERR.puts "protocol error: #{pe.message}"
234
248
  STDERR.puts pe.backtrace.map {|l| "\t" + l}
235
249
  end
236
250
  end
@@ -286,6 +300,9 @@ module H2
286
300
  @socket.write bytes
287
301
  end
288
302
  @socket.flush
303
+
304
+ @first = false if @first
305
+ read unless @first or @reading
289
306
  end
290
307
 
291
308
  # fake exceptionless IO for writing on older ruby versions
@@ -9,6 +9,7 @@ module H2
9
9
  include ::Celluloid
10
10
 
11
11
  def read client, maxlen = DEFAULT_MAXLEN
12
+ client.reading!
12
13
  client._read maxlen
13
14
  end
14
15
  end
@@ -18,6 +18,7 @@ module H2
18
18
  def read maxlen = DEFAULT_MAXLEN
19
19
  main = Thread.current
20
20
  @reader = self.class.thread_pool.post do
21
+ reading!
21
22
  begin
22
23
  _read maxlen
23
24
  rescue => e
data/lib/h2/server.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'celluloid/current'
2
- require 'logger'
3
2
  require 'reel'
4
3
  require 'h2/reel/ext'
5
4
  require 'h2'
@@ -8,8 +7,6 @@ module H2
8
7
 
9
8
  CONTENT_LENGTH_KEY = 'content-length'
10
9
 
11
- Logger = ::Logger.new STDOUT
12
-
13
10
  class << self
14
11
 
15
12
  def alpn?
@@ -21,17 +18,6 @@ module H2
21
18
  @jruby = RUBY_ENGINE == 'jruby'
22
19
  end
23
20
 
24
- # turn on extra verbose debug logging
25
- #
26
- def verbose!
27
- @verbose = true
28
- end
29
-
30
- def verbose?
31
- @verbose = false unless defined?(@verbose)
32
- @verbose
33
- end
34
-
35
21
  end
36
22
 
37
23
  # base H2 server, a direct subclass of +Reel::Server+
@@ -13,12 +13,12 @@ module H2
13
13
  #
14
14
  PARSER_EVENTS = [
15
15
  :frame,
16
- :frame_sent,
17
- :frame_received,
18
16
  :stream,
19
17
  :goaway
20
18
  ]
21
19
 
20
+ # include FrameDebugger
21
+
22
22
  attr_reader :parser, :server, :socket
23
23
 
24
24
  def initialize socket:, server:
@@ -94,7 +94,7 @@ module H2
94
94
 
95
95
  rescue => e
96
96
  Logger.error "Exception: #{e.message} - closing socket"
97
- STDERR.puts e.backtrace
97
+ STDERR.puts e.backtrace if H2.verbose?
98
98
  close
99
99
 
100
100
  end
@@ -107,24 +107,12 @@ module H2
107
107
  # called by +@parser+ with a binary frame to write to the +@socket+
108
108
  #
109
109
  def on_frame bytes
110
- Logger.debug "Writing bytes: #{truncate_string(bytes.unpack("H*").first)}" if H2.verbose?
111
-
112
- # N.B. this is the important bit
113
- #
114
110
  @socket.write bytes
115
111
  rescue IOError, Errno::EPIPE => e
116
112
  Logger.error e.message
117
113
  close
118
114
  end
119
115
 
120
- def on_frame_sent f
121
- Logger.debug "Sent frame: #{truncate_frame(f).inspect}" if H2.verbose?
122
- end
123
-
124
- def on_frame_received f
125
- Logger.debug "Received frame: #{truncate_frame(f).inspect}" if H2.verbose?
126
- end
127
-
128
116
  # the +@parser+ calls this when a new stream has been initiated by the
129
117
  # client
130
118
  #
@@ -138,16 +126,6 @@ module H2
138
126
  close
139
127
  end
140
128
 
141
- private
142
-
143
- def truncate_string s
144
- (String === s && s.length > 64) ? "#{s[0,64]}..." : s
145
- end
146
-
147
- def truncate_frame f
148
- f.reduce({}) { |h, (k, v)| h[k] = truncate_string(v); h }
149
- end
150
-
151
129
  end
152
130
  end
153
131
  end
data/lib/h2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module H2
2
- VERSION = '0.6.0'
2
+ VERSION = '0.6.1'
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.6.0
4
+ version: 0.6.1
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-25 00:00:00.000000000 Z
11
+ date: 2018-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2