From 865c0887efed13987db266fb7f154e4b354e7703 Mon Sep 17 00:00:00 2001 From: Wojtek Mach Date: Thu, 7 Aug 2025 12:44:34 +0200 Subject: [PATCH] Improve HTTP1 invalid header value crash Before this patch: iex> {:ok, conn} = Mint.HTTP1.connect(:http, "httpbin.org", 80) ; Mint.HTTP.request(conn, "GET", "/json", [{"accept", nil}], nil) ** (ErlangError) Erlang error: {:bad_generator, nil} (mint 1.7.1) lib/mint/http1/request.ex:61: Mint.HTTP1.Request."-validate_header_value!/2-lc$^0/1-0-"/3 (mint 1.7.1) lib/mint/http1/request.ex:61: Mint.HTTP1.Request.validate_header_value!/2 (mint 1.7.1) lib/mint/http1/request.ex:26: anonymous fn/2 in Mint.HTTP1.Request.encode_headers/1 (elixir 1.18.4) lib/enum.ex:2546: Enum."-reduce/3-lists^foldl/2-0-"/3 (mint 1.7.1) lib/mint/http1/request.ex:9: Mint.HTTP1.Request.encode/4 (mint 1.7.1) lib/mint/http1.ex:286: Mint.HTTP1.request/5 iex:4: (file) After: iex> {:ok, conn} = Mint.HTTP1.connect(:http, "httpbin.org", 80) ; Mint.HTTP.request(conn, "GET", "/json", [{"accept", nil}], nil) ** (FunctionClauseError) no function clause matching in Mint.HTTP1.Request.validate_header_value!/2 The following arguments were given to Mint.HTTP1.Request.validate_header_value!/2: # 1 "accept" # 2 nil Attempted function clauses (showing 1 out of 1): defp validate_header_value!(name, value) when is_binary(value) (mint 1.7.1) lib/mint/http1/request.ex:59: Mint.HTTP1.Request.validate_header_value!/2 (mint 1.7.1) lib/mint/http1/request.ex:26: anonymous fn/2 in Mint.HTTP1.Request.encode_headers/1 (elixir 1.18.4) lib/enum.ex:2546: Enum."-reduce/3-lists^foldl/2-0-"/3 (mint 1.7.1) lib/mint/http1/request.ex:9: Mint.HTTP1.Request.encode/4 (mint 1.7.1) lib/mint/http1.ex:286: Mint.HTTP1.request/5 iex:4: (file) The error message is still pretty bad for HTTP2 at the moment though: iex> {:ok, conn} = Mint.HTTP2.connect(:https, "httpbin.org", 443) ; Mint.HTTP.request(conn, "GET", "/json", [{"accept", nil}], nil) ** (FunctionClauseError) no function clause matching in HPAX.encode_headers/3 The following arguments were given to HPAX.encode_headers/3: # 1 [{:store_name, "accept", nil}] # 2 %HPAX.Table{ max_table_size: 4096, huffman_encoding: :never, entries: [], size: 0, length: 0 } # 3 [ [ [[[[], <<130>>], [<<4>>, [<<5>>, "/json"]]], <<135>>], [<<1>>, ["\v", "httpbin.org"]] ], [<<15, 43>>, ["\n", "mint/1.7.1"]] ] Attempted function clauses (showing 2 out of 2): defp encode_headers([], table, acc) defp encode_headers([{action, name, value} | rest], table, acc) when (action === :store or action === :store_name or action === :no_store or action === :never_store) and is_binary(name) and is_binary(value) (hpax 1.0.0) lib/hpax.ex:281: HPAX.encode_headers/3 (elixir 1.18.4) lib/map.ex:999: Map.get_and_update!/3 (mint 1.7.1) lib/mint/http2.ex:1134: Mint.HTTP2.encode_headers/4 (mint 1.7.1) lib/mint/http2.ex:520: Mint.HTTP2.request/5 iex:4: (file) --- lib/mint/http1/request.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mint/http1/request.ex b/lib/mint/http1/request.ex index 5c5ffe27..e8664fd9 100644 --- a/lib/mint/http1/request.ex +++ b/lib/mint/http1/request.ex @@ -45,7 +45,7 @@ defmodule Mint.HTTP1.Request do [Integer.to_string(length, 16), "\r\n", chunk, "\r\n"] end - defp validate_header_name!(name) do + defp validate_header_name!(name) when is_binary(name) do _ = for <> do unless is_tchar(char) do @@ -56,7 +56,7 @@ defmodule Mint.HTTP1.Request do :ok end - defp validate_header_value!(name, value) do + defp validate_header_value!(name, value) when is_binary(value) do _ = for <> do unless is_vchar(char) or char in ~c"\s\t" do