stream_handler_h.erl 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. %% This module behaves differently depending on a specific header.
  2. -module(stream_handler_h).
  3. -behavior(cowboy_stream).
  4. -export([init/3]).
  5. -export([data/4]).
  6. -export([info/3]).
  7. -export([terminate/3]).
  8. -export([early_error/5]).
  9. -record(state, {
  10. pid,
  11. test
  12. }).
  13. init(StreamID, Req, Opts) ->
  14. Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))),
  15. Test = binary_to_atom(cowboy_req:header(<<"x-test-case">>, Req), latin1),
  16. State = #state{pid=Pid, test=Test},
  17. Pid ! {Pid, self(), init, StreamID, Req, Opts},
  18. {init_commands(StreamID, Req, State), State}.
  19. init_commands(_, _, #state{test=crash_in_init}) ->
  20. error(crash);
  21. init_commands(_, _, #state{test=crash_in_data}) ->
  22. [];
  23. init_commands(_, _, #state{test=crash_in_info}) ->
  24. [];
  25. init_commands(_, _, #state{test=crash_in_terminate}) ->
  26. [{response, 200, #{<<"content-length">> => <<"12">>}, <<"Hello world!">>}, stop];
  27. init_commands(_, _, #state{test=crash_in_early_error}) ->
  28. error(crash);
  29. init_commands(_, _, State=#state{test=shutdown_on_stream_stop}) ->
  30. Spawn = init_process(false, State),
  31. [{headers, 200, #{}}, {spawn, Spawn, 5000}, stop];
  32. init_commands(_, _, State=#state{test=shutdown_on_socket_close}) ->
  33. Spawn = init_process(false, State),
  34. [{headers, 200, #{}}, {spawn, Spawn, 5000}];
  35. init_commands(_, _, State=#state{test=shutdown_timeout_on_stream_stop}) ->
  36. Spawn = init_process(true, State),
  37. [{headers, 200, #{}}, {spawn, Spawn, 2000}, stop];
  38. init_commands(_, _, State=#state{test=shutdown_timeout_on_socket_close}) ->
  39. Spawn = init_process(true, State),
  40. [{headers, 200, #{}}, {spawn, Spawn, 2000}];
  41. init_commands(_, _, _) ->
  42. [{headers, 200, #{}}].
  43. init_process(TrapExit, #state{pid=Pid}) ->
  44. Self = self(),
  45. Spawn = spawn_link(fun() ->
  46. process_flag(trap_exit, TrapExit),
  47. Pid ! {Pid, Self, spawned, self()},
  48. receive {Pid, ready} -> ok after 1000 -> error(timeout) end,
  49. Self ! {self(), ready},
  50. receive after 5000 ->
  51. Pid ! {Pid, Self, still_alive, self()}
  52. end
  53. end),
  54. receive {Spawn, ready} -> ok after 1000 -> error(timeout) end,
  55. Spawn.
  56. data(_, _, _, #state{test=crash_in_data}) ->
  57. error(crash);
  58. data(StreamID, IsFin, Data, State=#state{pid=Pid}) ->
  59. Pid ! {Pid, self(), data, StreamID, IsFin, Data, State},
  60. {[], State}.
  61. info(_, Resp={response, _, _, _}, State) ->
  62. {[Resp], State};
  63. info(_, crash, #state{test=crash_in_info}) ->
  64. error(crash);
  65. info(StreamID, Info, State=#state{pid=Pid}) ->
  66. Pid ! {Pid, self(), info, StreamID, Info, State},
  67. {[], State}.
  68. terminate(StreamID, Reason, State=#state{pid=Pid, test=crash_in_terminate}) ->
  69. Pid ! {Pid, self(), terminate, StreamID, Reason, State},
  70. error(crash);
  71. terminate(StreamID, Reason, State=#state{pid=Pid}) ->
  72. Pid ! {Pid, self(), terminate, StreamID, Reason, State},
  73. ok.
  74. %% This clause can only test for early errors that reached the required headers.
  75. early_error(StreamID, Reason, PartialReq, Resp, Opts) ->
  76. Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, PartialReq))),
  77. Pid ! {Pid, self(), early_error, StreamID, Reason, PartialReq, Resp, Opts},
  78. case cowboy_req:header(<<"x-test-case">>, PartialReq) of
  79. <<"crash_in_early_error",_/bits>> -> error(crash);
  80. _ -> Resp
  81. end.