Skip to content

Commit 7e102ee

Browse files
elfenlaidmtrudel
andauthored
Add a check for custom handle_info return types (#96)
* Add a check for custom handle_info return types * Refine pattern matches on a number of Handler callbacks --------- Co-authored-by: Mat Trudel <mat@geeky.net>
1 parent e3f0518 commit 7e102ee

File tree

1 file changed

+25
-18
lines changed

1 file changed

+25
-18
lines changed

lib/thousand_island/handler.ex

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,14 @@ defmodule ThousandIsland.Handler do
386386
{:stop, reason, {socket, state}}
387387
end
388388

389+
def handle_info({msg, _raw_socket, _data}, _state) when msg in [:tcp, :ssl] do
390+
raise """
391+
The callback's `state` doesn't match the expected `{socket, state}` form.
392+
Please ensure that you are returning a `{socket, state}` tuple from any
393+
`GenServer.handle_*` callbacks you have implemented
394+
"""
395+
end
396+
389397
def handle_info(:timeout, {%ThousandIsland.Socket{} = socket, state}) do
390398
{:stop, {:shutdown, :timeout}, {socket, state}}
391399
end
@@ -395,65 +403,64 @@ defmodule ThousandIsland.Handler do
395403
# This ensures that the `c:terminate/2` calls below are able to properly
396404
# close down the process
397405
@impl GenServer
398-
def handle_continue(:handle_connection, {socket, state}) do
406+
def handle_continue(:handle_connection, {%ThousandIsland.Socket{} = socket, state}) do
399407
__MODULE__.handle_connection(socket, state)
400408
|> handle_continuation(socket)
401409
end
402410

403-
@impl GenServer
404-
def terminate(reason, state)
405-
406-
# This clause could happen if we are shut down before we have had a chance to fully set up
407-
# the handler process. In this case we would have never called any of the `Handler`
408-
# callbacks so the connection hasn't started yet from the perspective of the user
409-
# See https://github.com/mtrudel/bandit/issues/54 for details
410-
def terminate(_reason, {nil, _state}) do
411-
:ok
412-
end
413-
414411
# Called if the remote end closed the connection before we could initialize it
412+
@impl GenServer
415413
def terminate({:shutdown, {:premature_conn_closing, _reason}}, {_raw_socket, _state}) do
416414
:ok
417415
end
418416

419417
# Called by GenServer if we hit our read_timeout. Socket is still open
420-
def terminate({:shutdown, :timeout}, {socket, state}) do
418+
def terminate({:shutdown, :timeout}, {%ThousandIsland.Socket{} = socket, state}) do
421419
__MODULE__.handle_timeout(socket, state)
422420
do_socket_close(socket, :timeout)
423421
end
424422

425423
# Called if we're being shutdown in an orderly manner. Socket is still open
426-
def terminate(:shutdown, {socket, state}) do
424+
def terminate(:shutdown, {%ThousandIsland.Socket{} = socket, state}) do
427425
__MODULE__.handle_shutdown(socket, state)
428426
do_socket_close(socket, :shutdown)
429427
end
430428

431429
# Called if the socket encountered an error during handshaking
432-
def terminate({:shutdown, {:handshake, reason}}, {socket, state}) do
430+
def terminate({:shutdown, {:handshake, reason}}, {%ThousandIsland.Socket{} = socket, state}) do
433431
__MODULE__.handle_error(reason, socket, state)
434432
do_socket_close(socket, reason)
435433
end
436434

437435
# Called if the socket encountered an error and we are configured to shutdown silently.
438436
# Socket is closed
439-
def terminate({:shutdown, {:silent_termination, reason}}, {socket, state}) do
437+
def terminate(
438+
{:shutdown, {:silent_termination, reason}},
439+
{%ThousandIsland.Socket{} = socket, state}
440+
) do
440441
__MODULE__.handle_error(reason, socket, state)
441442
do_socket_close(socket, reason)
442443
end
443444

444445
# Called if the remote end shut down the connection, or if the local end closed the
445446
# connection by returning a `{:close,...}` tuple (in which case the socket will be open)
446-
def terminate({:shutdown, reason}, {socket, state}) do
447+
def terminate({:shutdown, reason}, {%ThousandIsland.Socket{} = socket, state}) do
447448
__MODULE__.handle_close(socket, state)
448449
do_socket_close(socket, reason)
449450
end
450451

451452
# Called if the socket encountered an error. Socket is closed
452-
def terminate(reason, {socket, state}) do
453+
def terminate(reason, {%ThousandIsland.Socket{} = socket, state}) do
453454
__MODULE__.handle_error(reason, socket, state)
454455
do_socket_close(socket, reason)
455456
end
456457

458+
# This clause could happen if we do not have a socket defined in state (either because the
459+
# process crashed before setting it up, or because the user sent an invalid state)
460+
def terminate(_reason, _state) do
461+
:ok
462+
end
463+
457464
@spec do_socket_close(
458465
ThousandIsland.Socket.t(),
459466
reason :: :shutdown | :local_closed | term()

0 commit comments

Comments
 (0)