rfc7231_SUITE.erl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. %% Copyright (c) 2017, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(rfc7231_SUITE).
  15. -compile(export_all).
  16. -compile(nowarn_export_all).
  17. -import(ct_helper, [config/2]).
  18. -import(ct_helper, [doc/1]).
  19. -import(cowboy_test, [gun_open/1]).
  20. -import(cowboy_test, [raw_open/1]).
  21. -import(cowboy_test, [raw_send/2]).
  22. -import(cowboy_test, [raw_recv_head/1]).
  23. -import(cowboy_test, [raw_recv/3]).
  24. all() ->
  25. cowboy_test:common_all().
  26. groups() ->
  27. cowboy_test:common_groups(ct_helper:all(?MODULE)).
  28. init_per_group(Name, Config) ->
  29. cowboy_test:init_common_groups(Name, Config, ?MODULE).
  30. end_per_group(Name, _) ->
  31. cowboy:stop_listener(Name).
  32. init_dispatch(_) ->
  33. cowboy_router:compile([{"[...]", [
  34. {"*", asterisk_h, []},
  35. {"/", hello_h, []},
  36. {"/echo/:key", echo_h, []},
  37. {"/resp/:key[/:arg]", resp_h, []},
  38. {"/ws", ws_init_h, []}
  39. ]}]).
  40. %% @todo The documentation should list what methods, headers and status codes
  41. %% are handled automatically so users can know what befalls to them to implement.
  42. %% Methods.
  43. method_get(Config) ->
  44. doc("The GET method is accepted. (RFC7231 4.3.1)"),
  45. ConnPid = gun_open(Config),
  46. Ref = gun:get(ConnPid, "/", [
  47. {<<"accept-encoding">>, <<"gzip">>}
  48. ]),
  49. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  50. {ok, <<"Hello world!">>} = gun:await_body(ConnPid, Ref),
  51. ok.
  52. method_head(Config) ->
  53. doc("The HEAD method is accepted. (RFC7231 4.3.2)"),
  54. ConnPid = gun_open(Config),
  55. Ref = gun:head(ConnPid, "/", [
  56. {<<"accept-encoding">>, <<"gzip">>}
  57. ]),
  58. {response, fin, 200, _} = gun:await(ConnPid, Ref),
  59. ok.
  60. method_head_same_resp_headers_as_get(Config) ->
  61. doc("Responses to HEAD should return the same headers as GET. (RFC7231 4.3.2)"),
  62. ConnPid = gun_open(Config),
  63. Ref1 = gun:get(ConnPid, "/", [
  64. {<<"accept-encoding">>, <<"gzip">>}
  65. ]),
  66. {response, nofin, 200, Headers1} = gun:await(ConnPid, Ref1),
  67. {ok, <<"Hello world!">>} = gun:await_body(ConnPid, Ref1),
  68. Ref2 = gun:head(ConnPid, "/", [
  69. {<<"accept-encoding">>, <<"gzip">>}
  70. ]),
  71. {response, fin, 200, Headers2} = gun:await(ConnPid, Ref2),
  72. %% We remove the date header since the date might have changed between requests.
  73. Headers = lists:keydelete(<<"date">>, 1, Headers1),
  74. Headers = lists:keydelete(<<"date">>, 1, Headers2),
  75. ok.
  76. method_head_same_resp_headers_as_get_stream_reply(Config) ->
  77. doc("Responses to HEAD should return the same headers as GET. (RFC7231 4.3.2)"),
  78. ConnPid = gun_open(Config),
  79. Ref1 = gun:get(ConnPid, "/resp/stream_reply2/200", [
  80. {<<"accept-encoding">>, <<"gzip">>}
  81. ]),
  82. {response, nofin, 200, Headers1} = gun:await(ConnPid, Ref1),
  83. {ok, _} = gun:await_body(ConnPid, Ref1),
  84. Ref2 = gun:head(ConnPid, "/resp/stream_reply2/200", [
  85. {<<"accept-encoding">>, <<"gzip">>}
  86. ]),
  87. {response, fin, 200, Headers2} = gun:await(ConnPid, Ref2),
  88. %% We remove the date header since the date might have changed between requests.
  89. Headers = lists:keydelete(<<"date">>, 1, Headers1),
  90. Headers = lists:keydelete(<<"date">>, 1, Headers2),
  91. ok.
  92. method_post(Config) ->
  93. doc("The POST method is accepted. (RFC7231 4.3.3)"),
  94. ConnPid = gun_open(Config),
  95. Ref = gun:post(ConnPid, "/echo/read_body", [
  96. {<<"accept-encoding">>, <<"gzip">>},
  97. {<<"content-type">>, <<"application/x-www-form-urlencoded">>}
  98. ], <<"hello=world">>),
  99. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  100. {ok, <<"hello=world">>} = gun:await_body(ConnPid, Ref),
  101. ok.
  102. method_put(Config) ->
  103. doc("The PUT method is accepted. (RFC7231 4.3.4)"),
  104. ConnPid = gun_open(Config),
  105. Ref = gun:put(ConnPid, "/echo/read_body", [
  106. {<<"accept-encoding">>, <<"gzip">>},
  107. {<<"content-type">>, <<"application/x-www-form-urlencoded">>}
  108. ], <<"hello=world">>),
  109. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  110. {ok, <<"hello=world">>} = gun:await_body(ConnPid, Ref),
  111. ok.
  112. method_delete(Config) ->
  113. doc("The DELETE method is accepted. (RFC7231 4.3.5)"),
  114. ConnPid = gun_open(Config),
  115. Ref = gun:delete(ConnPid, "/echo/method", [
  116. {<<"accept-encoding">>, <<"gzip">>}
  117. ]),
  118. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  119. {ok, <<"DELETE">>} = gun:await_body(ConnPid, Ref),
  120. ok.
  121. method_connect(Config) ->
  122. doc("The CONNECT method is currently not implemented. (RFC7231 4.3.6)"),
  123. ConnPid = gun_open(Config),
  124. Ref = gun:request(ConnPid, <<"CONNECT">>, "localhost:8080", [
  125. {<<"accept-encoding">>, <<"gzip">>}
  126. ]),
  127. {response, fin, 501, _} = gun:await(ConnPid, Ref),
  128. ok.
  129. % A client sending a CONNECT request MUST send the authority form of
  130. % request-target (Section 5.3 of [RFC7230]); i.e., the request-target
  131. % consists of only the host name and port number of the tunnel
  132. % destination, separated by a colon.
  133. %
  134. % A server MUST NOT send any Transfer-Encoding or Content-Length header
  135. % fields in a 2xx (Successful) response to CONNECT. A client MUST
  136. % ignore any Content-Length or Transfer-Encoding header fields received
  137. % in a successful response to CONNECT.
  138. %
  139. % A payload within a CONNECT request message has no defined semantics;
  140. % sending a payload body on a CONNECT request might cause some existing
  141. % implementations to reject the request.
  142. method_options(Config) ->
  143. doc("The OPTIONS method is accepted. (RFC7231 4.3.7)"),
  144. ConnPid = gun_open(Config),
  145. Ref = gun:options(ConnPid, "/echo/method", [
  146. {<<"accept-encoding">>, <<"gzip">>}
  147. ]),
  148. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  149. {ok, <<"OPTIONS">>} = gun:await_body(ConnPid, Ref),
  150. ok.
  151. method_options_asterisk(Config) ->
  152. doc("The OPTIONS method is accepted with an asterisk. (RFC7231 4.3.7)"),
  153. ConnPid = gun_open(Config),
  154. Ref = gun:options(ConnPid, "*", [
  155. {<<"accept-encoding">>, <<"gzip">>},
  156. {<<"x-echo">>, <<"method">>}
  157. ]),
  158. {response, nofin, 200, _} = gun:await(ConnPid, Ref),
  159. {ok, <<"OPTIONS">>} = gun:await_body(ConnPid, Ref),
  160. ok.
  161. method_options_content_length_0(Config) ->
  162. doc("The OPTIONS method must set the content-length header "
  163. "to 0 when no body is returned. (RFC7231 4.3.7)"),
  164. ConnPid = gun_open(Config),
  165. Ref = gun:options(ConnPid, "*", [
  166. {<<"accept-encoding">>, <<"gzip">>}
  167. ]),
  168. {response, fin, 200, Headers} = gun:await(ConnPid, Ref),
  169. {_, <<"0">>} = lists:keyfind(<<"content-length">>, 1, Headers),
  170. ok.
  171. method_trace(Config) ->
  172. doc("The TRACE method is currently not implemented. (RFC7231 4.3.8)"),
  173. ConnPid = gun_open(Config),
  174. Ref = gun:request(ConnPid, <<"TRACE">>, "/", [
  175. {<<"accept-encoding">>, <<"gzip">>}
  176. ]),
  177. {response, fin, 501, _} = gun:await(ConnPid, Ref),
  178. ok.
  179. %% Request headers.
  180. %% @todo
  181. %% Status codes.
  182. http10_status_code_100(Config) ->
  183. case config(protocol, Config) of
  184. http ->
  185. doc("The 100 Continue status code must not "
  186. "be sent to HTTP/1.0 endpoints. (RFC7231 6.2)"),
  187. do_http10_status_code_1xx(100, Config);
  188. http2 ->
  189. status_code_100(Config)
  190. end.
  191. http10_status_code_101(Config) ->
  192. case config(protocol, Config) of
  193. http ->
  194. doc("The 101 Switching Protocols status code must not "
  195. "be sent to HTTP/1.0 endpoints. (RFC7231 6.2)"),
  196. do_http10_status_code_1xx(101, Config);
  197. http2 ->
  198. status_code_101(Config)
  199. end.
  200. do_http10_status_code_1xx(StatusCode, Config) ->
  201. ConnPid = gun_open([{http_opts, #{version => 'HTTP/1.0'}}|Config]),
  202. Ref = gun:get(ConnPid, "/resp/inform2/" ++ integer_to_list(StatusCode), [
  203. {<<"accept-encoding">>, <<"gzip">>}
  204. ]),
  205. {response, _, 200, _} = gun:await(ConnPid, Ref),
  206. ok.
  207. status_code_100(Config) ->
  208. doc("The 100 Continue status code can be sent. (RFC7231 6.2.1)"),
  209. ConnPid = gun_open(Config),
  210. Ref = gun:get(ConnPid, "/resp/inform2/100", [
  211. {<<"accept-encoding">>, <<"gzip">>}
  212. ]),
  213. {inform, 100, []} = gun:await(ConnPid, Ref),
  214. ok.
  215. status_code_101(Config) ->
  216. doc("The 101 Switching Protocols status code can be sent. (RFC7231 6.2.2)"),
  217. ConnPid = gun_open(Config),
  218. Ref = gun:get(ConnPid, "/resp/inform2/101", [
  219. {<<"accept-encoding">>, <<"gzip">>}
  220. ]),
  221. {inform, 101, []} = gun:await(ConnPid, Ref),
  222. ok.
  223. status_code_200(Config) ->
  224. doc("The 200 OK status code can be sent. (RFC7231 6.3.1)"),
  225. ConnPid = gun_open(Config),
  226. Ref = gun:get(ConnPid, "/resp/reply2/200", [
  227. {<<"accept-encoding">>, <<"gzip">>}
  228. ]),
  229. {response, _, 200, _} = gun:await(ConnPid, Ref),
  230. ok.
  231. status_code_201(Config) ->
  232. doc("The 201 Created status code can be sent. (RFC7231 6.3.2)"),
  233. ConnPid = gun_open(Config),
  234. Ref = gun:get(ConnPid, "/resp/reply2/201", [
  235. {<<"accept-encoding">>, <<"gzip">>}
  236. ]),
  237. {response, _, 201, _} = gun:await(ConnPid, Ref),
  238. ok.
  239. status_code_202(Config) ->
  240. doc("The 202 Accepted status code can be sent. (RFC7231 6.3.3)"),
  241. ConnPid = gun_open(Config),
  242. Ref = gun:get(ConnPid, "/resp/reply2/202", [
  243. {<<"accept-encoding">>, <<"gzip">>}
  244. ]),
  245. {response, _, 202, _} = gun:await(ConnPid, Ref),
  246. ok.
  247. status_code_203(Config) ->
  248. doc("The 203 Non-Authoritative Information status code can be sent. (RFC7231 6.3.4)"),
  249. ConnPid = gun_open(Config),
  250. Ref = gun:get(ConnPid, "/resp/reply2/203", [
  251. {<<"accept-encoding">>, <<"gzip">>}
  252. ]),
  253. {response, _, 203, _} = gun:await(ConnPid, Ref),
  254. ok.
  255. status_code_204(Config) ->
  256. doc("The 204 No Content status code can be sent. (RFC7231 6.3.5)"),
  257. ConnPid = gun_open(Config),
  258. Ref = gun:get(ConnPid, "/resp/reply2/204", [
  259. {<<"accept-encoding">>, <<"gzip">>}
  260. ]),
  261. {response, _, 204, _} = gun:await(ConnPid, Ref),
  262. ok.
  263. status_code_205(Config) ->
  264. doc("The 205 Reset Content status code can be sent. (RFC7231 6.3.6)"),
  265. ConnPid = gun_open(Config),
  266. Ref = gun:get(ConnPid, "/resp/reply2/205", [
  267. {<<"accept-encoding">>, <<"gzip">>}
  268. ]),
  269. {response, _, 205, _} = gun:await(ConnPid, Ref),
  270. ok.
  271. status_code_300(Config) ->
  272. doc("The 300 Multiple Choices status code can be sent. (RFC7231 6.4.1)"),
  273. ConnPid = gun_open(Config),
  274. Ref = gun:get(ConnPid, "/resp/reply2/300", [
  275. {<<"accept-encoding">>, <<"gzip">>}
  276. ]),
  277. {response, _, 300, _} = gun:await(ConnPid, Ref),
  278. ok.
  279. status_code_301(Config) ->
  280. doc("The 301 Moved Permanently status code can be sent. (RFC7231 6.4.2)"),
  281. ConnPid = gun_open(Config),
  282. Ref = gun:get(ConnPid, "/resp/reply2/301", [
  283. {<<"accept-encoding">>, <<"gzip">>}
  284. ]),
  285. {response, _, 301, _} = gun:await(ConnPid, Ref),
  286. ok.
  287. status_code_302(Config) ->
  288. doc("The 302 Found status code can be sent. (RFC7231 6.4.3)"),
  289. ConnPid = gun_open(Config),
  290. Ref = gun:get(ConnPid, "/resp/reply2/302", [
  291. {<<"accept-encoding">>, <<"gzip">>}
  292. ]),
  293. {response, _, 302, _} = gun:await(ConnPid, Ref),
  294. ok.
  295. status_code_303(Config) ->
  296. doc("The 303 See Other status code can be sent. (RFC7231 6.4.4)"),
  297. ConnPid = gun_open(Config),
  298. Ref = gun:get(ConnPid, "/resp/reply2/303", [
  299. {<<"accept-encoding">>, <<"gzip">>}
  300. ]),
  301. {response, _, 303, _} = gun:await(ConnPid, Ref),
  302. ok.
  303. status_code_305(Config) ->
  304. doc("The 305 Use Proxy status code can be sent. (RFC7231 6.4.5)"),
  305. ConnPid = gun_open(Config),
  306. Ref = gun:get(ConnPid, "/resp/reply2/305", [
  307. {<<"accept-encoding">>, <<"gzip">>}
  308. ]),
  309. {response, _, 305, _} = gun:await(ConnPid, Ref),
  310. ok.
  311. %% The status code 306 is no longer used. (RFC7231 6.4.6)
  312. status_code_307(Config) ->
  313. doc("The 307 Temporary Redirect status code can be sent. (RFC7231 6.4.7)"),
  314. ConnPid = gun_open(Config),
  315. Ref = gun:get(ConnPid, "/resp/reply2/307", [
  316. {<<"accept-encoding">>, <<"gzip">>}
  317. ]),
  318. {response, _, 307, _} = gun:await(ConnPid, Ref),
  319. ok.
  320. status_code_400(Config) ->
  321. doc("The 400 Bad Request status code can be sent. (RFC7231 6.5.1)"),
  322. ConnPid = gun_open(Config),
  323. Ref = gun:get(ConnPid, "/resp/reply2/400", [
  324. {<<"accept-encoding">>, <<"gzip">>}
  325. ]),
  326. {response, _, 400, _} = gun:await(ConnPid, Ref),
  327. ok.
  328. status_code_402(Config) ->
  329. doc("The 402 Payment Required status code can be sent. (RFC7231 6.5.2)"),
  330. ConnPid = gun_open(Config),
  331. Ref = gun:get(ConnPid, "/resp/reply2/402", [
  332. {<<"accept-encoding">>, <<"gzip">>}
  333. ]),
  334. {response, _, 402, _} = gun:await(ConnPid, Ref),
  335. ok.
  336. status_code_403(Config) ->
  337. doc("The 403 Forbidden status code can be sent. (RFC7231 6.5.3)"),
  338. ConnPid = gun_open(Config),
  339. Ref = gun:get(ConnPid, "/resp/reply2/403", [
  340. {<<"accept-encoding">>, <<"gzip">>}
  341. ]),
  342. {response, _, 403, _} = gun:await(ConnPid, Ref),
  343. ok.
  344. status_code_404(Config) ->
  345. doc("The 404 Not Found status code can be sent. (RFC7231 6.5.4)"),
  346. ConnPid = gun_open(Config),
  347. Ref = gun:get(ConnPid, "/resp/reply2/404", [
  348. {<<"accept-encoding">>, <<"gzip">>}
  349. ]),
  350. {response, _, 404, _} = gun:await(ConnPid, Ref),
  351. ok.
  352. status_code_405(Config) ->
  353. doc("The 405 Method Not Allowed status code can be sent. (RFC7231 6.5.5)"),
  354. ConnPid = gun_open(Config),
  355. Ref = gun:get(ConnPid, "/resp/reply2/405", [
  356. {<<"accept-encoding">>, <<"gzip">>}
  357. ]),
  358. {response, _, 405, _} = gun:await(ConnPid, Ref),
  359. ok.
  360. status_code_406(Config) ->
  361. doc("The 406 Not Acceptable status code can be sent. (RFC7231 6.5.6)"),
  362. ConnPid = gun_open(Config),
  363. Ref = gun:get(ConnPid, "/resp/reply2/406", [
  364. {<<"accept-encoding">>, <<"gzip">>}
  365. ]),
  366. {response, _, 406, _} = gun:await(ConnPid, Ref),
  367. ok.
  368. status_code_408(Config) ->
  369. doc("The 408 Request Timeout status code can be sent. (RFC7231 6.5.7)"),
  370. ConnPid = gun_open(Config),
  371. Ref = gun:get(ConnPid, "/resp/reply2/408", [
  372. {<<"accept-encoding">>, <<"gzip">>}
  373. ]),
  374. {response, _, 408, _} = gun:await(ConnPid, Ref),
  375. ok.
  376. status_code_408_connection_close(Config) ->
  377. case config(protocol, Config) of
  378. http ->
  379. do_http11_status_code_408_connection_close(Config);
  380. http2 ->
  381. doc("HTTP/2 connections are not closed on 408 responses.")
  382. end.
  383. do_http11_status_code_408_connection_close(Config) ->
  384. doc("A 408 response should result in a connection close "
  385. "for HTTP/1.1 connections. (RFC7231 6.5.7)"),
  386. Client = raw_open(Config),
  387. ok = raw_send(Client, "GET / HTTP/1.1\r\n"),
  388. {_, 408, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
  389. {Headers, <<>>} = cow_http:parse_headers(Rest),
  390. {_, <<"close">>} = lists:keyfind(<<"connection">>, 1, Headers),
  391. {error, closed} = raw_recv(Client, 0, 1000),
  392. ok.
  393. status_code_409(Config) ->
  394. doc("The 409 Conflict status code can be sent. (RFC7231 6.5.8)"),
  395. ConnPid = gun_open(Config),
  396. Ref = gun:get(ConnPid, "/resp/reply2/409", [
  397. {<<"accept-encoding">>, <<"gzip">>}
  398. ]),
  399. {response, _, 409, _} = gun:await(ConnPid, Ref),
  400. ok.
  401. status_code_410(Config) ->
  402. doc("The 410 Gone status code can be sent. (RFC7231 6.5.9)"),
  403. ConnPid = gun_open(Config),
  404. Ref = gun:get(ConnPid, "/resp/reply2/410", [
  405. {<<"accept-encoding">>, <<"gzip">>}
  406. ]),
  407. {response, _, 410, _} = gun:await(ConnPid, Ref),
  408. ok.
  409. status_code_411(Config) ->
  410. doc("The 411 Length Required status code can be sent. (RFC7231 6.5.10)"),
  411. ConnPid = gun_open(Config),
  412. Ref = gun:get(ConnPid, "/resp/reply2/411", [
  413. {<<"accept-encoding">>, <<"gzip">>}
  414. ]),
  415. {response, _, 411, _} = gun:await(ConnPid, Ref),
  416. ok.
  417. status_code_413(Config) ->
  418. doc("The 413 Payload Too Large status code can be sent. (RFC7231 6.5.11)"),
  419. ConnPid = gun_open(Config),
  420. Ref = gun:get(ConnPid, "/resp/reply2/413", [
  421. {<<"accept-encoding">>, <<"gzip">>}
  422. ]),
  423. {response, _, 413, _} = gun:await(ConnPid, Ref),
  424. ok.
  425. status_code_414(Config) ->
  426. doc("The 414 URI Too Long status code can be sent. (RFC7231 6.5.12)"),
  427. ConnPid = gun_open(Config),
  428. Ref = gun:get(ConnPid, "/resp/reply2/414", [
  429. {<<"accept-encoding">>, <<"gzip">>}
  430. ]),
  431. {response, _, 414, _} = gun:await(ConnPid, Ref),
  432. ok.
  433. status_code_415(Config) ->
  434. doc("The 415 Unsupported Media Type status code can be sent. (RFC7231 6.5.13)"),
  435. ConnPid = gun_open(Config),
  436. Ref = gun:get(ConnPid, "/resp/reply2/415", [
  437. {<<"accept-encoding">>, <<"gzip">>}
  438. ]),
  439. {response, _, 415, _} = gun:await(ConnPid, Ref),
  440. ok.
  441. status_code_417(Config) ->
  442. doc("The 417 Expectation Failed status code can be sent. (RFC7231 6.5.14)"),
  443. ConnPid = gun_open(Config),
  444. Ref = gun:get(ConnPid, "/resp/reply2/417", [
  445. {<<"accept-encoding">>, <<"gzip">>}
  446. ]),
  447. {response, _, 417, _} = gun:await(ConnPid, Ref),
  448. ok.
  449. status_code_426(Config) ->
  450. doc("The 426 Upgrade Required status code can be sent. (RFC7231 6.5.15)"),
  451. ConnPid = gun_open(Config),
  452. Ref = gun:get(ConnPid, "/resp/reply2/426", [
  453. {<<"accept-encoding">>, <<"gzip">>}
  454. ]),
  455. {response, _, 426, _} = gun:await(ConnPid, Ref),
  456. ok.
  457. status_code_426_upgrade_header(Config) ->
  458. case config(protocol, Config) of
  459. http ->
  460. do_status_code_426_upgrade_header(Config);
  461. http2 ->
  462. doc("HTTP/2 does not support the HTTP/1.1 Upgrade mechanism.")
  463. end.
  464. do_status_code_426_upgrade_header(Config) ->
  465. doc("A 426 response must include a upgrade header. (RFC7231 6.5.15)"),
  466. ConnPid = gun_open(Config),
  467. Ref = gun:get(ConnPid, "/ws?ok", [
  468. {<<"accept-encoding">>, <<"gzip">>}
  469. ]),
  470. {response, _, 426, Headers} = gun:await(ConnPid, Ref),
  471. {_, <<"upgrade">>} = lists:keyfind(<<"connection">>, 1, Headers),
  472. {_, <<"websocket">>} = lists:keyfind(<<"upgrade">>, 1, Headers),
  473. ok.
  474. status_code_500(Config) ->
  475. doc("The 500 Internal Server Error status code can be sent. (RFC7231 6.6.1)"),
  476. ConnPid = gun_open(Config),
  477. Ref = gun:get(ConnPid, "/resp/reply2/500", [
  478. {<<"accept-encoding">>, <<"gzip">>}
  479. ]),
  480. {response, _, 500, _} = gun:await(ConnPid, Ref),
  481. ok.
  482. status_code_501(Config) ->
  483. doc("The 501 Not Implemented status code can be sent. (RFC7231 6.6.2)"),
  484. ConnPid = gun_open(Config),
  485. Ref = gun:get(ConnPid, "/resp/reply2/501", [
  486. {<<"accept-encoding">>, <<"gzip">>}
  487. ]),
  488. {response, _, 501, _} = gun:await(ConnPid, Ref),
  489. ok.
  490. status_code_502(Config) ->
  491. doc("The 502 Bad Gateway status code can be sent. (RFC7231 6.6.3)"),
  492. ConnPid = gun_open(Config),
  493. Ref = gun:get(ConnPid, "/resp/reply2/502", [
  494. {<<"accept-encoding">>, <<"gzip">>}
  495. ]),
  496. {response, _, 502, _} = gun:await(ConnPid, Ref),
  497. ok.
  498. status_code_503(Config) ->
  499. doc("The 503 Service Unavailable status code can be sent. (RFC7231 6.6.4)"),
  500. ConnPid = gun_open(Config),
  501. Ref = gun:get(ConnPid, "/resp/reply2/503", [
  502. {<<"accept-encoding">>, <<"gzip">>}
  503. ]),
  504. {response, _, 503, _} = gun:await(ConnPid, Ref),
  505. ok.
  506. status_code_504(Config) ->
  507. doc("The 504 Gateway Timeout status code can be sent. (RFC7231 6.6.5)"),
  508. ConnPid = gun_open(Config),
  509. Ref = gun:get(ConnPid, "/resp/reply2/504", [
  510. {<<"accept-encoding">>, <<"gzip">>}
  511. ]),
  512. {response, _, 504, _} = gun:await(ConnPid, Ref),
  513. ok.
  514. status_code_505(Config) ->
  515. doc("The 505 HTTP Version Not Supported status code can be sent. (RFC7231 6.6.6)"),
  516. ConnPid = gun_open(Config),
  517. Ref = gun:get(ConnPid, "/resp/reply2/505", [
  518. {<<"accept-encoding">>, <<"gzip">>}
  519. ]),
  520. {response, _, 505, _} = gun:await(ConnPid, Ref),
  521. ok.