http-2 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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