Packages
bandit
1.6.5
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/http1/handler.ex
defmodule Bandit.HTTP1.Handler do
@moduledoc false
# An HTTP 1.0 & 1.1 Thousand Island Handler
use ThousandIsland.Handler
@impl ThousandIsland.Handler
def handle_data(data, socket, state) do
transport = %Bandit.HTTP1.Socket{socket: socket, buffer: data, opts: state.opts}
connection_span = ThousandIsland.Socket.telemetry_span(socket)
case Bandit.Pipeline.run(transport, state.plug, connection_span, state.opts) do
{:ok, transport} -> maybe_keepalive(transport, state)
{:error, _reason} -> {:close, state}
{:upgrade, _transport, :websocket, opts} -> do_websocket_upgrade(opts, state)
end
end
defp maybe_keepalive(transport, state) do
requests_processed = Map.get(state, :requests_processed, 0) + 1
request_limit = Keyword.get(state.opts.http_1, :max_requests, 0)
under_limit = request_limit == 0 || requests_processed < request_limit
if under_limit && transport.keepalive do
if Keyword.get(state.opts.http_1, :clear_process_dict, true), do: clear_process_dict()
gc_every_n_requests = Keyword.get(state.opts.http_1, :gc_every_n_keepalive_requests, 5)
if rem(requests_processed, gc_every_n_requests) == 0, do: :erlang.garbage_collect()
state = Map.put(state, :requests_processed, requests_processed)
# We have bytes that we've read but haven't yet processed, tail call handle_data to start
# reading the next request
if IO.iodata_length(transport.buffer) != 0 do
handle_data(transport.buffer, transport.socket, state)
else
{:continue, state}
end
else
{:close, state}
end
end
defp clear_process_dict do
Process.get_keys()
|> Enum.each(&if &1 not in ~w[$ancestors $initial_call]a, do: Process.delete(&1))
end
defp do_websocket_upgrade(upgrade_opts, state) do
:erlang.garbage_collect()
{:switch, Bandit.WebSocket.Handler, Map.put(state, :upgrade_opts, upgrade_opts)}
end
def handle_info({:plug_conn, :sent}, {socket, state}),
do: {:noreply, {socket, state}, socket.read_timeout}
def handle_info({:EXIT, _pid, :normal}, {socket, state}),
do: {:noreply, {socket, state}, socket.read_timeout}
def handle_info(msg, {socket, state}) do
if Keyword.get(state.opts.http_1, :log_unknown_messages, false), do: log_no_handle_info(msg)
{:noreply, {socket, state}, socket.read_timeout}
end
def handle_info(msg, state) do
log_no_handle_info(msg)
{:noreply, state}
end
defp log_no_handle_info(msg) do
# Copied verbatim from lib/elixir/lib/gen_server.ex
proc =
case Process.info(self(), :registered_name) do
{_, []} -> self()
{_, name} -> name
end
:logger.error(
%{
label: {GenServer, :no_handle_info},
report: %{
module: __MODULE__,
message: msg,
name: proc
}
},
%{
domain: [:otp, :elixir],
error_logger: %{tag: :error_msg},
report_cb: &GenServer.format_report/1
}
)
end
end