-
Notifications
You must be signed in to change notification settings - Fork 5
Handler
以下の例を確認してください
@impl Requiem
def init(conn, client) do
Logger.debug("new connection is established, connection_id: #{conn.dcid}")
if client.origin == "my-origin.example.com" && client.path == "/my_path" do
my_state = %{path: client.path}
{:ok, conn, state}
else
{:stop, 400, :forbidden}
end
end
GenServerのinitに似ている役割を持っています。QUICのハンドシェイクに成功した後に呼ばれます。
引数が2つあり、ConnectionStateと、ClientIndicationです。
必要ならClientIndicationのパラメータであるoriginとpathの値を確認し、任意の処理を行うことが出来ます。 上の例ではoriginが正しくなければここで切断し、originが期待通りであれば接続を維持するような処理になっています。
WebTransportモードをoffにした場合は、client indicationの部分はnilが渡されます。詳しくはWebTransportのページを参照してください。
originの扱いは、HTTPにおけるCORS と同じような話だと捉えてもらってよいです。
pathはこのサーバーにアクセスされるときに指定されたURLのパスの部分が入ります。
quic-transport://my-service.example.org/foobar
というURLでアクセスされたとしたら、/foobar
の部分が入ります。
必要によっては、この値を見て、サービスを分岐させて見ると良いでしょう。
特に問題が無ければ、{:ok, conn, state}
のように値を返してください。自由にstateを作って渡すところは、GenServer.init/1
と同じです。
違うのはConnectionStateの構造体も一緒に引き回すということだけです。
問題があって接続をここで遮断したい場合は{:stop, error_code, reason}
という形のデータを返します。
ここで使われたerror_codeとreasonは、クライアントに対して送信するCLOSE FRAME
に使われます。
@callback init(conn :: Requiem.ConnectionState.t(), client :: Requiem.ClientIndication.t()) ::
{:ok, Requiem.ConnectionState.t(), any}
| {:ok, Requiem.ConnectionState.t(), any, timeout | :hibernate}
| {:stop, non_neg_integer, atom}
@callback handle_info(
request :: term,
conn :: Requiem.ConnectionState.t(),
state :: any
) ::
{:noreply, Requiem.ConnectionState.t(), any}
| {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
| {:stop, non_neg_integer, atom}
@callback handle_cast(
request :: term,
conn :: Requiem.ConnectionState.t(),
state :: any
) ::
{:noreply, Requiem.ConnectionState.t(), any}
| {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
| {:stop, non_neg_integer, atom}
@callback handle_call(
request :: term,
from :: pid,
conn :: Requiem.ConnectionState.t(),
state :: any
) ::
{:noreply, Requiem.ConnectionState.t(), any}
| {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
| {:stop, non_neg_integer, atom}
@type terminate_reason :: :normal | :shutdown | {:shutdown, term} | term
@callback terminate(
reason :: terminate_reason,
conn :: Requiem.ConnectionState.t(),
state :: any
) :: :ok
各コールバックで渡されるconnの実態はRequiem.ConnectionStateモジュールで定義されている構造体です。
以下のようなフィールドを持っています
- conn.scid
- conn.dcid
- conn.odcid
これらはQUICのフレームで利用される接続IDで、クライアントが接続開始の際に指定したものです。 (サーバー側がクライアントに対して指定したものではありません) odcidは、retryフレームを利用したトークンによるバリデーションを行う前に指定されたものです。
また、相手のAddressを持っています
- conn.address
これはRequiem.Addressモジュールの構造体です。
- conn.address.host
- conn.address.port
のように相手の接続に関する情報にアクセスできます。
ConnectionState以外にも知っておかなければならないものが一つあります。
init/2
の第二引数として渡されるClientIndicationです。
@impl Requiem
def init(conn, client) do
my_state = %{}
{:ok, conn, my_state}
end
これは、WebTransportモードのときだけ利用されます。
WebTransportモードではない場合はここにはnil
が渡されます。
(WebTransportモードについて詳しくは、ConfigurationやWebTransportを参照してください。)
WebTransportモードの場合は、クライアントからstream_idが2のstreamを通して受け取ったデータを自動的にパースし、init/2
に渡します。
ここで、origin
やpath
の値をチェックして、問題があれば切断することが出来ます。
@impl Requiem
def init(conn, client) do
if client.origin == "example.org" && client.path == "/service" do
my_state = %{}
{:ok, conn, my_state}
else
{:stop, 400, :shutdown}
end
end