http-2 0.8.0 → 0.8.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
  SHA1:
3
- metadata.gz: cf205c4c32086ed1a2ec2d784283e7e2c2c983d2
4
- data.tar.gz: 272d84cd37cac57b38d391480795b39661fcb20a
3
+ metadata.gz: 5e4d8a543b24380552462863450caaa90dcc5d1f
4
+ data.tar.gz: 5948ffc6c3aa27f7d81bd86cd0ef62ad163e412f
5
5
  SHA512:
6
- metadata.gz: 338b39a100523327a407abec0cf68586e079290626661e8d39c803dbee7eee1b958d3f70bdcbfb0712d7fd36db0cb315cb729a1704ce8b655485c7b02a2108fb
7
- data.tar.gz: d34d0a7325076767c9c36a85319c733268a812968482ff4c81be7533b7467f0a7abfb99ad498bd707dd93a706438ba709b2356554aaa6a34af768290524599b9
6
+ metadata.gz: 32a27c2213a6c8b18b56f752495a938d65260c63644be63af58fd0aaf133795bf9e2748d23fe8b8c49bf96500e30a551ac0001001a1fe46a2082f06d8420dcc8
7
+ data.tar.gz: 2fdc75f407ecb70fb601a04d9c8fe5b76e23bebafc495e48bf2a1e3d96ada6d1784ed29a9c352cfa04027ebd5dace72779fc009b1cd0f87366cfab035c72f66a
data/.travis.yml CHANGED
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - 2.1
5
5
  - 2.2
6
+ - 2.3.0
6
7
  - jruby-9.0.0.0
7
8
  - jruby-head
8
9
  - rbx-2
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ group :test do
10
10
  gem 'coveralls', require: false
11
11
  gem 'pry'
12
12
  gem 'pry-byebug', platform: :mri
13
- gem 'rspec'
13
+ gem 'rspec', '~> 3.4.0'
14
14
  gem 'rspec-autotest'
15
15
  gem 'rubocop', '~> 0.30.0'
16
16
  end
data/example/client.rb CHANGED
@@ -110,7 +110,8 @@ while !sock.closed? && !sock.eof?
110
110
  begin
111
111
  conn << data
112
112
  rescue => e
113
- puts "Exception: #{e}, #{e.message} - closing socket."
113
+ puts "#{e.class} exception: #{e.message} - closing socket."
114
+ e.backtrace.each { |l| puts "\t" + l }
114
115
  sock.close
115
116
  end
116
117
  end
data/example/server.rb CHANGED
@@ -45,7 +45,7 @@ loop do
45
45
  log = Logger.new(stream.id)
46
46
  req, buffer = {}, ''
47
47
 
48
- stream.on(:active) { log.info 'cliend opened new stream' }
48
+ stream.on(:active) { log.info 'client opened new stream' }
49
49
  stream.on(:close) { log.info 'stream closed' }
50
50
 
51
51
  stream.on(:headers) do |h|
@@ -89,7 +89,8 @@ loop do
89
89
  begin
90
90
  conn << data
91
91
  rescue => e
92
- puts "Exception: #{e}, #{e.message} - closing socket."
92
+ puts "#{e.class} exception: #{e.message} - closing socket."
93
+ e.backtrace.each { |l| puts "\t" + l }
93
94
  sock.close
94
95
  end
95
96
  end
@@ -28,15 +28,17 @@ if options[:secure]
28
28
  end
29
29
 
30
30
  class UpgradeHandler
31
+ VALID_UPGRADE_METHODS = %w(GET OPTIONS)
32
+ UPGRADE_RESPONSE = <<-RESP
33
+ HTTP/1.1 101 Switching Protocols
34
+ Connection: Upgrade
35
+ Upgrade: h2c
31
36
 
32
- VALID_UPGRADE_METHODS = %w[GET OPTIONS]
33
- UPGRADE_RESPONSE = ("HTTP/1.1 101 Switching Protocols\n" +
34
- "Connection: Upgrade\n" +
35
- "Upgrade: h2c\n\n").freeze
37
+ RESP
36
38
 
37
39
  attr_reader :complete, :headers, :body, :parsing
38
40
 
39
- def initialize conn, sock
41
+ def initialize(conn, sock)
40
42
  @conn, @sock = conn, sock
41
43
  @complete, @parsing = false, false
42
44
  @body = ''
@@ -46,23 +48,24 @@ class UpgradeHandler
46
48
  def <<(data)
47
49
  @parsing ||= true
48
50
  @parser << data
49
- if complete
51
+ return unless complete
50
52
 
51
- @sock.write UPGRADE_RESPONSE
53
+ @sock.write UPGRADE_RESPONSE
52
54
 
53
- settings = headers['http2-settings']
54
- request = {
55
- ':scheme' => 'http',
56
- ':method' => @parser.http_method,
57
- ':authority' => headers['Host'],
58
- ':path' => @parser.request_url
59
- }.merge(headers)
55
+ settings = headers['http2-settings']
56
+ request = {
57
+ ':scheme' => 'http',
58
+ ':method' => @parser.http_method,
59
+ ':authority' => headers['Host'],
60
+ ':path' => @parser.request_url,
61
+ }.merge(headers)
60
62
 
61
- @conn.upgrade(settings, request, @body)
62
- end
63
+ @conn.upgrade(settings, request, @body)
63
64
  end
64
65
 
65
- def complete!; @complete = true; end
66
+ def complete!
67
+ @complete = true
68
+ end
66
69
 
67
70
  def on_headers_complete(headers)
68
71
  @headers = headers
@@ -73,11 +76,10 @@ class UpgradeHandler
73
76
  end
74
77
 
75
78
  def on_message_complete
76
- raise unless VALID_UPGRADE_METHODS.include?(@parser.http_method)
79
+ fail unless VALID_UPGRADE_METHODS.include?(@parser.http_method)
77
80
  @parsing = false
78
81
  complete!
79
82
  end
80
-
81
83
  end
82
84
 
83
85
  loop do
@@ -122,7 +124,7 @@ loop do
122
124
  log.info "Processing h2c Upgrade request: #{req}"
123
125
 
124
126
  # Don't respond to OPTIONS...
125
- if req[':method'] != "OPTIONS"
127
+ if req[':method'] != 'OPTIONS'
126
128
  response = 'Hello h2c world!'
127
129
  stream.headers({
128
130
  ':status' => '200',
data/http-2.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = spec.description
13
13
  spec.homepage = 'https://github.com/igrigorik/http-2'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = '>=2.0.0'
15
+ spec.required_ruby_version = '>=2.1.0'
16
16
 
17
17
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
data/lib/http/2/buffer.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  module HTTP2
2
2
  # Simple binary buffer backed by string.
3
3
  #
4
+ # TODO: Refactor, it would be better if Buffer were not a String subclass,
5
+ # but rather wrap a string and only expose the mutating API needed so that
6
+ # the possible surface for things to go wrong stays controllable.
7
+ # - https://github.com/igrigorik/http-2/pull/46
8
+ #
4
9
  class Buffer < String
5
10
  UINT32 = 'N'.freeze
6
11
  private_constant :UINT32
@@ -30,5 +35,14 @@ module HTTP2
30
35
  def read_uint32
31
36
  read(4).unpack(UINT32).first
32
37
  end
38
+
39
+ # Ensures that data that is added is binary encoded as well,
40
+ # otherwise this could lead to the Buffer instance changing its encoding.
41
+ [:<<, :prepend].each do |mutating_method|
42
+ define_method(mutating_method) do |string|
43
+ string = string.dup if string.frozen?
44
+ super(string.force_encoding(Encoding::BINARY))
45
+ end
46
+ end
33
47
  end
34
48
  end
@@ -321,7 +321,7 @@ module HTTP2
321
321
 
322
322
  rescue => e
323
323
  raise if e.is_a?(Error::Error)
324
- connection_error
324
+ connection_error(e: e)
325
325
  end
326
326
  alias_method :<<, :receive
327
327
 
@@ -574,7 +574,7 @@ module HTTP2
574
574
  end
575
575
 
576
576
  rescue => e
577
- connection_error(:compression_error, msg: e.message)
577
+ connection_error(:compression_error, e: e)
578
578
  end
579
579
 
580
580
  # Encode headers payload and update connection compressor state.
@@ -605,7 +605,8 @@ module HTTP2
605
605
  frames
606
606
 
607
607
  rescue => e
608
- [connection_error(:compression_error, msg: e.message)]
608
+ connection_error(:compression_error, e: e)
609
+ nil
609
610
  end
610
611
 
611
612
  # Activates new incoming or outgoing stream and registers appropriate
@@ -642,12 +643,12 @@ module HTTP2
642
643
  # @option error [Symbol] :frame_too_large
643
644
  # @option error [Symbol] :compression_error
644
645
  # @param msg [String]
645
- def connection_error(error = :protocol_error, msg: nil)
646
+ def connection_error(error = :protocol_error, msg: nil, e: nil)
646
647
  goaway(error) unless @state == :closed || @state == :new
647
648
 
648
649
  @state, @error = :closed, error
649
650
  klass = error.to_s.split('_').map(&:capitalize).join
650
- fail Error.const_get(klass), msg
651
+ fail Error.const_get(klass), msg || e.message, e.backtrace || []
651
652
  end
652
653
  end
653
654
  end
data/lib/http/2/server.rb CHANGED
@@ -72,12 +72,13 @@ module HTTP2
72
72
 
73
73
  # Process received HTTP2-Settings payload
74
74
  buf = HTTP2::Buffer.new Base64.urlsafe_decode64(settings)
75
- buf.prepend(@framer.common_header(
75
+ header = @framer.common_header(
76
76
  length: buf.bytesize,
77
77
  type: :settings,
78
78
  stream: 0,
79
- flags: []
80
- ))
79
+ flags: [],
80
+ )
81
+ buf.prepend(header)
81
82
  receive(buf)
82
83
 
83
84
  # Activate stream (id: 1) with on HTTP/1.1 request parameters
@@ -98,7 +99,7 @@ module HTTP2
98
99
  stream << headers_frame
99
100
  else
100
101
  stream << headers_frame
101
- stream << {type: :data, stream: 1, payload: body, flags: [:end_stream]}
102
+ stream << { type: :data, stream: 1, payload: body, flags: [:end_stream] }
102
103
  end
103
104
 
104
105
  # Mark h2c upgrade as finished
@@ -1,3 +1,3 @@
1
1
  module HTTP2
2
- VERSION = '0.8.0'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
data/spec/buffer_spec.rb CHANGED
@@ -7,6 +7,13 @@ RSpec.describe HTTP2::Buffer do
7
7
  expect(b.encoding.to_s).to eq 'ASCII-8BIT'
8
8
  end
9
9
 
10
+ it 'should force 8-bit encoding when adding data' do
11
+ b << 'émalgré'
12
+ expect(b.encoding.to_s).to eq 'ASCII-8BIT'
13
+ b.prepend('émalgré')
14
+ expect(b.encoding.to_s).to eq 'ASCII-8BIT'
15
+ end
16
+
10
17
  it 'should return bytesize of the buffer' do
11
18
  expect(b.size).to eq 9
12
19
  end
data/spec/helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'active_support/core_ext/object/deep_dup'
2
2
 
3
3
  RSpec.configure(&:disable_monkey_patching!)
4
+ RSpec::Expectations.configuration.warn_about_potential_false_positives = false
4
5
 
5
6
  require 'json'
6
7
  require 'coveralls'
@@ -0,0 +1,84 @@
1
+ require 'helper'
2
+ require 'json'
3
+
4
+ RSpec.describe HTTP2::Header do
5
+ folders = %w(
6
+ go-hpack
7
+ haskell-http2-diff
8
+ haskell-http2-diff-huffman
9
+ haskell-http2-linear
10
+ haskell-http2-linear-huffman
11
+ haskell-http2-naive
12
+ haskell-http2-naive-huffman
13
+ haskell-http2-static
14
+ haskell-http2-static-huffman
15
+ #hyper-hpack
16
+ nghttp2
17
+ nghttp2-16384-4096
18
+ nghttp2-change-table-size
19
+ node-http2-hpack
20
+ )
21
+
22
+ context 'Decompressor' do
23
+ folders.each do |folder|
24
+ next if folder =~ /#/
25
+ path = File.expand_path("hpack-test-case/#{folder}", File.dirname(__FILE__))
26
+ next unless Dir.exist?(path)
27
+ context "#{folder}" do
28
+ Dir.foreach(path) do |file|
29
+ next if file !~ /\.json/
30
+ it "should decode #{file}" do
31
+ story = JSON.parse(File.read("#{path}/#{file}"))
32
+ cases = story['cases']
33
+ table_size = cases[0]['header_table_size'] || 4096
34
+ @dc = Decompressor.new(table_size: table_size)
35
+ cases.each do |c|
36
+ wire = [c['wire']].pack('H*').force_encoding(Encoding::BINARY)
37
+ @emitted = @dc.decode(HTTP2::Buffer.new(wire))
38
+ headers = c['headers'].flat_map(&:to_a)
39
+ expect(@emitted).to eq headers
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'Compressor' do
48
+ %w(
49
+ LINEAR
50
+ NAIVE
51
+ SHORTER
52
+ STATIC
53
+ ).each do |mode|
54
+ next if mode =~ /#/
55
+ ['', 'H'].each do |huffman|
56
+ encoding_mode = "#{mode}#{huffman}".to_sym
57
+ encoding_options = HTTP2::Header::EncodingContext.const_get(encoding_mode)
58
+ [4096, 512].each do |table_size|
59
+ options = { table_size: table_size }
60
+ options.update(encoding_options)
61
+
62
+ context "with #{mode}#{huffman} mode and table_size #{table_size}" do
63
+ path = File.expand_path('hpack-test-case/raw-data', File.dirname(__FILE__))
64
+ Dir.foreach(path) do |file|
65
+ next if file !~ /\.json/
66
+ it "should encode #{file}" do
67
+ story = JSON.parse(File.read("#{path}/#{file}"))
68
+ cases = story['cases']
69
+ @cc = Compressor .new(options)
70
+ @dc = Decompressor.new(options)
71
+ cases.each do |c|
72
+ headers = c['headers'].flat_map(&:to_a)
73
+ wire = @cc.encode(headers)
74
+ decoded = @dc.decode(HTTP2::Buffer.new(wire))
75
+ expect(decoded).to eq headers
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Grigorik
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-27 00:00:00.000000000 Z
12
+ date: 2016-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -73,6 +73,7 @@ files:
73
73
  - spec/emitter_spec.rb
74
74
  - spec/framer_spec.rb
75
75
  - spec/helper.rb
76
+ - spec/hpack_test_spec.rb
76
77
  - spec/huffman_spec.rb
77
78
  - spec/server_spec.rb
78
79
  - spec/stream_spec.rb
@@ -88,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
89
  requirements:
89
90
  - - ">="
90
91
  - !ruby/object:Gem::Version
91
- version: 2.0.0
92
+ version: 2.1.0
92
93
  required_rubygems_version: !ruby/object:Gem::Requirement
93
94
  requirements:
94
95
  - - ">="
@@ -108,6 +109,7 @@ test_files:
108
109
  - spec/emitter_spec.rb
109
110
  - spec/framer_spec.rb
110
111
  - spec/helper.rb
112
+ - spec/hpack_test_spec.rb
111
113
  - spec/huffman_spec.rb
112
114
  - spec/server_spec.rb
113
115
  - spec/stream_spec.rb