http-2 0.8.0 → 0.8.1

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
  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