Packages

HTTP/1.1, HTTP/2, and HTTP/3 server for Erlang/OTP 27+

Current section

Files

Jump to
nhttp src nhttp_acceptor.erl
Raw

src/nhttp_acceptor.erl

-module(nhttp_acceptor).
-moduledoc false.
-behaviour(nhttp_acceptor_core).
%%%-----------------------------------------------------------------------------
%% API EXPORTS
%%%-----------------------------------------------------------------------------
-export([
get_listen_port/1,
start_link/2,
stop_accepting/1
]).
%%%-----------------------------------------------------------------------------
%% BEHAVIOUR CALLBACKS
%%%-----------------------------------------------------------------------------
-export([
do_accept/1,
init_sub/1,
reject/1,
spawn_conn/2
]).
%%%-----------------------------------------------------------------------------
%% INTERNAL RECORDS
%%%-----------------------------------------------------------------------------
-record(sub, {
listen_socket :: nhttp_sock:t()
}).
%%%-----------------------------------------------------------------------------
%% API
%%%-----------------------------------------------------------------------------
-spec get_listen_port(pid()) -> {ok, inet:port_number()} | nhttp_error:t().
get_listen_port(AcceptorPid) ->
nhttp_acceptor_core:get_listen_port(AcceptorPid).
-spec start_link(nhttp_registry:tab(), nhttp:opts()) -> {ok, pid()}.
start_link(Tab, Opts) ->
nhttp_acceptor_core:start_link(?MODULE, Tab, Opts).
-spec stop_accepting(pid()) -> ok.
stop_accepting(AcceptorPid) ->
nhttp_acceptor_core:stop_accepting(AcceptorPid).
%%%-----------------------------------------------------------------------------
%% BEHAVIOUR CALLBACKS
%%%-----------------------------------------------------------------------------
-spec do_accept(#sub{}) -> {ok, nhttp_sock:t()} | {error, term()}.
do_accept(#sub{listen_socket = ListenSocket}) ->
nhttp_sock:accept(ListenSocket, 1000).
-spec init_sub(nhttp:opts()) -> #sub{}.
init_sub(Opts) ->
#sub{listen_socket = maps:get(listen_socket, Opts)}.
-spec reject(nhttp_sock:t()) -> ok.
reject(Socket) ->
send_service_unavailable(Socket),
nhttp_sock:close(Socket),
ok.
-spec spawn_conn(nhttp_sock:t(), nhttp_acceptor_core:spawn_ctx()) -> ok.
spawn_conn(Socket, #{
name := Name, counter := Counter, opts := Opts, conn_sup := ConnSup, tracker := Tracker
}) ->
case nhttp_conn_sup:start_conn(ConnSup, Tracker, [Name, Socket, Opts]) of
{ok, Pid} ->
case nhttp_sock:controlling_process(Socket, Pid) of
ok ->
Pid ! {socket_ready, Socket},
ok;
{error, _Reason} ->
nhttp_conn:drain(Pid),
nhttp_sock:close(Socket),
ok
end;
{error, _Reason} ->
nhttp_listener_counter:release(Counter),
nhttp_sock:close(Socket),
ok
end.
%%%-----------------------------------------------------------------------------
%% INTERNAL FUNCTIONS
%%%-----------------------------------------------------------------------------
-spec send_service_unavailable(nhttp_sock:t()) -> ok.
send_service_unavailable(Socket) ->
Response =
<<"HTTP/1.1 503 Service Unavailable\r\n", "Content-Length: 19\r\n", "Connection: close\r\n",
"\r\n", "Service Unavailable">>,
_ = nhttp_sock:send(Socket, Response),
ok.