Packages
bandit
0.7.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
# credo:disable-for-this-file Credo.Check.Design.AliasUsage
@impl ThousandIsland.Handler
def handle_data(data, socket, state) do
{_, _, _, connection_span} = transport_info = build_transport_info(socket)
span =
Bandit.Telemetry.start_span(:request, %{}, %{
connection_telemetry_span_context: connection_span.telemetry_span_context
})
req = %Bandit.HTTP1.Adapter{socket: socket, buffer: data, opts: state.opts}
try do
with {:ok, headers, method, request_target, req} <-
Bandit.HTTP1.Adapter.read_headers(req),
{:ok, %Plug.Conn{adapter: {Bandit.HTTP1.Adapter, req}} = conn} <-
Bandit.Pipeline.run(
{Bandit.HTTP1.Adapter, req},
transport_info,
method,
request_target,
headers,
state.plug
) do
Bandit.Telemetry.stop_span(span, Map.put(req.metrics, :conn, conn))
maybe_keepalive(req, state)
else
{:error, reason} ->
attempt_to_send_fallback(req, code_for_reason(reason))
Bandit.Telemetry.stop_span(span, %{}, %{error: reason})
{:error, reason, state}
{:ok, :websocket, %Plug.Conn{adapter: {Bandit.HTTP1.Adapter, req}} = conn, upgrade_opts} ->
Bandit.Telemetry.stop_span(span, Map.put(req.metrics, :conn, conn))
state =
state
|> Map.put(:upgrade_opts, upgrade_opts)
|> Map.put(:origin_telemetry_span_context, span.telemetry_span_context)
{:switch, Bandit.WebSocket.Handler, state}
end
rescue
exception ->
# Raise here so that users can see useful stacktraces
attempt_to_send_fallback(req, 500)
Bandit.Telemetry.span_exception(span, :exit, exception, __STACKTRACE__)
reraise(exception, __STACKTRACE__)
end
end
defp build_transport_info(socket) do
{ThousandIsland.Socket.secure?(socket), ThousandIsland.Socket.local_info(socket),
ThousandIsland.Socket.peer_info(socket), ThousandIsland.Socket.telemetry_span(socket)}
end
defp code_for_reason(:timeout), do: 408
defp code_for_reason(:request_uri_too_long), do: 414
defp code_for_reason(:header_too_long), do: 431
defp code_for_reason(:too_many_headers), do: 431
defp code_for_reason(_), do: 400
defp attempt_to_send_fallback(req, code) do
Bandit.HTTP1.Adapter.send_resp(req, code, [], <<>>)
rescue
_ -> :ok
end
defp maybe_keepalive(req, 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 && Bandit.HTTP1.Adapter.keepalive?(req) do
{:continue, Map.put(state, :requests_processed, requests_processed)}
else
{:close, state}
end
end
def handle_info({:plug_conn, :sent}, state), do: {:noreply, state}
def handle_info({:EXIT, _pid, :normal}, state), do: {:noreply, state}
end