protocol-hpack 1.1.0 → 1.2.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.
- checksums.yaml +4 -4
- data/.gitmodules +2 -2
- data/lib/protocol/hpack/compressor.rb +2 -2
- data/lib/protocol/hpack/context.rb +44 -54
- data/lib/protocol/hpack/decompressor.rb +11 -4
- data/lib/protocol/hpack/huffman.rb +2 -2
- data/lib/protocol/hpack/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4f37a74f63435d104e330527a394230a528ac8e1739c0ec6dcab1e0d40ba2fa
|
4
|
+
data.tar.gz: 15e11514d7bf7dc987577272e73114ac0179c750f065ddde4eceb8b10f19e46a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c6cf113a2141feb408615117dfed35d13a61a297f47bd4cfd2bcc63d42b38c21f875ef1dc99a0542035a17b7cd630c05fb6fb885b9294f8dc46533efb5bb48d
|
7
|
+
data.tar.gz: d7f96e39202967a77c73a39a4ca65e582676e8b533f990e3bd02062e1fe279387d663918247aa4baf3a50ea3da42099068783359e2b0a21ed1bd94e08909a18b
|
data/.gitmodules
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
[submodule "spec/
|
2
|
-
path = spec/
|
1
|
+
[submodule "spec/protocol/hpack/fixtures"]
|
2
|
+
path = spec/protocol/hpack/fixtures
|
3
3
|
url = https://github.com/http2jp/hpack-test-case.git
|
@@ -100,7 +100,7 @@ module Protocol
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def huffman
|
103
|
-
@context.
|
103
|
+
@context.huffman
|
104
104
|
end
|
105
105
|
|
106
106
|
# Encodes provided value via string literal representation.
|
@@ -158,7 +158,7 @@ module Protocol
|
|
158
158
|
case command[:type]
|
159
159
|
when :indexed
|
160
160
|
write_integer(command[:name] + 1, representation[:prefix])
|
161
|
-
when :
|
161
|
+
when :change_table_size
|
162
162
|
write_integer(command[:value], representation[:prefix])
|
163
163
|
else
|
164
164
|
if command[:name].is_a? Integer
|
@@ -31,9 +31,9 @@ module Protocol
|
|
31
31
|
HEADER_REPRESENTATION = {
|
32
32
|
indexed: {prefix: 7, pattern: 0x80},
|
33
33
|
incremental: {prefix: 6, pattern: 0x40},
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
no_index: {prefix: 4, pattern: 0x00},
|
35
|
+
never_indexed: {prefix: 4, pattern: 0x10},
|
36
|
+
change_table_size: {prefix: 5, pattern: 0x20},
|
37
37
|
}
|
38
38
|
|
39
39
|
# To decompress header blocks, a decoder only needs to maintain a
|
@@ -105,48 +105,38 @@ module Protocol
|
|
105
105
|
['vary', ''],
|
106
106
|
['via', ''],
|
107
107
|
['www-authenticate', ''],
|
108
|
-
|
109
|
-
|
110
|
-
#
|
111
|
-
attr_reader :table
|
112
|
-
|
113
|
-
# Current encoding options
|
114
|
-
#
|
115
|
-
# :table_size Integer maximum dynamic table size in bytes
|
116
|
-
# :huffman Symbol :always, :never, :shorter
|
117
|
-
# :index Symbol :all, :static, :never
|
118
|
-
attr_reader :options
|
119
|
-
|
120
|
-
# Initializes compression context with appropriate client/server
|
121
|
-
# defaults and maximum size of the dynamic table.
|
108
|
+
].each {|pair| pair.each(&:freeze).freeze}.freeze
|
109
|
+
|
110
|
+
# Initializes compression context with appropriate client/server defaults and maximum size of the dynamic table.
|
122
111
|
#
|
123
|
-
# @param
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
def initialize(
|
128
|
-
|
129
|
-
|
130
|
-
index: :all,
|
131
|
-
table_size: 4096,
|
132
|
-
}
|
112
|
+
# @param table [Array] Table of header key-value pairs.
|
113
|
+
# @option huffman [Symbol] One of `:always`, `:never`, `:shorter`. Controls use of compression.
|
114
|
+
# @option index [Symbol] One of `:all`, `:static`, `:never`. Controls use of static/dynamic tables.
|
115
|
+
# @option table_size [Integer] The current maximum dynamic table size.
|
116
|
+
def initialize(table = nil, huffman: :shorter, index: :all, table_size: 4096)
|
117
|
+
@huffman = huffman
|
118
|
+
@index = index
|
133
119
|
|
134
|
-
@
|
135
|
-
@options = default_options.merge(options)
|
136
|
-
@limit = @options[:table_size]
|
137
|
-
end
|
138
|
-
|
139
|
-
# Duplicates current compression context
|
140
|
-
# @return [Context]
|
141
|
-
def dup
|
142
|
-
other = Context.new(@options)
|
120
|
+
@table_size = table_size
|
143
121
|
|
144
|
-
|
145
|
-
|
122
|
+
@table = (table&.dup) || []
|
123
|
+
end
|
124
|
+
|
125
|
+
def initialize_copy(other)
|
126
|
+
super
|
146
127
|
|
147
|
-
|
128
|
+
# This is the only mutable state:
|
129
|
+
@table = @table.dup
|
148
130
|
end
|
149
|
-
|
131
|
+
|
132
|
+
# Current table of header key-value pairs.
|
133
|
+
attr :table
|
134
|
+
|
135
|
+
attr :huffman
|
136
|
+
attr :index
|
137
|
+
|
138
|
+
attr :table_size
|
139
|
+
|
150
140
|
# Finds an entry in current dynamic table by index.
|
151
141
|
# Note that index is zero-based in this module.
|
152
142
|
#
|
@@ -175,7 +165,7 @@ module Protocol
|
|
175
165
|
emit = nil
|
176
166
|
|
177
167
|
case command[:type]
|
178
|
-
when :
|
168
|
+
when :change_table_size
|
179
169
|
self.table_size = command[:value]
|
180
170
|
|
181
171
|
when :indexed
|
@@ -189,7 +179,7 @@ module Protocol
|
|
189
179
|
k, v = dereference(idx)
|
190
180
|
emit = [k, v]
|
191
181
|
|
192
|
-
when :incremental, :
|
182
|
+
when :incremental, :no_index, :never_indexed
|
193
183
|
# A _literal representation_ that is _not added_ to the dynamic table
|
194
184
|
# entails the following action:
|
195
185
|
# o The header field is added to the decoded header list.
|
@@ -219,7 +209,7 @@ module Protocol
|
|
219
209
|
return emit
|
220
210
|
end
|
221
211
|
|
222
|
-
# Plan header compression according to +@
|
212
|
+
# Plan header compression according to +@index+
|
223
213
|
# :never Do not use dynamic table or static table reference at all.
|
224
214
|
# :static Use static table only.
|
225
215
|
# :all Use all of them.
|
@@ -229,12 +219,12 @@ module Protocol
|
|
229
219
|
def encode(headers)
|
230
220
|
commands = []
|
231
221
|
|
232
|
-
# Literals commands are marked with :
|
233
|
-
|
222
|
+
# Literals commands are marked with :no_index when index is not used
|
223
|
+
no_index = [:static, :never].include?(@index)
|
234
224
|
|
235
225
|
headers.each do |field, value|
|
236
226
|
command = add_command(field, value)
|
237
|
-
command[:type] = :
|
227
|
+
command[:type] = :no_index if no_index && command[:type] == :incremental
|
238
228
|
commands << command
|
239
229
|
|
240
230
|
decode(command)
|
@@ -247,7 +237,7 @@ module Protocol
|
|
247
237
|
# Prefer static table over dynamic table.
|
248
238
|
# Prefer exact match over name-only match.
|
249
239
|
#
|
250
|
-
# +@
|
240
|
+
# +@index+ controls whether to use the dynamic table,
|
251
241
|
# static table, or both.
|
252
242
|
# :never Do not use dynamic table or static table reference at all.
|
253
243
|
# :static Use static table only.
|
@@ -259,7 +249,7 @@ module Protocol
|
|
259
249
|
exact = nil
|
260
250
|
name_only = nil
|
261
251
|
|
262
|
-
if [:all, :static].include?(@
|
252
|
+
if [:all, :static].include?(@index)
|
263
253
|
STATIC_TABLE.each_index do |i|
|
264
254
|
if STATIC_TABLE[i] == header
|
265
255
|
exact ||= i
|
@@ -269,7 +259,7 @@ module Protocol
|
|
269
259
|
end
|
270
260
|
end
|
271
261
|
end
|
272
|
-
if [:all].include?(@
|
262
|
+
if [:all].include?(@index) && !exact
|
273
263
|
@table.each_index do |i|
|
274
264
|
if @table[i] == header
|
275
265
|
exact ||= i + STATIC_TABLE.size
|
@@ -291,8 +281,8 @@ module Protocol
|
|
291
281
|
|
292
282
|
# Alter dynamic table size.
|
293
283
|
# When the size is reduced, some headers might be evicted.
|
294
|
-
def table_size=
|
295
|
-
@
|
284
|
+
def table_size= size
|
285
|
+
@table_size = size
|
296
286
|
size_check(nil)
|
297
287
|
end
|
298
288
|
|
@@ -314,7 +304,7 @@ module Protocol
|
|
314
304
|
@table.unshift(command)
|
315
305
|
end
|
316
306
|
|
317
|
-
# To keep the dynamic table size lower than or equal to @
|
307
|
+
# To keep the dynamic table size lower than or equal to @table_size,
|
318
308
|
# remove one or more entries at the end of the dynamic table.
|
319
309
|
#
|
320
310
|
# @param command [Hash]
|
@@ -323,14 +313,14 @@ module Protocol
|
|
323
313
|
cursize = current_table_size
|
324
314
|
cmdsize = command.nil? ? 0 : command[0].bytesize + command[1].bytesize + 32
|
325
315
|
|
326
|
-
while cursize + cmdsize > @
|
316
|
+
while cursize + cmdsize > @table_size
|
327
317
|
break if @table.empty?
|
328
318
|
|
329
319
|
e = @table.pop
|
330
320
|
cursize -= e[0].bytesize + e[1].bytesize + 32
|
331
321
|
end
|
332
322
|
|
333
|
-
cmdsize <= @
|
323
|
+
cmdsize <= @table_size
|
334
324
|
end
|
335
325
|
end
|
336
326
|
end
|
@@ -28,16 +28,20 @@ module Protocol
|
|
28
28
|
# context of the opposing peer. Decompressor must be initialized with
|
29
29
|
# appropriate starting context based on local role: client or server.
|
30
30
|
class Decompressor
|
31
|
-
def initialize(buffer, context = Context.new)
|
31
|
+
def initialize(buffer, context = Context.new, table_size_limit: nil)
|
32
32
|
@buffer = buffer
|
33
33
|
@context = context
|
34
34
|
@offset = 0
|
35
|
+
|
36
|
+
@table_size_limit = table_size_limit
|
35
37
|
end
|
36
38
|
|
37
39
|
attr :buffer
|
38
40
|
attr :context
|
39
41
|
attr :offset
|
40
|
-
|
42
|
+
|
43
|
+
attr :table_size_limit
|
44
|
+
|
41
45
|
def end?
|
42
46
|
@offset >= @buffer.bytesize
|
43
47
|
end
|
@@ -50,7 +54,6 @@ module Protocol
|
|
50
54
|
return byte
|
51
55
|
end
|
52
56
|
|
53
|
-
|
54
57
|
def peek_byte
|
55
58
|
@buffer.getbyte(@offset)
|
56
59
|
end
|
@@ -121,8 +124,12 @@ module Protocol
|
|
121
124
|
when :indexed
|
122
125
|
raise CompressionError if header[:name].zero?
|
123
126
|
header[:name] -= 1
|
124
|
-
when :
|
127
|
+
when :change_table_size
|
125
128
|
header[:value] = header[:name]
|
129
|
+
|
130
|
+
if @table_size_limit and header[:value] > @table_size_limit
|
131
|
+
raise CompressionError, "Table size #{header[:value]} exceeds limit #{@table_size_limit}!"
|
132
|
+
end
|
126
133
|
else
|
127
134
|
if (header[:name]).zero?
|
128
135
|
header[:name] = read_string
|
@@ -333,8 +333,8 @@ module Protocol
|
|
333
333
|
[0x7fffff0, 27],
|
334
334
|
[0x3ffffee, 26],
|
335
335
|
[0x3fffffff, 30],
|
336
|
-
|
337
|
-
|
336
|
+
].each(&:freeze).freeze
|
337
|
+
|
338
338
|
ENCODE_TABLE = CODES.map {|c, l| [c].pack('N').unpack('B*').first[-l..-1]}.each(&:freeze).freeze
|
339
339
|
end
|
340
340
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protocol-hpack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: covered
|