From 8580d198d4950c1b48f05c3fececffdfb626b847 Mon Sep 17 00:00:00 2001 From: ruslandoga Date: Thu, 7 Aug 2025 19:55:14 +0300 Subject: [PATCH 1/4] add failing test --- test/mint/http1/request_test.exs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/mint/http1/request_test.exs b/test/mint/http1/request_test.exs index c9fe9574..29afb9e8 100644 --- a/test/mint/http1/request_test.exs +++ b/test/mint/http1/request_test.exs @@ -42,6 +42,11 @@ defmodule Mint.HTTP1.RequestTest do assert Request.encode("GET", "/", [{"foo", "bar\r\n"}], nil) == {:error, {:invalid_header_value, "foo", "bar\r\n"}} end + + test "empty target" do + assert Request.encode("GET", "", [], nil) == + {:error, {:invalid_target, ""}} + end end describe "encode_chunk/1" do From ebb013400e3eec68a3a5e94d2b5bf5060e13c34e Mon Sep 17 00:00:00 2001 From: ruslandoga Date: Thu, 7 Aug 2025 20:02:51 +0300 Subject: [PATCH 2/4] throw on empty target --- lib/mint/http1/request.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mint/http1/request.ex b/lib/mint/http1/request.ex index 5c5ffe27..edb5f1dd 100644 --- a/lib/mint/http1/request.ex +++ b/lib/mint/http1/request.ex @@ -17,6 +17,7 @@ defmodule Mint.HTTP1.Request do end defp encode_request_line(method, target) do + validate_target!(target) [method, ?\s, target, " HTTP/1.1\r\n"] end @@ -45,6 +46,9 @@ defmodule Mint.HTTP1.Request do [Integer.to_string(length, 16), "\r\n", chunk, "\r\n"] end + defp validate_target!("" = target), do: throw({:mint, {:invalid_target, target}}) + defp validate_target!(_target), do: :ok + defp validate_header_name!(name) do _ = for <> do From 57a90e17348d4e066a625f547d5af7416c4ab4b1 Mon Sep 17 00:00:00 2001 From: ruslandoga Date: Thu, 7 Aug 2025 20:11:11 +0300 Subject: [PATCH 3/4] use existing target validation functions --- lib/mint/http1.ex | 1 + lib/mint/http1/request.ex | 4 ---- test/mint/http1/integration_test.exs | 6 ++++++ test/mint/http1/request_test.exs | 5 ----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/mint/http1.ex b/lib/mint/http1.ex index 4747f891..8c05e2cf 100644 --- a/lib/mint/http1.ex +++ b/lib/mint/http1.ex @@ -978,6 +978,7 @@ defmodule Mint.HTTP1 do # Percent-encoding is not case sensitive so we have to account for lowercase and uppercase. @hex_characters ~c"0123456789abcdefABCDEF" + defp validate_target(<<>> = empty_target), do: {:error, {:invalid_request_target, empty_target}} defp validate_target(target), do: validate_target(target, target) defp validate_target(<>, original_target) diff --git a/lib/mint/http1/request.ex b/lib/mint/http1/request.ex index edb5f1dd..5c5ffe27 100644 --- a/lib/mint/http1/request.ex +++ b/lib/mint/http1/request.ex @@ -17,7 +17,6 @@ defmodule Mint.HTTP1.Request do end defp encode_request_line(method, target) do - validate_target!(target) [method, ?\s, target, " HTTP/1.1\r\n"] end @@ -46,9 +45,6 @@ defmodule Mint.HTTP1.Request do [Integer.to_string(length, 16), "\r\n", chunk, "\r\n"] end - defp validate_target!("" = target), do: throw({:mint, {:invalid_target, target}}) - defp validate_target!(_target), do: :ok - defp validate_header_name!(name) do _ = for <> do diff --git a/test/mint/http1/integration_test.exs b/test/mint/http1/integration_test.exs index 17f6dfa7..54f8bb93 100644 --- a/test/mint/http1/integration_test.exs +++ b/test/mint/http1/integration_test.exs @@ -100,6 +100,12 @@ defmodule Mint.HTTP1.IntegrationTest do assert byte_size(merge_body(responses, request)) == 1024 end + + test "empty target" do + {:ok, conn} = HTTP1.connect(:http, "localhost", 8080) + assert {:error, _conn, %Mint.HTTPError{} = error} = HTTP1.request(conn, "GET", "", [], nil) + assert Exception.message(error) == ~s|invalid request target: ""| + end end describe "twitter.com" do diff --git a/test/mint/http1/request_test.exs b/test/mint/http1/request_test.exs index 29afb9e8..c9fe9574 100644 --- a/test/mint/http1/request_test.exs +++ b/test/mint/http1/request_test.exs @@ -42,11 +42,6 @@ defmodule Mint.HTTP1.RequestTest do assert Request.encode("GET", "/", [{"foo", "bar\r\n"}], nil) == {:error, {:invalid_header_value, "foo", "bar\r\n"}} end - - test "empty target" do - assert Request.encode("GET", "", [], nil) == - {:error, {:invalid_target, ""}} - end end describe "encode_chunk/1" do From b0bff08e35445f68fe5f41a22de1a1dd78f454bf Mon Sep 17 00:00:00 2001 From: ruslandoga Date: Thu, 7 Aug 2025 21:36:45 +0300 Subject: [PATCH 4/4] use existing tests for http/1.1 target validation --- test/mint/http1/conn_test.exs | 2 +- test/mint/http1/integration_test.exs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/test/mint/http1/conn_test.exs b/test/mint/http1/conn_test.exs index cecfbcd0..b627c386 100644 --- a/test/mint/http1/conn_test.exs +++ b/test/mint/http1/conn_test.exs @@ -761,7 +761,7 @@ defmodule Mint.HTTP1Test do """) end - @invalid_request_targets ["/ /", "/%foo", "/foo%x"] + @invalid_request_targets ["", "/ /", "/%foo", "/foo%x"] test "targets are validated by default", %{port: port, server_ref: server_ref} do assert {:ok, conn} = HTTP1.connect(:http, "localhost", port) diff --git a/test/mint/http1/integration_test.exs b/test/mint/http1/integration_test.exs index 54f8bb93..17f6dfa7 100644 --- a/test/mint/http1/integration_test.exs +++ b/test/mint/http1/integration_test.exs @@ -100,12 +100,6 @@ defmodule Mint.HTTP1.IntegrationTest do assert byte_size(merge_body(responses, request)) == 1024 end - - test "empty target" do - {:ok, conn} = HTTP1.connect(:http, "localhost", 8080) - assert {:error, _conn, %Mint.HTTPError{} = error} = HTTP1.request(conn, "GET", "", [], nil) - assert Exception.message(error) == ~s|invalid request target: ""| - end end describe "twitter.com" do