From 55061138939710b88056102ad2919c8f7b143e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Thu, 16 Apr 2026 09:41:45 -0700 Subject: [PATCH 1/2] Run HTTP/2 integration tests against local Caddy instead of nghttp2.org The tests hitting nghttp2.org/httpbin/ had been failing on every CI run because the upstream httpbin backend behind nghttpx returns 502 to GitHub Actions runners. Enable h2c on the Caddy docker service (via a new HTTPBIN_H2C_PORT, default 8081, since the existing HTTPBIN_HTTP_PORT mapping goes directly to httpbin), point the TCP h2c test at it, and drop the duplicate "nghttp2.org/httpbin" describe block (ping and GET are already covered by the local "httpbin.org" block). --- Caddyfile | 3 +++ README.md | 2 +- docker-compose.yml | 1 + test/mint/http2/integration_test.exs | 36 +++------------------------- test/support/mint/http_bin.ex | 4 ++++ 5 files changed, 12 insertions(+), 34 deletions(-) diff --git a/Caddyfile b/Caddyfile index dbd52ff1..efce4d63 100644 --- a/Caddyfile +++ b/Caddyfile @@ -2,6 +2,9 @@ local_certs skip_install_trust storage file_system /caddy_storage + servers :{$HTTPBIN_HTTP_PORT:8080} { + protocols h1 h2c + } } https://localhost:{$HTTPBIN_HTTPS_PORT:8443} { diff --git a/README.md b/README.md index 9a538b05..49649d69 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ TINYPROXY_PORT=8887 docker compose up --detach TINYPROXY_PORT=8887 mix test --include proxy ``` -Available port variables: `TINYPROXY_PORT` (default 8888), `TINYPROXY_AUTH_PORT` (default 8889), `HTTPBIN_HTTP_PORT` (default 8080), `HTTPBIN_HTTPS_PORT` (default 8443). +Available port variables: `TINYPROXY_PORT` (default 8888), `TINYPROXY_AUTH_PORT` (default 8889), `HTTPBIN_HTTP_PORT` (default 8080), `HTTPBIN_HTTPS_PORT` (default 8443), `HTTPBIN_H2C_PORT` (default 8081). ## License diff --git a/docker-compose.yml b/docker-compose.yml index e602d3f5..5f55e0d8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,3 +34,4 @@ services: - "./Caddyfile:/etc/caddy/Caddyfile:z" ports: - "${HTTPBIN_HTTPS_PORT:-8443}:${HTTPBIN_HTTPS_PORT:-8443}" + - "${HTTPBIN_H2C_PORT:-8081}:${HTTPBIN_HTTP_PORT:-8080}" diff --git a/test/mint/http2/integration_test.exs b/test/mint/http2/integration_test.exs index 823381c1..1f9e85c0 100644 --- a/test/mint/http2/integration_test.exs +++ b/test/mint/http2/integration_test.exs @@ -32,14 +32,10 @@ defmodule HTTP2.IntegrationTest do end end - test "TCP - nghttp2.org" do - assert {:ok, %HTTP2{} = conn} = HTTP2.connect(:http, "nghttp2.org", 80) + test "TCP - h2c prior knowledge" do + assert {:ok, %HTTP2{} = conn} = HTTP2.connect(:http, HttpBin.host(), HttpBin.h2c_port()) - assert {:ok, %HTTP2{} = conn, ref} = HTTP2.request(conn, "GET", "/httpbin/", [], nil) - - # For some reason, we get an SSL message sneaking in here. Instead of going - # crazy trying to debug it, for now let's just swallow it. - assert_receive {:ssl, _socket, _data}, 1000 + assert {:ok, %HTTP2{} = conn, ref} = HTTP2.request(conn, "GET", "/", [], nil) assert {:ok, %HTTP2{} = conn, responses} = receive_stream(conn) @@ -159,32 +155,6 @@ defmodule HTTP2.IntegrationTest do end end - describe "nghttp2.org/httpbin" do - @describetag connect: {"nghttp2.org", 443} - - test "ping", %{conn: conn} do - assert {:ok, %HTTP2{} = conn, ref} = HTTP2.ping(conn) - assert {:ok, %HTTP2{} = conn, [{:pong, ^ref}]} = receive_stream(conn) - assert conn.buffer == "" - assert HTTP2.open?(conn) - end - - test "GET /", %{conn: conn} do - assert {:ok, %HTTP2{} = conn, ref} = HTTP2.request(conn, "GET", "/httpbin/", [], nil) - - assert {:ok, %HTTP2{} = conn, responses} = receive_stream(conn) - - assert [{:status, ^ref, status}, {:headers, ^ref, headers} | rest] = responses - assert {_, [{:done, ^ref}]} = Enum.split_while(rest, &match?({:data, ^ref, _}, &1)) - - assert status == 200 - assert is_list(headers) - - assert conn.buffer == "" - assert HTTP2.open?(conn) - end - end - describe "robynthinks.wordpress.com" do @describetag connect: {"robynthinks.wordpress.com", 443} diff --git a/test/support/mint/http_bin.ex b/test/support/mint/http_bin.ex index 46468abe..0a0c19d3 100644 --- a/test/support/mint/http_bin.ex +++ b/test/support/mint/http_bin.ex @@ -17,6 +17,10 @@ defmodule Mint.HttpBin do get_env_port("HTTPBIN_HTTPS_PORT", 8443) end + def h2c_port() do + get_env_port("HTTPBIN_H2C_PORT", 8081) + end + def proxy_port() do get_env_port("TINYPROXY_PORT", 8888) end From ef5fd4b6b8872516891d56b0dc8b9954b8b996e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Thu, 16 Apr 2026 09:54:59 -0700 Subject: [PATCH 2/2] Fix stray :ssl message leak in HTTP/2 integration tests The twitter.com describe block was using @moduletag instead of @describetag, which made its connect: {"twitter.com", 443} tag apply to the whole module. That caused the top-level setup to open an HTTPS connection to twitter.com even for tests outside the describe (like the TCP h2c test), and the SSL socket's SETTINGS frame would land in the test mailbox. The previous test had a swallow-hack comment about "SSL messages sneaking in"; this removes the root cause. --- test/mint/http2/integration_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mint/http2/integration_test.exs b/test/mint/http2/integration_test.exs index 1f9e85c0..a6692990 100644 --- a/test/mint/http2/integration_test.exs +++ b/test/mint/http2/integration_test.exs @@ -101,7 +101,7 @@ defmodule HTTP2.IntegrationTest do end describe "twitter.com" do - @moduletag connect: {"twitter.com", 443} + @describetag connect: {"twitter.com", 443} @browser_user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" test "ping", %{conn: conn} do