sys_SUITE.erl 51 KB

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