ninenines / gun

HTTP/1.1, HTTP/2, Websocket client (and more) for Erlang/OTP.
ISC License
891 stars 232 forks source link

Websocket upgrade fails on unix socket #318

Open mortont opened 9 months ago

mortont commented 9 months ago

When upgrading a unix socket connection to a websocket connection using this snippet I get a failure ws_upgrade_failed response. I'm able to connect to this service and perform a websocket upgrade using other clients in other languages, so I don't think it is an issue with the server implementation

    {:ok, pid} = :gun.open_unix('test.sock', %{})

    case :gun.await_up(pid) do
      {:ok, _} ->
        :ok

      {:error, error} ->
        IO.inspect(error)
    end

    streamref = :gun.ws_upgrade(pid, '/ws')

    receive do
      {:gun_upgrade, connpid, streamref, [<<"websocket">>], headers} ->
        :ok

      {:gun_response, connpid, _, _, status, headers} ->
        exit({:ws_upgrade_failed, status, headers})

      {:gun_error, connpid, streamref, reason} ->
        exit({:ws_upgrade_failed, reason})
    after
      1000 ->
        Logger.error("timeout connecting")
    end

results

{:ws_upgrade_failed, 400, [{"connection", "close"}, {"content-length", "0"}]}

This is successful if I use a standard :gun.open connection over TCP/IP, is there something I'm missing for the unix socket case?

essen commented 9 months ago

Please add trace => true to the map given to open_unix so we can see what's going on.

mortont commented 9 months ago

I've attached the trace, I don't see anything obvious at first glance: trace.txt

essen commented 9 months ago

Right the problem is with the host header, since you are using a Unix socket you will need to provide the host header for every request you make as Gun is not able to figure it out and sends garbage.

Gun should not send garbage so this ticket should remain open, and I believe users of unix sockets will be required to provide the host themselves as we cannot guess it in this scenario so the documentation should be updated to reflect that.

Thanks for the trace!

mortont commented 9 months ago

Thanks! That fixed it for me. For anyone coming here with the same issue, this was my change:

streamref = :gun.ws_upgrade(pid, '/ws', [{<<"host">>, <<"localhost">>}])