Skip to content

Commit e82d8e1

Browse files
committed
Ensure we *always* send a dynamic table resize command
Closer reading of RFC9113§4.3.1para¶4 (https://www.rfc-editor.org/rfc/rfc9113.html#section-4.3.1) suggests that we should always send a dynamic resize Fixes #20
1 parent 6d034a1 commit e82d8e1

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

lib/hpax/table.ex

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -264,24 +264,22 @@ defmodule HPAX.Table do
264264
In all cases, the table's `:protocol_max_table_size` is updated accordingly
265265
"""
266266
@spec resize(t(), non_neg_integer()) :: t()
267-
def resize(%__MODULE__{max_table_size: max_table_size} = table, new_protocol_max_table_size)
268-
when new_protocol_max_table_size >= max_table_size do
269-
%__MODULE__{
270-
table
271-
| protocol_max_table_size: new_protocol_max_table_size,
272-
max_table_size: new_protocol_max_table_size
273-
}
274-
end
275-
276267
def resize(%__MODULE__{} = table, new_protocol_max_table_size) do
277268
pending_minimum_resize =
278269
case table.pending_minimum_resize do
279270
nil -> new_protocol_max_table_size
280271
current -> min(current, new_protocol_max_table_size)
281272
end
282273

274+
table =
275+
if new_protocol_max_table_size < table.size do
276+
evict_to_size(table, new_protocol_max_table_size)
277+
else
278+
table
279+
end
280+
283281
%__MODULE__{
284-
evict_to_size(table, new_protocol_max_table_size)
282+
table
285283
| protocol_max_table_size: new_protocol_max_table_size,
286284
max_table_size: new_protocol_max_table_size,
287285
pending_minimum_resize: pending_minimum_resize

test/hpax_test.exs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ defmodule HPAXTest do
109109

110110
property "encode/3 prepends dynamic resizes at the start of a block" do
111111
enc_table = HPAX.new(20_000)
112-
# Start with a non-empty decode table
113112
dec_table = HPAX.new(20_000)
114113

115114
# Put a record in both to prime the pump. The table sizes should match
@@ -120,14 +119,45 @@ defmodule HPAXTest do
120119
assert enc_table.max_table_size == 20_000
121120
assert dec_table.max_table_size == 20_000
122121

123-
# Encode a record after resizing the table. We expect a dynamic resize to be
124-
# encoded and the for two table sizes to be identical after decoding
122+
# Scenario 1: Simulate the decoder growing the table via settings
123+
124+
# First, the decoder resizes its table to some maximum size
125+
dec_table = HPAX.resize(dec_table, 40_000)
126+
127+
# It then communicates that size to the encoder, who chooses a smaller size
128+
enc_table = HPAX.resize(enc_table, 30_000)
129+
130+
# Now, encode a header
131+
{encoded, enc_table} = HPAX.encode([{:store, "lame", "LAME"}], enc_table)
132+
encoded = IO.iodata_to_binary(encoded)
133+
134+
# Ensure that we encoded a resize on the wire
135+
assert <<0b001::3, rest::bitstring>> = encoded
136+
assert {:ok, 30_000, _rest} = HPAX.Types.decode_integer(rest, 5)
137+
138+
# Finally, ensure that the decoder makes proper sense of this encoding and that it resizes
139+
# back down to the size chosen by the encoder
140+
assert {:ok, _decoded, dec_table} = HPAX.decode(encoded, dec_table)
141+
assert dec_table.size == enc_table.size
142+
assert enc_table.max_table_size == 30_000
143+
assert dec_table.max_table_size == 30_000
144+
145+
# Scenario 2: Simulate the decoder shrinking the table ia settings
146+
147+
# First, the decoder resizes its table to some maximum size
148+
dec_table = HPAX.resize(dec_table, 10_000)
149+
150+
# It then communicates that size to the encoder, who chooses a smaller size
125151
enc_table = HPAX.resize(enc_table, 0)
152+
153+
# It then changes its mind and goes back up to a size still smaller than the decoder's choice
126154
enc_table = HPAX.resize(enc_table, 1234)
155+
156+
# Now, encode a header
127157
{encoded, enc_table} = HPAX.encode([{:store, "lame", "LAME"}], enc_table)
128158
encoded = IO.iodata_to_binary(encoded)
129159

130-
# Ensure that we see two resizes in order
160+
# Ensure that we encoded two resizes in order on the wire
131161
assert <<0b001::3, rest::bitstring>> = encoded
132162
assert {:ok, 0, rest} = HPAX.Types.decode_integer(rest, 5)
133163
assert <<0b001::3, rest::bitstring>> = rest

0 commit comments

Comments
 (0)