Packages
bandit
0.6.4
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
retired
1.9.0
1.8.0
1.7.0
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.2
1.4.1
1.4.0
1.3.0
1.2.3
1.2.2
1.2.1
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-pre.18
1.0.0-pre.17
1.0.0-pre.16
1.0.0-pre.15
1.0.0-pre.14
1.0.0-pre.13
1.0.0-pre.12
1.0.0-pre.11
1.0.0-pre.10
1.0.0-pre.9
1.0.0-pre.8
1.0.0-pre.7
1.0.0-pre.6
1.0.0-pre.5
1.0.0-pre.4
1.0.0-pre.3
1.0.0-pre.2
1.0.0-pre.1
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.2.3
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
A pure-Elixir HTTP server built for Plug & WebSock apps
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/bandit/websocket/handler.ex
defmodule Bandit.WebSocket.Handler do
@moduledoc false
# A WebSocket handler conforming to RFC6455, structured as a ThousandIsland.Handler
use ThousandIsland.Handler
alias Bandit.WebSocket.{Connection, Frame}
@impl ThousandIsland.Handler
def handle_connection(socket, state) do
{websock, websock_opts, connection_opts} = state.upgrade_opts
connection_opts
|> Keyword.take([:fullsweep_after])
|> Enum.each(fn {key, value} -> :erlang.process_flag(key, value) end)
state =
state
|> Map.take([:handler_module])
|> Map.put(:buffer, <<>>)
case Connection.init(websock, websock_opts, connection_opts, socket) do
{:continue, connection} ->
case Keyword.get(connection_opts, :timeout) do
nil -> {:continue, Map.put(state, :connection, connection)}
timeout -> {:continue, Map.put(state, :connection, connection), {:persistent, timeout}}
end
{:error, reason, connection} ->
{:error, reason, Map.put(state, :connection, connection)}
end
end
@impl ThousandIsland.Handler
def handle_data(data, socket, state) do
(state.buffer <> data)
|> Stream.unfold(&Frame.deserialize(&1))
|> Enum.reduce_while({:continue, state}, fn
{:ok, frame}, {:continue, state} ->
case Connection.handle_frame(frame, socket, state.connection) do
{:continue, connection} ->
{:cont, {:continue, %{state | connection: connection, buffer: <<>>}}}
{:close, connection} ->
{:halt, {:close, %{state | connection: connection, buffer: <<>>}}}
{:error, reason, connection} ->
{:halt, {:error, reason, %{state | connection: connection, buffer: <<>>}}}
end
{:more, rest}, {:continue, state} ->
{:halt, {:continue, %{state | buffer: rest}}}
{:error, message}, {:continue, state} ->
{:halt, {:error, {:protocol, message}, state}}
end)
end
@impl ThousandIsland.Handler
def handle_close(socket, %{connection: connection}),
do: Connection.handle_close(socket, connection)
def handle_close(_socket, _state), do: :ok
@impl ThousandIsland.Handler
def handle_shutdown(socket, state), do: Connection.handle_shutdown(socket, state.connection)
@impl ThousandIsland.Handler
def handle_error(reason, socket, state),
do: Connection.handle_error(reason, socket, state.connection)
@impl ThousandIsland.Handler
def handle_timeout(socket, state), do: Connection.handle_timeout(socket, state.connection)
def handle_info({:plug_conn, :sent}, {socket, state}),
do: {:noreply, {socket, state}, socket.read_timeout}
def handle_info({:EXIT, _pid, :normal}, state), do: {:noreply, state}
def handle_info(msg, {socket, state}) do
case Connection.handle_info(msg, socket, state.connection) do
{:continue, connection_state} ->
{:noreply, {socket, %{state | connection: connection_state}}, socket.read_timeout}
{:error, reason, connection_state} ->
{:stop, reason, {socket, %{state | connection: connection_state}}}
end
end
end