cowboy_req.erl 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351
  1. %% Copyright (c) 2011-2014, Loïc Hoguin <essen@ninenines.eu>
  2. %% Copyright (c) 2011, Anthony Ramine <nox@dev-extend.eu>
  3. %%
  4. %% Permission to use, copy, modify, and/or distribute this software for any
  5. %% purpose with or without fee is hereby granted, provided that the above
  6. %% copyright notice and this permission notice appear in all copies.
  7. %%
  8. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. -module(cowboy_req).
  16. %% Request API.
  17. -export([new/14]).
  18. -export([method/1]).
  19. -export([version/1]).
  20. -export([peer/1]).
  21. -export([host/1]).
  22. -export([host_info/1]).
  23. -export([port/1]).
  24. -export([path/1]).
  25. -export([path_info/1]).
  26. -export([qs/1]).
  27. -export([qs_val/2]).
  28. -export([qs_val/3]).
  29. -export([qs_vals/1]).
  30. -export([host_url/1]).
  31. -export([url/1]).
  32. -export([binding/2]).
  33. -export([binding/3]).
  34. -export([bindings/1]).
  35. -export([header/2]).
  36. -export([header/3]).
  37. -export([headers/1]).
  38. -export([parse_header/2]).
  39. -export([parse_header/3]).
  40. -export([cookie/2]).
  41. -export([cookie/3]).
  42. -export([cookies/1]).
  43. -export([meta/2]).
  44. -export([meta/3]).
  45. -export([set_meta/3]).
  46. %% Request body API.
  47. -export([has_body/1]).
  48. -export([body_length/1]).
  49. -export([init_stream/4]).
  50. -export([stream_body/1]).
  51. -export([stream_body/2]).
  52. -export([skip_body/1]).
  53. -export([body/1]).
  54. -export([body/2]).
  55. -export([body_qs/1]).
  56. -export([body_qs/2]).
  57. %% Multipart API.
  58. -export([part/1]).
  59. -export([part_body/1]).
  60. -export([part_body/2]).
  61. %% Response API.
  62. -export([set_resp_cookie/4]).
  63. -export([set_resp_header/3]).
  64. -export([set_resp_body/2]).
  65. -export([set_resp_body_fun/2]).
  66. -export([set_resp_body_fun/3]).
  67. -export([has_resp_header/2]).
  68. -export([has_resp_body/1]).
  69. -export([delete_resp_header/2]).
  70. -export([reply/2]).
  71. -export([reply/3]).
  72. -export([reply/4]).
  73. -export([chunked_reply/2]).
  74. -export([chunked_reply/3]).
  75. -export([chunk/2]).
  76. -export([upgrade_reply/3]).
  77. -export([maybe_reply/2]).
  78. -export([ensure_response/2]).
  79. %% Private setter/getter API.
  80. -export([append_buffer/2]).
  81. -export([get/2]).
  82. -export([set/2]).
  83. -export([set_bindings/4]).
  84. %% Misc API.
  85. -export([compact/1]).
  86. -export([lock/1]).
  87. -export([to_list/1]).
  88. -type cookie_opts() :: cow_cookie:cookie_opts().
  89. -export_type([cookie_opts/0]).
  90. -type content_decode_fun() :: fun((binary())
  91. -> {ok, binary()}
  92. | {error, atom()}).
  93. -type transfer_decode_fun() :: fun((binary(), any())
  94. -> {ok, binary(), binary(), any()}
  95. | more | {more, non_neg_integer(), binary(), any()}
  96. | {done, non_neg_integer(), binary()}
  97. | {done, binary(), non_neg_integer(), binary()}
  98. | {error, atom()}).
  99. -type resp_body_fun() :: fun((any(), module()) -> ok).
  100. -type send_chunk_fun() :: fun((iodata()) -> ok | {error, atom()}).
  101. -type resp_chunked_fun() :: fun((send_chunk_fun()) -> ok).
  102. -record(http_req, {
  103. %% Transport.
  104. socket = undefined :: any(),
  105. transport = undefined :: undefined | module(),
  106. connection = keepalive :: keepalive | close,
  107. %% Request.
  108. pid = undefined :: pid(),
  109. method = <<"GET">> :: binary(),
  110. version = 'HTTP/1.1' :: cowboy:http_version(),
  111. peer = undefined :: undefined | {inet:ip_address(), inet:port_number()},
  112. host = undefined :: undefined | binary(),
  113. host_info = undefined :: undefined | cowboy_router:tokens(),
  114. port = undefined :: undefined | inet:port_number(),
  115. path = undefined :: binary(),
  116. path_info = undefined :: undefined | cowboy_router:tokens(),
  117. qs = undefined :: binary(),
  118. qs_vals = undefined :: undefined | list({binary(), binary() | true}),
  119. bindings = undefined :: undefined | cowboy_router:bindings(),
  120. headers = [] :: cowboy:http_headers(),
  121. p_headers = [] :: [any()], %% @todo Improve those specs.
  122. cookies = undefined :: undefined | [{binary(), binary()}],
  123. meta = [] :: [{atom(), any()}],
  124. %% Request body.
  125. body_state = waiting :: waiting | done | {stream, non_neg_integer(),
  126. transfer_decode_fun(), any(), content_decode_fun()},
  127. buffer = <<>> :: binary(),
  128. multipart = undefined :: undefined | {binary(), binary()},
  129. %% Response.
  130. resp_compress = false :: boolean(),
  131. resp_state = waiting :: locked | waiting | waiting_stream
  132. | chunks | stream | done,
  133. resp_headers = [] :: cowboy:http_headers(),
  134. resp_body = <<>> :: iodata() | resp_body_fun()
  135. | {non_neg_integer(), resp_body_fun()}
  136. | {chunked, resp_chunked_fun()},
  137. %% Functions.
  138. onresponse = undefined :: undefined | already_called
  139. | cowboy:onresponse_fun()
  140. }).
  141. -opaque req() :: #http_req{}.
  142. -export_type([req/0]).
  143. %% Request API.
  144. -spec new(any(), module(),
  145. undefined | {inet:ip_address(), inet:port_number()},
  146. binary(), binary(), binary(),
  147. cowboy:http_version(), cowboy:http_headers(), binary(),
  148. inet:port_number() | undefined, binary(), boolean(), boolean(),
  149. undefined | cowboy:onresponse_fun())
  150. -> req().
  151. new(Socket, Transport, Peer, Method, Path, Query,
  152. Version, Headers, Host, Port, Buffer, CanKeepalive,
  153. Compress, OnResponse) ->
  154. Req = #http_req{socket=Socket, transport=Transport, pid=self(), peer=Peer,
  155. method=Method, path=Path, qs=Query, version=Version,
  156. headers=Headers, host=Host, port=Port, buffer=Buffer,
  157. resp_compress=Compress, onresponse=OnResponse},
  158. case CanKeepalive and (Version =:= 'HTTP/1.1') of
  159. false ->
  160. Req#http_req{connection=close};
  161. true ->
  162. case lists:keyfind(<<"connection">>, 1, Headers) of
  163. false ->
  164. Req; %% keepalive
  165. {_, ConnectionHeader} ->
  166. Tokens = cow_http_hd:parse_connection(ConnectionHeader),
  167. Connection = connection_to_atom(Tokens),
  168. Req#http_req{connection=Connection,
  169. p_headers=[{<<"connection">>, Tokens}]}
  170. end
  171. end.
  172. -spec method(Req) -> {binary(), Req} when Req::req().
  173. method(Req) ->
  174. {Req#http_req.method, Req}.
  175. -spec version(Req) -> {cowboy:http_version(), Req} when Req::req().
  176. version(Req) ->
  177. {Req#http_req.version, Req}.
  178. -spec peer(Req)
  179. -> {{inet:ip_address(), inet:port_number()}, Req}
  180. when Req::req().
  181. peer(Req) ->
  182. {Req#http_req.peer, Req}.
  183. -spec host(Req) -> {binary(), Req} when Req::req().
  184. host(Req) ->
  185. {Req#http_req.host, Req}.
  186. -spec host_info(Req)
  187. -> {cowboy_router:tokens() | undefined, Req} when Req::req().
  188. host_info(Req) ->
  189. {Req#http_req.host_info, Req}.
  190. -spec port(Req) -> {inet:port_number(), Req} when Req::req().
  191. port(Req) ->
  192. {Req#http_req.port, Req}.
  193. -spec path(Req) -> {binary(), Req} when Req::req().
  194. path(Req) ->
  195. {Req#http_req.path, Req}.
  196. -spec path_info(Req)
  197. -> {cowboy_router:tokens() | undefined, Req} when Req::req().
  198. path_info(Req) ->
  199. {Req#http_req.path_info, Req}.
  200. -spec qs(Req) -> {binary(), Req} when Req::req().
  201. qs(Req) ->
  202. {Req#http_req.qs, Req}.
  203. -spec qs_val(binary(), Req)
  204. -> {binary() | true | undefined, Req} when Req::req().
  205. qs_val(Name, Req) when is_binary(Name) ->
  206. qs_val(Name, Req, undefined).
  207. -spec qs_val(binary(), Req, Default)
  208. -> {binary() | true | Default, Req} when Req::req(), Default::any().
  209. qs_val(Name, Req=#http_req{qs=RawQs, qs_vals=undefined}, Default)
  210. when is_binary(Name) ->
  211. QsVals = cow_qs:parse_qs(RawQs),
  212. qs_val(Name, Req#http_req{qs_vals=QsVals}, Default);
  213. qs_val(Name, Req, Default) ->
  214. case lists:keyfind(Name, 1, Req#http_req.qs_vals) of
  215. {Name, Value} -> {Value, Req};
  216. false -> {Default, Req}
  217. end.
  218. -spec qs_vals(Req) -> {list({binary(), binary() | true}), Req} when Req::req().
  219. qs_vals(Req=#http_req{qs=RawQs, qs_vals=undefined}) ->
  220. QsVals = cow_qs:parse_qs(RawQs),
  221. qs_vals(Req#http_req{qs_vals=QsVals});
  222. qs_vals(Req=#http_req{qs_vals=QsVals}) ->
  223. {QsVals, Req}.
  224. %% The URL includes the scheme, host and port only.
  225. -spec host_url(Req) -> {undefined | binary(), Req} when Req::req().
  226. host_url(Req=#http_req{port=undefined}) ->
  227. {undefined, Req};
  228. host_url(Req=#http_req{transport=Transport, host=Host, port=Port}) ->
  229. TransportName = Transport:name(),
  230. Secure = case TransportName of
  231. ssl -> <<"s">>;
  232. _ -> <<>>
  233. end,
  234. PortBin = case {TransportName, Port} of
  235. {ssl, 443} -> <<>>;
  236. {tcp, 80} -> <<>>;
  237. _ -> << ":", (list_to_binary(integer_to_list(Port)))/binary >>
  238. end,
  239. {<< "http", Secure/binary, "://", Host/binary, PortBin/binary >>, Req}.
  240. %% The URL includes the scheme, host, port, path and query string.
  241. -spec url(Req) -> {undefined | binary(), Req} when Req::req().
  242. url(Req=#http_req{}) ->
  243. {HostURL, Req2} = host_url(Req),
  244. url(HostURL, Req2).
  245. url(undefined, Req=#http_req{}) ->
  246. {undefined, Req};
  247. url(HostURL, Req=#http_req{path=Path, qs=QS}) ->
  248. QS2 = case QS of
  249. <<>> -> <<>>;
  250. _ -> << "?", QS/binary >>
  251. end,
  252. {<< HostURL/binary, Path/binary, QS2/binary >>, Req}.
  253. -spec binding(atom(), Req) -> {any() | undefined, Req} when Req::req().
  254. binding(Name, Req) when is_atom(Name) ->
  255. binding(Name, Req, undefined).
  256. -spec binding(atom(), Req, Default)
  257. -> {any() | Default, Req} when Req::req(), Default::any().
  258. binding(Name, Req, Default) when is_atom(Name) ->
  259. case lists:keyfind(Name, 1, Req#http_req.bindings) of
  260. {Name, Value} -> {Value, Req};
  261. false -> {Default, Req}
  262. end.
  263. -spec bindings(Req) -> {[{atom(), any()}], Req} when Req::req().
  264. bindings(Req) ->
  265. {Req#http_req.bindings, Req}.
  266. -spec header(binary(), Req)
  267. -> {binary() | undefined, Req} when Req::req().
  268. header(Name, Req) ->
  269. header(Name, Req, undefined).
  270. -spec header(binary(), Req, Default)
  271. -> {binary() | Default, Req} when Req::req(), Default::any().
  272. header(Name, Req, Default) ->
  273. case lists:keyfind(Name, 1, Req#http_req.headers) of
  274. {Name, Value} -> {Value, Req};
  275. false -> {Default, Req}
  276. end.
  277. -spec headers(Req) -> {cowboy:http_headers(), Req} when Req::req().
  278. headers(Req) ->
  279. {Req#http_req.headers, Req}.
  280. -spec parse_header(binary(), Req)
  281. -> {ok, any(), Req} | {undefined, binary(), Req}
  282. | {error, badarg} when Req::req().
  283. parse_header(Name, Req=#http_req{p_headers=PHeaders}) ->
  284. case lists:keyfind(Name, 1, PHeaders) of
  285. false -> parse_header(Name, Req, parse_header_default(Name));
  286. {Name, Value} -> {ok, Value, Req}
  287. end.
  288. -spec parse_header_default(binary()) -> any().
  289. parse_header_default(<<"transfer-encoding">>) -> [<<"identity">>];
  290. parse_header_default(_Name) -> undefined.
  291. -spec parse_header(binary(), Req, any())
  292. -> {ok, any(), Req} | {undefined, binary(), Req}
  293. | {error, badarg} when Req::req().
  294. parse_header(Name = <<"accept">>, Req, Default) ->
  295. parse_header(Name, Req, Default,
  296. fun (Value) ->
  297. cowboy_http:list(Value, fun cowboy_http:media_range/2)
  298. end);
  299. parse_header(Name = <<"accept-charset">>, Req, Default) ->
  300. parse_header(Name, Req, Default,
  301. fun (Value) ->
  302. cowboy_http:nonempty_list(Value, fun cowboy_http:conneg/2)
  303. end);
  304. parse_header(Name = <<"accept-encoding">>, Req, Default) ->
  305. parse_header(Name, Req, Default,
  306. fun (Value) ->
  307. cowboy_http:list(Value, fun cowboy_http:conneg/2)
  308. end);
  309. parse_header(Name = <<"accept-language">>, Req, Default) ->
  310. parse_header(Name, Req, Default,
  311. fun (Value) ->
  312. cowboy_http:nonempty_list(Value, fun cowboy_http:language_range/2)
  313. end);
  314. parse_header(Name = <<"authorization">>, Req, Default) ->
  315. parse_header(Name, Req, Default,
  316. fun (Value) ->
  317. cowboy_http:token_ci(Value, fun cowboy_http:authorization/2)
  318. end);
  319. parse_header(Name = <<"content-length">>, Req, Default) ->
  320. parse_header(Name, Req, Default, fun cow_http_hd:parse_content_length/1);
  321. parse_header(Name = <<"content-type">>, Req, Default) ->
  322. parse_header(Name, Req, Default, fun cowboy_http:content_type/1);
  323. parse_header(Name = <<"cookie">>, Req, Default) ->
  324. parse_header(Name, Req, Default, fun cow_cookie:parse_cookie/1);
  325. parse_header(Name = <<"expect">>, Req, Default) ->
  326. parse_header(Name, Req, Default,
  327. fun (Value) ->
  328. cowboy_http:nonempty_list(Value, fun cowboy_http:expectation/2)
  329. end);
  330. parse_header(Name, Req, Default)
  331. when Name =:= <<"if-match">>;
  332. Name =:= <<"if-none-match">> ->
  333. parse_header(Name, Req, Default, fun cowboy_http:entity_tag_match/1);
  334. parse_header(Name, Req, Default)
  335. when Name =:= <<"if-modified-since">>;
  336. Name =:= <<"if-unmodified-since">> ->
  337. parse_header(Name, Req, Default, fun cowboy_http:http_date/1);
  338. parse_header(Name = <<"range">>, Req, Default) ->
  339. parse_header(Name, Req, Default, fun cowboy_http:range/1);
  340. parse_header(Name, Req, Default)
  341. when Name =:= <<"sec-websocket-protocol">>;
  342. Name =:= <<"x-forwarded-for">> ->
  343. parse_header(Name, Req, Default,
  344. fun (Value) ->
  345. cowboy_http:nonempty_list(Value, fun cowboy_http:token/2)
  346. end);
  347. parse_header(Name = <<"transfer-encoding">>, Req, Default) ->
  348. parse_header(Name, Req, Default, fun cow_http_hd:parse_transfer_encoding/1);
  349. %% @todo Product version.
  350. parse_header(Name = <<"upgrade">>, Req, Default) ->
  351. parse_header(Name, Req, Default,
  352. fun (Value) ->
  353. cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2)
  354. end);
  355. parse_header(Name = <<"sec-websocket-extensions">>, Req, Default) ->
  356. parse_header(Name, Req, Default, fun cowboy_http:parameterized_tokens/1);
  357. parse_header(Name, Req, Default) ->
  358. {Value, Req2} = header(Name, Req, Default),
  359. {undefined, Value, Req2}.
  360. parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) ->
  361. case header(Name, Req) of
  362. {undefined, Req2} ->
  363. {ok, Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
  364. {Value, Req2} ->
  365. case Fun(Value) of
  366. {error, badarg} ->
  367. {error, badarg};
  368. P ->
  369. {ok, P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}}
  370. end
  371. end.
  372. -spec cookie(binary(), Req)
  373. -> {binary() | undefined, Req} when Req::req().
  374. cookie(Name, Req) when is_binary(Name) ->
  375. cookie(Name, Req, undefined).
  376. -spec cookie(binary(), Req, Default)
  377. -> {binary() | Default, Req} when Req::req(), Default::any().
  378. cookie(Name, Req=#http_req{cookies=undefined}, Default) when is_binary(Name) ->
  379. case parse_header(<<"cookie">>, Req) of
  380. {ok, undefined, Req2} ->
  381. {Default, Req2#http_req{cookies=[]}};
  382. {ok, Cookies, Req2} ->
  383. cookie(Name, Req2#http_req{cookies=Cookies}, Default)
  384. end;
  385. cookie(Name, Req, Default) ->
  386. case lists:keyfind(Name, 1, Req#http_req.cookies) of
  387. {Name, Value} -> {Value, Req};
  388. false -> {Default, Req}
  389. end.
  390. -spec cookies(Req) -> {list({binary(), binary()}), Req} when Req::req().
  391. cookies(Req=#http_req{cookies=undefined}) ->
  392. case parse_header(<<"cookie">>, Req) of
  393. {ok, undefined, Req2} ->
  394. {[], Req2#http_req{cookies=[]}};
  395. {ok, Cookies, Req2} ->
  396. cookies(Req2#http_req{cookies=Cookies});
  397. %% Flash player incorrectly sends an empty Cookie header.
  398. {error, badarg} ->
  399. {[], Req#http_req{cookies=[]}}
  400. end;
  401. cookies(Req=#http_req{cookies=Cookies}) ->
  402. {Cookies, Req}.
  403. -spec meta(atom(), Req) -> {any() | undefined, Req} when Req::req().
  404. meta(Name, Req) ->
  405. meta(Name, Req, undefined).
  406. -spec meta(atom(), Req, any()) -> {any(), Req} when Req::req().
  407. meta(Name, Req, Default) ->
  408. case lists:keyfind(Name, 1, Req#http_req.meta) of
  409. {Name, Value} -> {Value, Req};
  410. false -> {Default, Req}
  411. end.
  412. -spec set_meta(atom(), any(), Req) -> Req when Req::req().
  413. set_meta(Name, Value, Req=#http_req{meta=Meta}) ->
  414. Req#http_req{meta=lists:keystore(Name, 1, Meta, {Name, Value})}.
  415. %% Request Body API.
  416. -spec has_body(req()) -> boolean().
  417. has_body(Req) ->
  418. case lists:keyfind(<<"content-length">>, 1, Req#http_req.headers) of
  419. {_, <<"0">>} ->
  420. false;
  421. {_, _} ->
  422. true;
  423. _ ->
  424. lists:keymember(<<"transfer-encoding">>, 1, Req#http_req.headers)
  425. end.
  426. %% The length may not be known if Transfer-Encoding is not identity,
  427. %% and the body hasn't been read at the time of the call.
  428. -spec body_length(Req) -> {undefined | non_neg_integer(), Req} when Req::req().
  429. body_length(Req) ->
  430. case parse_header(<<"transfer-encoding">>, Req) of
  431. {ok, [<<"identity">>], Req2} ->
  432. {ok, Length, Req3} = parse_header(<<"content-length">>, Req2, 0),
  433. {Length, Req3};
  434. {ok, _, Req2} ->
  435. {undefined, Req2}
  436. end.
  437. %% Two decodings happen. First a decoding function is applied to the
  438. %% transferred data, and then another is applied to the actual content.
  439. %%
  440. %% Transfer encoding is generally used for chunked bodies. The decoding
  441. %% function uses a state to keep track of how much it has read, which is
  442. %% also initialized through this function.
  443. %%
  444. %% Content encoding is generally used for compression.
  445. -spec init_stream(transfer_decode_fun(), any(), content_decode_fun(), Req)
  446. -> {ok, Req} when Req::req().
  447. init_stream(TransferDecode, TransferState, ContentDecode, Req) ->
  448. {ok, Req#http_req{body_state=
  449. {stream, 0, TransferDecode, TransferState, ContentDecode}}}.
  450. -spec stream_body(Req) -> {ok, binary(), Req}
  451. | {done, Req} | {error, atom()} when Req::req().
  452. stream_body(Req) ->
  453. stream_body(1000000, Req).
  454. -spec stream_body(non_neg_integer(), Req) -> {ok, binary(), Req}
  455. | {done, Req} | {error, atom()} when Req::req().
  456. stream_body(MaxLength, Req=#http_req{body_state=waiting, version=Version,
  457. transport=Transport, socket=Socket}) ->
  458. {ok, ExpectHeader, Req1} = parse_header(<<"expect">>, Req),
  459. case ExpectHeader of
  460. [<<"100-continue">>] ->
  461. HTTPVer = atom_to_binary(Version, latin1),
  462. Transport:send(Socket,
  463. << HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>);
  464. undefined ->
  465. ok
  466. end,
  467. case parse_header(<<"transfer-encoding">>, Req1) of
  468. {ok, [<<"chunked">>], Req2} ->
  469. stream_body(MaxLength, Req2#http_req{body_state=
  470. {stream, 0,
  471. fun cow_http_te:stream_chunked/2, {0, 0},
  472. fun cowboy_http:ce_identity/1}});
  473. {ok, [<<"identity">>], Req2} ->
  474. {Length, Req3} = body_length(Req2),
  475. case Length of
  476. 0 ->
  477. {done, Req3#http_req{body_state=done}};
  478. Length ->
  479. stream_body(MaxLength, Req3#http_req{body_state=
  480. {stream, Length,
  481. fun cow_http_te:stream_identity/2, {0, Length},
  482. fun cowboy_http:ce_identity/1}})
  483. end
  484. end;
  485. stream_body(_, Req=#http_req{body_state=done}) ->
  486. {done, Req};
  487. stream_body(_, Req=#http_req{buffer=Buffer})
  488. when Buffer =/= <<>> ->
  489. transfer_decode(Buffer, Req#http_req{buffer= <<>>});
  490. stream_body(MaxLength, Req) ->
  491. stream_body_recv(MaxLength, Req).
  492. -spec stream_body_recv(non_neg_integer(), Req)
  493. -> {ok, binary(), Req} | {error, atom()} when Req::req().
  494. stream_body_recv(MaxLength, Req=#http_req{
  495. transport=Transport, socket=Socket, buffer=Buffer,
  496. body_state={stream, Length, _, _, _}}) ->
  497. %% @todo Allow configuring the timeout.
  498. case Transport:recv(Socket, min(Length, MaxLength), 5000) of
  499. {ok, Data} -> transfer_decode(<< Buffer/binary, Data/binary >>,
  500. Req#http_req{buffer= <<>>});
  501. {error, Reason} -> {error, Reason}
  502. end.
  503. %% @todo Handle chunked after-the-facts headers.
  504. %% @todo Depending on the length returned we might want to 0 or +5 it.
  505. -spec transfer_decode(binary(), Req)
  506. -> {ok, binary(), Req} | {error, atom()} when Req::req().
  507. transfer_decode(Data, Req=#http_req{body_state={stream, _,
  508. TransferDecode, TransferState, ContentDecode}}) ->
  509. case TransferDecode(Data, TransferState) of
  510. more ->
  511. stream_body_recv(0, Req#http_req{buffer=Data, body_state={stream,
  512. 0, TransferDecode, TransferState, ContentDecode}});
  513. {more, Data2, TransferState2} ->
  514. content_decode(ContentDecode, Data2,
  515. Req#http_req{body_state={stream, 0,
  516. TransferDecode, TransferState2, ContentDecode}});
  517. {more, Data2, Length, TransferState2} ->
  518. content_decode(ContentDecode, Data2,
  519. Req#http_req{body_state={stream, Length,
  520. TransferDecode, TransferState2, ContentDecode}});
  521. {more, Data2, Length, Rest, TransferState2} ->
  522. content_decode(ContentDecode, Data2,
  523. Req#http_req{buffer=Rest, body_state={stream, Length,
  524. TransferDecode, TransferState2, ContentDecode}});
  525. {done, Length, Rest} ->
  526. Req2 = transfer_decode_done(Length, Rest, Req),
  527. {done, Req2};
  528. {done, Data2, Length, Rest} ->
  529. Req2 = transfer_decode_done(Length, Rest, Req),
  530. content_decode(ContentDecode, Data2, Req2)
  531. end.
  532. -spec transfer_decode_done(non_neg_integer(), binary(), Req)
  533. -> Req when Req::req().
  534. transfer_decode_done(Length, Rest, Req=#http_req{
  535. headers=Headers, p_headers=PHeaders}) ->
  536. Headers2 = lists:keystore(<<"content-length">>, 1, Headers,
  537. {<<"content-length">>, list_to_binary(integer_to_list(Length))}),
  538. %% At this point we just assume TEs were all decoded.
  539. Headers3 = lists:keydelete(<<"transfer-encoding">>, 1, Headers2),
  540. PHeaders2 = lists:keystore(<<"content-length">>, 1, PHeaders,
  541. {<<"content-length">>, Length}),
  542. PHeaders3 = lists:keydelete(<<"transfer-encoding">>, 1, PHeaders2),
  543. Req#http_req{buffer=Rest, body_state=done,
  544. headers=Headers3, p_headers=PHeaders3}.
  545. -spec content_decode(content_decode_fun(), binary(), Req)
  546. -> {ok, binary(), Req} | {error, atom()} when Req::req().
  547. content_decode(ContentDecode, Data, Req) ->
  548. case ContentDecode(Data) of
  549. {ok, Data2} -> {ok, Data2, Req};
  550. {error, Reason} -> {error, Reason}
  551. end.
  552. -spec body(Req) -> {ok, binary(), Req} | {error, atom()} when Req::req().
  553. body(Req) ->
  554. body(8000000, Req).
  555. -spec body(non_neg_integer() | infinity, Req)
  556. -> {ok, binary(), Req} | {error, atom()} when Req::req().
  557. body(MaxBodyLength, Req) ->
  558. case parse_header(<<"transfer-encoding">>, Req) of
  559. {ok, [<<"identity">>], Req2} ->
  560. {ok, Length, Req3} = parse_header(<<"content-length">>, Req2, 0),
  561. if Length > MaxBodyLength ->
  562. {error, badlength};
  563. true ->
  564. read_body(Req3, <<>>)
  565. end;
  566. {ok, _, _} ->
  567. {error, chunked}
  568. end.
  569. -spec read_body(Req, binary())
  570. -> {ok, binary(), Req} | {error, atom()} when Req::req().
  571. read_body(Req, Acc) ->
  572. case stream_body(Req) of
  573. {ok, Data, Req2} ->
  574. read_body(Req2, << Acc/binary, Data/binary >>);
  575. {done, Req2} ->
  576. {ok, Acc, Req2};
  577. {error, Reason} ->
  578. {error, Reason}
  579. end.
  580. -spec skip_body(Req) -> {ok, Req} | {error, atom()} when Req::req().
  581. skip_body(Req) ->
  582. case stream_body(Req) of
  583. {ok, _, Req2} -> skip_body(Req2);
  584. {done, Req2} -> {ok, Req2};
  585. {error, Reason} -> {error, Reason}
  586. end.
  587. -spec body_qs(Req)
  588. -> {ok, [{binary(), binary() | true}], Req} | {error, atom()}
  589. when Req::req().
  590. body_qs(Req) ->
  591. body_qs(16000, Req).
  592. %% Essentially a POST query string.
  593. -spec body_qs(non_neg_integer() | infinity, Req)
  594. -> {ok, [{binary(), binary() | true}], Req} | {error, atom()}
  595. when Req::req().
  596. body_qs(MaxBodyLength, Req) ->
  597. case body(MaxBodyLength, Req) of
  598. {ok, Body, Req2} ->
  599. {ok, cow_qs:parse_qs(Body), Req2};
  600. {error, Reason} ->
  601. {error, Reason}
  602. end.
  603. %% Multipart API.
  604. -spec part(Req)
  605. -> {ok, cow_multipart:headers(), Req} | {done, Req}
  606. when Req::req().
  607. part(Req=#http_req{multipart=undefined}) ->
  608. part(init_multipart(Req));
  609. part(Req) ->
  610. {ok, Data, Req2} = stream_multipart(Req),
  611. part(Data, Req2).
  612. part(Buffer, Req=#http_req{multipart={Boundary, _}}) ->
  613. case cow_multipart:parse_headers(Buffer, Boundary) of
  614. more ->
  615. {ok, Data, Req2} = stream_multipart(Req),
  616. part(<< Buffer/binary, Data/binary >>, Req2);
  617. {more, Buffer2} ->
  618. {ok, Data, Req2} = stream_multipart(Req),
  619. part(<< Buffer2/binary, Data/binary >>, Req2);
  620. {ok, Headers, Rest} ->
  621. {ok, Headers, Req#http_req{multipart={Boundary, Rest}}};
  622. %% Ignore epilogue.
  623. {done, _} ->
  624. {done, Req#http_req{multipart=undefined}}
  625. end.
  626. -spec part_body(Req)
  627. -> {ok, binary(), Req} | {more, binary(), Req}
  628. when Req::req().
  629. part_body(Req) ->
  630. part_body(8000000, Req).
  631. -spec part_body(non_neg_integer(), Req)
  632. -> {ok, binary(), Req} | {more, binary(), Req}
  633. when Req::req().
  634. part_body(MaxLength, Req=#http_req{multipart=undefined}) ->
  635. part_body(MaxLength, init_multipart(Req));
  636. part_body(MaxLength, Req) ->
  637. part_body(<<>>, MaxLength, Req, <<>>).
  638. part_body(Buffer, MaxLength, Req=#http_req{multipart={Boundary, _}}, Acc)
  639. when byte_size(Acc) > MaxLength ->
  640. {more, Acc, Req#http_req{multipart={Boundary, Buffer}}};
  641. part_body(Buffer, MaxLength, Req=#http_req{multipart={Boundary, _}}, Acc) ->
  642. {ok, Data, Req2} = stream_multipart(Req),
  643. case cow_multipart:parse_body(<< Buffer/binary, Data/binary >>, Boundary) of
  644. {ok, Body} ->
  645. part_body(<<>>, MaxLength, Req2, << Acc/binary, Body/binary >>);
  646. {ok, Body, Rest} ->
  647. part_body(Rest, MaxLength, Req2, << Acc/binary, Body/binary >>);
  648. done ->
  649. {ok, Acc, Req2};
  650. {done, Body} ->
  651. {ok, << Acc/binary, Body/binary >>, Req2};
  652. {done, Body, Rest} ->
  653. {ok, << Acc/binary, Body/binary >>,
  654. Req2#http_req{multipart={Boundary, Rest}}}
  655. end.
  656. init_multipart(Req) ->
  657. {ok, {<<"multipart">>, _, Params}, Req2}
  658. = parse_header(<<"content-type">>, Req),
  659. {_, Boundary} = lists:keyfind(<<"boundary">>, 1, Params),
  660. Req2#http_req{multipart={Boundary, <<>>}}.
  661. stream_multipart(Req=#http_req{multipart={_, <<>>}}) ->
  662. stream_body(Req);
  663. stream_multipart(Req=#http_req{multipart={Boundary, Buffer}}) ->
  664. {ok, Buffer, Req#http_req{multipart={Boundary, <<>>}}}.
  665. %% Response API.
  666. %% The cookie name cannot contain any of the following characters:
  667. %% =,;\s\t\r\n\013\014
  668. %%
  669. %% The cookie value cannot contain any of the following characters:
  670. %% ,; \t\r\n\013\014
  671. -spec set_resp_cookie(iodata(), iodata(), cookie_opts(), Req)
  672. -> Req when Req::req().
  673. set_resp_cookie(Name, Value, Opts, Req) ->
  674. Cookie = cow_cookie:setcookie(Name, Value, Opts),
  675. set_resp_header(<<"set-cookie">>, Cookie, Req).
  676. -spec set_resp_header(binary(), iodata(), Req)
  677. -> Req when Req::req().
  678. set_resp_header(Name, Value, Req=#http_req{resp_headers=RespHeaders}) ->
  679. Req#http_req{resp_headers=[{Name, Value}|RespHeaders]}.
  680. -spec set_resp_body(iodata(), Req) -> Req when Req::req().
  681. set_resp_body(Body, Req) ->
  682. Req#http_req{resp_body=Body}.
  683. -spec set_resp_body_fun(resp_body_fun(), Req) -> Req when Req::req().
  684. set_resp_body_fun(StreamFun, Req) when is_function(StreamFun) ->
  685. Req#http_req{resp_body=StreamFun}.
  686. %% If the body function crashes while writing the response body or writes
  687. %% fewer bytes than declared the behaviour is undefined.
  688. -spec set_resp_body_fun(non_neg_integer(), resp_body_fun(), Req)
  689. -> Req when Req::req();
  690. (chunked, resp_chunked_fun(), Req)
  691. -> Req when Req::req().
  692. set_resp_body_fun(StreamLen, StreamFun, Req)
  693. when is_integer(StreamLen), is_function(StreamFun) ->
  694. Req#http_req{resp_body={StreamLen, StreamFun}};
  695. set_resp_body_fun(chunked, StreamFun, Req)
  696. when is_function(StreamFun) ->
  697. Req#http_req{resp_body={chunked, StreamFun}}.
  698. -spec has_resp_header(binary(), req()) -> boolean().
  699. has_resp_header(Name, #http_req{resp_headers=RespHeaders}) ->
  700. lists:keymember(Name, 1, RespHeaders).
  701. -spec has_resp_body(req()) -> boolean().
  702. has_resp_body(#http_req{resp_body=RespBody}) when is_function(RespBody) ->
  703. true;
  704. has_resp_body(#http_req{resp_body={chunked, _}}) ->
  705. true;
  706. has_resp_body(#http_req{resp_body={Length, _}}) ->
  707. Length > 0;
  708. has_resp_body(#http_req{resp_body=RespBody}) ->
  709. iolist_size(RespBody) > 0.
  710. -spec delete_resp_header(binary(), Req)
  711. -> Req when Req::req().
  712. delete_resp_header(Name, Req=#http_req{resp_headers=RespHeaders}) ->
  713. RespHeaders2 = lists:keydelete(Name, 1, RespHeaders),
  714. Req#http_req{resp_headers=RespHeaders2}.
  715. -spec reply(cowboy:http_status(), Req) -> {ok, Req} when Req::req().
  716. reply(Status, Req=#http_req{resp_body=Body}) ->
  717. reply(Status, [], Body, Req).
  718. -spec reply(cowboy:http_status(), cowboy:http_headers(), Req)
  719. -> {ok, Req} when Req::req().
  720. reply(Status, Headers, Req=#http_req{resp_body=Body}) ->
  721. reply(Status, Headers, Body, Req).
  722. -spec reply(cowboy:http_status(), cowboy:http_headers(),
  723. iodata() | {non_neg_integer() | resp_body_fun()}, Req)
  724. -> {ok, Req} when Req::req().
  725. reply(Status, Headers, Body, Req=#http_req{
  726. socket=Socket, transport=Transport,
  727. version=Version, connection=Connection,
  728. method=Method, resp_compress=Compress,
  729. resp_state=RespState, resp_headers=RespHeaders})
  730. when RespState =:= waiting; RespState =:= waiting_stream ->
  731. HTTP11Headers = if
  732. Transport =/= cowboy_spdy, Version =:= 'HTTP/1.1' ->
  733. [{<<"connection">>, atom_to_connection(Connection)}];
  734. true ->
  735. []
  736. end,
  737. Req3 = case Body of
  738. BodyFun when is_function(BodyFun) ->
  739. %% We stream the response body until we close the connection.
  740. RespConn = close,
  741. {RespType, Req2} = if
  742. Transport =:= cowboy_spdy ->
  743. response(Status, Headers, RespHeaders, [
  744. {<<"date">>, cowboy_clock:rfc1123()},
  745. {<<"server">>, <<"Cowboy">>}
  746. ], stream, Req);
  747. true ->
  748. response(Status, Headers, RespHeaders, [
  749. {<<"connection">>, <<"close">>},
  750. {<<"date">>, cowboy_clock:rfc1123()},
  751. {<<"server">>, <<"Cowboy">>},
  752. {<<"transfer-encoding">>, <<"identity">>}
  753. ], <<>>, Req)
  754. end,
  755. if RespType =/= hook, Method =/= <<"HEAD">> ->
  756. BodyFun(Socket, Transport);
  757. true -> ok
  758. end,
  759. Req2#http_req{connection=RespConn};
  760. {chunked, BodyFun} ->
  761. %% We stream the response body in chunks.
  762. {RespType, Req2} = chunked_response(Status, Headers, Req),
  763. if RespType =/= hook, Method =/= <<"HEAD">> ->
  764. ChunkFun = fun(IoData) -> chunk(IoData, Req2) end,
  765. BodyFun(ChunkFun),
  766. %% Send the last chunk if chunked encoding was used.
  767. if
  768. Version =:= 'HTTP/1.0'; RespState =:= waiting_stream ->
  769. Req2;
  770. true ->
  771. last_chunk(Req2)
  772. end;
  773. true -> Req2
  774. end;
  775. {ContentLength, BodyFun} ->
  776. %% We stream the response body for ContentLength bytes.
  777. RespConn = response_connection(Headers, Connection),
  778. {RespType, Req2} = response(Status, Headers, RespHeaders, [
  779. {<<"content-length">>, integer_to_list(ContentLength)},
  780. {<<"date">>, cowboy_clock:rfc1123()},
  781. {<<"server">>, <<"Cowboy">>}
  782. |HTTP11Headers], stream, Req),
  783. if RespType =/= hook, Method =/= <<"HEAD">> ->
  784. BodyFun(Socket, Transport);
  785. true -> ok
  786. end,
  787. Req2#http_req{connection=RespConn};
  788. _ when Compress ->
  789. RespConn = response_connection(Headers, Connection),
  790. Req2 = reply_may_compress(Status, Headers, Body, Req,
  791. RespHeaders, HTTP11Headers, Method),
  792. Req2#http_req{connection=RespConn};
  793. _ ->
  794. RespConn = response_connection(Headers, Connection),
  795. Req2 = reply_no_compress(Status, Headers, Body, Req,
  796. RespHeaders, HTTP11Headers, Method, iolist_size(Body)),
  797. Req2#http_req{connection=RespConn}
  798. end,
  799. {ok, Req3#http_req{resp_state=done, resp_headers=[], resp_body= <<>>}}.
  800. reply_may_compress(Status, Headers, Body, Req,
  801. RespHeaders, HTTP11Headers, Method) ->
  802. BodySize = iolist_size(Body),
  803. case parse_header(<<"accept-encoding">>, Req) of
  804. {ok, Encodings, Req2} ->
  805. CanGzip = (BodySize > 300)
  806. andalso (false =:= lists:keyfind(<<"content-encoding">>,
  807. 1, Headers))
  808. andalso (false =:= lists:keyfind(<<"content-encoding">>,
  809. 1, RespHeaders))
  810. andalso (false =:= lists:keyfind(<<"transfer-encoding">>,
  811. 1, Headers))
  812. andalso (false =:= lists:keyfind(<<"transfer-encoding">>,
  813. 1, RespHeaders))
  814. andalso (Encodings =/= undefined)
  815. andalso (false =/= lists:keyfind(<<"gzip">>, 1, Encodings)),
  816. case CanGzip of
  817. true ->
  818. GzBody = zlib:gzip(Body),
  819. {_, Req3} = response(Status, Headers, RespHeaders, [
  820. {<<"content-length">>, integer_to_list(byte_size(GzBody))},
  821. {<<"content-encoding">>, <<"gzip">>},
  822. {<<"date">>, cowboy_clock:rfc1123()},
  823. {<<"server">>, <<"Cowboy">>}
  824. |HTTP11Headers],
  825. case Method of <<"HEAD">> -> <<>>; _ -> GzBody end,
  826. Req2),
  827. Req3;
  828. false ->
  829. reply_no_compress(Status, Headers, Body, Req,
  830. RespHeaders, HTTP11Headers, Method, BodySize)
  831. end;
  832. {error, badarg} ->
  833. reply_no_compress(Status, Headers, Body, Req,
  834. RespHeaders, HTTP11Headers, Method, BodySize)
  835. end.
  836. reply_no_compress(Status, Headers, Body, Req,
  837. RespHeaders, HTTP11Headers, Method, BodySize) ->
  838. {_, Req2} = response(Status, Headers, RespHeaders, [
  839. {<<"content-length">>, integer_to_list(BodySize)},
  840. {<<"date">>, cowboy_clock:rfc1123()},
  841. {<<"server">>, <<"Cowboy">>}
  842. |HTTP11Headers],
  843. case Method of <<"HEAD">> -> <<>>; _ -> Body end,
  844. Req),
  845. Req2.
  846. -spec chunked_reply(cowboy:http_status(), Req) -> {ok, Req} when Req::req().
  847. chunked_reply(Status, Req) ->
  848. chunked_reply(Status, [], Req).
  849. -spec chunked_reply(cowboy:http_status(), cowboy:http_headers(), Req)
  850. -> {ok, Req} when Req::req().
  851. chunked_reply(Status, Headers, Req) ->
  852. {_, Req2} = chunked_response(Status, Headers, Req),
  853. {ok, Req2}.
  854. -spec chunk(iodata(), req()) -> ok | {error, atom()}.
  855. chunk(_Data, #http_req{method= <<"HEAD">>}) ->
  856. ok;
  857. chunk(Data, #http_req{socket=Socket, transport=cowboy_spdy,
  858. resp_state=chunks}) ->
  859. cowboy_spdy:stream_data(Socket, Data);
  860. chunk(Data, #http_req{socket=Socket, transport=Transport,
  861. resp_state=stream}) ->
  862. Transport:send(Socket, Data);
  863. chunk(Data, #http_req{socket=Socket, transport=Transport,
  864. resp_state=chunks}) ->
  865. Transport:send(Socket, [integer_to_list(iolist_size(Data), 16),
  866. <<"\r\n">>, Data, <<"\r\n">>]).
  867. %% If ever made public, need to send nothing if HEAD.
  868. -spec last_chunk(Req) -> Req when Req::req().
  869. last_chunk(Req=#http_req{socket=Socket, transport=cowboy_spdy}) ->
  870. _ = cowboy_spdy:stream_close(Socket),
  871. Req#http_req{resp_state=done};
  872. last_chunk(Req=#http_req{socket=Socket, transport=Transport}) ->
  873. _ = Transport:send(Socket, <<"0\r\n\r\n">>),
  874. Req#http_req{resp_state=done}.
  875. -spec upgrade_reply(cowboy:http_status(), cowboy:http_headers(), Req)
  876. -> {ok, Req} when Req::req().
  877. upgrade_reply(Status, Headers, Req=#http_req{transport=Transport,
  878. resp_state=waiting, resp_headers=RespHeaders})
  879. when Transport =/= cowboy_spdy ->
  880. {_, Req2} = response(Status, Headers, RespHeaders, [
  881. {<<"connection">>, <<"Upgrade">>}
  882. ], <<>>, Req),
  883. {ok, Req2#http_req{resp_state=done, resp_headers=[], resp_body= <<>>}}.
  884. %% Meant to be used internally for sending errors after crashes.
  885. -spec maybe_reply(cowboy:http_status(), req()) -> ok.
  886. maybe_reply(Status, Req) ->
  887. receive
  888. {cowboy_req, resp_sent} -> ok
  889. after 0 ->
  890. _ = cowboy_req:reply(Status, Req),
  891. ok
  892. end.
  893. -spec ensure_response(req(), cowboy:http_status()) -> ok.
  894. %% The response has already been fully sent to the client.
  895. ensure_response(#http_req{resp_state=done}, _) ->
  896. ok;
  897. %% No response has been sent but everything apparently went fine.
  898. %% Reply with the status code found in the second argument.
  899. ensure_response(Req=#http_req{resp_state=RespState}, Status)
  900. when RespState =:= waiting; RespState =:= waiting_stream ->
  901. _ = reply(Status, [], [], Req),
  902. ok;
  903. %% Terminate the chunked body for HTTP/1.1 only.
  904. ensure_response(#http_req{method= <<"HEAD">>}, _) ->
  905. ok;
  906. ensure_response(Req=#http_req{resp_state=chunks}, _) ->
  907. _ = last_chunk(Req),
  908. ok;
  909. ensure_response(#http_req{}, _) ->
  910. ok.
  911. %% Private setter/getter API.
  912. -spec append_buffer(binary(), Req) -> Req when Req::req().
  913. append_buffer(Suffix, Req=#http_req{buffer=Buffer}) ->
  914. Req#http_req{buffer= << Buffer/binary, Suffix/binary >>}.
  915. -spec get(atom(), req()) -> any(); ([atom()], req()) -> any().
  916. get(List, Req) when is_list(List) ->
  917. [g(Atom, Req) || Atom <- List];
  918. get(Atom, Req) when is_atom(Atom) ->
  919. g(Atom, Req).
  920. g(bindings, #http_req{bindings=Ret}) -> Ret;
  921. g(body_state, #http_req{body_state=Ret}) -> Ret;
  922. g(buffer, #http_req{buffer=Ret}) -> Ret;
  923. g(connection, #http_req{connection=Ret}) -> Ret;
  924. g(cookies, #http_req{cookies=Ret}) -> Ret;
  925. g(headers, #http_req{headers=Ret}) -> Ret;
  926. g(host, #http_req{host=Ret}) -> Ret;
  927. g(host_info, #http_req{host_info=Ret}) -> Ret;
  928. g(meta, #http_req{meta=Ret}) -> Ret;
  929. g(method, #http_req{method=Ret}) -> Ret;
  930. g(multipart, #http_req{multipart=Ret}) -> Ret;
  931. g(onresponse, #http_req{onresponse=Ret}) -> Ret;
  932. g(p_headers, #http_req{p_headers=Ret}) -> Ret;
  933. g(path, #http_req{path=Ret}) -> Ret;
  934. g(path_info, #http_req{path_info=Ret}) -> Ret;
  935. g(peer, #http_req{peer=Ret}) -> Ret;
  936. g(pid, #http_req{pid=Ret}) -> Ret;
  937. g(port, #http_req{port=Ret}) -> Ret;
  938. g(qs, #http_req{qs=Ret}) -> Ret;
  939. g(qs_vals, #http_req{qs_vals=Ret}) -> Ret;
  940. g(resp_body, #http_req{resp_body=Ret}) -> Ret;
  941. g(resp_compress, #http_req{resp_compress=Ret}) -> Ret;
  942. g(resp_headers, #http_req{resp_headers=Ret}) -> Ret;
  943. g(resp_state, #http_req{resp_state=Ret}) -> Ret;
  944. g(socket, #http_req{socket=Ret}) -> Ret;
  945. g(transport, #http_req{transport=Ret}) -> Ret;
  946. g(version, #http_req{version=Ret}) -> Ret.
  947. -spec set([{atom(), any()}], Req) -> Req when Req::req().
  948. set([], Req) -> Req;
  949. set([{bindings, Val}|Tail], Req) -> set(Tail, Req#http_req{bindings=Val});
  950. set([{body_state, Val}|Tail], Req) -> set(Tail, Req#http_req{body_state=Val});
  951. set([{buffer, Val}|Tail], Req) -> set(Tail, Req#http_req{buffer=Val});
  952. set([{connection, Val}|Tail], Req) -> set(Tail, Req#http_req{connection=Val});
  953. set([{cookies, Val}|Tail], Req) -> set(Tail, Req#http_req{cookies=Val});
  954. set([{headers, Val}|Tail], Req) -> set(Tail, Req#http_req{headers=Val});
  955. set([{host, Val}|Tail], Req) -> set(Tail, Req#http_req{host=Val});
  956. set([{host_info, Val}|Tail], Req) -> set(Tail, Req#http_req{host_info=Val});
  957. set([{meta, Val}|Tail], Req) -> set(Tail, Req#http_req{meta=Val});
  958. set([{method, Val}|Tail], Req) -> set(Tail, Req#http_req{method=Val});
  959. set([{multipart, Val}|Tail], Req) -> set(Tail, Req#http_req{multipart=Val});
  960. set([{onresponse, Val}|Tail], Req) -> set(Tail, Req#http_req{onresponse=Val});
  961. set([{p_headers, Val}|Tail], Req) -> set(Tail, Req#http_req{p_headers=Val});
  962. set([{path, Val}|Tail], Req) -> set(Tail, Req#http_req{path=Val});
  963. set([{path_info, Val}|Tail], Req) -> set(Tail, Req#http_req{path_info=Val});
  964. set([{peer, Val}|Tail], Req) -> set(Tail, Req#http_req{peer=Val});
  965. set([{pid, Val}|Tail], Req) -> set(Tail, Req#http_req{pid=Val});
  966. set([{port, Val}|Tail], Req) -> set(Tail, Req#http_req{port=Val});
  967. set([{qs, Val}|Tail], Req) -> set(Tail, Req#http_req{qs=Val});
  968. set([{qs_vals, Val}|Tail], Req) -> set(Tail, Req#http_req{qs_vals=Val});
  969. set([{resp_body, Val}|Tail], Req) -> set(Tail, Req#http_req{resp_body=Val});
  970. set([{resp_headers, Val}|Tail], Req) -> set(Tail, Req#http_req{resp_headers=Val});
  971. set([{resp_state, Val}|Tail], Req) -> set(Tail, Req#http_req{resp_state=Val});
  972. set([{socket, Val}|Tail], Req) -> set(Tail, Req#http_req{socket=Val});
  973. set([{transport, Val}|Tail], Req) -> set(Tail, Req#http_req{transport=Val});
  974. set([{version, Val}|Tail], Req) -> set(Tail, Req#http_req{version=Val}).
  975. -spec set_bindings(cowboy_router:tokens(), cowboy_router:tokens(),
  976. cowboy_router:bindings(), Req) -> Req when Req::req().
  977. set_bindings(HostInfo, PathInfo, Bindings, Req) ->
  978. Req#http_req{host_info=HostInfo, path_info=PathInfo,
  979. bindings=Bindings}.
  980. %% Misc API.
  981. -spec compact(Req) -> Req when Req::req().
  982. compact(Req) ->
  983. Req#http_req{host_info=undefined,
  984. path_info=undefined, qs_vals=undefined,
  985. bindings=undefined, headers=[],
  986. p_headers=[], cookies=[]}.
  987. -spec lock(Req) -> Req when Req::req().
  988. lock(Req) ->
  989. Req#http_req{resp_state=locked}.
  990. -spec to_list(req()) -> [{atom(), any()}].
  991. to_list(Req) ->
  992. lists:zip(record_info(fields, http_req), tl(tuple_to_list(Req))).
  993. %% Internal.
  994. -spec chunked_response(cowboy:http_status(), cowboy:http_headers(), Req) ->
  995. {normal | hook, Req} when Req::req().
  996. chunked_response(Status, Headers, Req=#http_req{
  997. transport=cowboy_spdy, resp_state=waiting,
  998. resp_headers=RespHeaders}) ->
  999. {RespType, Req2} = response(Status, Headers, RespHeaders, [
  1000. {<<"date">>, cowboy_clock:rfc1123()},
  1001. {<<"server">>, <<"Cowboy">>}
  1002. ], stream, Req),
  1003. {RespType, Req2#http_req{resp_state=chunks,
  1004. resp_headers=[], resp_body= <<>>}};
  1005. chunked_response(Status, Headers, Req=#http_req{
  1006. version=Version, connection=Connection,
  1007. resp_state=RespState, resp_headers=RespHeaders})
  1008. when RespState =:= waiting; RespState =:= waiting_stream ->
  1009. RespConn = response_connection(Headers, Connection),
  1010. HTTP11Headers = if
  1011. Version =:= 'HTTP/1.0' -> [];
  1012. true ->
  1013. MaybeTE = if
  1014. RespState =:= waiting_stream -> [];
  1015. true -> [{<<"transfer-encoding">>, <<"chunked">>}]
  1016. end,
  1017. [{<<"connection">>, atom_to_connection(Connection)}|MaybeTE]
  1018. end,
  1019. RespState2 = if
  1020. Version =:= 'HTTP/1.1', RespState =:= 'waiting' -> chunks;
  1021. true -> stream
  1022. end,
  1023. {RespType, Req2} = response(Status, Headers, RespHeaders, [
  1024. {<<"date">>, cowboy_clock:rfc1123()},
  1025. {<<"server">>, <<"Cowboy">>}
  1026. |HTTP11Headers], <<>>, Req),
  1027. {RespType, Req2#http_req{connection=RespConn, resp_state=RespState2,
  1028. resp_headers=[], resp_body= <<>>}}.
  1029. -spec response(cowboy:http_status(), cowboy:http_headers(),
  1030. cowboy:http_headers(), cowboy:http_headers(), stream | iodata(), Req)
  1031. -> {normal | hook, Req} when Req::req().
  1032. response(Status, Headers, RespHeaders, DefaultHeaders, Body, Req=#http_req{
  1033. socket=Socket, transport=Transport, version=Version,
  1034. pid=ReqPid, onresponse=OnResponse}) ->
  1035. FullHeaders = case OnResponse of
  1036. already_called -> Headers;
  1037. _ -> response_merge_headers(Headers, RespHeaders, DefaultHeaders)
  1038. end,
  1039. Body2 = case Body of stream -> <<>>; _ -> Body end,
  1040. Req2 = case OnResponse of
  1041. already_called -> Req;
  1042. undefined -> Req;
  1043. OnResponse ->
  1044. OnResponse(Status, FullHeaders, Body2,
  1045. %% Don't call 'onresponse' from the hook itself.
  1046. Req#http_req{resp_headers=[], resp_body= <<>>,
  1047. onresponse=already_called})
  1048. end,
  1049. ReplyType = case Req2#http_req.resp_state of
  1050. waiting when Transport =:= cowboy_spdy, Body =:= stream ->
  1051. cowboy_spdy:stream_reply(Socket, status(Status), FullHeaders),
  1052. ReqPid ! {?MODULE, resp_sent},
  1053. normal;
  1054. waiting when Transport =:= cowboy_spdy ->
  1055. cowboy_spdy:reply(Socket, status(Status), FullHeaders, Body),
  1056. ReqPid ! {?MODULE, resp_sent},
  1057. normal;
  1058. RespState when RespState =:= waiting; RespState =:= waiting_stream ->
  1059. HTTPVer = atom_to_binary(Version, latin1),
  1060. StatusLine = << HTTPVer/binary, " ",
  1061. (status(Status))/binary, "\r\n" >>,
  1062. HeaderLines = [[Key, <<": ">>, Value, <<"\r\n">>]
  1063. || {Key, Value} <- FullHeaders],
  1064. Transport:send(Socket, [StatusLine, HeaderLines, <<"\r\n">>, Body2]),
  1065. ReqPid ! {?MODULE, resp_sent},
  1066. normal;
  1067. _ ->
  1068. hook
  1069. end,
  1070. {ReplyType, Req2}.
  1071. -spec response_connection(cowboy:http_headers(), keepalive | close)
  1072. -> keepalive | close.
  1073. response_connection([], Connection) ->
  1074. Connection;
  1075. response_connection([{Name, Value}|Tail], Connection) ->
  1076. case Name of
  1077. <<"connection">> ->
  1078. Tokens = cow_http_hd:parse_connection(Value),
  1079. connection_to_atom(Tokens);
  1080. _ ->
  1081. response_connection(Tail, Connection)
  1082. end.
  1083. -spec response_merge_headers(cowboy:http_headers(), cowboy:http_headers(),
  1084. cowboy:http_headers()) -> cowboy:http_headers().
  1085. response_merge_headers(Headers, RespHeaders, DefaultHeaders) ->
  1086. Headers2 = [{Key, Value} || {Key, Value} <- Headers],
  1087. merge_headers(
  1088. merge_headers(Headers2, RespHeaders),
  1089. DefaultHeaders).
  1090. -spec merge_headers(cowboy:http_headers(), cowboy:http_headers())
  1091. -> cowboy:http_headers().
  1092. %% Merge headers by prepending the tuples in the second list to the
  1093. %% first list. It also handles Set-Cookie properly, which supports
  1094. %% duplicated entries. Notice that, while the RFC2109 does allow more
  1095. %% than one cookie to be set per Set-Cookie header, we are following
  1096. %% the implementation of common web servers and applications which
  1097. %% return many distinct headers per each Set-Cookie entry to avoid
  1098. %% issues with clients/browser which may not support it.
  1099. merge_headers(Headers, []) ->
  1100. Headers;
  1101. merge_headers(Headers, [{<<"set-cookie">>, Value}|Tail]) ->
  1102. merge_headers([{<<"set-cookie">>, Value}|Headers], Tail);
  1103. merge_headers(Headers, [{Name, Value}|Tail]) ->
  1104. Headers2 = case lists:keymember(Name, 1, Headers) of
  1105. true -> Headers;
  1106. false -> [{Name, Value}|Headers]
  1107. end,
  1108. merge_headers(Headers2, Tail).
  1109. -spec atom_to_connection(keepalive) -> <<_:80>>;
  1110. (close) -> <<_:40>>.
  1111. atom_to_connection(keepalive) ->
  1112. <<"keep-alive">>;
  1113. atom_to_connection(close) ->
  1114. <<"close">>.
  1115. %% We don't match on "keep-alive" since it is the default value.
  1116. -spec connection_to_atom([binary()]) -> keepalive | close.
  1117. connection_to_atom([]) ->
  1118. keepalive;
  1119. connection_to_atom([<<"close">>|_]) ->
  1120. close;
  1121. connection_to_atom([_|Tail]) ->
  1122. connection_to_atom(Tail).
  1123. -spec status(cowboy:http_status()) -> binary().
  1124. status(100) -> <<"100 Continue">>;
  1125. status(101) -> <<"101 Switching Protocols">>;
  1126. status(102) -> <<"102 Processing">>;
  1127. status(200) -> <<"200 OK">>;
  1128. status(201) -> <<"201 Created">>;
  1129. status(202) -> <<"202 Accepted">>;
  1130. status(203) -> <<"203 Non-Authoritative Information">>;
  1131. status(204) -> <<"204 No Content">>;
  1132. status(205) -> <<"205 Reset Content">>;
  1133. status(206) -> <<"206 Partial Content">>;
  1134. status(207) -> <<"207 Multi-Status">>;
  1135. status(226) -> <<"226 IM Used">>;
  1136. status(300) -> <<"300 Multiple Choices">>;
  1137. status(301) -> <<"301 Moved Permanently">>;
  1138. status(302) -> <<"302 Found">>;
  1139. status(303) -> <<"303 See Other">>;
  1140. status(304) -> <<"304 Not Modified">>;
  1141. status(305) -> <<"305 Use Proxy">>;
  1142. status(306) -> <<"306 Switch Proxy">>;
  1143. status(307) -> <<"307 Temporary Redirect">>;
  1144. status(400) -> <<"400 Bad Request">>;
  1145. status(401) -> <<"401 Unauthorized">>;
  1146. status(402) -> <<"402 Payment Required">>;
  1147. status(403) -> <<"403 Forbidden">>;
  1148. status(404) -> <<"404 Not Found">>;
  1149. status(405) -> <<"405 Method Not Allowed">>;
  1150. status(406) -> <<"406 Not Acceptable">>;
  1151. status(407) -> <<"407 Proxy Authentication Required">>;
  1152. status(408) -> <<"408 Request Timeout">>;
  1153. status(409) -> <<"409 Conflict">>;
  1154. status(410) -> <<"410 Gone">>;
  1155. status(411) -> <<"411 Length Required">>;
  1156. status(412) -> <<"412 Precondition Failed">>;
  1157. status(413) -> <<"413 Request Entity Too Large">>;
  1158. status(414) -> <<"414 Request-URI Too Long">>;
  1159. status(415) -> <<"415 Unsupported Media Type">>;
  1160. status(416) -> <<"416 Requested Range Not Satisfiable">>;
  1161. status(417) -> <<"417 Expectation Failed">>;
  1162. status(418) -> <<"418 I'm a teapot">>;
  1163. status(422) -> <<"422 Unprocessable Entity">>;
  1164. status(423) -> <<"423 Locked">>;
  1165. status(424) -> <<"424 Failed Dependency">>;
  1166. status(425) -> <<"425 Unordered Collection">>;
  1167. status(426) -> <<"426 Upgrade Required">>;
  1168. status(428) -> <<"428 Precondition Required">>;
  1169. status(429) -> <<"429 Too Many Requests">>;
  1170. status(431) -> <<"431 Request Header Fields Too Large">>;
  1171. status(500) -> <<"500 Internal Server Error">>;
  1172. status(501) -> <<"501 Not Implemented">>;
  1173. status(502) -> <<"502 Bad Gateway">>;
  1174. status(503) -> <<"503 Service Unavailable">>;
  1175. status(504) -> <<"504 Gateway Timeout">>;
  1176. status(505) -> <<"505 HTTP Version Not Supported">>;
  1177. status(506) -> <<"506 Variant Also Negotiates">>;
  1178. status(507) -> <<"507 Insufficient Storage">>;
  1179. status(510) -> <<"510 Not Extended">>;
  1180. status(511) -> <<"511 Network Authentication Required">>;
  1181. status(B) when is_binary(B) -> B.
  1182. %% Tests.
  1183. -ifdef(TEST).
  1184. url_test() ->
  1185. {undefined, _} =
  1186. url(#http_req{transport=ranch_tcp, host= <<>>, port= undefined,
  1187. path= <<>>, qs= <<>>, pid=self()}),
  1188. {<<"http://localhost/path">>, _ } =
  1189. url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=80,
  1190. path= <<"/path">>, qs= <<>>, pid=self()}),
  1191. {<<"http://localhost:443/path">>, _} =
  1192. url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=443,
  1193. path= <<"/path">>, qs= <<>>, pid=self()}),
  1194. {<<"http://localhost:8080/path">>, _} =
  1195. url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080,
  1196. path= <<"/path">>, qs= <<>>, pid=self()}),
  1197. {<<"http://localhost:8080/path?dummy=2785">>, _} =
  1198. url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080,
  1199. path= <<"/path">>, qs= <<"dummy=2785">>, pid=self()}),
  1200. {<<"https://localhost/path">>, _} =
  1201. url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=443,
  1202. path= <<"/path">>, qs= <<>>, pid=self()}),
  1203. {<<"https://localhost:8443/path">>, _} =
  1204. url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443,
  1205. path= <<"/path">>, qs= <<>>, pid=self()}),
  1206. {<<"https://localhost:8443/path?dummy=2785">>, _} =
  1207. url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443,
  1208. path= <<"/path">>, qs= <<"dummy=2785">>, pid=self()}),
  1209. ok.
  1210. connection_to_atom_test_() ->
  1211. Tests = [
  1212. {[<<"close">>], close},
  1213. {[<<"keep-alive">>], keepalive},
  1214. {[<<"keep-alive">>, <<"upgrade">>], keepalive}
  1215. ],
  1216. [{lists:flatten(io_lib:format("~p", [T])),
  1217. fun() -> R = connection_to_atom(T) end} || {T, R} <- Tests].
  1218. merge_headers_test_() ->
  1219. Tests = [
  1220. {[{<<"content-length">>,<<"13">>},{<<"server">>,<<"Cowboy">>}],
  1221. [{<<"set-cookie">>,<<"foo=bar">>},{<<"content-length">>,<<"11">>}],
  1222. [{<<"set-cookie">>,<<"foo=bar">>},
  1223. {<<"content-length">>,<<"13">>},
  1224. {<<"server">>,<<"Cowboy">>}]},
  1225. {[{<<"content-length">>,<<"13">>},{<<"server">>,<<"Cowboy">>}],
  1226. [{<<"set-cookie">>,<<"foo=bar">>},{<<"set-cookie">>,<<"bar=baz">>}],
  1227. [{<<"set-cookie">>,<<"bar=baz">>},
  1228. {<<"set-cookie">>,<<"foo=bar">>},
  1229. {<<"content-length">>,<<"13">>},
  1230. {<<"server">>,<<"Cowboy">>}]}
  1231. ],
  1232. [fun() -> Res = merge_headers(L,R) end || {L, R, Res} <- Tests].
  1233. -endif.