sys_SUITE.erl 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395
  1. %% Copyright (c) 2018, 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(sys_SUITE).
  15. -compile(export_all).
  16. -compile(nowarn_export_all).
  17. -import(ct_helper, [config/2]).
  18. -import(ct_helper, [doc/1]).
  19. -import(ct_helper, [get_parent_pid/1]).
  20. -import(ct_helper, [get_remote_pid_tcp/1]).
  21. -import(ct_helper, [get_remote_pid_tls/1]).
  22. -import(ct_helper, [is_process_down/1]).
  23. -import(cowboy_test, [gun_open/1]).
  24. all() ->
  25. [{group, sys}].
  26. groups() ->
  27. [{sys, [parallel], ct_helper:all(?MODULE)}].
  28. init_per_suite(Config) ->
  29. ProtoOpts = #{
  30. env => #{dispatch => init_dispatch(Config)},
  31. logger => ?MODULE
  32. },
  33. %% Clear listener.
  34. {ok, _} = cowboy:start_clear(clear, [{port, 0}], ProtoOpts),
  35. ClearPort = ranch:get_port(clear),
  36. %% TLS listener.
  37. TLSOpts = ct_helper:get_certs_from_ets(),
  38. {ok, _} = cowboy:start_tls(tls, TLSOpts ++ [{port, 0}], ProtoOpts),
  39. TLSPort = ranch:get_port(tls),
  40. [
  41. {clear_port, ClearPort},
  42. %% @todo Add the h2 stuff to the opts.
  43. {tls_opts, TLSOpts},
  44. {tls_port, TLSPort}
  45. |Config].
  46. end_per_suite(_) ->
  47. ok = cowboy:stop_listener(clear),
  48. ok = cowboy:stop_listener(tls).
  49. init_dispatch(_) ->
  50. cowboy_router:compile([{"[...]", [
  51. {"/", hello_h, []},
  52. {"/loop", long_polling_sys_h, []},
  53. {"/ws", ws_echo, []}
  54. ]}]).
  55. %% Logger function silencing the expected warnings.
  56. error(Format, Args) ->
  57. error_logger:error_msg(Format, Args).
  58. warning("Received EXIT signal " ++ _, [{'EXIT', _, {shutdown, ?MODULE}}|_]) ->
  59. ok;
  60. warning(Format, Args) ->
  61. error_logger:warning_msg(Format, Args).
  62. %% proc_lib.
  63. proc_lib_initial_call_clear(Config) ->
  64. doc("Confirm that clear connection processes are started using proc_lib."),
  65. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  66. timer:sleep(100),
  67. Pid = get_remote_pid_tcp(Socket),
  68. {cowboy_clear, _, _} = proc_lib:initial_call(Pid),
  69. ok.
  70. proc_lib_initial_call_tls(Config) ->
  71. doc("Confirm that TLS connection processes are started using proc_lib."),
  72. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config), config(tls_opts, Config)),
  73. timer:sleep(100),
  74. Pid = get_remote_pid_tls(Socket),
  75. {cowboy_tls, _, _} = proc_lib:initial_call(Pid),
  76. ok.
  77. %% System messages.
  78. %%
  79. %% Plain system messages are received as {system, From, Msg}.
  80. %% The content and meaning of this message are not interpreted by
  81. %% the receiving process module. When a system message is received,
  82. %% function handle_system_msg/6 is called to handle the request.
  83. bad_system_from_h1(Config) ->
  84. doc("h1: Sending a system message with a bad From value results in a process crash."),
  85. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  86. timer:sleep(100),
  87. Pid = get_remote_pid_tcp(Socket),
  88. ct_helper_error_h:ignore(Pid, gen, reply, 2),
  89. Pid ! {system, bad, get_state},
  90. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  91. false = is_process_alive(Pid),
  92. ok.
  93. bad_system_from_h2(Config) ->
  94. doc("h2: Sending a system message with a bad From value results in a process crash."),
  95. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  96. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  97. %% Skip the SETTINGS frame.
  98. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  99. timer:sleep(100),
  100. Pid = get_remote_pid_tls(Socket),
  101. ct_helper_error_h:ignore(Pid, gen, reply, 2),
  102. Pid ! {system, bad, get_state},
  103. {error, closed} = ssl:recv(Socket, 0, 1000),
  104. false = is_process_alive(Pid),
  105. ok.
  106. bad_system_from_ws(Config) ->
  107. doc("ws: Sending a system message with a bad From value results in a process crash."),
  108. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  109. [binary, {active, false}]),
  110. ok = gen_tcp:send(Socket,
  111. "GET /ws HTTP/1.1\r\n"
  112. "Host: localhost\r\n"
  113. "Connection: Upgrade\r\n"
  114. "Origin: http://localhost\r\n"
  115. "Sec-WebSocket-Version: 13\r\n"
  116. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  117. "Upgrade: websocket\r\n"
  118. "\r\n"),
  119. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  120. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  121. timer:sleep(100),
  122. Pid = get_remote_pid_tcp(Socket),
  123. ct_helper_error_h:ignore(Pid, gen, reply, 2),
  124. Pid ! {system, bad, get_state},
  125. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  126. false = is_process_alive(Pid),
  127. ok.
  128. bad_system_from_loop(Config) ->
  129. doc("loop: Sending a system message with a bad From value results in a process crash."),
  130. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  131. ok = gen_tcp:send(Socket,
  132. "GET /loop HTTP/1.1\r\n"
  133. "Host: localhost\r\n"
  134. "\r\n"),
  135. timer:sleep(100),
  136. SupPid = get_remote_pid_tcp(Socket),
  137. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  138. ct_helper_error_h:ignore(Pid, gen, reply, 2),
  139. Pid ! {system, bad, get_state},
  140. {ok, "HTTP/1.1 500 "} = gen_tcp:recv(Socket, 13, 1000),
  141. false = is_process_alive(Pid),
  142. ok.
  143. bad_system_message_h1(Config) ->
  144. doc("h1: Sending a system message with a bad Request value results in an error."),
  145. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  146. timer:sleep(100),
  147. Pid = get_remote_pid_tcp(Socket),
  148. Ref = make_ref(),
  149. Pid ! {system, {self(), Ref}, hello},
  150. receive
  151. {Ref, {error, {unknown_system_msg, hello}}} ->
  152. ok
  153. after 1000 ->
  154. error(timeout)
  155. end.
  156. bad_system_message_h2(Config) ->
  157. doc("h2: Sending a system message with a bad Request value results in an error."),
  158. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  159. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  160. %% Skip the SETTINGS frame.
  161. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  162. timer:sleep(100),
  163. Pid = get_remote_pid_tls(Socket),
  164. Ref = make_ref(),
  165. Pid ! {system, {self(), Ref}, hello},
  166. receive
  167. {Ref, {error, {unknown_system_msg, hello}}} ->
  168. ok
  169. after 1000 ->
  170. error(timeout)
  171. end.
  172. bad_system_message_ws(Config) ->
  173. doc("ws: Sending a system message with a bad Request value results in an error."),
  174. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  175. [binary, {active, false}]),
  176. ok = gen_tcp:send(Socket,
  177. "GET /ws HTTP/1.1\r\n"
  178. "Host: localhost\r\n"
  179. "Connection: Upgrade\r\n"
  180. "Origin: http://localhost\r\n"
  181. "Sec-WebSocket-Version: 13\r\n"
  182. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  183. "Upgrade: websocket\r\n"
  184. "\r\n"),
  185. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  186. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  187. timer:sleep(100),
  188. Pid = get_remote_pid_tcp(Socket),
  189. Ref = make_ref(),
  190. Pid ! {system, {self(), Ref}, hello},
  191. receive
  192. {Ref, {error, {unknown_system_msg, hello}}} ->
  193. ok
  194. after 1000 ->
  195. error(timeout)
  196. end.
  197. bad_system_message_loop(Config) ->
  198. doc("loop: Sending a system message with a bad Request value results in an error."),
  199. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  200. ok = gen_tcp:send(Socket,
  201. "GET /loop HTTP/1.1\r\n"
  202. "Host: localhost\r\n"
  203. "\r\n"),
  204. timer:sleep(100),
  205. SupPid = get_remote_pid_tcp(Socket),
  206. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  207. Ref = make_ref(),
  208. Pid ! {system, {self(), Ref}, hello},
  209. receive
  210. {Ref, {error, {unknown_system_msg, hello}}} ->
  211. ok
  212. after 1000 ->
  213. error(timeout)
  214. end.
  215. good_system_message_h1(Config) ->
  216. doc("h1: System messages are handled properly."),
  217. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  218. timer:sleep(100),
  219. Pid = get_remote_pid_tcp(Socket),
  220. Ref = make_ref(),
  221. Pid ! {system, {self(), Ref}, get_state},
  222. receive
  223. {Ref, Result} when element(1, Result) =/= error ->
  224. ok
  225. after 1000 ->
  226. error(timeout)
  227. end.
  228. good_system_message_h2(Config) ->
  229. doc("h2: System messages are handled properly."),
  230. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  231. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  232. %% Skip the SETTINGS frame.
  233. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  234. timer:sleep(100),
  235. Pid = get_remote_pid_tls(Socket),
  236. Ref = make_ref(),
  237. Pid ! {system, {self(), Ref}, get_state},
  238. receive
  239. {Ref, Result} when element(1, Result) =/= error ->
  240. ok
  241. after 1000 ->
  242. error(timeout)
  243. end.
  244. good_system_message_ws(Config) ->
  245. doc("ws: System messages are handled properly."),
  246. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  247. [binary, {active, false}]),
  248. ok = gen_tcp:send(Socket,
  249. "GET /ws HTTP/1.1\r\n"
  250. "Host: localhost\r\n"
  251. "Connection: Upgrade\r\n"
  252. "Origin: http://localhost\r\n"
  253. "Sec-WebSocket-Version: 13\r\n"
  254. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  255. "Upgrade: websocket\r\n"
  256. "\r\n"),
  257. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  258. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  259. timer:sleep(100),
  260. Pid = get_remote_pid_tcp(Socket),
  261. Ref = make_ref(),
  262. Pid ! {system, {self(), Ref}, get_state},
  263. receive
  264. {Ref, Result} when element(1, Result) =/= error ->
  265. ok
  266. after 1000 ->
  267. error(timeout)
  268. end.
  269. good_system_message_loop(Config) ->
  270. doc("loop: System messages are handled properly."),
  271. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  272. ok = gen_tcp:send(Socket,
  273. "GET /loop HTTP/1.1\r\n"
  274. "Host: localhost\r\n"
  275. "\r\n"),
  276. timer:sleep(100),
  277. SupPid = get_remote_pid_tcp(Socket),
  278. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  279. Ref = make_ref(),
  280. Pid ! {system, {self(), Ref}, get_state},
  281. receive
  282. {Ref, Result} when element(1, Result) =/= error ->
  283. ok
  284. after 1000 ->
  285. error(timeout)
  286. end.
  287. %% 'EXIT'.
  288. %%
  289. %% Shutdown messages. If the process traps exits, it must be able
  290. %% to handle a shutdown request from its parent, the supervisor.
  291. %% The message {'EXIT', Parent, Reason} from the parent is an order
  292. %% to terminate. The process must terminate when this message is
  293. %% received, normally with the same Reason as Parent.
  294. trap_exit_parent_exit_h1(Config) ->
  295. doc("h1: A process trapping exits must stop when receiving "
  296. "an 'EXIT' message from its parent."),
  297. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  298. [{active, false}]),
  299. timer:sleep(100),
  300. Pid = get_remote_pid_tcp(Socket),
  301. Parent = get_parent_pid(Pid),
  302. Pid ! {'EXIT', Parent, {shutdown, ?MODULE}},
  303. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  304. true = is_process_down(Pid),
  305. ok.
  306. trap_exit_parent_exit_h2(Config) ->
  307. doc("h2: A process trapping exits must stop when receiving "
  308. "an 'EXIT' message from its parent."),
  309. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  310. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  311. %% Skip the SETTINGS frame.
  312. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  313. timer:sleep(100),
  314. Pid = get_remote_pid_tls(Socket),
  315. Parent = get_parent_pid(Pid),
  316. Pid ! {'EXIT', Parent, {shutdown, ?MODULE}},
  317. {error, closed} = ssl:recv(Socket, 0, 1000),
  318. true = is_process_down(Pid),
  319. ok.
  320. trap_exit_parent_exit_ws(Config) ->
  321. doc("ws: A process trapping exits must stop when receiving "
  322. "an 'EXIT' message from its parent."),
  323. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  324. [binary, {active, false}]),
  325. ok = gen_tcp:send(Socket,
  326. "GET /ws HTTP/1.1\r\n"
  327. "Host: localhost\r\n"
  328. "Connection: Upgrade\r\n"
  329. "Origin: http://localhost\r\n"
  330. "Sec-WebSocket-Version: 13\r\n"
  331. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  332. "Upgrade: websocket\r\n"
  333. "\r\n"),
  334. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  335. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  336. timer:sleep(100),
  337. Pid = get_remote_pid_tcp(Socket),
  338. Parent = get_parent_pid(Pid),
  339. Pid ! {'EXIT', Parent, {shutdown, ?MODULE}},
  340. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  341. true = is_process_down(Pid),
  342. ok.
  343. trap_exit_parent_exit_loop(Config) ->
  344. doc("loop: A process trapping exits must stop when receiving "
  345. "an 'EXIT' message from its parent."),
  346. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  347. ok = gen_tcp:send(Socket,
  348. "GET /loop HTTP/1.1\r\n"
  349. "Host: localhost\r\n"
  350. "\r\n"),
  351. timer:sleep(100),
  352. Parent = get_remote_pid_tcp(Socket),
  353. [{_, Pid, _, _}] = supervisor:which_children(Parent),
  354. Pid ! {'EXIT', Parent, {shutdown, ?MODULE}},
  355. %% We exit normally but didn't send a response.
  356. {ok, "HTTP/1.1 204 "} = gen_tcp:recv(Socket, 13, 1000),
  357. true = is_process_down(Pid),
  358. ok.
  359. trap_exit_other_exit_h1(Config) ->
  360. doc("h1: A process trapping exits must ignore "
  361. "'EXIT' messages from unknown processes."),
  362. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  363. [{active, false}]),
  364. timer:sleep(100),
  365. Pid = get_remote_pid_tcp(Socket),
  366. Pid ! {'EXIT', self(), {shutdown, ?MODULE}},
  367. ok = gen_tcp:send(Socket,
  368. "GET / HTTP/1.1\r\n"
  369. "Host: localhost\r\n"
  370. "\r\n"),
  371. {ok, "HTTP/1.1 200 "} = gen_tcp:recv(Socket, 13, 1000),
  372. true = is_process_alive(Pid),
  373. ok.
  374. trap_exit_other_exit_h2(Config) ->
  375. doc("h2: A process trapping exits must ignore "
  376. "'EXIT' messages from unknown processes."),
  377. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  378. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  379. do_http2_handshake(Socket),
  380. Pid = get_remote_pid_tls(Socket),
  381. Pid ! {'EXIT', self(), {shutdown, ?MODULE}},
  382. %% Send a HEADERS frame as a request.
  383. {HeadersBlock, _} = cow_hpack:encode([
  384. {<<":method">>, <<"GET">>},
  385. {<<":scheme">>, <<"https">>},
  386. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  387. {<<":path">>, <<"/">>}
  388. ]),
  389. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  390. %% Receive a HEADERS frame as a response.
  391. {ok, << _:24, 1:8, _:40 >>} = ssl:recv(Socket, 9, 6000),
  392. true = is_process_alive(Pid),
  393. ok.
  394. trap_exit_other_exit_ws(Config) ->
  395. doc("ws: A process trapping exits must ignore "
  396. "'EXIT' messages from unknown processes."),
  397. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  398. [binary, {active, false}]),
  399. ok = gen_tcp:send(Socket,
  400. "GET /ws HTTP/1.1\r\n"
  401. "Host: localhost\r\n"
  402. "Connection: Upgrade\r\n"
  403. "Origin: http://localhost\r\n"
  404. "Sec-WebSocket-Version: 13\r\n"
  405. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  406. "Upgrade: websocket\r\n"
  407. "\r\n"),
  408. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  409. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  410. timer:sleep(100),
  411. Pid = get_remote_pid_tcp(Socket),
  412. Pid ! {'EXIT', self(), {shutdown, ?MODULE}},
  413. %% The process stays alive.
  414. {error, timeout} = gen_tcp:recv(Socket, 0, 1000),
  415. true = is_process_alive(Pid),
  416. ok.
  417. trap_exit_other_exit_loop(Config) ->
  418. doc("loop: A process trapping exits must ignore "
  419. "'EXIT' messages from unknown processes."),
  420. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  421. ok = gen_tcp:send(Socket,
  422. "GET /loop HTTP/1.1\r\n"
  423. "Host: localhost\r\n"
  424. "\r\n"),
  425. timer:sleep(100),
  426. Parent = get_remote_pid_tcp(Socket),
  427. [{_, Pid, _, _}] = supervisor:which_children(Parent),
  428. Pid ! {'EXIT', self(), {shutdown, ?MODULE}},
  429. %% The process stays alive.
  430. {ok, "HTTP/1.1 299 "} = gen_tcp:recv(Socket, 13, 1000),
  431. true = is_process_alive(Pid),
  432. ok.
  433. %% get_modules.
  434. %%
  435. %% If the modules used to implement the process change dynamically
  436. %% during runtime, the process must understand one more message.
  437. %% An example is the gen_event processes. The message is
  438. %% {_Label, {From, Ref}, get_modules}. The reply to this message is
  439. %% From ! {Ref, Modules}, where Modules is a list of the currently
  440. %% active modules in the process.
  441. %%
  442. %% For example:
  443. %%
  444. %% 1> application:start(sasl).
  445. %% ok
  446. %% 2> gen:call(alarm_handler, self(), get_modules).
  447. %% {ok,[alarm_handler]}
  448. %% 3> whereis(alarm_handler) ! {'$gen', {self(), make_ref()}, get_modules}.
  449. %% {'$gen',{<0.61.0>,#Ref<0.2900144977.374865921.142102>},
  450. %% get_modules}
  451. %% 4> flush().
  452. %% Shell got {#Ref<0.2900144977.374865921.142102>,[alarm_handler]}
  453. %%
  454. %% Cowboy's connection processes change dynamically: it starts with
  455. %% cowboy_clear or cowboy_tls, then becomes cowboy_http or cowboy_http2
  456. %% and may then become or involve cowboy_websocket. On top of that
  457. %% it has various callback modules in the form of stream handlers.
  458. %% @todo
  459. %get_modules_h1(Config) ->
  460. %get_modules_h2(Config) ->
  461. %get_modules_ws(Config) ->
  462. %get_modules_loop(Config) ->
  463. %% @todo On top of this we will want to make the supervisor calls
  464. %% in ranch_conns_sup return dynamic instead of a list of modules.
  465. %% sys:change_code/4,5.
  466. %%
  467. %% We do not actually change the module code, we just ensure that
  468. %% calling this function does not crash the process. The function
  469. %% Module:system_code_change/4 will be called within the process.
  470. sys_change_code_h1(Config) ->
  471. doc("h1: The sys:change_code/4 function works as expected."),
  472. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  473. timer:sleep(100),
  474. Pid = get_remote_pid_tcp(Socket),
  475. ok = sys:suspend(Pid),
  476. ok = gen_tcp:send(Socket,
  477. "GET / HTTP/1.1\r\n"
  478. "Host: localhost\r\n"
  479. "\r\n"),
  480. {error, timeout} = gen_tcp:recv(Socket, 13, 500),
  481. ok = sys:change_code(Pid, cowboy_http, undefined, undefined),
  482. ok = sys:resume(Pid),
  483. {ok, "HTTP/1.1 200 "} = gen_tcp:recv(Socket, 13, 500),
  484. ok.
  485. sys_change_code_h2(Config) ->
  486. doc("h2: The sys:change_code/4 function works as expected."),
  487. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  488. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  489. do_http2_handshake(Socket),
  490. Pid = get_remote_pid_tls(Socket),
  491. %% Suspend the process and try to get a request in. The
  492. %% response will not come back until we resume the process.
  493. ok = sys:suspend(Pid),
  494. {HeadersBlock, _} = cow_hpack:encode([
  495. {<<":method">>, <<"GET">>},
  496. {<<":scheme">>, <<"http">>},
  497. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  498. {<<":path">>, <<"/">>}
  499. ]),
  500. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  501. %% Receive a HEADERS frame as a response.
  502. {error, timeout} = ssl:recv(Socket, 9, 500),
  503. ok = sys:change_code(Pid, cowboy_http2, undefined, undefined),
  504. ok = sys:resume(Pid),
  505. {ok, << _:24, 1:8, _:40 >>} = ssl:recv(Socket, 9, 6000),
  506. ok.
  507. sys_change_code_ws(Config) ->
  508. doc("ws: The sys:change_code/4 function works as expected."),
  509. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  510. [binary, {active, false}]),
  511. ok = gen_tcp:send(Socket,
  512. "GET /ws HTTP/1.1\r\n"
  513. "Host: localhost\r\n"
  514. "Connection: Upgrade\r\n"
  515. "Origin: http://localhost\r\n"
  516. "Sec-WebSocket-Version: 13\r\n"
  517. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  518. "Upgrade: websocket\r\n"
  519. "\r\n"),
  520. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  521. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  522. timer:sleep(100),
  523. Pid = get_remote_pid_tcp(Socket),
  524. ok = sys:suspend(Pid),
  525. Mask = 16#37fa213d,
  526. MaskedHello = ws_SUITE:do_mask(<<"Hello">>, Mask, <<>>),
  527. ok = gen_tcp:send(Socket, << 1:1, 0:3, 1:4, 1:1, 5:7, Mask:32, MaskedHello/binary >>),
  528. {error, timeout} = gen_tcp:recv(Socket, 0, 500),
  529. ok = sys:change_code(Pid, cowboy_websocket, undefined, undefined),
  530. ok = sys:resume(Pid),
  531. {ok, << 1:1, 0:3, 1:4, 0:1, 5:7, "Hello" >>} = gen_tcp:recv(Socket, 0, 6000),
  532. ok.
  533. sys_change_code_loop(Config) ->
  534. doc("loop: The sys:change_code/4 function works as expected."),
  535. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  536. ok = gen_tcp:send(Socket,
  537. "GET /loop HTTP/1.1\r\n"
  538. "Host: localhost\r\n"
  539. "\r\n"),
  540. timer:sleep(100),
  541. SupPid = get_remote_pid_tcp(Socket),
  542. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  543. %% The process sends a response 500ms after initializing.
  544. %% We expect to not receive it until we resume it.
  545. ok = sys:suspend(Pid),
  546. {error, timeout} = gen_tcp:recv(Socket, 13, 1000),
  547. ok = sys:change_code(Pid, cowboy_loop, undefined, undefined),
  548. ok = sys:resume(Pid),
  549. {ok, "HTTP/1.1 299 "} = gen_tcp:recv(Socket, 13, 500),
  550. ok.
  551. %% sys:get_state/1,2.
  552. %%
  553. %% None of the modules implement Module:system_get_state/1
  554. %% at this time so sys:get_state/1,2 returns the Misc value.
  555. sys_get_state_h1(Config) ->
  556. doc("h1: The sys:get_state/1 function works as expected."),
  557. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  558. timer:sleep(100),
  559. Pid = get_remote_pid_tcp(Socket),
  560. {State, Buffer} = sys:get_state(Pid),
  561. state = element(1, State),
  562. true = is_binary(Buffer),
  563. ok.
  564. sys_get_state_h2(Config) ->
  565. doc("h2: The sys:get_state/1 function works as expected."),
  566. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  567. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  568. %% Skip the SETTINGS frame.
  569. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  570. timer:sleep(100),
  571. Pid = get_remote_pid_tls(Socket),
  572. {State, Buffer} = sys:get_state(Pid),
  573. state = element(1, State),
  574. true = is_binary(Buffer),
  575. ok.
  576. sys_get_state_ws(Config) ->
  577. doc("ws: The sys:get_state/1 function works as expected."),
  578. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  579. [binary, {active, false}]),
  580. ok = gen_tcp:send(Socket,
  581. "GET /ws HTTP/1.1\r\n"
  582. "Host: localhost\r\n"
  583. "Connection: Upgrade\r\n"
  584. "Origin: http://localhost\r\n"
  585. "Sec-WebSocket-Version: 13\r\n"
  586. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  587. "Upgrade: websocket\r\n"
  588. "\r\n"),
  589. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  590. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  591. timer:sleep(100),
  592. Pid = get_remote_pid_tcp(Socket),
  593. {State, undefined, ParseState} = sys:get_state(Pid),
  594. state = element(1, State),
  595. case element(1, ParseState) of
  596. ps_header -> ok;
  597. ps_payload -> ok
  598. end.
  599. sys_get_state_loop(Config) ->
  600. doc("loop: The sys:get_state/1 function works as expected."),
  601. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  602. ok = gen_tcp:send(Socket,
  603. "GET /loop HTTP/1.1\r\n"
  604. "Host: localhost\r\n"
  605. "\r\n"),
  606. timer:sleep(100),
  607. SupPid = get_remote_pid_tcp(Socket),
  608. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  609. {Req, Env, long_polling_sys_h, undefined} = sys:get_state(Pid),
  610. #{pid := _, streamid := _} = Req,
  611. #{dispatch := _} = Env,
  612. ok.
  613. %% sys:get_status/1,2.
  614. sys_get_status_h1(Config) ->
  615. doc("h1: The sys:get_status/1 function works as expected."),
  616. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  617. timer:sleep(100),
  618. Pid = get_remote_pid_tcp(Socket),
  619. {status, Pid, {module, cowboy_http}, _} = sys:get_status(Pid),
  620. ok.
  621. sys_get_status_h2(Config) ->
  622. doc("h2: The sys:get_status/1 function works as expected."),
  623. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  624. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  625. %% Skip the SETTINGS frame.
  626. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  627. timer:sleep(100),
  628. Pid = get_remote_pid_tls(Socket),
  629. {status, Pid, {module, cowboy_http2}, _} = sys:get_status(Pid),
  630. ok.
  631. sys_get_status_ws(Config) ->
  632. doc("ws: The sys:get_status/1 function works as expected."),
  633. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  634. [binary, {active, false}]),
  635. ok = gen_tcp:send(Socket,
  636. "GET /ws HTTP/1.1\r\n"
  637. "Host: localhost\r\n"
  638. "Connection: Upgrade\r\n"
  639. "Origin: http://localhost\r\n"
  640. "Sec-WebSocket-Version: 13\r\n"
  641. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  642. "Upgrade: websocket\r\n"
  643. "\r\n"),
  644. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  645. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  646. timer:sleep(100),
  647. Pid = get_remote_pid_tcp(Socket),
  648. {status, Pid, {module, cowboy_websocket}, _} = sys:get_status(Pid),
  649. ok.
  650. sys_get_status_loop(Config) ->
  651. doc("loop: The sys:get_status/1 function works as expected."),
  652. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  653. ok = gen_tcp:send(Socket,
  654. "GET /loop HTTP/1.1\r\n"
  655. "Host: localhost\r\n"
  656. "\r\n"),
  657. timer:sleep(100),
  658. SupPid = get_remote_pid_tcp(Socket),
  659. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  660. {status, Pid, {module, cowboy_loop}, _} = sys:get_status(Pid),
  661. ok.
  662. %% sys:replace_state/2,3.
  663. %%
  664. %% None of the modules implement Module:system_replace_state/2
  665. %% at this time so sys:replace_state/2,3 handles the Misc value.
  666. %%
  667. %% We don't actually replace the state, we only care about
  668. %% whether the call executes as expected.
  669. sys_replace_state_h1(Config) ->
  670. doc("h1: The sys:replace_state/2 function works as expected."),
  671. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  672. timer:sleep(100),
  673. Pid = get_remote_pid_tcp(Socket),
  674. {State, Buffer} = sys:replace_state(Pid, fun(S) -> S end),
  675. state = element(1, State),
  676. true = is_binary(Buffer),
  677. ok.
  678. sys_replace_state_h2(Config) ->
  679. doc("h2: The sys:replace_state/2 function works as expected."),
  680. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  681. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  682. %% Skip the SETTINGS frame.
  683. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  684. timer:sleep(100),
  685. Pid = get_remote_pid_tls(Socket),
  686. {State, Buffer} = sys:replace_state(Pid, fun(S) -> S end),
  687. state = element(1, State),
  688. true = is_binary(Buffer),
  689. ok.
  690. sys_replace_state_ws(Config) ->
  691. doc("ws: The sys:replace_state/2 function works as expected."),
  692. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  693. [binary, {active, false}]),
  694. ok = gen_tcp:send(Socket,
  695. "GET /ws HTTP/1.1\r\n"
  696. "Host: localhost\r\n"
  697. "Connection: Upgrade\r\n"
  698. "Origin: http://localhost\r\n"
  699. "Sec-WebSocket-Version: 13\r\n"
  700. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  701. "Upgrade: websocket\r\n"
  702. "\r\n"),
  703. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  704. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  705. timer:sleep(100),
  706. Pid = get_remote_pid_tcp(Socket),
  707. {State, undefined, ParseState} = sys:replace_state(Pid, fun(S) -> S end),
  708. state = element(1, State),
  709. case element(1, ParseState) of
  710. ps_header -> ok;
  711. ps_payload -> ok
  712. end.
  713. sys_replace_state_loop(Config) ->
  714. doc("loop: The sys:replace_state/2 function works as expected."),
  715. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  716. ok = gen_tcp:send(Socket,
  717. "GET /loop HTTP/1.1\r\n"
  718. "Host: localhost\r\n"
  719. "\r\n"),
  720. timer:sleep(100),
  721. SupPid = get_remote_pid_tcp(Socket),
  722. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  723. {Req, Env, long_polling_sys_h, undefined} = sys:replace_state(Pid, fun(S) -> S end),
  724. #{pid := _, streamid := _} = Req,
  725. #{dispatch := _} = Env,
  726. ok.
  727. %% sys:suspend/1 and sys:resume/1.
  728. sys_suspend_and_resume_h1(Config) ->
  729. doc("h1: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  730. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  731. timer:sleep(100),
  732. Pid = get_remote_pid_tcp(Socket),
  733. ok = sys:suspend(Pid),
  734. ok = gen_tcp:send(Socket,
  735. "GET / HTTP/1.1\r\n"
  736. "Host: localhost\r\n"
  737. "\r\n"),
  738. {error, timeout} = gen_tcp:recv(Socket, 13, 500),
  739. ok = sys:resume(Pid),
  740. {ok, "HTTP/1.1 200 "} = gen_tcp:recv(Socket, 13, 500),
  741. ok.
  742. sys_suspend_and_resume_h2(Config) ->
  743. doc("h2: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  744. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  745. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  746. do_http2_handshake(Socket),
  747. Pid = get_remote_pid_tls(Socket),
  748. %% Suspend the process and try to get a request in. The
  749. %% response will not come back until we resume the process.
  750. ok = sys:suspend(Pid),
  751. {HeadersBlock, _} = cow_hpack:encode([
  752. {<<":method">>, <<"GET">>},
  753. {<<":scheme">>, <<"http">>},
  754. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  755. {<<":path">>, <<"/">>}
  756. ]),
  757. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  758. %% Receive a HEADERS frame as a response.
  759. {error, timeout} = ssl:recv(Socket, 9, 500),
  760. ok = sys:resume(Pid),
  761. {ok, << _:24, 1:8, _:40 >>} = ssl:recv(Socket, 9, 6000),
  762. ok.
  763. sys_suspend_and_resume_ws(Config) ->
  764. doc("ws: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  765. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  766. [binary, {active, false}]),
  767. ok = gen_tcp:send(Socket,
  768. "GET /ws HTTP/1.1\r\n"
  769. "Host: localhost\r\n"
  770. "Connection: Upgrade\r\n"
  771. "Origin: http://localhost\r\n"
  772. "Sec-WebSocket-Version: 13\r\n"
  773. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  774. "Upgrade: websocket\r\n"
  775. "\r\n"),
  776. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  777. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  778. timer:sleep(100),
  779. Pid = get_remote_pid_tcp(Socket),
  780. ok = sys:suspend(Pid),
  781. Mask = 16#37fa213d,
  782. MaskedHello = ws_SUITE:do_mask(<<"Hello">>, Mask, <<>>),
  783. ok = gen_tcp:send(Socket, << 1:1, 0:3, 1:4, 1:1, 5:7, Mask:32, MaskedHello/binary >>),
  784. {error, timeout} = gen_tcp:recv(Socket, 0, 500),
  785. ok = sys:resume(Pid),
  786. {ok, << 1:1, 0:3, 1:4, 0:1, 5:7, "Hello" >>} = gen_tcp:recv(Socket, 0, 6000),
  787. ok.
  788. sys_suspend_and_resume_loop(Config) ->
  789. doc("loop: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  790. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  791. ok = gen_tcp:send(Socket,
  792. "GET /loop HTTP/1.1\r\n"
  793. "Host: localhost\r\n"
  794. "\r\n"),
  795. timer:sleep(100),
  796. SupPid = get_remote_pid_tcp(Socket),
  797. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  798. %% The process sends a response 500ms after initializing.
  799. %% We expect to not receive it until we resume it.
  800. ok = sys:suspend(Pid),
  801. {error, timeout} = gen_tcp:recv(Socket, 13, 1000),
  802. ok = sys:resume(Pid),
  803. {ok, "HTTP/1.1 299 "} = gen_tcp:recv(Socket, 13, 500),
  804. ok.
  805. %% sys:terminate/2,3.
  806. %%
  807. %% The callback Module:system_terminate/4 is used in all cases.
  808. sys_terminate_h1(Config) ->
  809. doc("h1: The sys:terminate/2,3 function works as expected."),
  810. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  811. timer:sleep(100),
  812. Pid = get_remote_pid_tcp(Socket),
  813. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  814. {error, closed} = gen_tcp:recv(Socket, 0, 500),
  815. ok.
  816. sys_terminate_h2(Config) ->
  817. doc("h2: The sys:terminate/2,3 function works as expected."),
  818. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  819. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  820. %% Skip the SETTINGS frame.
  821. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  822. timer:sleep(100),
  823. Pid = get_remote_pid_tls(Socket),
  824. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  825. {error, closed} = ssl:recv(Socket, 0, 500),
  826. ok.
  827. sys_terminate_ws(Config) ->
  828. doc("ws: The sys:terminate/2,3 function works as expected."),
  829. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  830. [binary, {active, false}]),
  831. ok = gen_tcp:send(Socket,
  832. "GET /ws HTTP/1.1\r\n"
  833. "Host: localhost\r\n"
  834. "Connection: Upgrade\r\n"
  835. "Origin: http://localhost\r\n"
  836. "Sec-WebSocket-Version: 13\r\n"
  837. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  838. "Upgrade: websocket\r\n"
  839. "\r\n"),
  840. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  841. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  842. timer:sleep(100),
  843. Pid = get_remote_pid_tcp(Socket),
  844. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  845. {error, closed} = gen_tcp:recv(Socket, 0, 500),
  846. ok.
  847. sys_terminate_loop(Config) ->
  848. doc("loop: The sys:terminate/2,3 function works as expected."),
  849. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  850. ok = gen_tcp:send(Socket,
  851. "GET /loop HTTP/1.1\r\n"
  852. "Host: localhost\r\n"
  853. "\r\n"),
  854. timer:sleep(100),
  855. SupPid = get_remote_pid_tcp(Socket),
  856. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  857. %% We stop the process normally and therefore get a 204.
  858. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  859. {ok, "HTTP/1.1 204 "} = gen_tcp:recv(Socket, 13, 500),
  860. ok.
  861. %% @todo Debugging functionality from sys.
  862. %%
  863. %% The functions make references to a debug structure.
  864. %% The debug structure is a list of dbg_opt(), which is
  865. %% an internal data type used by the function handle_system_msg/6.
  866. %% No debugging is performed if it is an empty list.
  867. %%
  868. %% Cowboy currently does not implement sys debugging.
  869. %%
  870. %% The following functions are concerned:
  871. %%
  872. %% * sys:install/2,3
  873. %% * sys:log/2,3
  874. %% * sys:log_to_file/2,3
  875. %% * sys:no_debug/1,2
  876. %% * sys:remove/2,3
  877. %% * sys:statistics/2,3
  878. %% * sys:trace/2,3
  879. %% * call debug_options/1
  880. %% * call get_debug/3
  881. %% * call handle_debug/4
  882. %% * call print_log/1
  883. %% supervisor.
  884. %%
  885. %% The connection processes act as supervisors by default
  886. %% so they must handle the supervisor messages.
  887. %% supervisor:count_children/1.
  888. supervisor_count_children_h1(Config) ->
  889. doc("h1: The function supervisor:count_children/1 must work."),
  890. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  891. [{active, false}]),
  892. timer:sleep(100),
  893. Pid = get_remote_pid_tcp(Socket),
  894. %% No request was sent so there's no children.
  895. Counts1 = supervisor:count_children(Pid),
  896. 1 = proplists:get_value(specs, Counts1),
  897. 0 = proplists:get_value(active, Counts1),
  898. 0 = proplists:get_value(supervisors, Counts1),
  899. 0 = proplists:get_value(workers, Counts1),
  900. %% Send a request, observe that a children exists.
  901. ok = gen_tcp:send(Socket,
  902. "GET /loop HTTP/1.1\r\n"
  903. "Host: localhost\r\n"
  904. "\r\n"),
  905. timer:sleep(100),
  906. Counts2 = supervisor:count_children(Pid),
  907. 1 = proplists:get_value(specs, Counts2),
  908. 1 = proplists:get_value(active, Counts2),
  909. 0 = proplists:get_value(supervisors, Counts2),
  910. 1 = proplists:get_value(workers, Counts2),
  911. ok.
  912. supervisor_count_children_h2(Config) ->
  913. doc("h2: The function supervisor:count_children/1 must work."),
  914. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  915. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  916. do_http2_handshake(Socket),
  917. Pid = get_remote_pid_tls(Socket),
  918. %% No request was sent so there's no children.
  919. Counts1 = supervisor:count_children(Pid),
  920. 1 = proplists:get_value(specs, Counts1),
  921. 0 = proplists:get_value(active, Counts1),
  922. 0 = proplists:get_value(supervisors, Counts1),
  923. 0 = proplists:get_value(workers, Counts1),
  924. %% Send a request, observe that a children exists.
  925. {HeadersBlock, _} = cow_hpack:encode([
  926. {<<":method">>, <<"GET">>},
  927. {<<":scheme">>, <<"https">>},
  928. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  929. {<<":path">>, <<"/loop">>}
  930. ]),
  931. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  932. timer:sleep(100),
  933. Counts2 = supervisor:count_children(Pid),
  934. 1 = proplists:get_value(specs, Counts2),
  935. 1 = proplists:get_value(active, Counts2),
  936. 0 = proplists:get_value(supervisors, Counts2),
  937. 1 = proplists:get_value(workers, Counts2),
  938. ok.
  939. supervisor_count_children_ws(Config) ->
  940. doc("ws: The function supervisor:count_children/1 must work. "
  941. "Websocket connections never have children."),
  942. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  943. [binary, {active, false}]),
  944. ok = gen_tcp:send(Socket,
  945. "GET /ws HTTP/1.1\r\n"
  946. "Host: localhost\r\n"
  947. "Connection: Upgrade\r\n"
  948. "Origin: http://localhost\r\n"
  949. "Sec-WebSocket-Version: 13\r\n"
  950. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  951. "Upgrade: websocket\r\n"
  952. "\r\n"),
  953. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  954. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  955. timer:sleep(100),
  956. Pid = get_remote_pid_tcp(Socket),
  957. Counts = supervisor:count_children(Pid),
  958. 1 = proplists:get_value(specs, Counts),
  959. 0 = proplists:get_value(active, Counts),
  960. 0 = proplists:get_value(supervisors, Counts),
  961. 0 = proplists:get_value(workers, Counts),
  962. ok.
  963. %% supervisor:delete_child/2.
  964. supervisor_delete_child_not_found_h1(Config) ->
  965. doc("h1: The function supervisor:delete_child/2 must return {error, not_found}."),
  966. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  967. [{active, false}]),
  968. timer:sleep(100),
  969. Pid = get_remote_pid_tcp(Socket),
  970. %% When no children exist.
  971. {error, not_found} = supervisor:delete_child(Pid, cowboy_http),
  972. %% When a child exists.
  973. ok = gen_tcp:send(Socket,
  974. "GET /loop HTTP/1.1\r\n"
  975. "Host: localhost\r\n"
  976. "\r\n"),
  977. timer:sleep(100),
  978. {error, not_found} = supervisor:delete_child(Pid, cowboy_http),
  979. ok.
  980. supervisor_delete_child_not_found_h2(Config) ->
  981. doc("h2: The function supervisor:delete_child/2 must return {error, not_found}."),
  982. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  983. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  984. do_http2_handshake(Socket),
  985. Pid = get_remote_pid_tls(Socket),
  986. %% When no children exist.
  987. {error, not_found} = supervisor:delete_child(Pid, cowboy_http2),
  988. %% When a child exists.
  989. {HeadersBlock, _} = cow_hpack:encode([
  990. {<<":method">>, <<"GET">>},
  991. {<<":scheme">>, <<"https">>},
  992. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  993. {<<":path">>, <<"/loop">>}
  994. ]),
  995. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  996. timer:sleep(100),
  997. {error, not_found} = supervisor:delete_child(Pid, cowboy_http2),
  998. ok.
  999. supervisor_delete_child_not_found_ws(Config) ->
  1000. doc("ws: The function supervisor:delete_child/2 must return {error, not_found}."),
  1001. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1002. [binary, {active, false}]),
  1003. ok = gen_tcp:send(Socket,
  1004. "GET /ws HTTP/1.1\r\n"
  1005. "Host: localhost\r\n"
  1006. "Connection: Upgrade\r\n"
  1007. "Origin: http://localhost\r\n"
  1008. "Sec-WebSocket-Version: 13\r\n"
  1009. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1010. "Upgrade: websocket\r\n"
  1011. "\r\n"),
  1012. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1013. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1014. timer:sleep(100),
  1015. Pid = get_remote_pid_tcp(Socket),
  1016. {error, not_found} = supervisor:delete_child(Pid, cowboy_websocket),
  1017. ok.
  1018. %% supervisor:get_childspec/2.
  1019. supervisor_get_childspec_not_found_h1(Config) ->
  1020. doc("h1: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1021. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1022. [{active, false}]),
  1023. timer:sleep(100),
  1024. Pid = get_remote_pid_tcp(Socket),
  1025. %% When no children exist.
  1026. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http),
  1027. %% When a child exists.
  1028. ok = gen_tcp:send(Socket,
  1029. "GET /loop HTTP/1.1\r\n"
  1030. "Host: localhost\r\n"
  1031. "\r\n"),
  1032. timer:sleep(100),
  1033. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http),
  1034. ok.
  1035. supervisor_get_childspec_not_found_h2(Config) ->
  1036. doc("h2: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1037. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1038. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1039. do_http2_handshake(Socket),
  1040. Pid = get_remote_pid_tls(Socket),
  1041. %% When no children exist.
  1042. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http2),
  1043. %% When a child exists.
  1044. {HeadersBlock, _} = cow_hpack:encode([
  1045. {<<":method">>, <<"GET">>},
  1046. {<<":scheme">>, <<"https">>},
  1047. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1048. {<<":path">>, <<"/loop">>}
  1049. ]),
  1050. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1051. timer:sleep(100),
  1052. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http2),
  1053. ok.
  1054. supervisor_get_childspec_not_found_ws(Config) ->
  1055. doc("ws: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1056. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1057. [binary, {active, false}]),
  1058. ok = gen_tcp:send(Socket,
  1059. "GET /ws HTTP/1.1\r\n"
  1060. "Host: localhost\r\n"
  1061. "Connection: Upgrade\r\n"
  1062. "Origin: http://localhost\r\n"
  1063. "Sec-WebSocket-Version: 13\r\n"
  1064. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1065. "Upgrade: websocket\r\n"
  1066. "\r\n"),
  1067. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1068. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1069. timer:sleep(100),
  1070. Pid = get_remote_pid_tcp(Socket),
  1071. {error, not_found} = supervisor:get_childspec(Pid, cowboy_websocket),
  1072. ok.
  1073. %% supervisor:restart_child/2.
  1074. supervisor_restart_child_not_found_h1(Config) ->
  1075. doc("h1: The function supervisor:restart_child/2 must return {error, not_found}."),
  1076. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1077. [{active, false}]),
  1078. timer:sleep(100),
  1079. Pid = get_remote_pid_tcp(Socket),
  1080. %% When no children exist.
  1081. {error, not_found} = supervisor:restart_child(Pid, cowboy_http),
  1082. %% When a child exists.
  1083. ok = gen_tcp:send(Socket,
  1084. "GET /loop HTTP/1.1\r\n"
  1085. "Host: localhost\r\n"
  1086. "\r\n"),
  1087. timer:sleep(100),
  1088. {error, not_found} = supervisor:restart_child(Pid, cowboy_http),
  1089. ok.
  1090. supervisor_restart_child_not_found_h2(Config) ->
  1091. doc("h2: The function supervisor:restart_child/2 must return {error, not_found}."),
  1092. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1093. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1094. do_http2_handshake(Socket),
  1095. Pid = get_remote_pid_tls(Socket),
  1096. %% When no children exist.
  1097. {error, not_found} = supervisor:restart_child(Pid, cowboy_http2),
  1098. %% When a child exists.
  1099. {HeadersBlock, _} = cow_hpack:encode([
  1100. {<<":method">>, <<"GET">>},
  1101. {<<":scheme">>, <<"https">>},
  1102. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1103. {<<":path">>, <<"/loop">>}
  1104. ]),
  1105. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1106. timer:sleep(100),
  1107. {error, not_found} = supervisor:restart_child(Pid, cowboy_http2),
  1108. ok.
  1109. supervisor_restart_child_not_found_ws(Config) ->
  1110. doc("ws: The function supervisor:restart_child/2 must return {error, not_found}."),
  1111. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1112. [binary, {active, false}]),
  1113. ok = gen_tcp:send(Socket,
  1114. "GET /ws HTTP/1.1\r\n"
  1115. "Host: localhost\r\n"
  1116. "Connection: Upgrade\r\n"
  1117. "Origin: http://localhost\r\n"
  1118. "Sec-WebSocket-Version: 13\r\n"
  1119. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1120. "Upgrade: websocket\r\n"
  1121. "\r\n"),
  1122. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1123. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1124. timer:sleep(100),
  1125. Pid = get_remote_pid_tcp(Socket),
  1126. {error, not_found} = supervisor:restart_child(Pid, cowboy_websocket),
  1127. ok.
  1128. %% supervisor:start_child/2 must return {error, start_child_disabled}
  1129. supervisor_start_child_not_found_h1(Config) ->
  1130. doc("h1: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1131. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1132. [{active, false}]),
  1133. timer:sleep(100),
  1134. Pid = get_remote_pid_tcp(Socket),
  1135. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1136. id => error,
  1137. start => {error, error, []}
  1138. }),
  1139. ok.
  1140. supervisor_start_child_not_found_h2(Config) ->
  1141. doc("h2: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1142. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1143. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1144. do_http2_handshake(Socket),
  1145. Pid = get_remote_pid_tls(Socket),
  1146. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1147. id => error,
  1148. start => {error, error, []}
  1149. }),
  1150. ok.
  1151. supervisor_start_child_not_found_ws(Config) ->
  1152. doc("ws: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1153. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1154. [binary, {active, false}]),
  1155. ok = gen_tcp:send(Socket,
  1156. "GET /ws HTTP/1.1\r\n"
  1157. "Host: localhost\r\n"
  1158. "Connection: Upgrade\r\n"
  1159. "Origin: http://localhost\r\n"
  1160. "Sec-WebSocket-Version: 13\r\n"
  1161. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1162. "Upgrade: websocket\r\n"
  1163. "\r\n"),
  1164. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1165. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1166. timer:sleep(100),
  1167. Pid = get_remote_pid_tcp(Socket),
  1168. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1169. id => error,
  1170. start => {error, error, []}
  1171. }),
  1172. ok.
  1173. %% supervisor:terminate_child/2.
  1174. supervisor_terminate_child_not_found_h1(Config) ->
  1175. doc("h1: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1176. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1177. [{active, false}]),
  1178. timer:sleep(100),
  1179. Pid = get_remote_pid_tcp(Socket),
  1180. %% When no children exist.
  1181. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http),
  1182. %% When a child exists.
  1183. ok = gen_tcp:send(Socket,
  1184. "GET /loop HTTP/1.1\r\n"
  1185. "Host: localhost\r\n"
  1186. "\r\n"),
  1187. timer:sleep(100),
  1188. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http),
  1189. ok.
  1190. supervisor_terminate_child_not_found_h2(Config) ->
  1191. doc("h2: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1192. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1193. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1194. do_http2_handshake(Socket),
  1195. Pid = get_remote_pid_tls(Socket),
  1196. %% When no children exist.
  1197. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http2),
  1198. %% When a child exists.
  1199. {HeadersBlock, _} = cow_hpack:encode([
  1200. {<<":method">>, <<"GET">>},
  1201. {<<":scheme">>, <<"https">>},
  1202. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1203. {<<":path">>, <<"/loop">>}
  1204. ]),
  1205. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1206. timer:sleep(100),
  1207. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http2),
  1208. ok.
  1209. supervisor_terminate_child_not_found_ws(Config) ->
  1210. doc("ws: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1211. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1212. [binary, {active, false}]),
  1213. ok = gen_tcp:send(Socket,
  1214. "GET /ws HTTP/1.1\r\n"
  1215. "Host: localhost\r\n"
  1216. "Connection: Upgrade\r\n"
  1217. "Origin: http://localhost\r\n"
  1218. "Sec-WebSocket-Version: 13\r\n"
  1219. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1220. "Upgrade: websocket\r\n"
  1221. "\r\n"),
  1222. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1223. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1224. timer:sleep(100),
  1225. Pid = get_remote_pid_tcp(Socket),
  1226. {error, not_found} = supervisor:terminate_child(Pid, cowboy_websocket),
  1227. ok.
  1228. %% supervisor:which_children/1.
  1229. %%
  1230. %% @todo The list of modules returned is probably wrong. This will
  1231. %% need to be corrected when get_modules gets implemented.
  1232. supervisor_which_children_h1(Config) ->
  1233. doc("h1: The function supervisor:which_children/1 must work."),
  1234. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1235. [{active, false}]),
  1236. timer:sleep(100),
  1237. Pid = get_remote_pid_tcp(Socket),
  1238. %% No request was sent so there's no children.
  1239. [] = supervisor:which_children(Pid),
  1240. %% Send a request, observe that a children exists.
  1241. ok = gen_tcp:send(Socket,
  1242. "GET /loop HTTP/1.1\r\n"
  1243. "Host: localhost\r\n"
  1244. "\r\n"),
  1245. timer:sleep(100),
  1246. [{cowboy_http, Child, worker, [cowboy_http]}] = supervisor:which_children(Pid),
  1247. true = is_pid(Child),
  1248. ok.
  1249. supervisor_which_children_h2(Config) ->
  1250. doc("h2: The function supervisor:which_children/1 must work."),
  1251. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1252. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1253. do_http2_handshake(Socket),
  1254. Pid = get_remote_pid_tls(Socket),
  1255. %% No request was sent so there's no children.
  1256. [] = supervisor:which_children(Pid),
  1257. %% Send a request, observe that a children exists.
  1258. {HeadersBlock, _} = cow_hpack:encode([
  1259. {<<":method">>, <<"GET">>},
  1260. {<<":scheme">>, <<"https">>},
  1261. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1262. {<<":path">>, <<"/loop">>}
  1263. ]),
  1264. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1265. timer:sleep(100),
  1266. [{cowboy_http2, Child, worker, [cowboy_http2]}] = supervisor:which_children(Pid),
  1267. true = is_pid(Child),
  1268. ok.
  1269. supervisor_which_children_ws(Config) ->
  1270. doc("ws: The function supervisor:which_children/1 must work. "
  1271. "Websocket connections never have children."),
  1272. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1273. [binary, {active, false}]),
  1274. ok = gen_tcp:send(Socket,
  1275. "GET /ws HTTP/1.1\r\n"
  1276. "Host: localhost\r\n"
  1277. "Connection: Upgrade\r\n"
  1278. "Origin: http://localhost\r\n"
  1279. "Sec-WebSocket-Version: 13\r\n"
  1280. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1281. "Upgrade: websocket\r\n"
  1282. "\r\n"),
  1283. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1284. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1285. timer:sleep(100),
  1286. Pid = get_remote_pid_tcp(Socket),
  1287. [] = supervisor:which_children(Pid),
  1288. ok.
  1289. %% Internal.
  1290. do_http2_handshake(Socket) ->
  1291. ok = ssl:send(Socket, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"),
  1292. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  1293. ok = ssl:send(Socket, [cow_http2:settings(#{}), cow_http2:settings_ack()]),
  1294. {ok, << 0:24, 4:8, 1:8, 0:32 >>} = ssl:recv(Socket, 9, 1000),
  1295. ok.