cowboy_loop.erl 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. %% Copyright (c) 2011-2017, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(cowboy_loop).
  15. -behaviour(cowboy_sub_protocol).
  16. -ifdef(OTP_RELEASE).
  17. -compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
  18. -endif.
  19. -export([upgrade/4]).
  20. -export([upgrade/5]).
  21. -export([loop/4]).
  22. -export([system_continue/3]).
  23. -export([system_terminate/4]).
  24. -export([system_code_change/4]).
  25. -callback init(Req, any())
  26. -> {ok | module(), Req, any()}
  27. | {module(), Req, any(), any()}
  28. when Req::cowboy_req:req().
  29. -callback info(any(), Req, State)
  30. -> {ok, Req, State}
  31. | {ok, Req, State, hibernate}
  32. | {stop, Req, State}
  33. when Req::cowboy_req:req(), State::any().
  34. -callback terminate(any(), cowboy_req:req(), any()) -> ok.
  35. -optional_callbacks([terminate/3]).
  36. -spec upgrade(Req, Env, module(), any())
  37. -> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
  38. when Req::cowboy_req:req(), Env::cowboy_middleware:env().
  39. upgrade(Req, Env, Handler, HandlerState) ->
  40. loop(Req, Env, Handler, HandlerState).
  41. -spec upgrade(Req, Env, module(), any(), hibernate)
  42. -> {suspend, ?MODULE, loop, [any()]}
  43. when Req::cowboy_req:req(), Env::cowboy_middleware:env().
  44. upgrade(Req, Env, Handler, HandlerState, hibernate) ->
  45. suspend(Req, Env, Handler, HandlerState).
  46. -spec loop(Req, Env, module(), any())
  47. -> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
  48. when Req::cowboy_req:req(), Env::cowboy_middleware:env().
  49. %% @todo Handle system messages.
  50. loop(Req=#{pid := Parent}, Env, Handler, HandlerState) ->
  51. receive
  52. %% System messages.
  53. {'EXIT', Parent, Reason} ->
  54. terminate(Req, Env, Handler, HandlerState, Reason);
  55. {system, From, Request} ->
  56. sys:handle_system_msg(Request, From, Parent, ?MODULE, [],
  57. {Req, Env, Handler, HandlerState});
  58. %% Calls from supervisor module.
  59. {'$gen_call', From, Call} ->
  60. cowboy_children:handle_supervisor_call(Call, From, [], ?MODULE),
  61. loop(Req, Env, Handler, HandlerState);
  62. Message ->
  63. call(Req, Env, Handler, HandlerState, Message)
  64. end.
  65. call(Req0, Env, Handler, HandlerState0, Message) ->
  66. try Handler:info(Message, Req0, HandlerState0) of
  67. {ok, Req, HandlerState} ->
  68. loop(Req, Env, Handler, HandlerState);
  69. {ok, Req, HandlerState, hibernate} ->
  70. suspend(Req, Env, Handler, HandlerState);
  71. {stop, Req, HandlerState} ->
  72. terminate(Req, Env, Handler, HandlerState, stop)
  73. catch Class:Reason ->
  74. cowboy_handler:terminate({crash, Class, Reason}, Req0, HandlerState0, Handler),
  75. erlang:raise(Class, Reason, erlang:get_stacktrace())
  76. end.
  77. suspend(Req, Env, Handler, HandlerState) ->
  78. {suspend, ?MODULE, loop, [Req, Env, Handler, HandlerState]}.
  79. terminate(Req, Env, Handler, HandlerState, Reason) ->
  80. Result = cowboy_handler:terminate(Reason, Req, HandlerState, Handler),
  81. {ok, Req, Env#{result => Result}}.
  82. %% System callbacks.
  83. -spec system_continue(_, _, {Req, Env, module(), any()})
  84. -> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
  85. when Req::cowboy_req:req(), Env::cowboy_middleware:env().
  86. system_continue(_, _, {Req, Env, Handler, HandlerState}) ->
  87. loop(Req, Env, Handler, HandlerState).
  88. -spec system_terminate(any(), _, _, {Req, Env, module(), any()})
  89. -> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env().
  90. system_terminate(Reason, _, _, {Req, Env, Handler, HandlerState}) ->
  91. terminate(Req, Env, Handler, HandlerState, Reason).
  92. -spec system_code_change(Misc, _, _, _) -> {ok, Misc}
  93. when Misc::{cowboy_req:req(), cowboy_middleware:env(), module(), any()}.
  94. system_code_change(Misc, _, _, _) ->
  95. {ok, Misc}.