diff --git a/lib/plug/cowboy.ex b/lib/plug/cowboy.ex index 41d859e..4ed13e4 100644 --- a/lib/plug/cowboy.ex +++ b/lib/plug/cowboy.ex @@ -429,6 +429,36 @@ defmodule Plug.Cowboy do end @doc false + def handle_event( + [:cowboy, :request, :early_error], + _, + %{ + resp_status: 414, + reason: {:connection_error, :limit_reached, specific_reason}, + partial_req: partial_req + }, + _ + ) do + Logger.error(""" + Cowboy returned 414 because the request path was too long. + + The more specific reason is: + + #{inspect(specific_reason)} + + You can customize those limits when configuring your http/https + server. The configuration option and default values are shown below: + + protocol_options: [ + max_request_line_length: 50_000 + ] + + Request info: + + peer: #{format_peer(partial_req.peer)} + """) + end + def handle_event( [:cowboy, :request, :early_error], _, diff --git a/test/plug/cowboy/conn_test.exs b/test/plug/cowboy/conn_test.exs index f1742ea..f86ceda 100644 --- a/test/plug/cowboy/conn_test.exs +++ b/test/plug/cowboy/conn_test.exs @@ -245,6 +245,33 @@ defmodule Plug.Cowboy.ConnTest do :telemetry.detach(:early_error_test) end + test "emits telemetry events for cowboy early_error for paths that are too long" do + :telemetry.attach( + :early_error_test, + [:cowboy, :request, :early_error], + &__MODULE__.telemetry_send/4, + self() + ) + + assert capture_log(fn -> + # Send a request line that's too long (exceeds max_request_line_length) + long_path = String.duplicate("a", 10_000) + response = request(:get, "/#{long_path}") + assert match?({414, _, _}, response) or match?({:error, :closed}, response) + end) =~ "Cowboy returned 414 because the request path was too long" + + assert_receive {:telemetry, [:cowboy, :request, :early_error], + %{ + system_time: _ + }, + %{ + reason: {:connection_error, :limit_reached, _}, + partial_req: %{} + }} + + :telemetry.detach(:early_error_test) + end + def send_200(conn) do assert conn.state == :unset assert conn.resp_body == nil