http-2 0.7.0 → 0.8.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.
@@ -1,3 +1,3 @@
1
1
  module HTTP2
2
- VERSION = "0.7.0"
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -1,4 +1,4 @@
1
- desc "Generate Huffman precompiled table in huffman_statemachine.rb"
1
+ desc 'Generate Huffman precompiled table in huffman_statemachine.rb'
2
2
  task :generate_table do
3
3
  HuffmanTable::Node.generate_state_table
4
4
  end
@@ -14,16 +14,17 @@ module HuffmanTable
14
14
  attr_accessor :next, :emit, :final, :depth
15
15
  attr_accessor :transitions
16
16
  attr_accessor :id
17
- @@id = 0
17
+ @@id = 0 # rubocop:disable Style/ClassVars
18
18
  def initialize(depth)
19
19
  @next = [nil, nil]
20
20
  @id = @@id
21
- @@id += 1
21
+ @@id += 1 # rubocop:disable Style/ClassVars
22
22
  @final = false
23
23
  @depth = depth
24
24
  end
25
+
25
26
  def add(code, len, chr)
26
- chr == EOS && @depth <= 7 and self.final = true
27
+ self.final = true if chr == EOS && @depth <= 7
27
28
  if len == 0
28
29
  @emit = chr
29
30
  else
@@ -69,14 +70,13 @@ module HuffmanTable
69
70
  (BITS_AT_ONCE - 1).downto(0) do |i|
70
71
  bit = (input & (1 << i)) == 0 ? 0 : 1
71
72
  n = n.next[bit]
72
- if n.emit
73
- if n.emit == EOS
74
- emit = EOS # cause error on decoding
75
- else
76
- emit << n.emit.chr('binary') unless emit == EOS
77
- end
78
- n = @root
73
+ next unless n.emit
74
+ if n.emit == EOS
75
+ emit = EOS # cause error on decoding
76
+ else
77
+ emit << n.emit.chr(Encoding::BINARY) unless emit == EOS
79
78
  end
79
+ n = @root
80
80
  end
81
81
  node.transitions[input] = Transition.new(emit, n)
82
82
  togo << n
@@ -95,14 +95,14 @@ module HuffmanTable
95
95
  id_state[0] = @root
96
96
  max_final = 0
97
97
  id = 1
98
- (@states - [@root]).sort_by{|s|s.final ? 0 : 1}.each do |s|
98
+ (@states - [@root]).sort_by { |s| s.final ? 0 : 1 }.each do |s|
99
99
  state_id[s] = id
100
100
  id_state[id] = s
101
101
  max_final = id if s.final
102
102
  id += 1
103
103
  end
104
104
 
105
- File.open(File.expand_path("../http/2/huffman_statemachine.rb", File.dirname(__FILE__)), "w") do |f|
105
+ File.open(File.expand_path('../http/2/huffman_statemachine.rb', File.dirname(__FILE__)), 'w') do |f|
106
106
  f.print <<HEADER
107
107
  # Machine generated Huffman decoder state machine.
108
108
  # DO NOT EDIT THIS FILE.
@@ -119,16 +119,22 @@ module HTTP2
119
119
  HEADER
120
120
  id.times do |i|
121
121
  n = id_state[i]
122
- f.print " ["
123
- (1 << BITS_AT_ONCE).times do |t|
124
- emit = n.transitions[t].emit
125
- emit == EOS or emit = emit.dup.force_encoding('binary')
126
- f.print %Q/[#{emit == '' ? "nil" : emit.inspect},#{state_id[n.transitions[t].node]}],/
127
- end
122
+ f.print ' ['
123
+ string = (1 << BITS_AT_ONCE).times.map do |t|
124
+ transition = n.transitions.fetch(t)
125
+ emit = transition.emit
126
+ unless emit == EOS
127
+ bytes = emit.bytes
128
+ fail ArgumentError if bytes.size > 1
129
+ emit = bytes.first
130
+ end
131
+ "[#{emit.inspect}, #{state_id.fetch(transition.node)}]"
132
+ end.join(', ')
133
+ f.print(string)
128
134
  f.print "],\n"
129
135
  end
130
136
  f.print <<TAILER
131
- ]
137
+ ].each { |arr| arr.each { |subarr| subarr.each(&:freeze) }.freeze }.freeze
132
138
  end
133
139
  end
134
140
  end
@@ -136,22 +142,22 @@ TAILER
136
142
  end
137
143
  end
138
144
 
139
- def self.root
140
- @root
145
+ class << self
146
+ attr_reader :root
141
147
  end
142
148
 
143
149
  # Test decoder
144
150
  def self.decode(input)
145
151
  emit = ''
146
152
  n = root
147
- nibbles = input.unpack("C*").flat_map{|b| [((b & 0xf0) >> 4), b & 0xf]}
153
+ nibbles = input.unpack('C*').flat_map { |b| [((b & 0xf0) >> 4), b & 0xf] }
148
154
  until nibbles.empty?
149
155
  nb = nibbles.shift
150
156
  t = n.transitions[nb]
151
157
  emit << t.emit
152
158
  n = t.node
153
159
  end
154
- unless n.final && nibbles.all?{|x| x == 0xf}
160
+ unless n.final && nibbles.all? { |x| x == 0xf }
155
161
  puts "len = #{emit.size} n.final = #{n.final} nibbles = #{nibbles}"
156
162
  end
157
163
  emit
@@ -1,23 +1,21 @@
1
- require "helper"
1
+ require 'helper'
2
2
 
3
- describe HTTP2::Buffer do
3
+ RSpec.describe HTTP2::Buffer do
4
+ let(:b) { Buffer.new('émalgré') }
4
5
 
5
- let(:b) { Buffer.new("émalgré") }
6
-
7
- it "should force 8-bit encoding" do
8
- b.encoding.to_s.should eq "ASCII-8BIT"
6
+ it 'should force 8-bit encoding' do
7
+ expect(b.encoding.to_s).to eq 'ASCII-8BIT'
9
8
  end
10
9
 
11
- it "should return bytesize of the buffer" do
12
- b.size.should eq 9
10
+ it 'should return bytesize of the buffer' do
11
+ expect(b.size).to eq 9
13
12
  end
14
13
 
15
- it "should read single byte at a time" do
16
- 9.times { b.read(1).should_not be_nil }
14
+ it 'should read single byte at a time' do
15
+ 9.times { expect(b.read(1)).not_to be_nil }
17
16
  end
18
17
 
19
- it "should unpack an unsigned 32-bit int" do
20
- Buffer.new([256].pack("N")).read_uint32.should eq 256
18
+ it 'should unpack an unsigned 32-bit int' do
19
+ expect(Buffer.new([256].pack('N')).read_uint32).to eq 256
21
20
  end
22
-
23
21
  end
@@ -1,93 +1,92 @@
1
- require "helper"
1
+ require 'helper'
2
2
 
3
- describe HTTP2::Client do
3
+ RSpec.describe HTTP2::Client do
4
4
  before(:each) do
5
5
  @client = Client.new
6
6
  end
7
7
 
8
8
  let(:f) { Framer.new }
9
9
 
10
- context "initialization and settings" do
11
- it "should return odd stream IDs" do
12
- @client.new_stream.id.should_not be_even
10
+ context 'initialization and settings' do
11
+ it 'should return odd stream IDs' do
12
+ expect(@client.new_stream.id).not_to be_even
13
13
  end
14
14
 
15
- it "should emit connection header and SETTINGS on new client connection" do
15
+ it 'should emit connection header and SETTINGS on new client connection' do
16
16
  frames = []
17
17
  @client.on(:frame) { |bytes| frames << bytes }
18
- @client.ping("12345678")
18
+ @client.ping('12345678')
19
19
 
20
- frames[0].should eq CONNECTION_PREFACE_MAGIC
21
- f.parse(frames[1])[:type].should eq :settings
20
+ expect(frames[0]).to eq CONNECTION_PREFACE_MAGIC
21
+ expect(f.parse(frames[1])[:type]).to eq :settings
22
22
  end
23
23
 
24
- it "should initialize client with custom connection settings" do
24
+ it 'should initialize client with custom connection settings' do
25
25
  frames = []
26
26
 
27
- @client = Client.new(:settings_max_concurrent_streams => 200)
27
+ @client = Client.new(settings_max_concurrent_streams: 200)
28
28
  @client.on(:frame) { |bytes| frames << bytes }
29
- @client.ping("12345678")
29
+ @client.ping('12345678')
30
30
 
31
31
  frame = f.parse(frames[1])
32
- frame[:type].should eq :settings
33
- frame[:payload].should include([:settings_max_concurrent_streams, 200])
32
+ expect(frame[:type]).to eq :settings
33
+ expect(frame[:payload]).to include([:settings_max_concurrent_streams, 200])
34
34
  end
35
35
  end
36
36
 
37
- context "push" do
38
- it "should disallow client initiated push" do
37
+ context 'push' do
38
+ it 'should disallow client initiated push' do
39
39
  expect do
40
40
  @client.promise({}) {}
41
- end.to raise_error(Exception)
41
+ end.to raise_error(NoMethodError)
42
42
  end
43
43
 
44
- it "should raise error on PUSH_PROMISE against stream 0" do
45
- expect {
46
- @client << set_stream_id(f.generate(PUSH_PROMISE), 0)
47
- }.to raise_error(ProtocolError)
44
+ it 'should raise error on PUSH_PROMISE against stream 0' do
45
+ expect do
46
+ @client << set_stream_id(f.generate(PUSH_PROMISE.dup), 0)
47
+ end.to raise_error(ProtocolError)
48
48
  end
49
49
 
50
- it "should raise error on PUSH_PROMISE against bogus stream" do
51
- expect {
52
- @client << set_stream_id(f.generate(PUSH_PROMISE), 31415)
53
- }.to raise_error(ProtocolError)
50
+ it 'should raise error on PUSH_PROMISE against bogus stream' do
51
+ expect do
52
+ @client << set_stream_id(f.generate(PUSH_PROMISE.dup), 31_415)
53
+ end.to raise_error(ProtocolError)
54
54
  end
55
55
 
56
- it "should raise error on PUSH_PROMISE against non-idle stream" do
57
- expect {
56
+ it 'should raise error on PUSH_PROMISE against non-idle stream' do
57
+ expect do
58
58
  s = @client.new_stream
59
59
  s.send HEADERS
60
60
 
61
61
  @client << set_stream_id(f.generate(PUSH_PROMISE), s.id)
62
62
  @client << set_stream_id(f.generate(PUSH_PROMISE), s.id)
63
- }.to raise_error(ProtocolError)
63
+ end.to raise_error(ProtocolError)
64
64
  end
65
65
 
66
- it "should emit stream object for received PUSH_PROMISE" do
66
+ it 'should emit stream object for received PUSH_PROMISE' do
67
67
  s = @client.new_stream
68
- s.send HEADERS
68
+ s.send HEADERS.deep_dup
69
69
 
70
70
  promise = nil
71
- @client.on(:promise) {|s| promise = s }
72
- @client << set_stream_id(f.generate(PUSH_PROMISE), s.id)
71
+ @client.on(:promise) { |stream| promise = stream }
72
+ @client << set_stream_id(f.generate(PUSH_PROMISE.dup), s.id)
73
73
 
74
- promise.id.should eq 2
75
- promise.state.should eq :reserved_remote
74
+ expect(promise.id).to eq 2
75
+ expect(promise.state).to eq :reserved_remote
76
76
  end
77
77
 
78
- it "should auto RST_STREAM promises against locally-RST stream" do
78
+ it 'should auto RST_STREAM promises against locally-RST stream' do
79
79
  s = @client.new_stream
80
- s.send HEADERS
80
+ s.send HEADERS.deep_dup
81
81
  s.close
82
82
 
83
- @client.stub(:send)
84
- @client.should_receive(:send) do |frame|
85
- frame[:type].should eq :rst_stream
86
- frame[:stream].should eq 2
83
+ allow(@client).to receive(:send)
84
+ expect(@client).to receive(:send) do |frame|
85
+ expect(frame[:type]).to eq :rst_stream
86
+ expect(frame[:stream]).to eq 2
87
87
  end
88
88
 
89
- @client << set_stream_id(f.generate(PUSH_PROMISE), s.id)
89
+ @client << set_stream_id(f.generate(PUSH_PROMISE.dup), s.id)
90
90
  end
91
91
  end
92
-
93
92
  end
@@ -1,246 +1,246 @@
1
- require "helper"
2
-
3
- describe HTTP2::Header do
1
+ require 'helper'
4
2
 
3
+ RSpec.describe HTTP2::Header do
5
4
  let(:c) { Compressor.new }
6
5
  let(:d) { Decompressor.new }
7
6
 
8
- context "literal representation" do
9
- context "integer" do
10
- it "should encode 10 using a 5-bit prefix" do
7
+ context 'literal representation' do
8
+ context 'integer' do
9
+ it 'should encode 10 using a 5-bit prefix' do
11
10
  buf = c.integer(10, 5)
12
- buf.should eq [10].pack('C')
13
- d.integer(Buffer.new(buf), 5).should eq 10
11
+ expect(buf).to eq [10].pack('C')
12
+ expect(d.integer(Buffer.new(buf), 5)).to eq 10
14
13
  end
15
14
 
16
- it "should encode 10 using a 0-bit prefix" do
15
+ it 'should encode 10 using a 0-bit prefix' do
17
16
  buf = c.integer(10, 0)
18
- buf.should eq [10].pack('C')
19
- d.integer(Buffer.new(buf), 0).should eq 10
17
+ expect(buf).to eq [10].pack('C')
18
+ expect(d.integer(Buffer.new(buf), 0)).to eq 10
20
19
  end
21
20
 
22
- it "should encode 1337 using a 5-bit prefix" do
21
+ it 'should encode 1337 using a 5-bit prefix' do
23
22
  buf = c.integer(1337, 5)
24
- buf.should eq [31,128+26,10].pack('C*')
25
- d.integer(Buffer.new(buf), 5).should eq 1337
23
+ expect(buf).to eq [31, 128 + 26, 10].pack('C*')
24
+ expect(d.integer(Buffer.new(buf), 5)).to eq 1337
26
25
  end
27
26
 
28
- it "should encode 1337 using a 0-bit prefix" do
29
- buf = c.integer(1337,0)
30
- buf.should eq [128+57,10].pack('C*')
31
- d.integer(Buffer.new(buf), 0).should eq 1337
27
+ it 'should encode 1337 using a 0-bit prefix' do
28
+ buf = c.integer(1337, 0)
29
+ expect(buf).to eq [128 + 57, 10].pack('C*')
30
+ expect(d.integer(Buffer.new(buf), 0)).to eq 1337
32
31
  end
33
32
  end
34
33
 
35
- context "string" do
36
- [ ['with huffman', :always, 0x80 ],
37
- ['without huffman', :never, 0] ].each do |desc, option, msb|
38
- let (:trailer) { "trailer" }
34
+ context 'string' do
35
+ [
36
+ ['with huffman', :always, 0x80],
37
+ ['without huffman', :never, 0],
38
+ ].each do |desc, option, msb|
39
+ let(:trailer) { 'trailer' }
39
40
 
40
41
  [
41
42
  ['ascii codepoints', 'abcdefghij'],
42
43
  ['utf-8 codepoints', 'éáűőúöüó€'],
43
- ['long utf-8 strings', 'éáűőúöüó€'*100],
44
+ ['long utf-8 strings', 'éáűőúöüó€' * 100],
44
45
  ].each do |datatype, plain|
45
46
  it "should handle #{datatype} #{desc}" do
46
47
  # NOTE: don't put this new in before{} because of test case shuffling
47
48
  @c = Compressor.new(huffman: option)
48
49
  str = @c.string(plain)
49
- (str.getbyte(0) & 0x80).should eq msb
50
+ expect(str.getbyte(0) & 0x80).to eq msb
50
51
 
51
52
  buf = Buffer.new(str + trailer)
52
- d.string(buf).should eq plain
53
- buf.should eq trailer
53
+ expect(d.string(buf)).to eq plain
54
+ expect(buf).to eq trailer
54
55
  end
55
56
  end
56
57
  end
57
- context "choosing shorter representation" do
58
- [ ['日本語', :plain],
59
- ['200', :huffman],
60
- ['xq', :plain], # prefer plain if equal size
58
+ context 'choosing shorter representation' do
59
+ [['日本語', :plain],
60
+ ['200', :huffman],
61
+ ['xq', :plain], # prefer plain if equal size
61
62
  ].each do |string, choice|
62
63
  before { @c = Compressor.new(huffman: :shorter) }
63
64
 
64
65
  it "should return #{choice} representation" do
65
66
  wire = @c.string(string)
66
- (wire.getbyte(0) & 0x80).should eq (choice == :plain ? 0 : 0x80)
67
+ expect(wire.getbyte(0) & 0x80).to eq(choice == :plain ? 0 : 0x80)
67
68
  end
68
69
  end
69
70
  end
70
71
  end
71
72
  end
72
73
 
73
- context "header representation" do
74
- it "should handle indexed representation" do
75
- h = {name: 10, type: :indexed}
74
+ context 'header representation' do
75
+ it 'should handle indexed representation' do
76
+ h = { name: 10, type: :indexed }
76
77
  wire = c.header(h)
77
- (wire.readbyte(0) & 0x80).should eq 0x80
78
- (wire.readbyte(0) & 0x7f).should eq h[:name] + 1
79
- d.header(wire).should eq h
78
+ expect(wire.readbyte(0) & 0x80).to eq 0x80
79
+ expect(wire.readbyte(0) & 0x7f).to eq h[:name] + 1
80
+ expect(d.header(wire)).to eq h
80
81
  end
81
- it "should raise when decoding indexed representation with index zero" do
82
- h = {name: 10, type: :indexed}
82
+ it 'should raise when decoding indexed representation with index zero' do
83
+ h = { name: 10, type: :indexed }
83
84
  wire = c.header(h)
84
- wire[0] = 0x80.chr('binary')
85
+ wire[0] = 0x80.chr(Encoding::BINARY)
85
86
  expect { d.header(wire) }.to raise_error CompressionError
86
87
  end
87
88
 
88
- context "literal w/o indexing representation" do
89
- it "should handle indexed header" do
90
- h = {name: 10, value: "my-value", type: :noindex}
89
+ context 'literal w/o indexing representation' do
90
+ it 'should handle indexed header' do
91
+ h = { name: 10, value: 'my-value', type: :noindex }
91
92
  wire = c.header(h)
92
- (wire.readbyte(0) & 0xf0).should eq 0x0
93
- (wire.readbyte(0) & 0x0f).should eq h[:name] + 1
94
- d.header(wire).should eq h
93
+ expect(wire.readbyte(0) & 0xf0).to eq 0x0
94
+ expect(wire.readbyte(0) & 0x0f).to eq h[:name] + 1
95
+ expect(d.header(wire)).to eq h
95
96
  end
96
97
 
97
- it "should handle literal header" do
98
- h = {name: "x-custom", value: "my-value", type: :noindex}
98
+ it 'should handle literal header' do
99
+ h = { name: 'x-custom', value: 'my-value', type: :noindex }
99
100
  wire = c.header(h)
100
- (wire.readbyte(0) & 0xf0).should eq 0x0
101
- (wire.readbyte(0) & 0x0f).should eq 0
102
- d.header(wire).should eq h
101
+ expect(wire.readbyte(0) & 0xf0).to eq 0x0
102
+ expect(wire.readbyte(0) & 0x0f).to eq 0
103
+ expect(d.header(wire)).to eq h
103
104
  end
104
105
  end
105
106
 
106
- context "literal w/ incremental indexing" do
107
- it "should handle indexed header" do
108
- h = {name: 10, value: "my-value", type: :incremental}
107
+ context 'literal w/ incremental indexing' do
108
+ it 'should handle indexed header' do
109
+ h = { name: 10, value: 'my-value', type: :incremental }
109
110
  wire = c.header(h)
110
- (wire.readbyte(0) & 0xc0).should eq 0x40
111
- (wire.readbyte(0) & 0x3f).should eq h[:name] + 1
112
- d.header(wire).should eq h
111
+ expect(wire.readbyte(0) & 0xc0).to eq 0x40
112
+ expect(wire.readbyte(0) & 0x3f).to eq h[:name] + 1
113
+ expect(d.header(wire)).to eq h
113
114
  end
114
115
 
115
- it "should handle literal header" do
116
- h = {name: "x-custom", value: "my-value", type: :incremental}
116
+ it 'should handle literal header' do
117
+ h = { name: 'x-custom', value: 'my-value', type: :incremental }
117
118
  wire = c.header(h)
118
- (wire.readbyte(0) & 0xc0).should eq 0x40
119
- (wire.readbyte(0) & 0x3f).should eq 0
120
- d.header(wire).should eq h
119
+ expect(wire.readbyte(0) & 0xc0).to eq 0x40
120
+ expect(wire.readbyte(0) & 0x3f).to eq 0
121
+ expect(d.header(wire)).to eq h
121
122
  end
122
123
  end
123
124
 
124
- context "literal never indexed" do
125
- it "should handle indexed header" do
126
- h = {name: 10, value: "my-value", type: :neverindexed}
125
+ context 'literal never indexed' do
126
+ it 'should handle indexed header' do
127
+ h = { name: 10, value: 'my-value', type: :neverindexed }
127
128
  wire = c.header(h)
128
- (wire.readbyte(0) & 0xf0).should eq 0x10
129
- (wire.readbyte(0) & 0x0f).should eq h[:name] + 1
130
- d.header(wire).should eq h
129
+ expect(wire.readbyte(0) & 0xf0).to eq 0x10
130
+ expect(wire.readbyte(0) & 0x0f).to eq h[:name] + 1
131
+ expect(d.header(wire)).to eq h
131
132
  end
132
133
 
133
- it "should handle literal header" do
134
- h = {name: "x-custom", value: "my-value", type: :neverindexed}
134
+ it 'should handle literal header' do
135
+ h = { name: 'x-custom', value: 'my-value', type: :neverindexed }
135
136
  wire = c.header(h)
136
- (wire.readbyte(0) & 0xf0).should eq 0x10
137
- (wire.readbyte(0) & 0x0f).should eq 0
138
- d.header(wire).should eq h
137
+ expect(wire.readbyte(0) & 0xf0).to eq 0x10
138
+ expect(wire.readbyte(0) & 0x0f).to eq 0
139
+ expect(d.header(wire)).to eq h
139
140
  end
140
141
  end
141
142
  end
142
143
 
143
- context "shared compression context" do
144
+ context 'shared compression context' do
144
145
  before(:each) { @cc = EncodingContext.new }
145
146
 
146
- it "should be initialized with empty headers" do
147
+ it 'should be initialized with empty headers' do
147
148
  cc = EncodingContext.new
148
- cc.table.should be_empty
149
+ expect(cc.table).to be_empty
149
150
  end
150
151
 
151
- context "processing" do
152
- [ ["no indexing", :noindex],
153
- ["never indexed", :neverindexed]].each do |desc, type|
152
+ context 'processing' do
153
+ [
154
+ ['no indexing', :noindex],
155
+ ['never indexed', :neverindexed],
156
+ ].each do |desc, type|
154
157
  context "#{desc}" do
155
- it "should process indexed header with literal value" do
158
+ it 'should process indexed header with literal value' do
156
159
  original_table = @cc.table.dup
157
160
 
158
- emit = @cc.process({name: 4, value: "/path", type: type})
159
- emit.should eq [":path", "/path"]
160
- @cc.table.should eq original_table
161
+ emit = @cc.process(name: 4, value: '/path', type: type)
162
+ expect(emit).to eq [':path', '/path']
163
+ expect(@cc.table).to eq original_table
161
164
  end
162
165
 
163
- it "should process literal header with literal value" do
166
+ it 'should process literal header with literal value' do
164
167
  original_table = @cc.table.dup
165
168
 
166
- emit = @cc.process({name: "x-custom", value: "random", type: type})
167
- emit.should eq ["x-custom", "random"]
168
- @cc.table.should eq original_table
169
+ emit = @cc.process(name: 'x-custom', value: 'random', type: type)
170
+ expect(emit).to eq ['x-custom', 'random']
171
+ expect(@cc.table).to eq original_table
169
172
  end
170
173
  end
171
174
  end
172
175
 
173
- context "incremental indexing" do
174
- it "should process indexed header with literal value" do
176
+ context 'incremental indexing' do
177
+ it 'should process indexed header with literal value' do
175
178
  original_table = @cc.table.dup
176
179
 
177
- emit = @cc.process({name: 4, value: "/path", type: :incremental})
178
- emit.should eq [":path", "/path"]
179
- (@cc.table - original_table).should eq [[":path", "/path"]]
180
+ emit = @cc.process(name: 4, value: '/path', type: :incremental)
181
+ expect(emit).to eq [':path', '/path']
182
+ expect(@cc.table - original_table).to eq [[':path', '/path']]
180
183
  end
181
184
 
182
- it "should process literal header with literal value" do
185
+ it 'should process literal header with literal value' do
183
186
  original_table = @cc.table.dup
184
187
 
185
- @cc.process({name: "x-custom", value: "random", type: :incremental})
186
- (@cc.table - original_table).should eq [["x-custom", "random"]]
188
+ @cc.process(name: 'x-custom', value: 'random', type: :incremental)
189
+ expect(@cc.table - original_table).to eq [['x-custom', 'random']]
187
190
  end
188
191
  end
189
192
 
190
- context "size bounds" do
191
- it "should drop headers from end of table" do
193
+ context 'size bounds' do
194
+ it 'should drop headers from end of table' do
192
195
  cc = EncodingContext.new(table_size: 2048)
193
196
  cc.instance_eval do
194
- add_to_table(["test1", "1" * 1024])
195
- add_to_table(["test2", "2" * 500])
197
+ add_to_table(['test1', '1' * 1024])
198
+ add_to_table(['test2', '2' * 500])
196
199
  end
197
200
 
198
201
  original_table = cc.table.dup
199
- original_size = original_table.join.bytesize +
200
- original_table.size * 32
202
+ original_size = original_table.join.bytesize + original_table.size * 32
201
203
 
202
- cc.process({
203
- name: "x-custom",
204
- value: "a" * (2048 - original_size),
205
- type: :incremental
206
- })
204
+ cc.process(name: 'x-custom',
205
+ value: 'a' * (2048 - original_size),
206
+ type: :incremental)
207
207
 
208
- cc.table.first[0].should eq "x-custom"
209
- cc.table.size.should eq original_table.size # number of entries
208
+ expect(cc.table.first[0]).to eq 'x-custom'
209
+ expect(cc.table.size).to eq original_table.size # number of entries
210
210
  end
211
211
  end
212
212
 
213
- it "should clear table if entry exceeds table size" do
213
+ it 'should clear table if entry exceeds table size' do
214
214
  cc = EncodingContext.new(table_size: 2048)
215
215
  cc.instance_eval do
216
- add_to_table(["test1", "1" * 1024])
217
- add_to_table(["test2", "2" * 500])
216
+ add_to_table(['test1', '1' * 1024])
217
+ add_to_table(['test2', '2' * 500])
218
218
  end
219
219
 
220
- h = { name: "x-custom", value: "a", index: 0, type: :incremental }
221
- e = { name: "large", value: "a" * 2048, index: 0}
220
+ h = { name: 'x-custom', value: 'a', index: 0, type: :incremental }
221
+ e = { name: 'large', value: 'a' * 2048, index: 0 }
222
222
 
223
223
  cc.process(h)
224
- cc.process(e.merge({type: :incremental}))
225
- cc.table.should be_empty
224
+ cc.process(e.merge(type: :incremental))
225
+ expect(cc.table).to be_empty
226
226
  end
227
227
 
228
- it "should shrink table if set smaller size" do
228
+ it 'should shrink table if set smaller size' do
229
229
  cc = EncodingContext.new(table_size: 2048)
230
230
  cc.instance_eval do
231
- add_to_table(["test1", "1" * 1024])
232
- add_to_table(["test2", "2" * 500])
231
+ add_to_table(['test1', '1' * 1024])
232
+ add_to_table(['test2', '2' * 500])
233
233
  end
234
234
 
235
- cc.process({type: :changetablesize, value: 1500})
236
- cc.table.size.should be 1
237
- cc.table.first[0].should eq 'test2'
235
+ cc.process(type: :changetablesize, value: 1500)
236
+ expect(cc.table.size).to be 1
237
+ expect(cc.table.first[0]).to eq 'test2'
238
238
  end
239
239
  end
240
240
  end
241
241
 
242
242
  spec_examples = [
243
- { title: "D.3. Request Examples without Huffman",
243
+ { title: 'D.3. Request Examples without Huffman',
244
244
  type: :request,
245
245
  table_size: 4096,
246
246
  huffman: :never,
@@ -248,98 +248,98 @@ describe HTTP2::Header do
248
248
  { wire: "8286 8441 0f77 7777 2e65 7861 6d70 6c65
249
249
  2e63 6f6d",
250
250
  emitted: [
251
- [":method", "GET"],
252
- [":scheme", "http"],
253
- [":path", "/"],
254
- [":authority", "www.example.com"],
251
+ [':method', 'GET'],
252
+ [':scheme', 'http'],
253
+ [':path', '/'],
254
+ [':authority', 'www.example.com'],
255
255
  ],
256
256
  table: [
257
- [":authority", "www.example.com"],
257
+ [':authority', 'www.example.com'],
258
258
  ],
259
259
  table_size: 57,
260
260
  },
261
- { wire: "8286 84be 5808 6e6f 2d63 6163 6865",
261
+ { wire: '8286 84be 5808 6e6f 2d63 6163 6865',
262
262
  emitted: [
263
- [":method", "GET"],
264
- [":scheme", "http"],
265
- [":path", "/"],
266
- [":authority", "www.example.com"],
267
- ["cache-control", "no-cache"],
263
+ [':method', 'GET'],
264
+ [':scheme', 'http'],
265
+ [':path', '/'],
266
+ [':authority', 'www.example.com'],
267
+ ['cache-control', 'no-cache'],
268
268
  ],
269
269
  table: [
270
- ["cache-control", "no-cache"],
271
- [":authority", "www.example.com"],
270
+ ['cache-control', 'no-cache'],
271
+ [':authority', 'www.example.com'],
272
272
  ],
273
273
  table_size: 110,
274
274
  },
275
275
  { wire: "8287 85bf 400a 6375 7374 6f6d 2d6b 6579
276
276
  0c63 7573 746f 6d2d 7661 6c75 65",
277
277
  emitted: [
278
- [":method", "GET"],
279
- [":scheme", "https"],
280
- [":path", "/index.html"],
281
- [":authority", "www.example.com"],
282
- ["custom-key", "custom-value"],
278
+ [':method', 'GET'],
279
+ [':scheme', 'https'],
280
+ [':path', '/index.html'],
281
+ [':authority', 'www.example.com'],
282
+ ['custom-key', 'custom-value'],
283
283
  ],
284
284
  table: [
285
- ["custom-key", "custom-value"],
286
- ["cache-control", "no-cache"],
287
- [":authority", "www.example.com"],
285
+ ['custom-key', 'custom-value'],
286
+ ['cache-control', 'no-cache'],
287
+ [':authority', 'www.example.com'],
288
288
  ],
289
289
  table_size: 164,
290
- }
290
+ },
291
291
  ],
292
292
  },
293
- { title: "D.4. Request Examples with Huffman",
293
+ { title: 'D.4. Request Examples with Huffman',
294
294
  type: :request,
295
295
  table_size: 4096,
296
296
  huffman: :always,
297
297
  streams: [
298
- { wire: "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff",
298
+ { wire: '8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff',
299
299
  emitted: [
300
- [":method", "GET"],
301
- [":scheme", "http"],
302
- [":path", "/"],
303
- [":authority", "www.example.com"],
300
+ [':method', 'GET'],
301
+ [':scheme', 'http'],
302
+ [':path', '/'],
303
+ [':authority', 'www.example.com'],
304
304
  ],
305
305
  table: [
306
- [":authority", "www.example.com"],
306
+ [':authority', 'www.example.com'],
307
307
  ],
308
308
  table_size: 57,
309
309
  },
310
- { wire: "8286 84be 5886 a8eb 1064 9cbf",
310
+ { wire: '8286 84be 5886 a8eb 1064 9cbf',
311
311
  emitted: [
312
- [":method", "GET"],
313
- [":scheme", "http"],
314
- [":path", "/"],
315
- [":authority", "www.example.com"],
316
- ["cache-control", "no-cache"],
312
+ [':method', 'GET'],
313
+ [':scheme', 'http'],
314
+ [':path', '/'],
315
+ [':authority', 'www.example.com'],
316
+ ['cache-control', 'no-cache'],
317
317
  ],
318
318
  table: [
319
- ["cache-control", "no-cache"],
320
- [":authority", "www.example.com"],
319
+ ['cache-control', 'no-cache'],
320
+ [':authority', 'www.example.com'],
321
321
  ],
322
322
  table_size: 110,
323
323
  },
324
324
  { wire: "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925
325
325
  a849 e95b b8e8 b4bf",
326
326
  emitted: [
327
- [":method", "GET"],
328
- [":scheme", "https"],
329
- [":path", "/index.html"],
330
- [":authority", "www.example.com"],
331
- ["custom-key", "custom-value"],
327
+ [':method', 'GET'],
328
+ [':scheme', 'https'],
329
+ [':path', '/index.html'],
330
+ [':authority', 'www.example.com'],
331
+ ['custom-key', 'custom-value'],
332
332
  ],
333
333
  table: [
334
- ["custom-key", "custom-value"],
335
- ["cache-control", "no-cache"],
336
- [":authority", "www.example.com"],
334
+ ['custom-key', 'custom-value'],
335
+ ['cache-control', 'no-cache'],
336
+ [':authority', 'www.example.com'],
337
337
  ],
338
338
  table_size: 164,
339
339
  },
340
340
  ],
341
341
  },
342
- { title: "D.5. Response Examples without Huffman",
342
+ { title: 'D.5. Response Examples without Huffman',
343
343
  type: :response,
344
344
  table_size: 256,
345
345
  huffman: :never,
@@ -350,31 +350,31 @@ describe HTTP2::Header do
350
350
  7474 7073 3a2f 2f77 7777 2e65 7861 6d70
351
351
  6c65 2e63 6f6d",
352
352
  emitted: [
353
- [":status", "302"],
354
- ["cache-control", "private"],
355
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
356
- ["location", "https://www.example.com"],
353
+ [':status', '302'],
354
+ ['cache-control', 'private'],
355
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
356
+ ['location', 'https://www.example.com'],
357
357
  ],
358
358
  table: [
359
- ["location", "https://www.example.com"],
360
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
361
- ["cache-control", "private"],
362
- [":status", "302"],
359
+ ['location', 'https://www.example.com'],
360
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
361
+ ['cache-control', 'private'],
362
+ [':status', '302'],
363
363
  ],
364
364
  table_size: 222,
365
365
  },
366
- { wire: "4803 3330 37c1 c0bf",
366
+ { wire: '4803 3330 37c1 c0bf',
367
367
  emitted: [
368
- [":status", "307"],
369
- ["cache-control", "private"],
370
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
371
- ["location", "https://www.example.com"],
368
+ [':status', '307'],
369
+ ['cache-control', 'private'],
370
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
371
+ ['location', 'https://www.example.com'],
372
372
  ],
373
373
  table: [
374
- [":status", "307"],
375
- ["location", "https://www.example.com"],
376
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
377
- ["cache-control", "private"],
374
+ [':status', '307'],
375
+ ['location', 'https://www.example.com'],
376
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
377
+ ['cache-control', 'private'],
378
378
  ],
379
379
  table_size: 222,
380
380
  },
@@ -386,23 +386,23 @@ describe HTTP2::Header do
386
386
  6765 3d33 3630 303b 2076 6572 7369 6f6e
387
387
  3d31",
388
388
  emitted: [
389
- [":status", "200"],
390
- ["cache-control", "private"],
391
- ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
392
- ["location", "https://www.example.com"],
393
- ["content-encoding", "gzip"],
394
- ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"],
389
+ [':status', '200'],
390
+ ['cache-control', 'private'],
391
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
392
+ ['location', 'https://www.example.com'],
393
+ ['content-encoding', 'gzip'],
394
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'],
395
395
  ],
396
396
  table: [
397
- ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"],
398
- ["content-encoding", "gzip"],
399
- ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
397
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'],
398
+ ['content-encoding', 'gzip'],
399
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
400
400
  ],
401
401
  table_size: 215,
402
402
  },
403
403
  ],
404
404
  },
405
- { title: "D.6. Response Examples with Huffman",
405
+ { title: 'D.6. Response Examples with Huffman',
406
406
  type: :response,
407
407
  table_size: 256,
408
408
  huffman: :always,
@@ -412,31 +412,31 @@ describe HTTP2::Header do
412
412
  2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
413
413
  e9ae 82ae 43d3",
414
414
  emitted: [
415
- [":status", "302"],
416
- ["cache-control", "private"],
417
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
418
- ["location", "https://www.example.com"],
415
+ [':status', '302'],
416
+ ['cache-control', 'private'],
417
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
418
+ ['location', 'https://www.example.com'],
419
419
  ],
420
420
  table: [
421
- ["location", "https://www.example.com"],
422
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
423
- ["cache-control", "private"],
424
- [":status", "302"],
421
+ ['location', 'https://www.example.com'],
422
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
423
+ ['cache-control', 'private'],
424
+ [':status', '302'],
425
425
  ],
426
426
  table_size: 222,
427
427
  },
428
- { wire: "4883 640e ffc1 c0bf",
428
+ { wire: '4883 640e ffc1 c0bf',
429
429
  emitted: [
430
- [":status", "307"],
431
- ["cache-control", "private"],
432
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
433
- ["location", "https://www.example.com"],
430
+ [':status', '307'],
431
+ ['cache-control', 'private'],
432
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
433
+ ['location', 'https://www.example.com'],
434
434
  ],
435
435
  table: [
436
- [":status", "307"],
437
- ["location", "https://www.example.com"],
438
- ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
439
- ["cache-control", "private"],
436
+ [':status', '307'],
437
+ ['location', 'https://www.example.com'],
438
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
439
+ ['cache-control', 'private'],
440
440
  ],
441
441
  table_size: 222,
442
442
  },
@@ -446,17 +446,17 @@ describe HTTP2::Header do
446
446
  3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
447
447
  9587 3160 65c0 03ed 4ee5 b106 3d50 07",
448
448
  emitted: [
449
- [":status", "200"],
450
- ["cache-control", "private"],
451
- ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
452
- ["location", "https://www.example.com"],
453
- ["content-encoding", "gzip"],
454
- ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"],
449
+ [':status', '200'],
450
+ ['cache-control', 'private'],
451
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
452
+ ['location', 'https://www.example.com'],
453
+ ['content-encoding', 'gzip'],
454
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'],
455
455
  ],
456
456
  table: [
457
- ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"],
458
- ["content-encoding", "gzip"],
459
- ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
457
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'],
458
+ ['content-encoding', 'gzip'],
459
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
460
460
  ],
461
461
  table_size: 215,
462
462
  },
@@ -464,34 +464,34 @@ describe HTTP2::Header do
464
464
  },
465
465
  ]
466
466
 
467
- context "decode" do
467
+ context 'decode' do
468
468
  spec_examples.each do |ex|
469
469
  context "spec example #{ex[:title]}" do
470
470
  ex[:streams].size.times do |nth|
471
- context "request #{nth+1}" do
471
+ context "request #{nth + 1}" do
472
472
  before { @dc = Decompressor.new(table_size: ex[:table_size]) }
473
473
  before do
474
474
  (0...nth).each do |i|
475
- bytes = [ex[:streams][i][:wire].delete(" \n")].pack("H*")
475
+ bytes = [ex[:streams][i][:wire].delete(" \n")].pack('H*')
476
476
  @dc.decode(HTTP2::Buffer.new(bytes))
477
477
  end
478
478
  end
479
479
  subject do
480
- bytes = [ex[:streams][nth][:wire].delete(" \n")].pack("H*")
480
+ bytes = [ex[:streams][nth][:wire].delete(" \n")].pack('H*')
481
481
  @emitted = @dc.decode(HTTP2::Buffer.new(bytes))
482
482
  end
483
- it "should emit expected headers" do
483
+ it 'should emit expected headers' do
484
484
  subject
485
485
  # order-perserving compare
486
- @emitted.should eq ex[:streams][nth][:emitted]
486
+ expect(@emitted).to eq ex[:streams][nth][:emitted]
487
487
  end
488
- it "should update header table" do
488
+ it 'should update header table' do
489
489
  subject
490
- @dc.instance_eval{@cc.table}.should eq ex[:streams][nth][:table]
490
+ expect(@dc.instance_eval { @cc.table }).to eq ex[:streams][nth][:table]
491
491
  end
492
- it "should compute header table size" do
492
+ it 'should compute header table size' do
493
493
  subject
494
- @dc.instance_eval{@cc.current_table_size}.should eq ex[:streams][nth][:table_size]
494
+ expect(@dc.instance_eval { @cc.current_table_size }).to eq ex[:streams][nth][:table_size]
495
495
  end
496
496
  end
497
497
  end
@@ -499,13 +499,15 @@ describe HTTP2::Header do
499
499
  end
500
500
  end
501
501
 
502
- context "encode" do
502
+ context 'encode' do
503
503
  spec_examples.each do |ex|
504
504
  context "spec example #{ex[:title]}" do
505
505
  ex[:streams].size.times do |nth|
506
- context "request #{nth+1}" do
507
- before { @cc = Compressor.new(table_size: ex[:table_size],
508
- huffman: ex[:huffman]) }
506
+ context "request #{nth + 1}" do
507
+ before do
508
+ @cc = Compressor.new(table_size: ex[:table_size],
509
+ huffman: ex[:huffman])
510
+ end
509
511
  before do
510
512
  (0...nth).each do |i|
511
513
  @cc.encode(ex[:streams][i][:emitted])
@@ -514,21 +516,20 @@ describe HTTP2::Header do
514
516
  subject do
515
517
  @cc.encode(ex[:streams][nth][:emitted])
516
518
  end
517
- it "should emit expected bytes on wire" do
518
- subject.unpack("H*").first.should eq ex[:streams][nth][:wire].delete(" \n")
519
+ it 'should emit expected bytes on wire' do
520
+ expect(subject.unpack('H*').first).to eq ex[:streams][nth][:wire].delete(" \n")
519
521
  end
520
- it "should update header table" do
522
+ it 'should update header table' do
521
523
  subject
522
- @cc.instance_eval{@cc.table}.should eq ex[:streams][nth][:table]
524
+ expect(@cc.instance_eval { @cc.table }).to eq ex[:streams][nth][:table]
523
525
  end
524
- it "should compute header table size" do
526
+ it 'should compute header table size' do
525
527
  subject
526
- @cc.instance_eval{@cc.current_table_size}.should eq ex[:streams][nth][:table_size]
528
+ expect(@cc.instance_eval { @cc.current_table_size }).to eq ex[:streams][nth][:table_size]
527
529
  end
528
530
  end
529
531
  end
530
532
  end
531
533
  end
532
534
  end
533
-
534
535
  end