Websocket without upgrade?
ostinelli opened this issue · 9 comments
Hello,
Is it possible to use gun's WebSocket implementation without going through the upgrade exchange over an http connection?
My use case: I'm integrating with Janus WebRTC server which has a WebSocket gateway to perform server-to-server tasks. I'm unable to achieve a connection and my hypothesis is that gun goes through the whole http(s) Connection: upgrade
mechanism, while Janus implements the WebSocket protocol directly.
I can successfully connect to Janus using other libraries that expose the WebSocket protocol without an upgrade mechanism, however I'd rather use gun if possible.
Any input is welcome!
There's no such thing as an HTTP-less Websocket. You have to negotiate at least the Sec-Websocket-Key.
According to their docs it's just plain Websocket, except you have to set a specific subprotocol:
To interact with Janus using WebSockets you MUST specify a specific subprotocol, named janus-protocol, e.g.,
var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol');
Thank you for your response Loïc. Yes, I do that already. Maybe I'm not understanding how the connection upgrade works then, indeed I'm not familiar with it.
For some reason though I'm unable to connect with gun:
with {:ok, gun_pid} <- :gun.open(to_charlist(host()), port(), %{transport: :tcp}),
{:ok, _protocol} <- :gun.await_up(gun_pid),
stream_ref <- :gun.ws_upgrade(gun_pid, "/janus", [{"sec-websocket-protocol", "janus-protocol"}])
do:
[...]
I receive a {:gun_down, ^gun_pid, _protocol, reason, _killed_streams, _unprocessed_streams}
with reason :normal
, immediately after the upgrade call.
Does it look like I'm doing something wrong here?
For comparison, this works with another library (yet again, I'd prefer to use gun):
ws_url = "ws://#{host()}:#{port()}/janus"
opts = [extra_headers: [{"Sec-WebSocket-Protocol", "janus-protocol"}]]
{:ok, client_pid} = WebSockex.start_link(ws_url, __MODULE__, state, opts)
Other libraries are just hiding the upgrade.
I'm not sure why you would get a normal
here except under normal connection shutdown. Can you not use with
and instead do hard matches so the code crashes where it's having a problem? You'll be able to more easily figure out what fails exactly.
Also make sure that you match against the http
protocol value in await_up
return value.
Here's an Erlang example:
-module(guntest_janus).
-export([main/0]).
main() ->
{ok, GunPid} = gun:open("localhost", 8188, #{transport => tcp}),
{ok, http} = gun:await_up(GunPid),
_StreamRef = gun:ws_upgrade(GunPid, "/janus", [{"sec-websocket-protocol", "janus-protocol"}]),
receive
Any ->
gun:close(GunPid),
Any
end.
Running it:
1> guntest_janus:main().
{gun_down,<0.128.0>,http,normal,
[#Ref<0.1435093131.708313092.205050>],
[]}
Anything you think I might try?
Right I forgot how that worked. So you have to set the protocols
option like [{<<"janus-protocol">>, gun_ws_h}]
when you upgrade and not provide headers. Seems there's no test inside Gun for this, must be something developed for a customer. If that solves the problem please leave the ticket open so I can add a test and documentation if it's missing.
gun:ws_upgrade(ConnPid, Path, Headers, #{protocols => [...]})
Thank you Loïc, this worked.
-module(guntest_janus).
-export([main/0]).
main() ->
{ok, GunPid} = gun:open("localhost", 8188, #{transport => tcp}),
{ok, http} = gun:await_up(GunPid),
_StreamRef = gun:ws_upgrade(GunPid, "/janus", [], #{protocols => [{<<"janus-protocol">>, gun_ws_h}]}),
receive
Any ->
gun:close(GunPid),
Any
end.
FTR, it also works if the sec-websocket-protocol
is also set in the headers.
Leaving open per your request.
Opened a new ticket for the followup.