sys_SUITE.erl 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  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 = sys:get_state(Pid),
  561. state = element(1, State),
  562. ok.
  563. sys_get_state_h2(Config) ->
  564. doc("h2: The sys:get_state/1 function works as expected."),
  565. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  566. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  567. %% Skip the SETTINGS frame.
  568. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  569. timer:sleep(100),
  570. Pid = get_remote_pid_tls(Socket),
  571. {State, Buffer} = sys:get_state(Pid),
  572. state = element(1, State),
  573. true = is_binary(Buffer),
  574. ok.
  575. sys_get_state_ws(Config) ->
  576. doc("ws: The sys:get_state/1 function works as expected."),
  577. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  578. [binary, {active, false}]),
  579. ok = gen_tcp:send(Socket,
  580. "GET /ws HTTP/1.1\r\n"
  581. "Host: localhost\r\n"
  582. "Connection: Upgrade\r\n"
  583. "Origin: http://localhost\r\n"
  584. "Sec-WebSocket-Version: 13\r\n"
  585. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  586. "Upgrade: websocket\r\n"
  587. "\r\n"),
  588. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  589. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  590. timer:sleep(100),
  591. Pid = get_remote_pid_tcp(Socket),
  592. {State, undefined, ParseState} = sys:get_state(Pid),
  593. state = element(1, State),
  594. case element(1, ParseState) of
  595. ps_header -> ok;
  596. ps_payload -> ok
  597. end.
  598. sys_get_state_loop(Config) ->
  599. doc("loop: The sys:get_state/1 function works as expected."),
  600. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  601. ok = gen_tcp:send(Socket,
  602. "GET /loop HTTP/1.1\r\n"
  603. "Host: localhost\r\n"
  604. "\r\n"),
  605. timer:sleep(100),
  606. SupPid = get_remote_pid_tcp(Socket),
  607. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  608. {Req, Env, long_polling_sys_h, undefined} = sys:get_state(Pid),
  609. #{pid := _, streamid := _} = Req,
  610. #{dispatch := _} = Env,
  611. ok.
  612. %% sys:get_status/1,2.
  613. sys_get_status_h1(Config) ->
  614. doc("h1: The sys:get_status/1 function works as expected."),
  615. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  616. timer:sleep(100),
  617. Pid = get_remote_pid_tcp(Socket),
  618. {status, Pid, {module, cowboy_http}, _} = sys:get_status(Pid),
  619. ok.
  620. sys_get_status_h2(Config) ->
  621. doc("h2: The sys:get_status/1 function works as expected."),
  622. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  623. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  624. %% Skip the SETTINGS frame.
  625. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  626. timer:sleep(100),
  627. Pid = get_remote_pid_tls(Socket),
  628. {status, Pid, {module, cowboy_http2}, _} = sys:get_status(Pid),
  629. ok.
  630. sys_get_status_ws(Config) ->
  631. doc("ws: The sys:get_status/1 function works as expected."),
  632. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  633. [binary, {active, false}]),
  634. ok = gen_tcp:send(Socket,
  635. "GET /ws HTTP/1.1\r\n"
  636. "Host: localhost\r\n"
  637. "Connection: Upgrade\r\n"
  638. "Origin: http://localhost\r\n"
  639. "Sec-WebSocket-Version: 13\r\n"
  640. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  641. "Upgrade: websocket\r\n"
  642. "\r\n"),
  643. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  644. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  645. timer:sleep(100),
  646. Pid = get_remote_pid_tcp(Socket),
  647. {status, Pid, {module, cowboy_websocket}, _} = sys:get_status(Pid),
  648. ok.
  649. sys_get_status_loop(Config) ->
  650. doc("loop: The sys:get_status/1 function works as expected."),
  651. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  652. ok = gen_tcp:send(Socket,
  653. "GET /loop HTTP/1.1\r\n"
  654. "Host: localhost\r\n"
  655. "\r\n"),
  656. timer:sleep(100),
  657. SupPid = get_remote_pid_tcp(Socket),
  658. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  659. {status, Pid, {module, cowboy_loop}, _} = sys:get_status(Pid),
  660. ok.
  661. %% sys:replace_state/2,3.
  662. %%
  663. %% None of the modules implement Module:system_replace_state/2
  664. %% at this time so sys:replace_state/2,3 handles the Misc value.
  665. %%
  666. %% We don't actually replace the state, we only care about
  667. %% whether the call executes as expected.
  668. sys_replace_state_h1(Config) ->
  669. doc("h1: The sys:replace_state/2 function works as expected."),
  670. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), []),
  671. timer:sleep(100),
  672. Pid = get_remote_pid_tcp(Socket),
  673. State = sys:replace_state(Pid, fun(S) -> S end),
  674. state = element(1, State),
  675. ok.
  676. sys_replace_state_h2(Config) ->
  677. doc("h2: The sys:replace_state/2 function works as expected."),
  678. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  679. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  680. %% Skip the SETTINGS frame.
  681. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  682. timer:sleep(100),
  683. Pid = get_remote_pid_tls(Socket),
  684. {State, Buffer} = sys:replace_state(Pid, fun(S) -> S end),
  685. state = element(1, State),
  686. true = is_binary(Buffer),
  687. ok.
  688. sys_replace_state_ws(Config) ->
  689. doc("ws: The sys:replace_state/2 function works as expected."),
  690. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  691. [binary, {active, false}]),
  692. ok = gen_tcp:send(Socket,
  693. "GET /ws HTTP/1.1\r\n"
  694. "Host: localhost\r\n"
  695. "Connection: Upgrade\r\n"
  696. "Origin: http://localhost\r\n"
  697. "Sec-WebSocket-Version: 13\r\n"
  698. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  699. "Upgrade: websocket\r\n"
  700. "\r\n"),
  701. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  702. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  703. timer:sleep(100),
  704. Pid = get_remote_pid_tcp(Socket),
  705. {State, undefined, ParseState} = sys:replace_state(Pid, fun(S) -> S end),
  706. state = element(1, State),
  707. case element(1, ParseState) of
  708. ps_header -> ok;
  709. ps_payload -> ok
  710. end.
  711. sys_replace_state_loop(Config) ->
  712. doc("loop: The sys:replace_state/2 function works as expected."),
  713. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  714. ok = gen_tcp:send(Socket,
  715. "GET /loop HTTP/1.1\r\n"
  716. "Host: localhost\r\n"
  717. "\r\n"),
  718. timer:sleep(100),
  719. SupPid = get_remote_pid_tcp(Socket),
  720. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  721. {Req, Env, long_polling_sys_h, undefined} = sys:replace_state(Pid, fun(S) -> S end),
  722. #{pid := _, streamid := _} = Req,
  723. #{dispatch := _} = Env,
  724. ok.
  725. %% sys:suspend/1 and sys:resume/1.
  726. sys_suspend_and_resume_h1(Config) ->
  727. doc("h1: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  728. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  729. timer:sleep(100),
  730. Pid = get_remote_pid_tcp(Socket),
  731. ok = sys:suspend(Pid),
  732. ok = gen_tcp:send(Socket,
  733. "GET / HTTP/1.1\r\n"
  734. "Host: localhost\r\n"
  735. "\r\n"),
  736. {error, timeout} = gen_tcp:recv(Socket, 13, 500),
  737. ok = sys:resume(Pid),
  738. {ok, "HTTP/1.1 200 "} = gen_tcp:recv(Socket, 13, 500),
  739. ok.
  740. sys_suspend_and_resume_h2(Config) ->
  741. doc("h2: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  742. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  743. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  744. do_http2_handshake(Socket),
  745. Pid = get_remote_pid_tls(Socket),
  746. %% Suspend the process and try to get a request in. The
  747. %% response will not come back until we resume the process.
  748. ok = sys:suspend(Pid),
  749. {HeadersBlock, _} = cow_hpack:encode([
  750. {<<":method">>, <<"GET">>},
  751. {<<":scheme">>, <<"http">>},
  752. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  753. {<<":path">>, <<"/">>}
  754. ]),
  755. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  756. %% Receive a HEADERS frame as a response.
  757. {error, timeout} = ssl:recv(Socket, 9, 500),
  758. ok = sys:resume(Pid),
  759. {ok, << _:24, 1:8, _:40 >>} = ssl:recv(Socket, 9, 6000),
  760. ok.
  761. sys_suspend_and_resume_ws(Config) ->
  762. doc("ws: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  763. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  764. [binary, {active, false}]),
  765. ok = gen_tcp:send(Socket,
  766. "GET /ws HTTP/1.1\r\n"
  767. "Host: localhost\r\n"
  768. "Connection: Upgrade\r\n"
  769. "Origin: http://localhost\r\n"
  770. "Sec-WebSocket-Version: 13\r\n"
  771. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  772. "Upgrade: websocket\r\n"
  773. "\r\n"),
  774. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  775. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  776. timer:sleep(100),
  777. Pid = get_remote_pid_tcp(Socket),
  778. ok = sys:suspend(Pid),
  779. Mask = 16#37fa213d,
  780. MaskedHello = ws_SUITE:do_mask(<<"Hello">>, Mask, <<>>),
  781. ok = gen_tcp:send(Socket, << 1:1, 0:3, 1:4, 1:1, 5:7, Mask:32, MaskedHello/binary >>),
  782. {error, timeout} = gen_tcp:recv(Socket, 0, 500),
  783. ok = sys:resume(Pid),
  784. {ok, << 1:1, 0:3, 1:4, 0:1, 5:7, "Hello" >>} = gen_tcp:recv(Socket, 0, 6000),
  785. ok.
  786. sys_suspend_and_resume_loop(Config) ->
  787. doc("loop: The sys:suspend/1 and sys:resume/1 functions work as expected."),
  788. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  789. ok = gen_tcp:send(Socket,
  790. "GET /loop HTTP/1.1\r\n"
  791. "Host: localhost\r\n"
  792. "\r\n"),
  793. timer:sleep(100),
  794. SupPid = get_remote_pid_tcp(Socket),
  795. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  796. %% The process sends a response 500ms after initializing.
  797. %% We expect to not receive it until we resume it.
  798. ok = sys:suspend(Pid),
  799. {error, timeout} = gen_tcp:recv(Socket, 13, 1000),
  800. ok = sys:resume(Pid),
  801. {ok, "HTTP/1.1 299 "} = gen_tcp:recv(Socket, 13, 500),
  802. ok.
  803. %% sys:terminate/2,3.
  804. %%
  805. %% The callback Module:system_terminate/4 is used in all cases.
  806. sys_terminate_h1(Config) ->
  807. doc("h1: The sys:terminate/2,3 function works as expected."),
  808. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  809. timer:sleep(100),
  810. Pid = get_remote_pid_tcp(Socket),
  811. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  812. {error, closed} = gen_tcp:recv(Socket, 0, 500),
  813. ok.
  814. sys_terminate_h2(Config) ->
  815. doc("h2: The sys:terminate/2,3 function works as expected."),
  816. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  817. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  818. %% Skip the SETTINGS frame.
  819. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  820. timer:sleep(100),
  821. Pid = get_remote_pid_tls(Socket),
  822. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  823. {error, closed} = ssl:recv(Socket, 0, 500),
  824. ok.
  825. sys_terminate_ws(Config) ->
  826. doc("ws: The sys:terminate/2,3 function works as expected."),
  827. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  828. [binary, {active, false}]),
  829. ok = gen_tcp:send(Socket,
  830. "GET /ws HTTP/1.1\r\n"
  831. "Host: localhost\r\n"
  832. "Connection: Upgrade\r\n"
  833. "Origin: http://localhost\r\n"
  834. "Sec-WebSocket-Version: 13\r\n"
  835. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  836. "Upgrade: websocket\r\n"
  837. "\r\n"),
  838. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  839. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  840. timer:sleep(100),
  841. Pid = get_remote_pid_tcp(Socket),
  842. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  843. {error, closed} = gen_tcp:recv(Socket, 0, 500),
  844. ok.
  845. sys_terminate_loop(Config) ->
  846. doc("loop: The sys:terminate/2,3 function works as expected."),
  847. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config), [{active, false}]),
  848. ok = gen_tcp:send(Socket,
  849. "GET /loop HTTP/1.1\r\n"
  850. "Host: localhost\r\n"
  851. "\r\n"),
  852. timer:sleep(100),
  853. SupPid = get_remote_pid_tcp(Socket),
  854. [{_, Pid, _, _}] = supervisor:which_children(SupPid),
  855. %% We stop the process normally and therefore get a 204.
  856. ok = sys:terminate(Pid, {shutdown, ?MODULE}),
  857. {ok, "HTTP/1.1 204 "} = gen_tcp:recv(Socket, 13, 500),
  858. ok.
  859. %% @todo Debugging functionality from sys.
  860. %%
  861. %% The functions make references to a debug structure.
  862. %% The debug structure is a list of dbg_opt(), which is
  863. %% an internal data type used by the function handle_system_msg/6.
  864. %% No debugging is performed if it is an empty list.
  865. %%
  866. %% Cowboy currently does not implement sys debugging.
  867. %%
  868. %% The following functions are concerned:
  869. %%
  870. %% * sys:install/2,3
  871. %% * sys:log/2,3
  872. %% * sys:log_to_file/2,3
  873. %% * sys:no_debug/1,2
  874. %% * sys:remove/2,3
  875. %% * sys:statistics/2,3
  876. %% * sys:trace/2,3
  877. %% * call debug_options/1
  878. %% * call get_debug/3
  879. %% * call handle_debug/4
  880. %% * call print_log/1
  881. %% supervisor.
  882. %%
  883. %% The connection processes act as supervisors by default
  884. %% so they must handle the supervisor messages.
  885. %% supervisor:count_children/1.
  886. supervisor_count_children_h1(Config) ->
  887. doc("h1: The function supervisor:count_children/1 must work."),
  888. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  889. [{active, false}]),
  890. timer:sleep(100),
  891. Pid = get_remote_pid_tcp(Socket),
  892. %% No request was sent so there's no children.
  893. Counts1 = supervisor:count_children(Pid),
  894. 1 = proplists:get_value(specs, Counts1),
  895. 0 = proplists:get_value(active, Counts1),
  896. 0 = proplists:get_value(supervisors, Counts1),
  897. 0 = proplists:get_value(workers, Counts1),
  898. %% Send a request, observe that a children exists.
  899. ok = gen_tcp:send(Socket,
  900. "GET /loop HTTP/1.1\r\n"
  901. "Host: localhost\r\n"
  902. "\r\n"),
  903. timer:sleep(100),
  904. Counts2 = supervisor:count_children(Pid),
  905. 1 = proplists:get_value(specs, Counts2),
  906. 1 = proplists:get_value(active, Counts2),
  907. 0 = proplists:get_value(supervisors, Counts2),
  908. 1 = proplists:get_value(workers, Counts2),
  909. ok.
  910. supervisor_count_children_h2(Config) ->
  911. doc("h2: The function supervisor:count_children/1 must work."),
  912. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  913. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  914. do_http2_handshake(Socket),
  915. Pid = get_remote_pid_tls(Socket),
  916. %% No request was sent so there's no children.
  917. Counts1 = supervisor:count_children(Pid),
  918. 1 = proplists:get_value(specs, Counts1),
  919. 0 = proplists:get_value(active, Counts1),
  920. 0 = proplists:get_value(supervisors, Counts1),
  921. 0 = proplists:get_value(workers, Counts1),
  922. %% Send a request, observe that a children exists.
  923. {HeadersBlock, _} = cow_hpack:encode([
  924. {<<":method">>, <<"GET">>},
  925. {<<":scheme">>, <<"https">>},
  926. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  927. {<<":path">>, <<"/loop">>}
  928. ]),
  929. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  930. timer:sleep(100),
  931. Counts2 = supervisor:count_children(Pid),
  932. 1 = proplists:get_value(specs, Counts2),
  933. 1 = proplists:get_value(active, Counts2),
  934. 0 = proplists:get_value(supervisors, Counts2),
  935. 1 = proplists:get_value(workers, Counts2),
  936. ok.
  937. supervisor_count_children_ws(Config) ->
  938. doc("ws: The function supervisor:count_children/1 must work. "
  939. "Websocket connections never have children."),
  940. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  941. [binary, {active, false}]),
  942. ok = gen_tcp:send(Socket,
  943. "GET /ws HTTP/1.1\r\n"
  944. "Host: localhost\r\n"
  945. "Connection: Upgrade\r\n"
  946. "Origin: http://localhost\r\n"
  947. "Sec-WebSocket-Version: 13\r\n"
  948. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  949. "Upgrade: websocket\r\n"
  950. "\r\n"),
  951. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  952. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  953. timer:sleep(100),
  954. Pid = get_remote_pid_tcp(Socket),
  955. Counts = supervisor:count_children(Pid),
  956. 1 = proplists:get_value(specs, Counts),
  957. 0 = proplists:get_value(active, Counts),
  958. 0 = proplists:get_value(supervisors, Counts),
  959. 0 = proplists:get_value(workers, Counts),
  960. ok.
  961. %% supervisor:delete_child/2.
  962. supervisor_delete_child_not_found_h1(Config) ->
  963. doc("h1: The function supervisor:delete_child/2 must return {error, not_found}."),
  964. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  965. [{active, false}]),
  966. timer:sleep(100),
  967. Pid = get_remote_pid_tcp(Socket),
  968. %% When no children exist.
  969. {error, not_found} = supervisor:delete_child(Pid, cowboy_http),
  970. %% When a child exists.
  971. ok = gen_tcp:send(Socket,
  972. "GET /loop HTTP/1.1\r\n"
  973. "Host: localhost\r\n"
  974. "\r\n"),
  975. timer:sleep(100),
  976. {error, not_found} = supervisor:delete_child(Pid, cowboy_http),
  977. ok.
  978. supervisor_delete_child_not_found_h2(Config) ->
  979. doc("h2: The function supervisor:delete_child/2 must return {error, not_found}."),
  980. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  981. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  982. do_http2_handshake(Socket),
  983. Pid = get_remote_pid_tls(Socket),
  984. %% When no children exist.
  985. {error, not_found} = supervisor:delete_child(Pid, cowboy_http2),
  986. %% When a child exists.
  987. {HeadersBlock, _} = cow_hpack:encode([
  988. {<<":method">>, <<"GET">>},
  989. {<<":scheme">>, <<"https">>},
  990. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  991. {<<":path">>, <<"/loop">>}
  992. ]),
  993. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  994. timer:sleep(100),
  995. {error, not_found} = supervisor:delete_child(Pid, cowboy_http2),
  996. ok.
  997. supervisor_delete_child_not_found_ws(Config) ->
  998. doc("ws: The function supervisor:delete_child/2 must return {error, not_found}."),
  999. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1000. [binary, {active, false}]),
  1001. ok = gen_tcp:send(Socket,
  1002. "GET /ws HTTP/1.1\r\n"
  1003. "Host: localhost\r\n"
  1004. "Connection: Upgrade\r\n"
  1005. "Origin: http://localhost\r\n"
  1006. "Sec-WebSocket-Version: 13\r\n"
  1007. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1008. "Upgrade: websocket\r\n"
  1009. "\r\n"),
  1010. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1011. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1012. timer:sleep(100),
  1013. Pid = get_remote_pid_tcp(Socket),
  1014. {error, not_found} = supervisor:delete_child(Pid, cowboy_websocket),
  1015. ok.
  1016. %% supervisor:get_childspec/2.
  1017. supervisor_get_childspec_not_found_h1(Config) ->
  1018. doc("h1: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1019. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1020. [{active, false}]),
  1021. timer:sleep(100),
  1022. Pid = get_remote_pid_tcp(Socket),
  1023. %% When no children exist.
  1024. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http),
  1025. %% When a child exists.
  1026. ok = gen_tcp:send(Socket,
  1027. "GET /loop HTTP/1.1\r\n"
  1028. "Host: localhost\r\n"
  1029. "\r\n"),
  1030. timer:sleep(100),
  1031. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http),
  1032. ok.
  1033. supervisor_get_childspec_not_found_h2(Config) ->
  1034. doc("h2: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1035. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1036. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1037. do_http2_handshake(Socket),
  1038. Pid = get_remote_pid_tls(Socket),
  1039. %% When no children exist.
  1040. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http2),
  1041. %% When a child exists.
  1042. {HeadersBlock, _} = cow_hpack:encode([
  1043. {<<":method">>, <<"GET">>},
  1044. {<<":scheme">>, <<"https">>},
  1045. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1046. {<<":path">>, <<"/loop">>}
  1047. ]),
  1048. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1049. timer:sleep(100),
  1050. {error, not_found} = supervisor:get_childspec(Pid, cowboy_http2),
  1051. ok.
  1052. supervisor_get_childspec_not_found_ws(Config) ->
  1053. doc("ws: The function supervisor:get_childspec/2 must return {error, not_found}."),
  1054. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1055. [binary, {active, false}]),
  1056. ok = gen_tcp:send(Socket,
  1057. "GET /ws HTTP/1.1\r\n"
  1058. "Host: localhost\r\n"
  1059. "Connection: Upgrade\r\n"
  1060. "Origin: http://localhost\r\n"
  1061. "Sec-WebSocket-Version: 13\r\n"
  1062. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1063. "Upgrade: websocket\r\n"
  1064. "\r\n"),
  1065. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1066. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1067. timer:sleep(100),
  1068. Pid = get_remote_pid_tcp(Socket),
  1069. {error, not_found} = supervisor:get_childspec(Pid, cowboy_websocket),
  1070. ok.
  1071. %% supervisor:restart_child/2.
  1072. supervisor_restart_child_not_found_h1(Config) ->
  1073. doc("h1: The function supervisor:restart_child/2 must return {error, not_found}."),
  1074. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1075. [{active, false}]),
  1076. timer:sleep(100),
  1077. Pid = get_remote_pid_tcp(Socket),
  1078. %% When no children exist.
  1079. {error, not_found} = supervisor:restart_child(Pid, cowboy_http),
  1080. %% When a child exists.
  1081. ok = gen_tcp:send(Socket,
  1082. "GET /loop HTTP/1.1\r\n"
  1083. "Host: localhost\r\n"
  1084. "\r\n"),
  1085. timer:sleep(100),
  1086. {error, not_found} = supervisor:restart_child(Pid, cowboy_http),
  1087. ok.
  1088. supervisor_restart_child_not_found_h2(Config) ->
  1089. doc("h2: The function supervisor:restart_child/2 must return {error, not_found}."),
  1090. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1091. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1092. do_http2_handshake(Socket),
  1093. Pid = get_remote_pid_tls(Socket),
  1094. %% When no children exist.
  1095. {error, not_found} = supervisor:restart_child(Pid, cowboy_http2),
  1096. %% When a child exists.
  1097. {HeadersBlock, _} = cow_hpack:encode([
  1098. {<<":method">>, <<"GET">>},
  1099. {<<":scheme">>, <<"https">>},
  1100. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1101. {<<":path">>, <<"/loop">>}
  1102. ]),
  1103. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1104. timer:sleep(100),
  1105. {error, not_found} = supervisor:restart_child(Pid, cowboy_http2),
  1106. ok.
  1107. supervisor_restart_child_not_found_ws(Config) ->
  1108. doc("ws: The function supervisor:restart_child/2 must return {error, not_found}."),
  1109. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1110. [binary, {active, false}]),
  1111. ok = gen_tcp:send(Socket,
  1112. "GET /ws HTTP/1.1\r\n"
  1113. "Host: localhost\r\n"
  1114. "Connection: Upgrade\r\n"
  1115. "Origin: http://localhost\r\n"
  1116. "Sec-WebSocket-Version: 13\r\n"
  1117. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1118. "Upgrade: websocket\r\n"
  1119. "\r\n"),
  1120. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1121. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1122. timer:sleep(100),
  1123. Pid = get_remote_pid_tcp(Socket),
  1124. {error, not_found} = supervisor:restart_child(Pid, cowboy_websocket),
  1125. ok.
  1126. %% supervisor:start_child/2 must return {error, start_child_disabled}
  1127. supervisor_start_child_not_found_h1(Config) ->
  1128. doc("h1: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1129. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1130. [{active, false}]),
  1131. timer:sleep(100),
  1132. Pid = get_remote_pid_tcp(Socket),
  1133. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1134. id => error,
  1135. start => {error, error, []}
  1136. }),
  1137. ok.
  1138. supervisor_start_child_not_found_h2(Config) ->
  1139. doc("h2: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1140. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1141. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1142. do_http2_handshake(Socket),
  1143. Pid = get_remote_pid_tls(Socket),
  1144. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1145. id => error,
  1146. start => {error, error, []}
  1147. }),
  1148. ok.
  1149. supervisor_start_child_not_found_ws(Config) ->
  1150. doc("ws: The function supervisor:start_child/2 must return {error, start_child_disabled}."),
  1151. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1152. [binary, {active, false}]),
  1153. ok = gen_tcp:send(Socket,
  1154. "GET /ws HTTP/1.1\r\n"
  1155. "Host: localhost\r\n"
  1156. "Connection: Upgrade\r\n"
  1157. "Origin: http://localhost\r\n"
  1158. "Sec-WebSocket-Version: 13\r\n"
  1159. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1160. "Upgrade: websocket\r\n"
  1161. "\r\n"),
  1162. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1163. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1164. timer:sleep(100),
  1165. Pid = get_remote_pid_tcp(Socket),
  1166. {error, start_child_disabled} = supervisor:start_child(Pid, #{
  1167. id => error,
  1168. start => {error, error, []}
  1169. }),
  1170. ok.
  1171. %% supervisor:terminate_child/2.
  1172. supervisor_terminate_child_not_found_h1(Config) ->
  1173. doc("h1: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1174. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1175. [{active, false}]),
  1176. timer:sleep(100),
  1177. Pid = get_remote_pid_tcp(Socket),
  1178. %% When no children exist.
  1179. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http),
  1180. %% When a child exists.
  1181. ok = gen_tcp:send(Socket,
  1182. "GET /loop HTTP/1.1\r\n"
  1183. "Host: localhost\r\n"
  1184. "\r\n"),
  1185. timer:sleep(100),
  1186. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http),
  1187. ok.
  1188. supervisor_terminate_child_not_found_h2(Config) ->
  1189. doc("h2: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1190. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1191. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1192. do_http2_handshake(Socket),
  1193. Pid = get_remote_pid_tls(Socket),
  1194. %% When no children exist.
  1195. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http2),
  1196. %% When a child exists.
  1197. {HeadersBlock, _} = cow_hpack:encode([
  1198. {<<":method">>, <<"GET">>},
  1199. {<<":scheme">>, <<"https">>},
  1200. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1201. {<<":path">>, <<"/loop">>}
  1202. ]),
  1203. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1204. timer:sleep(100),
  1205. {error, not_found} = supervisor:terminate_child(Pid, cowboy_http2),
  1206. ok.
  1207. supervisor_terminate_child_not_found_ws(Config) ->
  1208. doc("ws: The function supervisor:terminate_child/2 must return {error, not_found}."),
  1209. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1210. [binary, {active, false}]),
  1211. ok = gen_tcp:send(Socket,
  1212. "GET /ws HTTP/1.1\r\n"
  1213. "Host: localhost\r\n"
  1214. "Connection: Upgrade\r\n"
  1215. "Origin: http://localhost\r\n"
  1216. "Sec-WebSocket-Version: 13\r\n"
  1217. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1218. "Upgrade: websocket\r\n"
  1219. "\r\n"),
  1220. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1221. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1222. timer:sleep(100),
  1223. Pid = get_remote_pid_tcp(Socket),
  1224. {error, not_found} = supervisor:terminate_child(Pid, cowboy_websocket),
  1225. ok.
  1226. %% supervisor:which_children/1.
  1227. %%
  1228. %% @todo The list of modules returned is probably wrong. This will
  1229. %% need to be corrected when get_modules gets implemented.
  1230. supervisor_which_children_h1(Config) ->
  1231. doc("h1: The function supervisor:which_children/1 must work."),
  1232. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1233. [{active, false}]),
  1234. timer:sleep(100),
  1235. Pid = get_remote_pid_tcp(Socket),
  1236. %% No request was sent so there's no children.
  1237. [] = supervisor:which_children(Pid),
  1238. %% Send a request, observe that a children exists.
  1239. ok = gen_tcp:send(Socket,
  1240. "GET /loop HTTP/1.1\r\n"
  1241. "Host: localhost\r\n"
  1242. "\r\n"),
  1243. timer:sleep(100),
  1244. [{cowboy_http, Child, worker, [cowboy_http]}] = supervisor:which_children(Pid),
  1245. true = is_pid(Child),
  1246. ok.
  1247. supervisor_which_children_h2(Config) ->
  1248. doc("h2: The function supervisor:which_children/1 must work."),
  1249. {ok, Socket} = ssl:connect("localhost", config(tls_port, Config),
  1250. [{active, false}, binary, {alpn_advertised_protocols, [<<"h2">>]}]),
  1251. do_http2_handshake(Socket),
  1252. Pid = get_remote_pid_tls(Socket),
  1253. %% No request was sent so there's no children.
  1254. [] = supervisor:which_children(Pid),
  1255. %% Send a request, observe that a children exists.
  1256. {HeadersBlock, _} = cow_hpack:encode([
  1257. {<<":method">>, <<"GET">>},
  1258. {<<":scheme">>, <<"https">>},
  1259. {<<":authority">>, <<"localhost">>}, %% @todo Correct port number.
  1260. {<<":path">>, <<"/loop">>}
  1261. ]),
  1262. ok = ssl:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
  1263. timer:sleep(100),
  1264. [{cowboy_http2, Child, worker, [cowboy_http2]}] = supervisor:which_children(Pid),
  1265. true = is_pid(Child),
  1266. ok.
  1267. supervisor_which_children_ws(Config) ->
  1268. doc("ws: The function supervisor:which_children/1 must work. "
  1269. "Websocket connections never have children."),
  1270. {ok, Socket} = gen_tcp:connect("localhost", config(clear_port, Config),
  1271. [binary, {active, false}]),
  1272. ok = gen_tcp:send(Socket,
  1273. "GET /ws HTTP/1.1\r\n"
  1274. "Host: localhost\r\n"
  1275. "Connection: Upgrade\r\n"
  1276. "Origin: http://localhost\r\n"
  1277. "Sec-WebSocket-Version: 13\r\n"
  1278. "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
  1279. "Upgrade: websocket\r\n"
  1280. "\r\n"),
  1281. {ok, Handshake} = gen_tcp:recv(Socket, 0, 5000),
  1282. {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []),
  1283. timer:sleep(100),
  1284. Pid = get_remote_pid_tcp(Socket),
  1285. [] = supervisor:which_children(Pid),
  1286. ok.
  1287. %% Internal.
  1288. do_http2_handshake(Socket) ->
  1289. ok = ssl:send(Socket, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"),
  1290. {ok, <<_,_,_,4,_/bits>>} = ssl:recv(Socket, 0, 1000),
  1291. ok = ssl:send(Socket, [cow_http2:settings(#{}), cow_http2:settings_ack()]),
  1292. {ok, << 0:24, 4:8, 1:8, 0:32 >>} = ssl:recv(Socket, 9, 1000),
  1293. ok.