Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 17 additions & 26 deletions lib/mint/http2.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2210,19 +2210,15 @@ defmodule Mint.HTTP2 do
# 32 bytes per field. The compressed block is bounded while it is accumulated,
# but indexed fields decode to far more bytes than they take on the wire.
defp header_list_size_error(conn, headers) do
case conn.client_settings.max_header_list_size do
:infinity ->
nil

max_size ->
# TODO: replace with Enum.sum_by when we depend on 1.18+
size =
Enum.reduce(headers, 0, fn {name, value}, acc ->
acc + byte_size(name) + byte_size(value) + 32
end)
max_size = conn.client_settings.max_header_list_size

if size > max_size, do: {:max_header_list_size_exceeded, size, max_size}
end
# TODO: replace with Enum.sum_by when we depend on 1.18+
size =
Enum.reduce(headers, 0, fn {name, value}, acc ->
acc + byte_size(name) + byte_size(value) + 32
end)

if size > max_size, do: {:max_header_list_size_exceeded, size, max_size}
end

# RFC 9113 5.1: HEADERS frames move a stream reserved by a PUSH_PROMISE to the
Expand Down Expand Up @@ -3089,22 +3085,17 @@ defmodule Mint.HTTP2 do
@max_dynamic_table_size_updates_size 2 * 6

defp assert_header_block_within_max_size(conn, size) do
case conn.client_settings.max_header_list_size do
:infinity ->
conn

max_size ->
max_block_size = div(max_size * 30, 8) + @max_dynamic_table_size_updates_size
max_size = conn.client_settings.max_header_list_size
max_block_size = div(max_size * 30, 8) + @max_dynamic_table_size_updates_size

if size > max_block_size do
debug_data =
"header block fragments exceed #{max_block_size} bytes, the bound for " <>
"SETTINGS_MAX_HEADER_LIST_SIZE of #{max_size} bytes"
if size > max_block_size do
debug_data =
"header block fragments exceed #{max_block_size} bytes, the bound for " <>
"SETTINGS_MAX_HEADER_LIST_SIZE of #{max_size} bytes"

send_connection_error!(conn, :protocol_error, debug_data)
else
conn
end
send_connection_error!(conn, :protocol_error, debug_data)
else
conn
end
end

Expand Down
16 changes: 16 additions & 0 deletions test/mint/http2/conn_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,18 @@ defmodule Mint.HTTP2Test do
end
end

test "raises an error if the client :max_header_list_size setting is :infinity",
%{server_port: port} do
message = ":max_header_list_size must be an integer, got: :infinity"

assert_raise ArgumentError, message, fn ->
HTTP2.connect(:https, "localhost", port,
client_settings: [max_header_list_size: :infinity],
transport_opts: [verify: :verify_none]
)
end
end

test "closes the transport socket if anything goes wrong during the setup",
%{server_port: port} do
{:ok, socket} = :ssl.connect(~c"localhost", port, verify: :verify_none)
Expand Down Expand Up @@ -4070,6 +4082,10 @@ defmodule Mint.HTTP2Test do
HTTP2.put_settings(conn, header_table_size: :oops)
end

assert_raise ArgumentError, ~r/:max_header_list_size must be an integer/, fn ->
HTTP2.put_settings(conn, max_header_list_size: :infinity)
end

assert_raise ArgumentError, "unknown setting parameter :oops", fn ->
HTTP2.put_settings(conn, oops: 1)
end
Expand Down
Loading