Packages
bandit
0.3.6
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/http2/stream_task.ex
defmodule Bandit.HTTP2.StreamTask do
@moduledoc false
use Task
alias Bandit.HTTP2.Adapter
def start_link(connection, stream_id, headers, peer, plug) do
Task.start_link(__MODULE__, :run, [connection, stream_id, headers, peer, plug])
end
def recv_data(pid, data), do: Process.send(pid, {:data, data}, [])
def recv_end_of_stream(pid), do: Process.send(pid, :end_stream, [])
def recv_rst_stream(pid, error_code), do: Process.exit(pid, {:recv_rst_stream, error_code})
def run(connection, stream_id, headers, peer, {plug, plug_opts}) do
headers = combine_cookie_crumbs(headers)
uri = uri(headers)
{Adapter, %Adapter{connection: connection, peer: peer, stream_id: stream_id, uri: uri}}
|> conn(method(headers), uri, peer.address, headers)
|> plug.call(plug_opts)
|> case do
%Plug.Conn{state: :unset} ->
raise(Plug.Conn.NotSentError)
%Plug.Conn{state: :set} = conn ->
Plug.Conn.send_resp(conn)
%Plug.Conn{state: :chunked, adapter: {adapter_mod, req}} = conn ->
adapter_mod.chunk(req, "")
conn
%Plug.Conn{} = conn ->
conn
_ = conn ->
raise("Expected #{plug}.call/2 to return %Plug.Conn{} but got: #{inspect(conn)}")
end
end
# TODO - remove this in favour of Plug.Conn.Adapter.conn/5 once Plug > 1.11.1 ships
defp conn(adapter, method, uri, remote_ip, req_headers) do
%URI{path: path, host: host, port: port, query: qs, scheme: scheme} = uri
%Plug.Conn{
adapter: adapter,
host: host,
method: method,
owner: self(),
path_info: split_path(path),
port: port,
remote_ip: remote_ip,
query_string: qs || "",
req_headers: req_headers,
request_path: path,
scheme: String.to_atom(scheme)
}
end
defp split_path(path) do
segments = :binary.split(path, "/", [:global])
for segment <- segments, segment != "", do: segment
end
# Per RFC7540§8.1.2.5
defp combine_cookie_crumbs(headers) do
{crumbs, other_headers} = headers |> Enum.split_with(fn {header, _} -> header == "cookie" end)
combined_cookie = crumbs |> Enum.map(fn {"cookie", crumb} -> crumb end) |> Enum.join("; ")
other_headers ++ [{"cookie", combined_cookie}]
end
defp method(headers), do: get_header(headers, ":method")
# Build up a URI based on RFC7540§8.1.2.3
# TODO - This is a bogus hack since the interface into URI is so anemic
# See https://github.com/elixir-plug/plug/issues/948 for future paths here
defp uri(headers) do
scheme = get_header(headers, ":scheme")
authority = get_header(headers, ":authority")
path = get_header(headers, ":path")
URI.parse(scheme <> "://" <> authority <> path)
end
defp get_header(headers, header, default \\ nil) do
case List.keyfind(headers, header, 0) do
{_, value} -> value
nil -> default
end
end
end