zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

cow_http_hd.erl (134749B)


      1 %% Copyright (c) 2014-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 
     15 -module(cow_http_hd).
     16 
     17 %% Functions are ordered by header name, with the parse
     18 %% function before the build function.
     19 
     20 -export([parse_accept/1]).
     21 -export([parse_accept_charset/1]).
     22 % @todo -export([parse_accept_datetime/1]). RFC7089
     23 -export([parse_accept_encoding/1]).
     24 % @todo -export([parse_accept_features/1]). RFC2295
     25 -export([parse_accept_language/1]).
     26 -export([parse_accept_ranges/1]).
     27 % @todo -export([parse_access_control_allow_credentials/1]). CORS
     28 -export([access_control_allow_credentials/0]).
     29 % @todo -export([parse_access_control_allow_headers/1]). CORS
     30 -export([access_control_allow_headers/1]).
     31 % @todo -export([parse_access_control_allow_methods/1]). CORS
     32 -export([access_control_allow_methods/1]).
     33 % @todo -export([parse_access_control_allow_origin/1]). CORS
     34 -export([access_control_allow_origin/1]).
     35 % @todo -export([parse_access_control_expose_headers/1]). CORS
     36 -export([access_control_expose_headers/1]).
     37 % @todo -export([parse_access_control_max_age/1]). CORS
     38 -export([access_control_max_age/1]).
     39 -export([parse_access_control_request_headers/1]).
     40 -export([parse_access_control_request_method/1]).
     41 -export([parse_age/1]).
     42 -export([parse_allow/1]).
     43 % @todo -export([parse_alternates/1]). RFC2295
     44 % @todo -export([parse_authentication_info/1]). RFC2617
     45 -export([parse_authorization/1]).
     46 -export([parse_cache_control/1]).
     47 -export([parse_connection/1]).
     48 % @todo -export([parse_content_disposition/1]). RFC6266
     49 -export([parse_content_encoding/1]).
     50 -export([parse_content_language/1]).
     51 -export([parse_content_length/1]).
     52 % @todo -export([parse_content_location/1]). RFC7231
     53 % @todo -export([parse_content_md5/1]). RFC2616 (deprecated)
     54 -export([parse_content_range/1]).
     55 % @todo -export([parse_content_security_policy/1]). CSP
     56 % @todo -export([parse_content_security_policy_report_only/1]). CSP
     57 -export([parse_content_type/1]).
     58 -export([parse_cookie/1]).
     59 -export([parse_date/1]).
     60 % @todo -export([parse_digest/1]). RFC3230
     61 % @todo -export([parse_dnt/1]). http://donottrack.us/
     62 -export([parse_etag/1]).
     63 -export([parse_expect/1]).
     64 -export([parse_expires/1]).
     65 % @todo -export([parse_forwarded/1]). RFC7239
     66 % @todo -export([parse_from/1]). RFC7231
     67 -export([parse_host/1]).
     68 -export([parse_http2_settings/1]).
     69 -export([parse_if_match/1]).
     70 -export([parse_if_modified_since/1]).
     71 -export([parse_if_none_match/1]).
     72 -export([parse_if_range/1]).
     73 -export([parse_if_unmodified_since/1]).
     74 % @todo -export([parse_last_event_id/1]). eventsource
     75 -export([parse_last_modified/1]).
     76 -export([parse_link/1]).
     77 % @todo -export([parse_location/1]). RFC7231
     78 -export([parse_max_forwards/1]).
     79 % @todo -export([parse_memento_datetime/1]). RFC7089
     80 % @todo -export([parse_negotiate/1]). RFC2295
     81 -export([parse_origin/1]).
     82 -export([parse_pragma/1]).
     83 % @todo -export([parse_prefer/1]). RFC7240
     84 -export([parse_proxy_authenticate/1]).
     85 % @todo -export([parse_proxy_authentication_info/1]). RFC2617
     86 -export([parse_proxy_authorization/1]).
     87 % @todo -export([parse_proxy_support/1]). RFC4559
     88 % @todo -export([parse_public_key_pins/1]). Key Pinning (upcoming)
     89 % @todo -export([parse_public_key_pins_report_only/1]). Key Pinning (upcoming)
     90 -export([parse_range/1]).
     91 % @todo -export([parse_referer/1]). RFC7231
     92 % @todo -export([parse_refresh/1]). Non-standard (examples: "5", "5; url=http://example.com/")
     93 -export([parse_retry_after/1]).
     94 -export([parse_sec_websocket_accept/1]).
     95 -export([parse_sec_websocket_extensions/1]).
     96 -export([parse_sec_websocket_key/1]).
     97 % @todo -export([parse_sec_websocket_origin/1]). Websocket drafts 7 and 8
     98 -export([parse_sec_websocket_protocol_req/1]).
     99 -export([parse_sec_websocket_protocol_resp/1]).
    100 -export([parse_sec_websocket_version_req/1]).
    101 -export([parse_sec_websocket_version_resp/1]).
    102 % @todo -export([parse_server/1]). RFC7231
    103 -export([parse_set_cookie/1]).
    104 % @todo -export([parse_strict_transport_security/1]). RFC6797
    105 % @todo -export([parse_tcn/1]). RFC2295
    106 -export([parse_te/1]).
    107 -export([parse_trailer/1]).
    108 -export([parse_transfer_encoding/1]).
    109 -export([parse_upgrade/1]).
    110 % @todo -export([parse_user_agent/1]). RFC7231
    111 % @todo -export([parse_variant_vary/1]). RFC2295
    112 -export([parse_variant_key/2]).
    113 -export([variant_key/1]).
    114 -export([parse_variants/1]).
    115 -export([variants/1]).
    116 -export([parse_vary/1]).
    117 % @todo -export([parse_via/1]). RFC7230
    118 % @todo -export([parse_want_digest/1]). RFC3230
    119 % @todo -export([parse_warning/1]). RFC7234
    120 -export([parse_www_authenticate/1]).
    121 % @todo -export([parse_x_content_duration/1]). Gecko/MDN (value: float)
    122 % @todo -export([parse_x_dns_prefetch_control/1]). Various (value: "on"|"off")
    123 -export([parse_x_forwarded_for/1]).
    124 % @todo -export([parse_x_frame_options/1]). RFC7034
    125 
    126 -type etag() :: {weak | strong, binary()}.
    127 -export_type([etag/0]).
    128 
    129 -type media_type() :: {binary(), binary(), [{binary(), binary()}]}.
    130 -export_type([media_type/0]).
    131 
    132 -type qvalue() :: 0..1000.
    133 -export_type([qvalue/0]).
    134 
    135 -type websocket_version() :: 0..255.
    136 -export_type([websocket_version/0]).
    137 
    138 -include("cow_inline.hrl").
    139 -include("cow_parse.hrl").
    140 
    141 -ifdef(TEST).
    142 -include_lib("proper/include/proper.hrl").
    143 
    144 vector(Min, Max, Dom) -> ?LET(N, choose(Min, Max), vector(N, Dom)).
    145 small_list(Dom) -> vector(0, 10, Dom).
    146 small_non_empty_list(Dom) -> vector(1, 10, Dom).
    147 
    148 alpha_chars() -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
    149 alphanum_chars() -> "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
    150 digit_chars() -> "0123456789".
    151 
    152 ows() -> list(elements([$\s, $\t])).
    153 alpha() -> elements(alpha_chars()).
    154 alphanum() -> elements(alphanum_chars()).
    155 digit() -> elements(digit_chars()).
    156 
    157 tchar() ->
    158 	frequency([
    159 		{1, elements([$!, $#, $$, $%, $&, $', $*, $+, $-, $., $^, $_, $`, $|, $~])},
    160 		{99, elements(alphanum_chars())}
    161 	]).
    162 
    163 token() ->
    164 	?LET(T,
    165 		non_empty(list(tchar())),
    166 		list_to_binary(T)).
    167 
    168 abnf_char() ->
    169 	integer(1, 127).
    170 
    171 vchar() ->
    172 	integer(33, 126).
    173 
    174 obs_text() ->
    175 	integer(128, 255).
    176 
    177 qdtext() ->
    178 	frequency([
    179 		{99, elements("\t\s!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")},
    180 		{1, obs_text()}
    181 	]).
    182 
    183 quoted_pair() ->
    184 	[$\\, frequency([
    185 		{99, elements("\t\s!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")},
    186 		{1, obs_text()}
    187 	])].
    188 
    189 quoted_string() ->
    190 	[$", list(frequency([{100, qdtext()}, {1, quoted_pair()}])), $"].
    191 
    192 %% Helper function for ( token / quoted-string ) values.
    193 unquote([$", V, $"]) -> unquote(V, <<>>);
    194 unquote(V) -> V.
    195 
    196 unquote([], Acc) -> Acc;
    197 unquote([[$\\, C]|Tail], Acc) -> unquote(Tail, << Acc/binary, C >>);
    198 unquote([C|Tail], Acc) -> unquote(Tail, << Acc/binary, C >>).
    199 
    200 parameter() ->
    201 	?SUCHTHAT({K, _, _, _},
    202 		{token(), oneof([token(), quoted_string()]), ows(), ows()},
    203 		K =/= <<"q">>).
    204 
    205 weight() ->
    206 	frequency([
    207 		{90, integer(0, 1000)},
    208 		{10, undefined}
    209 	]).
    210 
    211 %% Helper function for weight's qvalue formatting.
    212 qvalue_to_iodata(0) -> <<"0">>;
    213 qvalue_to_iodata(Q) when Q < 10 -> [<<"0.00">>, integer_to_binary(Q)];
    214 qvalue_to_iodata(Q) when Q < 100 -> [<<"0.0">>, integer_to_binary(Q)];
    215 qvalue_to_iodata(Q) when Q < 1000 -> [<<"0.">>, integer_to_binary(Q)];
    216 qvalue_to_iodata(1000) -> <<"1">>.
    217 -endif.
    218 
    219 %% Accept header.
    220 
    221 -spec parse_accept(binary()) -> [{media_type(), qvalue(), [binary() | {binary(), binary()}]}].
    222 parse_accept(<<"*/*">>) ->
    223 	[{{<<"*">>, <<"*">>, []}, 1000, []}];
    224 parse_accept(Accept) ->
    225 	media_range_list(Accept, []).
    226 
    227 media_range_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) -> ?LOWER(media_range_type, R, Acc, <<>>);
    228 media_range_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> media_range_list(R, Acc);
    229 media_range_list(<<>>, Acc) -> lists:reverse(Acc).
    230 
    231 media_range_type(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> ?LOWER(media_range_type, R, Acc, T);
    232 media_range_type(<< $/, C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> ?LOWER(media_range_subtype, R, Acc, T, <<>>);
    233 %% Special clause for badly behaving user agents that send * instead of */*.
    234 media_range_type(<< $;, R/bits >>, Acc, <<"*">>) -> media_range_before_param(R, Acc, <<"*">>, <<"*">>, []).
    235 
    236 media_range_subtype(<< C, R/bits >>, Acc, T, S) when ?IS_TOKEN(C) -> ?LOWER(media_range_subtype, R, Acc, T, S);
    237 media_range_subtype(R, Acc, T, S) -> media_range_param_sep(R, Acc, T, S, []).
    238 
    239 media_range_param_sep(<<>>, Acc, T, S, P) -> lists:reverse([{{T, S, lists:reverse(P)}, 1000, []}|Acc]);
    240 media_range_param_sep(<< $,, R/bits >>, Acc, T, S, P) -> media_range_list(R, [{{T, S, lists:reverse(P)}, 1000, []}|Acc]);
    241 media_range_param_sep(<< $;, R/bits >>, Acc, T, S, P) -> media_range_before_param(R, Acc, T, S, P);
    242 media_range_param_sep(<< C, R/bits >>, Acc, T, S, P) when ?IS_WS(C) -> media_range_param_sep(R, Acc, T, S, P).
    243 
    244 media_range_before_param(<< C, R/bits >>, Acc, T, S, P) when ?IS_WS(C) -> media_range_before_param(R, Acc, T, S, P);
    245 media_range_before_param(<< $q, $=, R/bits >>, Acc, T, S, P) -> media_range_weight(R, Acc, T, S, P);
    246 media_range_before_param(<< "charset=", $", R/bits >>, Acc, T, S, P) -> media_range_charset_quoted(R, Acc, T, S, P, <<>>);
    247 media_range_before_param(<< "charset=", R/bits >>, Acc, T, S, P) -> media_range_charset(R, Acc, T, S, P, <<>>);
    248 media_range_before_param(<< C, R/bits >>, Acc, T, S, P) when ?IS_TOKEN(C) -> ?LOWER(media_range_param, R, Acc, T, S, P, <<>>).
    249 
    250 media_range_charset_quoted(<< $", R/bits >>, Acc, T, S, P, V) ->
    251 	media_range_param_sep(R, Acc, T, S, [{<<"charset">>, V}|P]);
    252 media_range_charset_quoted(<< $\\, C, R/bits >>, Acc, T, S, P, V) when ?IS_VCHAR_OBS(C) ->
    253 	?LOWER(media_range_charset_quoted, R, Acc, T, S, P, V);
    254 media_range_charset_quoted(<< C, R/bits >>, Acc, T, S, P, V) when ?IS_VCHAR_OBS(C) ->
    255 	?LOWER(media_range_charset_quoted, R, Acc, T, S, P, V).
    256 
    257 media_range_charset(<< C, R/bits >>, Acc, T, S, P, V) when ?IS_TOKEN(C) ->
    258 	?LOWER(media_range_charset, R, Acc, T, S, P, V);
    259 media_range_charset(R, Acc, T, S, P, V) ->
    260 	media_range_param_sep(R, Acc, T, S, [{<<"charset">>, V}|P]).
    261 
    262 media_range_param(<< $=, $", R/bits >>, Acc, T, S, P, K) -> media_range_quoted(R, Acc, T, S, P, K, <<>>);
    263 media_range_param(<< $=, C, R/bits >>, Acc, T, S, P, K) when ?IS_TOKEN(C) -> media_range_value(R, Acc, T, S, P, K, << C >>);
    264 media_range_param(<< C, R/bits >>, Acc, T, S, P, K) when ?IS_TOKEN(C) -> ?LOWER(media_range_param, R, Acc, T, S, P, K).
    265 
    266 media_range_quoted(<< $", R/bits >>, Acc, T, S, P, K, V) -> media_range_param_sep(R, Acc, T, S, [{K, V}|P]);
    267 media_range_quoted(<< $\\, C, R/bits >>, Acc, T, S, P, K, V) when ?IS_VCHAR_OBS(C) -> media_range_quoted(R, Acc, T, S, P, K, << V/binary, C >>);
    268 media_range_quoted(<< C, R/bits >>, Acc, T, S, P, K, V) when ?IS_VCHAR_OBS(C) -> media_range_quoted(R, Acc, T, S, P, K, << V/binary, C >>).
    269 
    270 media_range_value(<< C, R/bits >>, Acc, T, S, P, K, V) when ?IS_TOKEN(C) -> media_range_value(R, Acc, T, S, P, K, << V/binary, C >>);
    271 media_range_value(R, Acc, T, S, P, K, V) -> media_range_param_sep(R, Acc, T, S, [{K, V}|P]).
    272 
    273 media_range_weight(<< "1.000", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 1000, []);
    274 media_range_weight(<< "1.00", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 1000, []);
    275 media_range_weight(<< "1.0", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 1000, []);
    276 media_range_weight(<< "1.", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 1000, []);
    277 media_range_weight(<< "1", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 1000, []);
    278 media_range_weight(<< "0.", A, B, C, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
    279 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100 + (B - $0) * 10 + (C - $0), []);
    280 media_range_weight(<< "0.", A, B, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A), ?IS_DIGIT(B) ->
    281 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100 + (B - $0) * 10, []);
    282 media_range_weight(<< "0.", A, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A) ->
    283 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100, []);
    284 media_range_weight(<< "0.", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 0, []);
    285 media_range_weight(<< "0", R/bits >>, Acc, T, S, P) -> accept_ext_sep(R, Acc, T, S, P, 0, []);
    286 %% Special clauses for badly behaving user agents that send .123 instead of 0.123.
    287 media_range_weight(<< ".", A, B, C, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
    288 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100 + (B - $0) * 10 + (C - $0), []);
    289 media_range_weight(<< ".", A, B, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A), ?IS_DIGIT(B) ->
    290 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100 + (B - $0) * 10, []);
    291 media_range_weight(<< ".", A, R/bits >>, Acc, T, S, P) when ?IS_DIGIT(A) ->
    292 	accept_ext_sep(R, Acc, T, S, P, (A - $0) * 100, []).
    293 
    294 accept_ext_sep(<<>>, Acc, T, S, P, Q, E) -> lists:reverse([{{T, S, lists:reverse(P)}, Q, lists:reverse(E)}|Acc]);
    295 accept_ext_sep(<< $,, R/bits >>, Acc, T, S, P, Q, E) -> media_range_list(R, [{{T, S, lists:reverse(P)}, Q, lists:reverse(E)}|Acc]);
    296 accept_ext_sep(<< $;, R/bits >>, Acc, T, S, P, Q, E) -> accept_before_ext(R, Acc, T, S, P, Q, E);
    297 accept_ext_sep(<< C, R/bits >>, Acc, T, S, P, Q, E) when ?IS_WS(C) -> accept_ext_sep(R, Acc, T, S, P, Q, E).
    298 
    299 accept_before_ext(<< C, R/bits >>, Acc, T, S, P, Q, E) when ?IS_WS(C) -> accept_before_ext(R, Acc, T, S, P, Q, E);
    300 accept_before_ext(<< C, R/bits >>, Acc, T, S, P, Q, E) when ?IS_TOKEN(C) -> ?LOWER(accept_ext, R, Acc, T, S, P, Q, E, <<>>).
    301 
    302 accept_ext(<< $=, $", R/bits >>, Acc, T, S, P, Q, E, K) -> accept_quoted(R, Acc, T, S, P, Q, E, K, <<>>);
    303 accept_ext(<< $=, C, R/bits >>, Acc, T, S, P, Q, E, K) when ?IS_TOKEN(C) -> accept_value(R, Acc, T, S, P, Q, E, K, << C >>);
    304 accept_ext(<< C, R/bits >>, Acc, T, S, P, Q, E, K) when ?IS_TOKEN(C) -> ?LOWER(accept_ext, R, Acc, T, S, P, Q, E, K);
    305 accept_ext(R, Acc, T, S, P, Q, E, K) -> accept_ext_sep(R, Acc, T, S, P, Q, [K|E]).
    306 
    307 accept_quoted(<< $", R/bits >>, Acc, T, S, P, Q, E, K, V) -> accept_ext_sep(R, Acc, T, S, P, Q, [{K, V}|E]);
    308 accept_quoted(<< $\\, C, R/bits >>, Acc, T, S, P, Q, E, K, V) when ?IS_VCHAR_OBS(C) -> accept_quoted(R, Acc, T, S, P, Q, E, K, << V/binary, C >>);
    309 accept_quoted(<< C, R/bits >>, Acc, T, S, P, Q, E, K, V) when ?IS_VCHAR_OBS(C) -> accept_quoted(R, Acc, T, S, P, Q, E, K, << V/binary, C >>).
    310 
    311 accept_value(<< C, R/bits >>, Acc, T, S, P, Q, E, K, V) when ?IS_TOKEN(C) -> accept_value(R, Acc, T, S, P, Q, E, K, << V/binary, C >>);
    312 accept_value(R, Acc, T, S, P, Q, E, K, V) -> accept_ext_sep(R, Acc, T, S, P, Q, [{K, V}|E]).
    313 
    314 -ifdef(TEST).
    315 accept_ext() ->
    316 	oneof([token(), parameter()]).
    317 
    318 accept_exts() ->
    319 	frequency([
    320 		{90, []},
    321 		{10, small_list(accept_ext())}
    322 	]).
    323 
    324 accept_param() ->
    325 	frequency([
    326 		{90, parameter()},
    327 		{10, {<<"charset">>, oneof([token(), quoted_string()]), <<>>, <<>>}}
    328 	]).
    329 
    330 accept_params() ->
    331 	small_list(accept_param()).
    332 
    333 accept() ->
    334 	?LET({T, S, P, W, E},
    335 		{token(), token(), accept_params(), weight(), accept_exts()},
    336 		{T, S, P, W, E, iolist_to_binary([T, $/, S,
    337 			[[OWS1, $;, OWS2, K, $=, V] || {K, V, OWS1, OWS2} <- P],
    338 			case W of
    339 				undefined -> [];
    340 				_ -> [
    341 					[<<";q=">>, qvalue_to_iodata(W)],
    342 					[case Ext of
    343 						{K, V, OWS1, OWS2} -> [OWS1, $;, OWS2, K, $=, V];
    344 						K -> [$;, K]
    345 					end || Ext <- E]]
    346 			end])}
    347 	).
    348 
    349 prop_parse_accept() ->
    350 	?FORALL(L,
    351 		vector(1, 50, accept()),
    352 		begin
    353 			<< _, Accept/binary >> = iolist_to_binary([[$,, A] || {_, _, _, _, _, A} <- L]),
    354 			ResL = parse_accept(Accept),
    355 			CheckedL = [begin
    356 				ExpectedP = [case ?LOWER(K) of
    357 					<<"charset">> -> {<<"charset">>, ?LOWER(unquote(V))};
    358 					LowK -> {LowK, unquote(V)}
    359 				end || {K, V, _, _} <- P],
    360 				ExpectedE = [case Ext of
    361 					{K, V, _, _} -> {?LOWER(K), unquote(V)};
    362 					K -> ?LOWER(K)
    363 				end || Ext <- E],
    364 				ResT =:= ?LOWER(T)
    365 					andalso ResS =:= ?LOWER(S)
    366 					andalso ResP =:= ExpectedP
    367 					andalso (ResW =:= W orelse (W =:= undefined andalso ResW =:= 1000))
    368 					andalso ((W =:= undefined andalso ResE =:= []) orelse (W =/= undefined andalso ResE =:= ExpectedE))
    369 			end || {{T, S, P, W, E, _}, {{ResT, ResS, ResP}, ResW, ResE}} <- lists:zip(L, ResL)],
    370 			[true] =:= lists:usort(CheckedL)
    371 		end
    372 	).
    373 
    374 parse_accept_test_() ->
    375 	Tests = [
    376 		{<<>>, []},
    377 		{<<"   ">>, []},
    378 		{<<"audio/*; q=0.2, audio/basic">>, [
    379 			{{<<"audio">>, <<"*">>, []}, 200, []},
    380 			{{<<"audio">>, <<"basic">>, []}, 1000, []}
    381 		]},
    382 		{<<"text/plain; q=0.5, text/html, "
    383 		   "text/x-dvi; q=0.8, text/x-c">>, [
    384 		   {{<<"text">>, <<"plain">>, []}, 500, []},
    385 		   {{<<"text">>, <<"html">>, []}, 1000, []},
    386 		   {{<<"text">>, <<"x-dvi">>, []}, 800, []},
    387 		   {{<<"text">>, <<"x-c">>, []}, 1000, []}
    388 		]},
    389 		{<<"text/*, text/html, text/html;level=1, */*">>, [
    390 			{{<<"text">>, <<"*">>, []}, 1000, []},
    391 			{{<<"text">>, <<"html">>, []}, 1000, []},
    392 			{{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []},
    393 			{{<<"*">>, <<"*">>, []}, 1000, []}
    394 		]},
    395 		{<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
    396 		   "text/html;level=2;q=0.4, */*;q=0.5">>, [
    397 		   {{<<"text">>, <<"*">>, []}, 300, []},
    398 		   {{<<"text">>, <<"html">>, []}, 700, []},
    399 		   {{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []},
    400 		   {{<<"text">>, <<"html">>, [{<<"level">>, <<"2">>}]}, 400, []},
    401 		   {{<<"*">>, <<"*">>, []}, 500, []}
    402 		]},
    403 		{<<"text/html;level=1;quoted=\"hi hi hi\";"
    404 		   "q=0.123;standalone;complex=gits, text/plain">>, [
    405 			{{<<"text">>, <<"html">>,
    406 				[{<<"level">>, <<"1">>}, {<<"quoted">>, <<"hi hi hi">>}]}, 123,
    407 				[<<"standalone">>, {<<"complex">>, <<"gits">>}]},
    408 			{{<<"text">>, <<"plain">>, []}, 1000, []}
    409 		]},
    410 		{<<"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2">>, [
    411 			{{<<"text">>, <<"html">>, []}, 1000, []},
    412 			{{<<"image">>, <<"gif">>, []}, 1000, []},
    413 			{{<<"image">>, <<"jpeg">>, []}, 1000, []},
    414 			{{<<"*">>, <<"*">>, []}, 200, []},
    415 			{{<<"*">>, <<"*">>, []}, 200, []}
    416 		]},
    417 		{<<"text/plain; charset=UTF-8">>, [
    418 			{{<<"text">>, <<"plain">>, [{<<"charset">>, <<"utf-8">>}]}, 1000, []}
    419 		]}
    420 	],
    421 	[{V, fun() -> R = parse_accept(V) end} || {V, R} <- Tests].
    422 
    423 parse_accept_error_test_() ->
    424 	Tests = [
    425 		<<"audio/basic, */;q=0.5">>,
    426 		<<"audio/, audio/basic">>,
    427 		<<"aud\tio/basic">>,
    428 		<<"audio/basic;t=\"zero \\", 0, " woo\"">>
    429 	],
    430 	[{V, fun() -> {'EXIT', _} = (catch parse_accept(V)) end} || V <- Tests].
    431 
    432 horse_parse_accept() ->
    433 	horse:repeat(20000,
    434 		parse_accept(<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
    435 			"text/html;level=2;q=0.4, */*;q=0.5">>)
    436 	).
    437 -endif.
    438 
    439 %% Accept-Charset header.
    440 
    441 -spec parse_accept_charset(binary()) -> [{binary(), qvalue()}].
    442 parse_accept_charset(Charset) ->
    443 	nonempty(conneg_list(Charset, [])).
    444 
    445 conneg_list(<<>>, Acc) -> lists:reverse(Acc);
    446 conneg_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> conneg_list(R, Acc);
    447 conneg_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) -> ?LOWER(conneg, R, Acc, <<>>).
    448 
    449 conneg(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> ?LOWER(conneg, R, Acc, T);
    450 conneg(R, Acc, T) -> conneg_param_sep(R, Acc, T).
    451 
    452 conneg_param_sep(<<>>, Acc, T) -> lists:reverse([{T, 1000}|Acc]);
    453 conneg_param_sep(<< $,, R/bits >>, Acc, T) -> conneg_list(R, [{T, 1000}|Acc]);
    454 conneg_param_sep(<< $;, R/bits >>, Acc, T) -> conneg_before_weight(R, Acc, T);
    455 conneg_param_sep(<< C, R/bits >>, Acc, T) when ?IS_WS(C) -> conneg_param_sep(R, Acc, T).
    456 
    457 conneg_before_weight(<< C, R/bits >>, Acc, T) when ?IS_WS(C) -> conneg_before_weight(R, Acc, T);
    458 conneg_before_weight(<< $q, $=, R/bits >>, Acc, T) -> conneg_weight(R, Acc, T);
    459 %% Special clause for broken user agents that confuse ; and , separators.
    460 conneg_before_weight(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> ?LOWER(conneg, R, [{T, 1000}|Acc], <<>>).
    461 
    462 conneg_weight(<< "1.000", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 1000}|Acc]);
    463 conneg_weight(<< "1.00", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 1000}|Acc]);
    464 conneg_weight(<< "1.0", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 1000}|Acc]);
    465 conneg_weight(<< "1.", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 1000}|Acc]);
    466 conneg_weight(<< "1", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 1000}|Acc]);
    467 conneg_weight(<< "0.", A, B, C, R/bits >>, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
    468 	conneg_list_sep(R, [{T, (A - $0) * 100 + (B - $0) * 10 + (C - $0)}|Acc]);
    469 conneg_weight(<< "0.", A, B, R/bits >>, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B) ->
    470 	conneg_list_sep(R, [{T, (A - $0) * 100 + (B - $0) * 10}|Acc]);
    471 conneg_weight(<< "0.", A, R/bits >>, Acc, T) when ?IS_DIGIT(A) ->
    472 	conneg_list_sep(R, [{T, (A - $0) * 100}|Acc]);
    473 conneg_weight(<< "0.", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 0}|Acc]);
    474 conneg_weight(<< "0", R/bits >>, Acc, T) -> conneg_list_sep(R, [{T, 0}|Acc]).
    475 
    476 conneg_list_sep(<<>>, Acc) -> lists:reverse(Acc);
    477 conneg_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> conneg_list_sep(R, Acc);
    478 conneg_list_sep(<< $,, R/bits >>, Acc) -> conneg_list(R, Acc).
    479 
    480 -ifdef(TEST).
    481 accept_charset() ->
    482 	?LET({C, W},
    483 		{token(), weight()},
    484 		{C, W, iolist_to_binary([C, case W of
    485 			undefined -> [];
    486 			_ -> [<<";q=">>, qvalue_to_iodata(W)]
    487 		end])}
    488 	).
    489 
    490 prop_parse_accept_charset() ->
    491 	?FORALL(L,
    492 		non_empty(list(accept_charset())),
    493 		begin
    494 			<< _, AcceptCharset/binary >> = iolist_to_binary([[$,, A] || {_, _, A} <- L]),
    495 			ResL = parse_accept_charset(AcceptCharset),
    496 			CheckedL = [begin
    497 				ResC =:= ?LOWER(Ch)
    498 					andalso (ResW =:= W orelse (W =:= undefined andalso ResW =:= 1000))
    499 			end || {{Ch, W, _}, {ResC, ResW}} <- lists:zip(L, ResL)],
    500 			[true] =:= lists:usort(CheckedL)
    501 		end).
    502 
    503 parse_accept_charset_test_() ->
    504 	Tests = [
    505 		{<<"iso-8859-5, unicode-1-1;q=0.8">>, [
    506 			{<<"iso-8859-5">>, 1000},
    507 			{<<"unicode-1-1">>, 800}
    508 		]},
    509 		%% Some user agents send this invalid value for the Accept-Charset header
    510 		{<<"ISO-8859-1;utf-8;q=0.7,*;q=0.7">>, [
    511 			{<<"iso-8859-1">>, 1000},
    512 			{<<"utf-8">>, 700},
    513 			{<<"*">>, 700}
    514 		]}
    515 	],
    516 	[{V, fun() -> R = parse_accept_charset(V) end} || {V, R} <- Tests].
    517 
    518 parse_accept_charset_error_test_() ->
    519 	Tests = [
    520 		<<>>
    521 	],
    522 	[{V, fun() -> {'EXIT', _} = (catch parse_accept_charset(V)) end} || V <- Tests].
    523 
    524 horse_parse_accept_charset() ->
    525 	horse:repeat(20000,
    526 		parse_accept_charset(<<"iso-8859-5, unicode-1-1;q=0.8">>)
    527 	).
    528 -endif.
    529 
    530 %% Accept-Encoding header.
    531 
    532 -spec parse_accept_encoding(binary()) -> [{binary(), qvalue()}].
    533 parse_accept_encoding(Encoding) ->
    534 	conneg_list(Encoding, []).
    535 
    536 -ifdef(TEST).
    537 accept_encoding() ->
    538 	?LET({E, W},
    539 		{token(), weight()},
    540 		{E, W, iolist_to_binary([E, case W of
    541 			undefined -> [];
    542 			_ -> [<<";q=">>, qvalue_to_iodata(W)]
    543 		end])}
    544 	).
    545 
    546 %% @todo This property seems useless, see prop_accept_charset.
    547 prop_parse_accept_encoding() ->
    548 	?FORALL(L,
    549 		non_empty(list(accept_encoding())),
    550 		begin
    551 			<< _, AcceptEncoding/binary >> = iolist_to_binary([[$,, A] || {_, _, A} <- L]),
    552 			ResL = parse_accept_encoding(AcceptEncoding),
    553 			CheckedL = [begin
    554 				ResE =:= ?LOWER(E)
    555 					andalso (ResW =:= W orelse (W =:= undefined andalso ResW =:= 1000))
    556 			end || {{E, W, _}, {ResE, ResW}} <- lists:zip(L, ResL)],
    557 			[true] =:= lists:usort(CheckedL)
    558 		end).
    559 
    560 parse_accept_encoding_test_() ->
    561 	Tests = [
    562 		{<<>>, []},
    563 		{<<"*">>, [{<<"*">>, 1000}]},
    564 		{<<"compress, gzip">>, [
    565 			{<<"compress">>, 1000},
    566 			{<<"gzip">>, 1000}
    567 		]},
    568 		{<<"compress;q=0.5, gzip;q=1.0">>, [
    569 			{<<"compress">>, 500},
    570 			{<<"gzip">>, 1000}
    571 		]},
    572 		{<<"gzip;q=1.0, identity; q=0.5, *;q=0">>, [
    573 			{<<"gzip">>, 1000},
    574 			{<<"identity">>, 500},
    575 			{<<"*">>, 0}
    576 		]}
    577 	],
    578 	[{V, fun() -> R = parse_accept_encoding(V) end} || {V, R} <- Tests].
    579 
    580 horse_parse_accept_encoding() ->
    581 	horse:repeat(20000,
    582 		parse_accept_encoding(<<"gzip;q=1.0, identity; q=0.5, *;q=0">>)
    583 	).
    584 -endif.
    585 
    586 %% Accept-Language header.
    587 
    588 -spec parse_accept_language(binary()) -> [{binary(), qvalue()}].
    589 parse_accept_language(LanguageRange) ->
    590 	nonempty(language_range_list(LanguageRange, [])).
    591 
    592 language_range_list(<<>>, Acc) -> lists:reverse(Acc);
    593 language_range_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> language_range_list(R, Acc);
    594 language_range_list(<< $*, R/bits >>, Acc) -> language_range_param_sep(R, Acc, <<"*">>);
    595 language_range_list(<< C, R/bits >>, Acc) when ?IS_ALPHA(C) ->
    596 	?LOWER(language_range, R, Acc, 1, <<>>).
    597 
    598 language_range(<< $-, C, R/bits >>, Acc, _, T) when ?IS_ALPHANUM(C) ->
    599 	?LOWER(language_range_sub, R, Acc, 1, << T/binary, $- >>);
    600 language_range(<< C, R/bits >>, Acc, N, T) when ?IS_ALPHA(C), N < 8 ->
    601 	?LOWER(language_range, R, Acc, N + 1, T);
    602 language_range(R, Acc, _, T) -> language_range_param_sep(R, Acc, T).
    603 
    604 language_range_sub(<< $-, R/bits >>, Acc, _, T) -> language_range_sub(R, Acc, 0, << T/binary, $- >>);
    605 language_range_sub(<< C, R/bits >>, Acc, N, T) when ?IS_ALPHANUM(C), N < 8 ->
    606 	?LOWER(language_range_sub, R, Acc, N + 1, T);
    607 language_range_sub(R, Acc, _, T) -> language_range_param_sep(R, Acc, T).
    608 
    609 language_range_param_sep(<<>>, Acc, T) -> lists:reverse([{T, 1000}|Acc]);
    610 language_range_param_sep(<< $,, R/bits >>, Acc, T) -> language_range_list(R, [{T, 1000}|Acc]);
    611 language_range_param_sep(<< $;, R/bits >>, Acc, T) -> language_range_before_weight(R, Acc, T);
    612 language_range_param_sep(<< C, R/bits >>, Acc, T) when ?IS_WS(C) -> language_range_param_sep(R, Acc, T).
    613 
    614 language_range_before_weight(<< C, R/bits >>, Acc, T) when ?IS_WS(C) -> language_range_before_weight(R, Acc, T);
    615 language_range_before_weight(<< $q, $=, R/bits >>, Acc, T) -> language_range_weight(R, Acc, T);
    616 %% Special clause for broken user agents that confuse ; and , separators.
    617 language_range_before_weight(<< C, R/bits >>, Acc, T) when ?IS_ALPHA(C) ->
    618 	?LOWER(language_range, R, [{T, 1000}|Acc], 1, <<>>).
    619 
    620 language_range_weight(<< "1.000", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 1000}|Acc]);
    621 language_range_weight(<< "1.00", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 1000}|Acc]);
    622 language_range_weight(<< "1.0", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 1000}|Acc]);
    623 language_range_weight(<< "1.", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 1000}|Acc]);
    624 language_range_weight(<< "1", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 1000}|Acc]);
    625 language_range_weight(<< "0.", A, B, C, R/bits >>, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
    626 	language_range_list_sep(R, [{T, (A - $0) * 100 + (B - $0) * 10 + (C - $0)}|Acc]);
    627 language_range_weight(<< "0.", A, B, R/bits >>, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B) ->
    628 	language_range_list_sep(R, [{T, (A - $0) * 100 + (B - $0) * 10}|Acc]);
    629 language_range_weight(<< "0.", A, R/bits >>, Acc, T) when ?IS_DIGIT(A) ->
    630 	language_range_list_sep(R, [{T, (A - $0) * 100}|Acc]);
    631 language_range_weight(<< "0.", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 0}|Acc]);
    632 language_range_weight(<< "0", R/bits >>, Acc, T) -> language_range_list_sep(R, [{T, 0}|Acc]).
    633 
    634 language_range_list_sep(<<>>, Acc) -> lists:reverse(Acc);
    635 language_range_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> language_range_list_sep(R, Acc);
    636 language_range_list_sep(<< $,, R/bits >>, Acc) -> language_range_list(R, Acc).
    637 
    638 -ifdef(TEST).
    639 language_range_tag() ->
    640 	vector(1, 8, alpha()).
    641 
    642 language_range_subtag() ->
    643 	[$-, vector(1, 8, alphanum())].
    644 
    645 language_range() ->
    646 	[language_range_tag(), small_list(language_range_subtag())].
    647 
    648 accept_language() ->
    649 	?LET({R, W},
    650 		{language_range(), weight()},
    651 		{iolist_to_binary(R), W, iolist_to_binary([R, case W of
    652 			undefined -> [];
    653 			_ -> [<<";q=">>, qvalue_to_iodata(W)]
    654 		end])}
    655 	).
    656 
    657 prop_parse_accept_language() ->
    658 	?FORALL(L,
    659 		non_empty(list(accept_language())),
    660 		begin
    661 			<< _, AcceptLanguage/binary >> = iolist_to_binary([[$,, A] || {_, _, A} <- L]),
    662 			ResL = parse_accept_language(AcceptLanguage),
    663 			CheckedL = [begin
    664 				ResR =:= ?LOWER(R)
    665 					andalso (ResW =:= W orelse (W =:= undefined andalso ResW =:= 1000))
    666 			end || {{R, W, _}, {ResR, ResW}} <- lists:zip(L, ResL)],
    667 			[true] =:= lists:usort(CheckedL)
    668 		end).
    669 
    670 parse_accept_language_test_() ->
    671 	Tests = [
    672 		{<<"da, en-gb;q=0.8, en;q=0.7">>, [
    673 			{<<"da">>, 1000},
    674 			{<<"en-gb">>, 800},
    675 			{<<"en">>, 700}
    676 		]},
    677 		{<<"en, en-US, en-cockney, i-cherokee, x-pig-latin, es-419">>, [
    678 			{<<"en">>, 1000},
    679 			{<<"en-us">>, 1000},
    680 			{<<"en-cockney">>, 1000},
    681 			{<<"i-cherokee">>, 1000},
    682 			{<<"x-pig-latin">>, 1000},
    683 			{<<"es-419">>, 1000}
    684 		]}
    685 	],
    686 	[{V, fun() -> R = parse_accept_language(V) end} || {V, R} <- Tests].
    687 
    688 parse_accept_language_error_test_() ->
    689 	Tests = [
    690 		<<>>,
    691 		<<"loooooong">>,
    692 		<<"en-us-loooooong">>,
    693 		<<"419-en-us">>
    694 	],
    695 	[{V, fun() -> {'EXIT', _} = (catch parse_accept_language(V)) end} || V <- Tests].
    696 
    697 horse_parse_accept_language() ->
    698 	horse:repeat(20000,
    699 		parse_accept_language(<<"da, en-gb;q=0.8, en;q=0.7">>)
    700 	).
    701 -endif.
    702 
    703 %% Accept-Ranges header.
    704 
    705 -spec parse_accept_ranges(binary()) -> [binary()].
    706 parse_accept_ranges(<<"none">>) -> [];
    707 parse_accept_ranges(<<"bytes">>) -> [<<"bytes">>];
    708 parse_accept_ranges(AcceptRanges) ->
    709 	nonempty(token_ci_list(AcceptRanges, [])).
    710 
    711 -ifdef(TEST).
    712 parse_accept_ranges_test_() ->
    713 	Tests = [
    714 		{<<"bytes">>, [<<"bytes">>]},
    715 		{<<"none">>, []},
    716 		{<<"bytes, pages, kilos">>, [<<"bytes">>, <<"pages">>, <<"kilos">>]}
    717 	],
    718 	[{V, fun() -> R = parse_accept_ranges(V) end} || {V, R} <- Tests].
    719 
    720 parse_accept_ranges_error_test_() ->
    721 	Tests = [
    722 		<<>>
    723 	],
    724 	[{V, fun() -> {'EXIT', _} = (catch parse_accept_ranges(V)) end} || V <- Tests].
    725 
    726 horse_parse_accept_ranges_none() ->
    727 	horse:repeat(200000,
    728 		parse_accept_ranges(<<"none">>)
    729 	).
    730 
    731 horse_parse_accept_ranges_bytes() ->
    732 	horse:repeat(200000,
    733 		parse_accept_ranges(<<"bytes">>)
    734 	).
    735 
    736 horse_parse_accept_ranges_other() ->
    737 	horse:repeat(200000,
    738 		parse_accept_ranges(<<"bytes, pages, kilos">>)
    739 	).
    740 -endif.
    741 
    742 %% Access-Control-Allow-Credentials header.
    743 
    744 -spec access_control_allow_credentials() -> iodata().
    745 access_control_allow_credentials() -> <<"true">>.
    746 
    747 %% Access-Control-Allow-Headers header.
    748 
    749 -spec access_control_allow_headers([binary()]) -> iodata().
    750 access_control_allow_headers(Headers) ->
    751 	join_token_list(nonempty(Headers)).
    752 
    753 -ifdef(TEST).
    754 access_control_allow_headers_test_() ->
    755 	Tests = [
    756 		{[<<"accept">>], <<"accept">>},
    757 		{[<<"accept">>, <<"authorization">>, <<"content-type">>], <<"accept, authorization, content-type">>}
    758 	],
    759 	[{lists:flatten(io_lib:format("~p", [V])),
    760 		fun() -> R = iolist_to_binary(access_control_allow_headers(V)) end} || {V, R} <- Tests].
    761 
    762 access_control_allow_headers_error_test_() ->
    763 	Tests = [
    764 		[]
    765 	],
    766 	[{lists:flatten(io_lib:format("~p", [V])),
    767 		fun() -> {'EXIT', _} = (catch access_control_allow_headers(V)) end} || V <- Tests].
    768 
    769 horse_access_control_allow_headers() ->
    770 	horse:repeat(200000,
    771 		access_control_allow_headers([<<"accept">>, <<"authorization">>, <<"content-type">>])
    772 	).
    773 -endif.
    774 
    775 %% Access-Control-Allow-Methods header.
    776 
    777 -spec access_control_allow_methods([binary()]) -> iodata().
    778 access_control_allow_methods(Methods) ->
    779 	join_token_list(nonempty(Methods)).
    780 
    781 -ifdef(TEST).
    782 access_control_allow_methods_test_() ->
    783 	Tests = [
    784 		{[<<"GET">>], <<"GET">>},
    785 		{[<<"GET">>, <<"POST">>, <<"DELETE">>], <<"GET, POST, DELETE">>}
    786 	],
    787 	[{lists:flatten(io_lib:format("~p", [V])),
    788 		fun() -> R = iolist_to_binary(access_control_allow_methods(V)) end} || {V, R} <- Tests].
    789 
    790 access_control_allow_methods_error_test_() ->
    791 	Tests = [
    792 		[]
    793 	],
    794 	[{lists:flatten(io_lib:format("~p", [V])),
    795 		fun() -> {'EXIT', _} = (catch access_control_allow_methods(V)) end} || V <- Tests].
    796 
    797 horse_access_control_allow_methods() ->
    798 	horse:repeat(200000,
    799 		access_control_allow_methods([<<"GET">>, <<"POST">>, <<"DELETE">>])
    800 	).
    801 -endif.
    802 
    803 %% Access-Control-Allow-Origin header.
    804 
    805 -spec access_control_allow_origin({binary(), binary(), 0..65535} | reference() | '*') -> iodata().
    806 access_control_allow_origin({Scheme, Host, Port}) ->
    807 	case default_port(Scheme) of
    808 		Port -> [Scheme, <<"://">>, Host];
    809 		_ -> [Scheme, <<"://">>, Host, <<":">>, integer_to_binary(Port)]
    810 	end;
    811 access_control_allow_origin('*') -> <<$*>>;
    812 access_control_allow_origin(Ref) when is_reference(Ref) -> <<"null">>.
    813 
    814 -ifdef(TEST).
    815 access_control_allow_origin_test_() ->
    816 	Tests = [
    817 		{{<<"http">>, <<"www.example.org">>, 8080}, <<"http://www.example.org:8080">>},
    818 		{{<<"http">>, <<"www.example.org">>, 80}, <<"http://www.example.org">>},
    819 		{{<<"http">>, <<"192.0.2.1">>, 8080}, <<"http://192.0.2.1:8080">>},
    820 		{{<<"http">>, <<"192.0.2.1">>, 80}, <<"http://192.0.2.1">>},
    821 		{{<<"http">>, <<"[2001:db8::1]">>, 8080}, <<"http://[2001:db8::1]:8080">>},
    822 		{{<<"http">>, <<"[2001:db8::1]">>, 80}, <<"http://[2001:db8::1]">>},
    823 		{{<<"http">>, <<"[::ffff:192.0.2.1]">>, 8080}, <<"http://[::ffff:192.0.2.1]:8080">>},
    824 		{{<<"http">>, <<"[::ffff:192.0.2.1]">>, 80}, <<"http://[::ffff:192.0.2.1]">>},
    825 		{make_ref(), <<"null">>},
    826 		{'*', <<$*>>}
    827 	],
    828 	[{lists:flatten(io_lib:format("~p", [V])),
    829 		fun() -> R = iolist_to_binary(access_control_allow_origin(V)) end} || {V, R} <- Tests].
    830 
    831 horse_access_control_allow_origin() ->
    832 	horse:repeat(200000,
    833 		access_control_allow_origin({<<"http">>, <<"example.org">>, 8080})
    834 	).
    835 -endif.
    836 
    837 %% Access-Control-Expose-Headers header.
    838 
    839 -spec access_control_expose_headers([binary()]) -> iodata().
    840 access_control_expose_headers(Headers) ->
    841 	join_token_list(nonempty(Headers)).
    842 
    843 -ifdef(TEST).
    844 access_control_expose_headers_test_() ->
    845 	Tests = [
    846 		{[<<"accept">>], <<"accept">>},
    847 		{[<<"accept">>, <<"authorization">>, <<"content-type">>], <<"accept, authorization, content-type">>}
    848 	],
    849 	[{lists:flatten(io_lib:format("~p", [V])),
    850 		fun() -> R = iolist_to_binary(access_control_expose_headers(V)) end} || {V, R} <- Tests].
    851 
    852 access_control_expose_headers_error_test_() ->
    853 	Tests = [
    854 		[]
    855 	],
    856 	[{lists:flatten(io_lib:format("~p", [V])),
    857 		fun() -> {'EXIT', _} = (catch access_control_expose_headers(V)) end} || V <- Tests].
    858 
    859 horse_access_control_expose_headers() ->
    860 	horse:repeat(200000,
    861 		access_control_expose_headers([<<"accept">>, <<"authorization">>, <<"content-type">>])
    862 	).
    863 -endif.
    864 
    865 %% Access-Control-Max-Age header.
    866 
    867 -spec access_control_max_age(non_neg_integer()) -> iodata().
    868 access_control_max_age(MaxAge) -> integer_to_binary(MaxAge).
    869 
    870 -ifdef(TEST).
    871 access_control_max_age_test_() ->
    872 	Tests = [
    873 		{0, <<"0">>},
    874 		{42, <<"42">>},
    875 		{69, <<"69">>},
    876 		{1337, <<"1337">>},
    877 		{3495, <<"3495">>},
    878 		{1234567890, <<"1234567890">>}
    879 	],
    880 	[{V, fun() -> R = access_control_max_age(V) end} || {V, R} <- Tests].
    881 -endif.
    882 
    883 %% Access-Control-Request-Headers header.
    884 
    885 -spec parse_access_control_request_headers(binary()) -> [binary()].
    886 parse_access_control_request_headers(Headers) ->
    887 	token_ci_list(Headers, []).
    888 
    889 -ifdef(TEST).
    890 headers() ->
    891 	?LET(L,
    892 		list({ows(), ows(), token()}),
    893 		case L of
    894 			[] -> {[], <<>>};
    895 			_ ->
    896 				<< _, Headers/binary >> = iolist_to_binary([[OWS1, $,, OWS2, M] || {OWS1, OWS2, M} <- L]),
    897 				{[?LOWER(M) || {_, _, M} <- L], Headers}
    898 		end).
    899 
    900 prop_parse_access_control_request_headers() ->
    901 	?FORALL({L, Headers},
    902 		headers(),
    903 		L =:= parse_access_control_request_headers(Headers)).
    904 
    905 parse_access_control_request_headers_test_() ->
    906 	Tests = [
    907 		{<<>>, []},
    908 		{<<"Content-Type">>, [<<"content-type">>]},
    909 		{<<"accept, authorization, content-type">>, [<<"accept">>, <<"authorization">>, <<"content-type">>]},
    910 		{<<"accept,, , authorization,content-type">>, [<<"accept">>, <<"authorization">>, <<"content-type">>]}
    911 	],
    912 	[{V, fun() -> R = parse_access_control_request_headers(V) end} || {V, R} <- Tests].
    913 
    914 horse_parse_access_control_request_headers() ->
    915 	horse:repeat(200000,
    916 		parse_access_control_request_headers(<<"accept, authorization, content-type">>)
    917 	).
    918 -endif.
    919 
    920 %% Access-Control-Request-Method header.
    921 
    922 -spec parse_access_control_request_method(binary()) -> binary().
    923 parse_access_control_request_method(Method) ->
    924 	true = <<>> =/= Method,
    925 	ok = validate_token(Method),
    926 	Method.
    927 
    928 validate_token(<< C, R/bits >>) when ?IS_TOKEN(C) -> validate_token(R);
    929 validate_token(<<>>) -> ok. 
    930 
    931 -ifdef(TEST).
    932 parse_access_control_request_method_test_() ->
    933 	Tests = [
    934 		<<"GET">>,
    935 		<<"HEAD">>,
    936 		<<"POST">>,
    937 		<<"PUT">>,
    938 		<<"DELETE">>,
    939 		<<"TRACE">>,
    940 		<<"CONNECT">>,
    941 		<<"whatever">>
    942 	],
    943 	[{V, fun() -> R = parse_access_control_request_method(V) end} || {V, R} <- Tests].
    944 
    945 parse_access_control_request_method_error_test_() ->
    946 	Tests = [
    947 		<<>>
    948 	],
    949 	[{V, fun() -> {'EXIT', _} = (catch parse_access_control_request_method(V)) end} || V <- Tests].
    950 
    951 horse_parse_access_control_request_method() ->
    952 	horse:repeat(200000,
    953 		parse_access_control_request_method(<<"POST">>)
    954 	).
    955 -endif.
    956 
    957 %% Age header.
    958 
    959 -spec parse_age(binary()) -> non_neg_integer().
    960 parse_age(Age) ->
    961 	I = binary_to_integer(Age),
    962 	true = I >= 0,
    963 	I.
    964 
    965 -ifdef(TEST).
    966 parse_age_test_() ->
    967 	Tests = [
    968 		{<<"0">>, 0},
    969 		{<<"42">>, 42},
    970 		{<<"69">>, 69},
    971 		{<<"1337">>, 1337},
    972 		{<<"3495">>, 3495},
    973 		{<<"1234567890">>, 1234567890}
    974 	],
    975 	[{V, fun() -> R = parse_age(V) end} || {V, R} <- Tests].
    976 
    977 parse_age_error_test_() ->
    978 	Tests = [
    979 		<<>>,
    980 		<<"123, 123">>,
    981 		<<"4.17">>
    982 	],
    983 	[{V, fun() -> {'EXIT', _} = (catch parse_age(V)) end} || V <- Tests].
    984 -endif.
    985 
    986 %% Allow header.
    987 
    988 -spec parse_allow(binary()) -> [binary()].
    989 parse_allow(Allow) ->
    990 	token_list(Allow, []).
    991 
    992 -ifdef(TEST).
    993 allow() ->
    994 	?LET(L,
    995 		list({ows(), ows(), token()}),
    996 		case L of
    997 			[] -> {[], <<>>};
    998 			_ ->
    999 				<< _, Allow/binary >> = iolist_to_binary([[OWS1, $,, OWS2, M] || {OWS1, OWS2, M} <- L]),
   1000 				{[M || {_, _, M} <- L], Allow}
   1001 		end).
   1002 
   1003 prop_parse_allow() ->
   1004 	?FORALL({L, Allow},
   1005 		allow(),
   1006 		L =:= parse_allow(Allow)).
   1007 
   1008 parse_allow_test_() ->
   1009 	Tests = [
   1010 		{<<>>, []},
   1011 		{<<"GET, HEAD, PUT">>, [<<"GET">>, <<"HEAD">>, <<"PUT">>]}
   1012 	],
   1013 	[{V, fun() -> R = parse_allow(V) end} || {V, R} <- Tests].
   1014 
   1015 horse_parse_allow() ->
   1016 	horse:repeat(200000,
   1017 		parse_allow(<<"GET, HEAD, PUT">>)
   1018 	).
   1019 -endif.
   1020 
   1021 %% Authorization header.
   1022 %%
   1023 %% We support Basic, Digest and Bearer schemes only.
   1024 %%
   1025 %% In the Digest case we do not validate that the mandatory
   1026 %% fields are present. When parsing auth-params, we do not
   1027 %% accept BWS characters around the "=".
   1028 
   1029 -spec parse_authorization(binary())
   1030 	-> {basic, binary(), binary()}
   1031 	| {bearer, binary()}
   1032 	| {digest, [{binary(), binary()}]}.
   1033 parse_authorization(<<B, A, S, I, C, " ", R/bits >>)
   1034 		when ((B =:= $B) or (B =:= $b)), ((A =:= $A) or (A =:= $a)),
   1035 			((S =:= $S) or (S =:= $s)), ((I =:= $I) or (I =:= $i)),
   1036 			((C =:= $C) or (C =:= $c)) ->
   1037 	auth_basic(base64:decode(R), <<>>);
   1038 parse_authorization(<<B, E1, A, R1, E2, R2, " ", R/bits >>)
   1039 		when (R =/= <<>>), ((B =:= $B) or (B =:= $b)),
   1040 			((E1 =:= $E) or (E1 =:= $e)), ((A =:= $A) or (A =:= $a)),
   1041 			((R1 =:= $R) or (R1 =:= $r)), ((E2 =:= $E) or (E2 =:= $e)),
   1042 			((R2 =:= $R) or (R2 =:= $r)) ->
   1043 	validate_auth_bearer(R),
   1044 	{bearer, R};
   1045 parse_authorization(<<D, I, G, E, S, T, " ", R/bits >>)
   1046 		when ((D =:= $D) or (D =:= $d)), ((I =:= $I) or (I =:= $i)),
   1047 			((G =:= $G) or (G =:= $g)), ((E =:= $E) or (E =:= $e)),
   1048 			((S =:= $S) or (S =:= $s)), ((T =:= $T) or (T =:= $t)) ->
   1049 	{digest, nonempty(auth_digest_list(R, []))}.
   1050 
   1051 auth_basic(<< $:, Password/bits >>, UserID) -> {basic, UserID, Password};
   1052 auth_basic(<< C, R/bits >>, UserID) -> auth_basic(R, << UserID/binary, C >>).
   1053 
   1054 validate_auth_bearer(<< C, R/bits >>) when ?IS_TOKEN68(C) -> validate_auth_bearer(R);
   1055 validate_auth_bearer(<< $=, R/bits >>) -> validate_auth_bearer_eq(R);
   1056 validate_auth_bearer(<<>>) -> ok.
   1057 
   1058 validate_auth_bearer_eq(<< $=, R/bits >>) -> validate_auth_bearer_eq(R);
   1059 validate_auth_bearer_eq(<<>>) -> ok.
   1060 
   1061 auth_digest_list(<<>>, Acc) -> lists:reverse(Acc);
   1062 auth_digest_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> auth_digest_list(R, Acc);
   1063 auth_digest_list(<< "algorithm=", C, R/bits >>, Acc) when ?IS_TOKEN(C) -> auth_digest_token(R, Acc, <<"algorithm">>, << C >>);
   1064 auth_digest_list(<< "cnonce=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"cnonce">>, <<>>);
   1065 auth_digest_list(<< "nc=", A, B, C, D, E, F, G, H, R/bits >>, Acc)
   1066 		when ?IS_LHEX(A), ?IS_LHEX(B), ?IS_LHEX(C), ?IS_LHEX(D),
   1067 			?IS_LHEX(E), ?IS_LHEX(F), ?IS_LHEX(G), ?IS_LHEX(H) ->
   1068 	auth_digest_list_sep(R, [{<<"nc">>, << A, B, C, D, E, F, G, H >>}|Acc]);
   1069 auth_digest_list(<< "nonce=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"nonce">>, <<>>);
   1070 auth_digest_list(<< "opaque=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"opaque">>, <<>>);
   1071 auth_digest_list(<< "qop=", C, R/bits >>, Acc) when ?IS_TOKEN(C) -> auth_digest_token(R, Acc, <<"qop">>, << C >>);
   1072 auth_digest_list(<< "realm=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"realm">>, <<>>);
   1073 auth_digest_list(<< "response=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"response">>, <<>>);
   1074 auth_digest_list(<< "uri=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"uri">>, <<>>);
   1075 auth_digest_list(<< "username=\"", R/bits >>, Acc) -> auth_digest_quoted(R, Acc, <<"username">>, <<>>);
   1076 auth_digest_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) ->
   1077 	?LOWER(auth_digest_param, R, Acc, <<>>).
   1078 
   1079 auth_digest_param(<< $=, $", R/bits >>, Acc, K) -> auth_digest_quoted(R, Acc, K, <<>>);
   1080 auth_digest_param(<< $=, C, R/bits >>, Acc, K) when ?IS_TOKEN(C) -> auth_digest_token(R, Acc, K, << C >>);
   1081 auth_digest_param(<< C, R/bits >>, Acc, K) when ?IS_TOKEN(C) ->
   1082 	?LOWER(auth_digest_param, R, Acc, K).
   1083 
   1084 auth_digest_token(<< C, R/bits >>, Acc, K, V) when ?IS_TOKEN(C) -> auth_digest_token(R, Acc, K, << V/binary, C >>);
   1085 auth_digest_token(R, Acc, K, V) -> auth_digest_list_sep(R, [{K, V}|Acc]).
   1086 
   1087 auth_digest_quoted(<< $", R/bits >>, Acc, K, V) -> auth_digest_list_sep(R, [{K, V}|Acc]);
   1088 auth_digest_quoted(<< $\\, C, R/bits >>, Acc, K, V) when ?IS_VCHAR_OBS(C) -> auth_digest_quoted(R, Acc, K, << V/binary, C >>);
   1089 auth_digest_quoted(<< C, R/bits >>, Acc, K, V) when ?IS_VCHAR_OBS(C) -> auth_digest_quoted(R, Acc, K, << V/binary, C >>).
   1090 
   1091 auth_digest_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   1092 auth_digest_list_sep(<< $,, R/bits >>, Acc) -> auth_digest_list(R, Acc);
   1093 auth_digest_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> auth_digest_list_sep(R, Acc).
   1094 
   1095 -ifdef(TEST).
   1096 parse_authorization_test_() ->
   1097 	Tests = [
   1098 		{<<"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>, {basic, <<"Aladdin">>, <<"open sesame">>}},
   1099 		{<<"bAsIc QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>, {basic, <<"Aladdin">>, <<"open sesame">>}},
   1100 		{<<"Bearer mF_9.B5f-4.1JqM">>, {bearer, <<"mF_9.B5f-4.1JqM">>}},
   1101 		{<<"bEaRer mF_9.B5f-4.1JqM">>, {bearer, <<"mF_9.B5f-4.1JqM">>}},
   1102 		{<<"Digest username=\"Mufasa\","
   1103 				"realm=\"testrealm@host.com\","
   1104 				"nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
   1105 				"uri=\"/dir/index.html\","
   1106 				"qop=auth,"
   1107 				"nc=00000001,"
   1108 				"cnonce=\"0a4f113b\","
   1109 				"response=\"6629fae49393a05397450978507c4ef1\","
   1110 				"opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"">>,
   1111 			{digest, [
   1112 				{<<"username">>, <<"Mufasa">>},
   1113 				{<<"realm">>, <<"testrealm@host.com">>},
   1114 				{<<"nonce">>, <<"dcd98b7102dd2f0e8b11d0f600bfb0c093">>},
   1115 				{<<"uri">>, <<"/dir/index.html">>},
   1116 				{<<"qop">>, <<"auth">>},
   1117 				{<<"nc">>, <<"00000001">>},
   1118 				{<<"cnonce">>, <<"0a4f113b">>},
   1119 				{<<"response">>, <<"6629fae49393a05397450978507c4ef1">>},
   1120 				{<<"opaque">>, <<"5ccc069c403ebaf9f0171e9517f40e41">>}]}}
   1121 	],
   1122 	[{V, fun() -> R = parse_authorization(V) end} || {V, R} <- Tests].
   1123 
   1124 horse_parse_authorization_basic() ->
   1125 	horse:repeat(20000,
   1126 		parse_authorization(<<"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>)
   1127 	).
   1128 
   1129 horse_parse_authorization_bearer() ->
   1130 	horse:repeat(20000,
   1131 		parse_authorization(<<"Bearer mF_9.B5f-4.1JqM">>)
   1132 	).
   1133 
   1134 horse_parse_authorization_digest() ->
   1135 	horse:repeat(20000,
   1136 		parse_authorization(
   1137 			<<"Digest username=\"Mufasa\","
   1138 				"realm=\"testrealm@host.com\","
   1139 				"nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
   1140 				"uri=\"/dir/index.html\","
   1141 				"qop=auth,"
   1142 				"nc=00000001,"
   1143 				"cnonce=\"0a4f113b\","
   1144 				"response=\"6629fae49393a05397450978507c4ef1\","
   1145 				"opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"">>)
   1146 	).
   1147 -endif.
   1148 
   1149 %% Cache-Control header.
   1150 %%
   1151 %% In the fields list case, we do not support escaping, which shouldn't be needed anyway.
   1152 
   1153 -spec parse_cache_control(binary())
   1154 	-> [binary() | {binary(), binary()} | {binary(), non_neg_integer()} | {binary(), [binary()]}].
   1155 parse_cache_control(<<"no-cache">>) ->
   1156 	[<<"no-cache">>];
   1157 parse_cache_control(<<"max-age=0">>) ->
   1158 	[{<<"max-age">>, 0}];
   1159 parse_cache_control(CacheControl) ->
   1160 	nonempty(cache_directive_list(CacheControl, [])).
   1161 
   1162 cache_directive_list(<<>>, Acc) -> lists:reverse(Acc);
   1163 cache_directive_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C)-> cache_directive_list(R, Acc);
   1164 cache_directive_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) ->
   1165 	?LOWER(cache_directive, R, Acc, <<>>).
   1166 
   1167 cache_directive(<< $=, $", R/bits >>, Acc, T)
   1168 		when (T =:= <<"no-cache">>) or (T =:= <<"private">>) ->
   1169 	cache_directive_fields_list(R, Acc, T, []);
   1170 cache_directive(<< $=, C, R/bits >>, Acc, T)
   1171 		when ?IS_DIGIT(C), (T =:= <<"max-age">>) or (T =:= <<"max-stale">>)
   1172 			or (T =:= <<"min-fresh">>) or (T =:= <<"s-maxage">>) ->
   1173 	cache_directive_delta(R, Acc, T, (C - $0));
   1174 cache_directive(<< $=, $", R/bits >>, Acc, T) -> cache_directive_quoted_string(R, Acc, T, <<>>);
   1175 cache_directive(<< $=, C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> cache_directive_token(R, Acc, T, << C >>);
   1176 cache_directive(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) ->
   1177 	?LOWER(cache_directive, R, Acc, T);
   1178 cache_directive(R, Acc, T) -> cache_directive_list_sep(R, [T|Acc]).
   1179 
   1180 cache_directive_delta(<< C, R/bits >>, Acc, K, V) when ?IS_DIGIT(C) -> cache_directive_delta(R, Acc, K, V * 10 + (C - $0));
   1181 cache_directive_delta(R, Acc, K, V) -> cache_directive_list_sep(R, [{K, V}|Acc]).
   1182 
   1183 cache_directive_fields_list(<< C, R/bits >>, Acc, K, L) when ?IS_WS_COMMA(C) -> cache_directive_fields_list(R, Acc, K, L);
   1184 cache_directive_fields_list(<< $", R/bits >>, Acc, K, L) -> cache_directive_list_sep(R, [{K, lists:reverse(L)}|Acc]);
   1185 cache_directive_fields_list(<< C, R/bits >>, Acc, K, L) when ?IS_TOKEN(C) ->
   1186 	?LOWER(cache_directive_field, R, Acc, K, L, <<>>).
   1187 
   1188 cache_directive_field(<< C, R/bits >>, Acc, K, L, F) when ?IS_TOKEN(C) ->
   1189 	?LOWER(cache_directive_field, R, Acc, K, L, F);
   1190 cache_directive_field(R, Acc, K, L, F) -> cache_directive_fields_list_sep(R, Acc, K, [F|L]).
   1191 
   1192 cache_directive_fields_list_sep(<< C, R/bits >>, Acc, K, L) when ?IS_WS(C) -> cache_directive_fields_list_sep(R, Acc, K, L);
   1193 cache_directive_fields_list_sep(<< $,, R/bits >>, Acc, K, L) -> cache_directive_fields_list(R, Acc, K, L);
   1194 cache_directive_fields_list_sep(<< $", R/bits >>, Acc, K, L) -> cache_directive_list_sep(R, [{K, lists:reverse(L)}|Acc]).
   1195 
   1196 cache_directive_token(<< C, R/bits >>, Acc, K, V) when ?IS_TOKEN(C) -> cache_directive_token(R, Acc, K, << V/binary, C >>);
   1197 cache_directive_token(R, Acc, K, V) -> cache_directive_list_sep(R, [{K, V}|Acc]).
   1198 
   1199 cache_directive_quoted_string(<< $", R/bits >>, Acc, K, V) -> cache_directive_list_sep(R, [{K, V}|Acc]);
   1200 cache_directive_quoted_string(<< $\\, C, R/bits >>, Acc, K, V) when ?IS_VCHAR_OBS(C) ->
   1201 	cache_directive_quoted_string(R, Acc, K, << V/binary, C >>);
   1202 cache_directive_quoted_string(<< C, R/bits >>, Acc, K, V) when ?IS_VCHAR_OBS(C) ->
   1203 	cache_directive_quoted_string(R, Acc, K, << V/binary, C >>).
   1204 
   1205 cache_directive_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   1206 cache_directive_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> cache_directive_list_sep(R, Acc);
   1207 cache_directive_list_sep(<< $,, R/bits >>, Acc) -> cache_directive_list(R, Acc).
   1208 
   1209 -ifdef(TEST).
   1210 cache_directive_unreserved_token() ->
   1211 	?SUCHTHAT(T,
   1212 		token(),
   1213 		T =/= <<"max-age">> andalso T =/= <<"max-stale">> andalso T =/= <<"min-fresh">>
   1214 			andalso T =/= <<"s-maxage">> andalso T =/= <<"no-cache">> andalso T =/= <<"private">>).
   1215 
   1216 cache_directive() ->
   1217 	oneof([
   1218 		token(),
   1219 		{cache_directive_unreserved_token(), token()},
   1220 		{cache_directive_unreserved_token(), quoted_string()},
   1221 		{elements([<<"max-age">>, <<"max-stale">>, <<"min-fresh">>, <<"s-maxage">>]), non_neg_integer()},
   1222 		{fields, elements([<<"no-cache">>, <<"private">>]), small_list(token())}
   1223 	]).
   1224 
   1225 cache_control() ->
   1226 	?LET(L,
   1227 		non_empty(list(cache_directive())),
   1228 		begin
   1229 			<< _, CacheControl/binary >> = iolist_to_binary([[$,,
   1230 				case C of
   1231 					{fields, K, V} -> [K, $=, $", [[F, $,] || F <- V], $"];
   1232 					{K, V} when is_integer(V) -> [K, $=, integer_to_binary(V)];
   1233 					{K, V} -> [K, $=, V];
   1234 					K -> K
   1235 				end] || C <- L]),
   1236 			{L, CacheControl}
   1237 		end).
   1238 
   1239 prop_parse_cache_control() ->
   1240 	?FORALL({L, CacheControl},
   1241 		cache_control(),
   1242 		begin
   1243 			ResL = parse_cache_control(CacheControl),
   1244 			CheckedL = [begin
   1245 				ExpectedCc = case Cc of
   1246 					{fields, K, V} -> {?LOWER(K), [?LOWER(F) || F <- V]};
   1247 					{K, V} -> {?LOWER(K), unquote(V)};
   1248 					K -> ?LOWER(K)
   1249 				end,
   1250 				ExpectedCc =:= ResCc
   1251 			end || {Cc, ResCc} <- lists:zip(L, ResL)],
   1252 			[true] =:= lists:usort(CheckedL)
   1253 		end).
   1254 
   1255 parse_cache_control_test_() ->
   1256 	Tests = [
   1257 		{<<"no-cache">>, [<<"no-cache">>]},
   1258 		{<<"no-store">>, [<<"no-store">>]},
   1259 		{<<"max-age=0">>, [{<<"max-age">>, 0}]},
   1260 		{<<"max-age=30">>, [{<<"max-age">>, 30}]},
   1261 		{<<"private, community=\"UCI\"">>, [<<"private">>, {<<"community">>, <<"UCI">>}]},
   1262 		{<<"private=\"Content-Type, Content-Encoding, Content-Language\"">>,
   1263 			[{<<"private">>, [<<"content-type">>, <<"content-encoding">>, <<"content-language">>]}]}
   1264 	],
   1265 	[{V, fun() -> R = parse_cache_control(V) end} || {V, R} <- Tests].
   1266 
   1267 parse_cache_control_error_test_() ->
   1268 	Tests = [
   1269 		<<>>
   1270 	],
   1271 	[{V, fun() -> {'EXIT', _} = (catch parse_cache_control(V)) end} || V <- Tests].
   1272 
   1273 horse_parse_cache_control_no_cache() ->
   1274 	horse:repeat(200000,
   1275 		parse_cache_control(<<"no-cache">>)
   1276 	).
   1277 
   1278 horse_parse_cache_control_max_age_0() ->
   1279 	horse:repeat(200000,
   1280 		parse_cache_control(<<"max-age=0">>)
   1281 	).
   1282 
   1283 horse_parse_cache_control_max_age_30() ->
   1284 	horse:repeat(200000,
   1285 		parse_cache_control(<<"max-age=30">>)
   1286 	).
   1287 
   1288 horse_parse_cache_control_custom() ->
   1289 	horse:repeat(200000,
   1290 		parse_cache_control(<<"private, community=\"UCI\"">>)
   1291 	).
   1292 
   1293 horse_parse_cache_control_fields() ->
   1294 	horse:repeat(200000,
   1295 		parse_cache_control(<<"private=\"Content-Type, Content-Encoding, Content-Language\"">>)
   1296 	).
   1297 -endif.
   1298 
   1299 %% Connection header.
   1300 
   1301 -spec parse_connection(binary()) -> [binary()].
   1302 parse_connection(<<"close">>) ->
   1303 	[<<"close">>];
   1304 parse_connection(<<"keep-alive">>) ->
   1305 	[<<"keep-alive">>];
   1306 parse_connection(Connection) ->
   1307 	nonempty(token_ci_list(Connection, [])).
   1308 
   1309 -ifdef(TEST).
   1310 prop_parse_connection() ->
   1311 	?FORALL(L,
   1312 		non_empty(list(token())),
   1313 		begin
   1314 			<< _, Connection/binary >> = iolist_to_binary([[$,, C] || C <- L]),
   1315 			ResL = parse_connection(Connection),
   1316 			CheckedL = [?LOWER(Co) =:= ResC || {Co, ResC} <- lists:zip(L, ResL)],
   1317 			[true] =:= lists:usort(CheckedL)
   1318 		end).
   1319 
   1320 parse_connection_test_() ->
   1321 	Tests = [
   1322 		{<<"close">>, [<<"close">>]},
   1323 		{<<"ClOsE">>, [<<"close">>]},
   1324 		{<<"Keep-Alive">>, [<<"keep-alive">>]},
   1325 		{<<"keep-alive, Upgrade">>, [<<"keep-alive">>, <<"upgrade">>]}
   1326 	],
   1327 	[{V, fun() -> R = parse_connection(V) end} || {V, R} <- Tests].
   1328 
   1329 parse_connection_error_test_() ->
   1330 	Tests = [
   1331 		<<>>
   1332 	],
   1333 	[{V, fun() -> {'EXIT', _} = (catch parse_connection(V)) end} || V <- Tests].
   1334 
   1335 horse_parse_connection_close() ->
   1336 	horse:repeat(200000,
   1337 		parse_connection(<<"close">>)
   1338 	).
   1339 
   1340 horse_parse_connection_keepalive() ->
   1341 	horse:repeat(200000,
   1342 		parse_connection(<<"keep-alive">>)
   1343 	).
   1344 
   1345 horse_parse_connection_keepalive_upgrade() ->
   1346 	horse:repeat(200000,
   1347 		parse_connection(<<"keep-alive, upgrade">>)
   1348 	).
   1349 -endif.
   1350 
   1351 %% Content-Encoding header.
   1352 
   1353 -spec parse_content_encoding(binary()) -> [binary()].
   1354 parse_content_encoding(ContentEncoding) ->
   1355 	nonempty(token_ci_list(ContentEncoding, [])).
   1356 
   1357 -ifdef(TEST).
   1358 parse_content_encoding_test_() ->
   1359 	Tests = [
   1360 		{<<"gzip">>, [<<"gzip">>]}
   1361 	],
   1362 	[{V, fun() -> R = parse_content_encoding(V) end} || {V, R} <- Tests].
   1363 
   1364 parse_content_encoding_error_test_() ->
   1365 	Tests = [
   1366 		<<>>
   1367 	],
   1368 	[{V, fun() -> {'EXIT', _} = (catch parse_content_encoding(V)) end} || V <- Tests].
   1369 
   1370 horse_parse_content_encoding() ->
   1371 	horse:repeat(200000,
   1372 		parse_content_encoding(<<"gzip">>)
   1373 	).
   1374 -endif.
   1375 
   1376 %% Content-Language header.
   1377 %%
   1378 %% We do not support irregular deprecated tags that do not match the ABNF.
   1379 
   1380 -spec parse_content_language(binary()) -> [binary()].
   1381 parse_content_language(ContentLanguage) ->
   1382 	nonempty(langtag_list(ContentLanguage, [])).
   1383 
   1384 langtag_list(<<>>, Acc) -> lists:reverse(Acc);
   1385 langtag_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> langtag_list(R, Acc);
   1386 langtag_list(<< A, B, C, R/bits >>, Acc) when ?IS_ALPHA(A), ?IS_ALPHA(B), ?IS_ALPHA(C) ->
   1387 	langtag_extlang(R, Acc, << ?LC(A), ?LC(B), ?LC(C) >>, 0);
   1388 langtag_list(<< A, B, R/bits >>, Acc) when ?IS_ALPHA(A), ?IS_ALPHA(B) ->
   1389 	langtag_extlang(R, Acc, << ?LC(A), ?LC(B) >>, 0);
   1390 langtag_list(<< X, R/bits >>, Acc) when X =:= $x; X =:= $X -> langtag_privateuse_sub(R, Acc, << $x >>, 0).
   1391 
   1392 langtag_extlang(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T, _)
   1393 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1394 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1395 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>);
   1396 langtag_extlang(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T, _)
   1397 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1398 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1399 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>);
   1400 langtag_extlang(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T, _)
   1401 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1402 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F) ->
   1403 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>);
   1404 langtag_extlang(<< $-, A, B, C, D, E, R/bits >>, Acc, T, _)
   1405 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1406 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>);
   1407 langtag_extlang(<< $-, A, B, C, D, R/bits >>, Acc, T, _)
   1408 		when ?IS_ALPHA(A), ?IS_ALPHA(B), ?IS_ALPHA(C), ?IS_ALPHA(D) ->
   1409 	langtag_region(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D) >>);
   1410 langtag_extlang(<< $-, A, B, C, R/bits >>, Acc, T, N)
   1411 		when ?IS_ALPHA(A), ?IS_ALPHA(B), ?IS_ALPHA(C) ->
   1412 	case N of
   1413 		2 -> langtag_script(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C) >>);
   1414 		_ -> langtag_extlang(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C) >>, N + 1)
   1415 	end;
   1416 langtag_extlang(R, Acc, T, _) -> langtag_region(R, Acc, T).
   1417 
   1418 langtag_script(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T)
   1419 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1420 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1421 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>);
   1422 langtag_script(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T)
   1423 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1424 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1425 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>);
   1426 langtag_script(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T)
   1427 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1428 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F) ->
   1429 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>);
   1430 langtag_script(<< $-, A, B, C, D, E, R/bits >>, Acc, T)
   1431 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1432 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>);
   1433 langtag_script(<< $-, A, B, C, D, R/bits >>, Acc, T)
   1434 		when ?IS_ALPHA(A), ?IS_ALPHA(B), ?IS_ALPHA(C), ?IS_ALPHA(D) ->
   1435 	langtag_region(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D) >>);
   1436 langtag_script(R, Acc, T) ->
   1437 	langtag_region(R, Acc, T).
   1438 
   1439 langtag_region(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T)
   1440 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1441 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1442 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>);
   1443 langtag_region(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T)
   1444 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1445 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1446 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>);
   1447 langtag_region(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T)
   1448 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1449 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F) ->
   1450 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>);
   1451 langtag_region(<< $-, A, B, C, D, E, R/bits >>, Acc, T)
   1452 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1453 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>);
   1454 langtag_region(<< $-, A, B, C, D, R/bits >>, Acc, T)
   1455 		when ?IS_DIGIT(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D) ->
   1456 	langtag_variant(R, Acc, << T/binary, $-, A, ?LC(B), ?LC(C), ?LC(D) >>);
   1457 langtag_region(<< $-, A, B, R/bits >>, Acc, T) when ?IS_ALPHA(A), ?IS_ALPHA(B) ->
   1458 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B) >>);
   1459 langtag_region(<< $-, A, B, C, R/bits >>, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
   1460 	langtag_variant(R, Acc, << T/binary, $-, A, B, C >>);
   1461 langtag_region(R, Acc, T) ->
   1462 	langtag_variant(R, Acc, T).
   1463 
   1464 langtag_variant(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T)
   1465 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1466 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1467 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>);
   1468 langtag_variant(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T)
   1469 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1470 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1471 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>);
   1472 langtag_variant(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T)
   1473 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1474 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F) ->
   1475 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>);
   1476 langtag_variant(<< $-, A, B, C, D, E, R/bits >>, Acc, T)
   1477 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1478 	langtag_variant(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>);
   1479 langtag_variant(<< $-, A, B, C, D, R/bits >>, Acc, T)
   1480 		when ?IS_DIGIT(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D) ->
   1481 	langtag_variant(R, Acc, << T/binary, $-, A, ?LC(B), ?LC(C), ?LC(D) >>);
   1482 langtag_variant(R, Acc, T) ->
   1483 	langtag_extension(R, Acc, T).
   1484 
   1485 langtag_extension(<< $-, X, R/bits >>, Acc, T) when X =:= $x; X =:= $X -> langtag_privateuse_sub(R, Acc, << T/binary, $-, $x >>, 0);
   1486 langtag_extension(<< $-, S, R/bits >>, Acc, T) when ?IS_ALPHANUM(S) -> langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(S) >>, 0);
   1487 langtag_extension(R, Acc, T) -> langtag_list_sep(R, [T|Acc]).
   1488 
   1489 langtag_extension_sub(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T, N)
   1490 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1491 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1492 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>, N + 1);
   1493 langtag_extension_sub(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T, N)
   1494 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1495 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1496 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>, N + 1);
   1497 langtag_extension_sub(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T, N)
   1498 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1499 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F) ->
   1500 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>, N + 1);
   1501 langtag_extension_sub(<< $-, A, B, C, D, E, R/bits >>, Acc, T, N)
   1502 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1503 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>, N + 1);
   1504 langtag_extension_sub(<< $-, A, B, C, D, R/bits >>, Acc, T, N)
   1505 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D)  ->
   1506 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D) >>, N + 1);
   1507 langtag_extension_sub(<< $-, A, B, C, R/bits >>, Acc, T, N)
   1508 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C)  ->
   1509 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C) >>, N + 1);
   1510 langtag_extension_sub(<< $-, A, B, R/bits >>, Acc, T, N)
   1511 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B)  ->
   1512 	langtag_extension_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B) >>, N + 1);
   1513 langtag_extension_sub(R, Acc, T, N) when N > 0 ->
   1514 	langtag_extension(R, Acc, T).
   1515 
   1516 langtag_privateuse_sub(<< $-, A, B, C, D, E, F, G, H, R/bits >>, Acc, T, N)
   1517 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1518 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G), ?IS_ALPHANUM(H) ->
   1519 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G), ?LC(H) >>, N + 1);
   1520 langtag_privateuse_sub(<< $-, A, B, C, D, E, F, G, R/bits >>, Acc, T, N)
   1521 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1522 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F), ?IS_ALPHANUM(G) ->
   1523 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F), ?LC(G) >>, N + 1);
   1524 langtag_privateuse_sub(<< $-, A, B, C, D, E, F, R/bits >>, Acc, T, N)
   1525 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D),
   1526 			?IS_ALPHANUM(E), ?IS_ALPHANUM(F)  ->
   1527 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E), ?LC(F) >>, N + 1);
   1528 langtag_privateuse_sub(<< $-, A, B, C, D, E, R/bits >>, Acc, T, N)
   1529 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D), ?IS_ALPHANUM(E) ->
   1530 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D), ?LC(E) >>, N + 1);
   1531 langtag_privateuse_sub(<< $-, A, B, C, D, R/bits >>, Acc, T, N)
   1532 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C), ?IS_ALPHANUM(D) ->
   1533 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C), ?LC(D) >>, N + 1);
   1534 langtag_privateuse_sub(<< $-, A, B, C, R/bits >>, Acc, T, N)
   1535 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B), ?IS_ALPHANUM(C) ->
   1536 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B), ?LC(C) >>, N + 1);
   1537 langtag_privateuse_sub(<< $-, A, B, R/bits >>, Acc, T, N)
   1538 		when ?IS_ALPHANUM(A), ?IS_ALPHANUM(B) ->
   1539 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A), ?LC(B) >>, N + 1);
   1540 langtag_privateuse_sub(<< $-, A, R/bits >>, Acc, T, N)
   1541 		when ?IS_ALPHANUM(A) ->
   1542 	langtag_privateuse_sub(R, Acc, << T/binary, $-, ?LC(A) >>, N + 1);
   1543 langtag_privateuse_sub(R, Acc, T, N) when N > 0 -> langtag_list_sep(R, [T|Acc]).
   1544 
   1545 langtag_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   1546 langtag_list_sep(<< $,, R/bits >>, Acc) -> langtag_list(R, Acc);
   1547 langtag_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> langtag_list_sep(R, Acc).
   1548 
   1549 -ifdef(TEST).
   1550 langtag_language() -> vector(2, 3, alpha()).
   1551 langtag_extlang() -> vector(0, 3, [$-, alpha(), alpha(), alpha()]).
   1552 langtag_script() -> oneof([[], [$-, alpha(), alpha(), alpha(), alpha()]]).
   1553 langtag_region() -> oneof([[], [$-, alpha(), alpha()], [$-, digit(), digit(), digit()]]).
   1554 
   1555 langtag_variant() ->
   1556 	small_list(frequency([
   1557 		{4, [$-, vector(5, 8, alphanum())]},
   1558 		{1, [$-, digit(), alphanum(), alphanum(), alphanum()]}
   1559 	])).
   1560 
   1561 langtag_extension() ->
   1562 	small_list([$-, ?SUCHTHAT(S, alphanum(), S =/= $x andalso S =/= $X),
   1563 		small_non_empty_list([$-, vector(2, 8, alphanum())])
   1564 	]).
   1565 
   1566 langtag_privateuse() -> oneof([[], [$-, langtag_privateuse_nodash()]]).
   1567 langtag_privateuse_nodash() -> [elements([$x, $X]), small_non_empty_list([$-, vector(1, 8, alphanum())])].
   1568 private_language_tag() -> ?LET(T, langtag_privateuse_nodash(), iolist_to_binary(T)).
   1569 
   1570 language_tag() ->
   1571 	?LET(IoList,
   1572 		[langtag_language(), langtag_extlang(), langtag_script(), langtag_region(),
   1573 			langtag_variant(), langtag_extension(), langtag_privateuse()],
   1574 		iolist_to_binary(IoList)).
   1575 
   1576 content_language() ->
   1577 	?LET(L,
   1578 		non_empty(list(frequency([
   1579 			{90, language_tag()},
   1580 			{10, private_language_tag()}
   1581 		]))),
   1582 		begin
   1583 			<< _, ContentLanguage/binary >> = iolist_to_binary([[$,, T] || T <- L]),
   1584 			{L, ContentLanguage}
   1585 		end).
   1586 
   1587 prop_parse_content_language() ->
   1588 	?FORALL({L, ContentLanguage},
   1589 		content_language(),
   1590 		begin
   1591 			ResL = parse_content_language(ContentLanguage),
   1592 			CheckedL = [?LOWER(T) =:= ResT || {T, ResT} <- lists:zip(L, ResL)],
   1593 			[true] =:= lists:usort(CheckedL)
   1594 		end).
   1595 
   1596 parse_content_language_test_() ->
   1597 	Tests = [
   1598 		{<<"de">>, [<<"de">>]},
   1599 		{<<"fr">>, [<<"fr">>]},
   1600 		{<<"ja">>, [<<"ja">>]},
   1601 		{<<"zh-Hant">>, [<<"zh-hant">>]},
   1602 		{<<"zh-Hans">>, [<<"zh-hans">>]},
   1603 		{<<"sr-Cyrl">>, [<<"sr-cyrl">>]},
   1604 		{<<"sr-Latn">>, [<<"sr-latn">>]},
   1605 		{<<"zh-cmn-Hans-CN">>, [<<"zh-cmn-hans-cn">>]},
   1606 		{<<"cmn-Hans-CN">>, [<<"cmn-hans-cn">>]},
   1607 		{<<"zh-yue-HK">>, [<<"zh-yue-hk">>]},
   1608 		{<<"yue-HK">>, [<<"yue-hk">>]},
   1609 		{<<"zh-Hans-CN">>, [<<"zh-hans-cn">>]},
   1610 		{<<"sr-Latn-RS">>, [<<"sr-latn-rs">>]},
   1611 		{<<"sl-rozaj">>, [<<"sl-rozaj">>]},
   1612 		{<<"sl-rozaj-biske">>, [<<"sl-rozaj-biske">>]},
   1613 		{<<"sl-nedis">>, [<<"sl-nedis">>]},
   1614 		{<<"de-CH-1901">>, [<<"de-ch-1901">>]},
   1615 		{<<"sl-IT-nedis">>, [<<"sl-it-nedis">>]},
   1616 		{<<"hy-Latn-IT-arevela">>, [<<"hy-latn-it-arevela">>]},
   1617 		{<<"de-DE">>, [<<"de-de">>]},
   1618 		{<<"en-US">>, [<<"en-us">>]},
   1619 		{<<"es-419">>, [<<"es-419">>]},
   1620 		{<<"de-CH-x-phonebk">>, [<<"de-ch-x-phonebk">>]},
   1621 		{<<"az-Arab-x-AZE-derbend">>, [<<"az-arab-x-aze-derbend">>]},
   1622 		{<<"x-whatever">>, [<<"x-whatever">>]},
   1623 		{<<"qaa-Qaaa-QM-x-southern">>, [<<"qaa-qaaa-qm-x-southern">>]},
   1624 		{<<"de-Qaaa">>, [<<"de-qaaa">>]},
   1625 		{<<"sr-Latn-QM">>, [<<"sr-latn-qm">>]},
   1626 		{<<"sr-Qaaa-RS">>, [<<"sr-qaaa-rs">>]},
   1627 		{<<"en-US-u-islamcal">>, [<<"en-us-u-islamcal">>]},
   1628 		{<<"zh-CN-a-myext-x-private">>, [<<"zh-cn-a-myext-x-private">>]},
   1629 		{<<"en-a-myext-b-another">>, [<<"en-a-myext-b-another">>]},
   1630 		{<<"mn-Cyrl-MN">>, [<<"mn-cyrl-mn">>]},
   1631 		{<<"MN-cYRL-mn">>, [<<"mn-cyrl-mn">>]},
   1632 		{<<"mN-cYrL-Mn">>, [<<"mn-cyrl-mn">>]},
   1633 		{<<"az-Arab-IR">>, [<<"az-arab-ir">>]},
   1634 		{<<"zh-gan">>, [<<"zh-gan">>]},
   1635 		{<<"zh-yue">>, [<<"zh-yue">>]},
   1636 		{<<"zh-cmn">>, [<<"zh-cmn">>]},
   1637 		{<<"de-AT">>, [<<"de-at">>]},
   1638 		{<<"de-CH-1996">>, [<<"de-ch-1996">>]},
   1639 		{<<"en-Latn-GB-boont-r-extended-sequence-x-private">>,
   1640 			[<<"en-latn-gb-boont-r-extended-sequence-x-private">>]},
   1641 		{<<"el-x-koine">>, [<<"el-x-koine">>]},
   1642 		{<<"el-x-attic">>, [<<"el-x-attic">>]},
   1643 		{<<"fr, en-US, es-419, az-Arab, x-pig-latin, man-Nkoo-GN">>,
   1644 			[<<"fr">>, <<"en-us">>, <<"es-419">>, <<"az-arab">>, <<"x-pig-latin">>, <<"man-nkoo-gn">>]},
   1645 		{<<"da">>, [<<"da">>]},
   1646 		{<<"mi, en">>, [<<"mi">>, <<"en">>]}
   1647 	],
   1648 	[{V, fun() -> R = parse_content_language(V) end} || {V, R} <- Tests].
   1649 
   1650 parse_content_language_error_test_() ->
   1651 	Tests = [
   1652 		<<>>
   1653 	],
   1654 	[{V, fun() -> {'EXIT', _} = (catch parse_content_language(V)) end} || V <- Tests].
   1655 
   1656 horse_parse_content_language() ->
   1657 	horse:repeat(100000,
   1658 		parse_content_language(<<"fr, en-US, es-419, az-Arab, x-pig-latin, man-Nkoo-GN">>)
   1659 	).
   1660 -endif.
   1661 
   1662 %% Content-Length header.
   1663 
   1664 -spec parse_content_length(binary()) -> non_neg_integer().
   1665 parse_content_length(ContentLength) ->
   1666 	I = binary_to_integer(ContentLength),
   1667 	true = I >= 0,
   1668 	I.
   1669 
   1670 -ifdef(TEST).
   1671 prop_parse_content_length() ->
   1672 	?FORALL(
   1673 		X,
   1674 		non_neg_integer(),
   1675 		X =:= parse_content_length(integer_to_binary(X))
   1676 	).
   1677 
   1678 parse_content_length_test_() ->
   1679 	Tests = [
   1680 		{<<"0">>, 0},
   1681 		{<<"42">>, 42},
   1682 		{<<"69">>, 69},
   1683 		{<<"1337">>, 1337},
   1684 		{<<"3495">>, 3495},
   1685 		{<<"1234567890">>, 1234567890}
   1686 	],
   1687 	[{V, fun() -> R = parse_content_length(V) end} || {V, R} <- Tests].
   1688 
   1689 parse_content_length_error_test_() ->
   1690 	Tests = [
   1691 		<<>>,
   1692 		<<"-1">>,
   1693 		<<"123, 123">>,
   1694 		<<"4.17">>
   1695 	],
   1696 	[{V, fun() -> {'EXIT', _} = (catch parse_content_length(V)) end} || V <- Tests].
   1697 
   1698 horse_parse_content_length_zero() ->
   1699 	horse:repeat(100000,
   1700 		parse_content_length(<<"0">>)
   1701 	).
   1702 
   1703 horse_parse_content_length_giga() ->
   1704 	horse:repeat(100000,
   1705 		parse_content_length(<<"1234567890">>)
   1706 	).
   1707 -endif.
   1708 
   1709 %% Content-Range header.
   1710 
   1711 -spec parse_content_range(binary())
   1712 	-> {bytes, non_neg_integer(), non_neg_integer(), non_neg_integer() | '*'}
   1713 	| {bytes, '*', non_neg_integer()} | {binary(), binary()}.
   1714 parse_content_range(<<"bytes */", C, R/bits >>) when ?IS_DIGIT(C) -> unsatisfied_range(R, C - $0);
   1715 parse_content_range(<<"bytes ", C, R/bits >>) when ?IS_DIGIT(C) -> byte_range_first(R, C - $0);
   1716 parse_content_range(<< C, R/bits >>) when ?IS_TOKEN(C) ->
   1717 	?LOWER(other_content_range_unit, R, <<>>).
   1718 
   1719 byte_range_first(<< $-, C, R/bits >>, First) when ?IS_DIGIT(C) -> byte_range_last(R, First, C - $0);
   1720 byte_range_first(<< C, R/bits >>, First) when ?IS_DIGIT(C) -> byte_range_first(R, First * 10 + C - $0).
   1721 
   1722 byte_range_last(<<"/*">>, First, Last) -> {bytes, First, Last, '*'};
   1723 byte_range_last(<< $/, C, R/bits >>, First, Last) when ?IS_DIGIT(C) -> byte_range_complete(R, First, Last, C - $0);
   1724 byte_range_last(<< C, R/bits >>, First, Last) when ?IS_DIGIT(C) -> byte_range_last(R, First, Last * 10 + C - $0).
   1725 
   1726 byte_range_complete(<<>>, First, Last, Complete) -> {bytes, First, Last, Complete};
   1727 byte_range_complete(<< C, R/bits >>, First, Last, Complete) when ?IS_DIGIT(C) ->
   1728 	byte_range_complete(R, First, Last, Complete * 10 + C - $0).
   1729 
   1730 unsatisfied_range(<<>>, Complete) -> {bytes, '*', Complete};
   1731 unsatisfied_range(<< C, R/bits >>, Complete) when ?IS_DIGIT(C) -> unsatisfied_range(R, Complete * 10 + C - $0).
   1732 
   1733 other_content_range_unit(<< $\s, R/bits >>, Unit) -> other_content_range_resp(R, Unit, <<>>);
   1734 other_content_range_unit(<< C, R/bits >>, Unit) when ?IS_TOKEN(C) ->
   1735 	?LOWER(other_content_range_unit, R, Unit).
   1736 
   1737 other_content_range_resp(<<>>, Unit, Resp) -> {Unit, Resp};
   1738 other_content_range_resp(<< C, R/bits >>, Unit, Resp) when ?IS_CHAR(C) -> other_content_range_resp(R, Unit, << Resp/binary, C >>).
   1739 
   1740 -ifdef(TEST).
   1741 content_range() ->
   1742 	?LET(ContentRange,
   1743 		oneof([
   1744 			?SUCHTHAT({bytes, First, Last, Complete},
   1745 				{bytes, non_neg_integer(), non_neg_integer(), non_neg_integer()},
   1746 				First =< Last andalso Last < Complete),
   1747 			?SUCHTHAT({bytes, First, Last, '*'},
   1748 				{bytes, non_neg_integer(), non_neg_integer(), '*'},
   1749 				First =< Last),
   1750 			{bytes, '*', non_neg_integer()},
   1751 			{token(), ?LET(L, list(abnf_char()), list_to_binary(L))}
   1752 		]),
   1753 		{case ContentRange of
   1754 			{Unit, Resp} when is_binary(Unit) -> {?LOWER(Unit), Resp};
   1755 			_ -> ContentRange
   1756 		end, case ContentRange of
   1757 			{bytes, First, Last, '*'} ->
   1758 				<< "bytes ", (integer_to_binary(First))/binary, "-",
   1759 					(integer_to_binary(Last))/binary, "/*">>;
   1760 			{bytes, First, Last, Complete} ->
   1761 				<< "bytes ", (integer_to_binary(First))/binary, "-",
   1762 					(integer_to_binary(Last))/binary, "/", (integer_to_binary(Complete))/binary >>;
   1763 			{bytes, '*', Complete} ->
   1764 				<< "bytes */", (integer_to_binary(Complete))/binary >>;
   1765 			{Unit, Resp} ->
   1766 				<< Unit/binary, $\s, Resp/binary >>
   1767 		end}).
   1768 
   1769 prop_parse_content_range() ->
   1770 	?FORALL({Res, ContentRange},
   1771 		content_range(),
   1772 		Res =:= parse_content_range(ContentRange)).
   1773 
   1774 parse_content_range_test_() ->
   1775 	Tests = [
   1776 		{<<"bytes 21010-47021/47022">>, {bytes, 21010, 47021, 47022}},
   1777 		{<<"bytes 500-999/8000">>, {bytes, 500, 999, 8000}},
   1778 		{<<"bytes 7000-7999/8000">>, {bytes, 7000, 7999, 8000}},
   1779 		{<<"bytes 42-1233/1234">>, {bytes, 42, 1233, 1234}},
   1780 		{<<"bytes 42-1233/*">>, {bytes, 42, 1233, '*'}},
   1781 		{<<"bytes */1234">>, {bytes, '*', 1234}},
   1782 		{<<"bytes 0-499/1234">>, {bytes, 0, 499, 1234}},
   1783 		{<<"bytes 500-999/1234">>, {bytes, 500, 999, 1234}},
   1784 		{<<"bytes 500-1233/1234">>, {bytes, 500, 1233, 1234}},
   1785 		{<<"bytes 734-1233/1234">>, {bytes, 734, 1233, 1234}},
   1786 		{<<"bytes */47022">>, {bytes, '*', 47022}},
   1787 		{<<"exampleunit 1.2-4.3/25">>, {<<"exampleunit">>, <<"1.2-4.3/25">>}},
   1788 		{<<"exampleunit 11.2-14.3/25">>, {<<"exampleunit">>, <<"11.2-14.3/25">>}}
   1789 	],
   1790 	[{V, fun() -> R = parse_content_range(V) end} || {V, R} <- Tests].
   1791 
   1792 parse_content_range_error_test_() ->
   1793 	Tests = [
   1794 		<<>>
   1795 	],
   1796 	[{V, fun() -> {'EXIT', _} = (catch parse_content_range(V)) end} || V <- Tests].
   1797 
   1798 horse_parse_content_range_bytes() ->
   1799 	horse:repeat(200000,
   1800 		parse_content_range(<<"bytes 21010-47021/47022">>)
   1801 	).
   1802 
   1803 horse_parse_content_range_other() ->
   1804 	horse:repeat(200000,
   1805 		parse_content_range(<<"exampleunit 11.2-14.3/25">>)
   1806 	).
   1807 -endif.
   1808 
   1809 %% Content-Type header.
   1810 
   1811 -spec parse_content_type(binary()) -> media_type().
   1812 parse_content_type(<< C, R/bits >>) when ?IS_TOKEN(C) ->
   1813 	?LOWER(media_type, R, <<>>).
   1814 
   1815 media_type(<< $/, C, R/bits >>, T) when ?IS_TOKEN(C) ->
   1816 	?LOWER(media_subtype, R, T, <<>>);
   1817 media_type(<< C, R/bits >>, T) when ?IS_TOKEN(C) ->
   1818 	?LOWER(media_type, R, T).
   1819 
   1820 media_subtype(<< C, R/bits >>, T, S) when ?IS_TOKEN(C) ->
   1821 	?LOWER(media_subtype, R, T, S);
   1822 media_subtype(R, T, S) -> media_param_sep(R, T, S, []).
   1823 
   1824 media_param_sep(<<>>, T, S, P) -> {T, S, lists:reverse(P)};
   1825 media_param_sep(<< $;, R/bits >>, T, S, P) -> media_before_param(R, T, S, P);
   1826 media_param_sep(<< C, R/bits >>, T, S, P) when ?IS_WS(C) -> media_param_sep(R, T, S, P).
   1827 
   1828 media_before_param(<< C, R/bits >>, T, S, P) when ?IS_WS(C)-> media_before_param(R, T, S, P);
   1829 media_before_param(<< "charset=", $", R/bits >>, T, S, P) -> media_charset_quoted(R, T, S, P, <<>>);
   1830 media_before_param(<< "charset=", R/bits >>, T, S, P) -> media_charset(R, T, S, P, <<>>);
   1831 media_before_param(<< C, R/bits >>, T, S, P) when ?IS_TOKEN(C) ->
   1832 	?LOWER(media_param, R, T, S, P, <<>>).
   1833 
   1834 media_charset_quoted(<< $", R/bits >>, T, S, P, V) ->
   1835 	media_param_sep(R, T, S, [{<<"charset">>, V}|P]);
   1836 media_charset_quoted(<< $\\, C, R/bits >>, T, S, P, V) when ?IS_VCHAR_OBS(C) ->
   1837 	?LOWER(media_charset_quoted, R, T, S, P, V);
   1838 media_charset_quoted(<< C, R/bits >>, T, S, P, V) when ?IS_VCHAR_OBS(C) ->
   1839 	?LOWER(media_charset_quoted, R, T, S, P, V).
   1840 
   1841 media_charset(<< C, R/bits >>, T, S, P, V) when ?IS_TOKEN(C) ->
   1842 	?LOWER(media_charset, R, T, S, P, V);
   1843 media_charset(R, T, S, P, V) -> media_param_sep(R, T, S, [{<<"charset">>, V}|P]).
   1844 
   1845 media_param(<< $=, $", R/bits >>, T, S, P, K) -> media_quoted(R, T, S, P, K, <<>>);
   1846 media_param(<< $=, C, R/bits >>, T, S, P, K) when ?IS_TOKEN(C) -> media_value(R, T, S, P, K, << C >>);
   1847 media_param(<< C, R/bits >>, T, S, P, K) when ?IS_TOKEN(C) ->
   1848 	?LOWER(media_param, R, T, S, P, K).
   1849 
   1850 media_quoted(<< $", R/bits >>, T, S, P, K, V) -> media_param_sep(R, T, S, [{K, V}|P]);
   1851 media_quoted(<< $\\, C, R/bits >>, T, S, P, K, V) when ?IS_VCHAR_OBS(C) -> media_quoted(R, T, S, P, K, << V/binary, C >>);
   1852 media_quoted(<< C, R/bits >>, T, S, P, K, V) when ?IS_VCHAR_OBS(C) -> media_quoted(R, T, S, P, K, << V/binary, C >>).
   1853 
   1854 media_value(<< C, R/bits >>, T, S, P, K, V) when ?IS_TOKEN(C) -> media_value(R, T, S, P, K, << V/binary, C >>);
   1855 media_value(R, T, S, P, K, V) -> media_param_sep(R, T, S, [{K, V}|P]).
   1856 
   1857 -ifdef(TEST).
   1858 media_type_parameter() ->
   1859 	frequency([
   1860 		{90, parameter()},
   1861 		{10, {<<"charset">>, oneof([token(), quoted_string()]), <<>>, <<>>}}
   1862 	]).
   1863 
   1864 media_type() ->
   1865 	?LET({T, S, P},
   1866 		{token(), token(), small_list(media_type_parameter())},
   1867 		{T, S, P, iolist_to_binary([T, $/, S, [[OWS1, $;, OWS2, K, $=, V] || {K, V, OWS1, OWS2} <- P]])}
   1868 	).
   1869 
   1870 prop_parse_content_type() ->
   1871 	?FORALL({T, S, P, MediaType},
   1872 		media_type(),
   1873 		begin
   1874 			{ResT, ResS, ResP} = parse_content_type(MediaType),
   1875 			ExpectedP = [case ?LOWER(K) of
   1876 				<<"charset">> -> {<<"charset">>, ?LOWER(unquote(V))};
   1877 				LowK -> {LowK, unquote(V)}
   1878 			end || {K, V, _, _} <- P],
   1879 			ResT =:= ?LOWER(T)
   1880 				andalso ResS =:= ?LOWER(S)
   1881 				andalso ResP =:= ExpectedP
   1882 		end
   1883 	).
   1884 
   1885 parse_content_type_test_() ->
   1886 	Tests = [
   1887 		{<<"text/html;charset=utf-8">>,
   1888 			{<<"text">>, <<"html">>, [{<<"charset">>, <<"utf-8">>}]}},
   1889 		{<<"text/html;charset=UTF-8">>,
   1890 			{<<"text">>, <<"html">>, [{<<"charset">>, <<"utf-8">>}]}},
   1891 		{<<"Text/HTML;Charset=\"utf-8\"">>,
   1892 			{<<"text">>, <<"html">>, [{<<"charset">>, <<"utf-8">>}]}},
   1893 		{<<"text/html; charset=\"utf-8\"">>,
   1894 			{<<"text">>, <<"html">>, [{<<"charset">>, <<"utf-8">>}]}},
   1895 		{<<"text/html; charset=ISO-8859-4">>,
   1896 			{<<"text">>, <<"html">>, [{<<"charset">>, <<"iso-8859-4">>}]}},
   1897 		{<<"text/plain; charset=iso-8859-4">>,
   1898 			{<<"text">>, <<"plain">>, [{<<"charset">>, <<"iso-8859-4">>}]}},
   1899 		{<<"multipart/form-data  \t;Boundary=\"MultipartIsUgly\"">>,
   1900 			{<<"multipart">>, <<"form-data">>, [
   1901 				{<<"boundary">>, <<"MultipartIsUgly">>}
   1902 			]}},
   1903 		{<<"foo/bar; one=FirstParam; two=SecondParam">>,
   1904 			{<<"foo">>, <<"bar">>, [
   1905 				{<<"one">>, <<"FirstParam">>},
   1906 				{<<"two">>, <<"SecondParam">>}
   1907 			]}}
   1908 	],
   1909 	[{V, fun() -> R = parse_content_type(V) end} || {V, R} <- Tests].
   1910 
   1911 horse_parse_content_type() ->
   1912 	horse:repeat(200000,
   1913 		parse_content_type(<<"text/html;charset=utf-8">>)
   1914 	).
   1915 -endif.
   1916 
   1917 %% Cookie header.
   1918 
   1919 -spec parse_cookie(binary()) -> [{binary(), binary()}].
   1920 parse_cookie(Cookie) ->
   1921 	cow_cookie:parse_cookie(Cookie).
   1922 
   1923 %% Date header.
   1924 
   1925 -spec parse_date(binary()) -> calendar:datetime().
   1926 parse_date(Date) ->
   1927 	cow_date:parse_date(Date).
   1928 
   1929 -ifdef(TEST).
   1930 parse_date_test_() ->
   1931 	Tests = [
   1932 		{<<"Tue, 15 Nov 1994 08:12:31 GMT">>, {{1994, 11, 15}, {8, 12, 31}}}
   1933 	],
   1934 	[{V, fun() -> R = parse_date(V) end} || {V, R} <- Tests].
   1935 -endif.
   1936 
   1937 %% ETag header.
   1938 
   1939 -spec parse_etag(binary()) -> etag().
   1940 parse_etag(<< $W, $/, $", R/bits >>) ->
   1941 	etag(R, weak, <<>>);
   1942 parse_etag(<< $", R/bits >>) ->
   1943 	etag(R, strong, <<>>).
   1944 
   1945 etag(<< $" >>, Strength, Tag) ->
   1946 	{Strength, Tag};
   1947 etag(<< C, R/bits >>, Strength, Tag) when ?IS_ETAGC(C) ->
   1948 	etag(R, Strength, << Tag/binary, C >>).
   1949 
   1950 -ifdef(TEST).
   1951 etagc() ->
   1952 	?SUCHTHAT(C, integer(16#21, 16#ff), C =/= 16#22 andalso C =/= 16#7f).
   1953 
   1954 etag() ->
   1955 	?LET({Strength, Tag},
   1956 		{elements([weak, strong]), list(etagc())},
   1957 		begin
   1958 			TagBin = list_to_binary(Tag),
   1959 			{{Strength, TagBin},
   1960 				case Strength of
   1961 					weak -> << $W, $/, $", TagBin/binary, $" >>;
   1962 					strong -> << $", TagBin/binary, $" >>
   1963 				end}
   1964 		end).
   1965 
   1966 prop_parse_etag() ->
   1967 	?FORALL({Tag, TagBin},
   1968 		etag(),
   1969 		Tag =:= parse_etag(TagBin)).
   1970 
   1971 parse_etag_test_() ->
   1972 	Tests = [
   1973 		{<<"\"xyzzy\"">>, {strong, <<"xyzzy">>}},
   1974 		{<<"W/\"xyzzy\"">>, {weak, <<"xyzzy">>}},
   1975 		{<<"\"\"">>, {strong, <<>>}}
   1976 	],
   1977 	[{V, fun() -> R = parse_etag(V) end} || {V, R} <- Tests].
   1978 
   1979 parse_etag_error_test_() ->
   1980 	Tests = [
   1981 		<<>>,
   1982 		<<"\"">>,
   1983 		<<"W">>,
   1984 		<<"W/">>
   1985 	],
   1986 	[{V, fun() -> {'EXIT', _} = (catch parse_etag(V)) end} || V <- Tests].
   1987 
   1988 horse_parse_etag() ->
   1989 	horse:repeat(200000,
   1990 		parse_etag(<<"W/\"xyzzy\"">>)
   1991 	).
   1992 -endif.
   1993 
   1994 %% Expect header.
   1995 
   1996 -spec parse_expect(binary()) -> continue.
   1997 parse_expect(<<"100-continue">>) ->
   1998 	continue;
   1999 parse_expect(<<"100-", C, O, N, T, I, M, U, E >>)
   2000 	when (C =:= $C) or (C =:= $c), (O =:= $O) or (O =:= $o),
   2001 		(N =:= $N) or (N =:= $n), (T =:= $T) or (T =:= $t),
   2002 		(I =:= $I) or (I =:= $i), (M =:= $N) or (M =:= $n),
   2003 		(U =:= $U) or (U =:= $u), (E =:= $E) or (E =:= $e) ->
   2004 	continue.
   2005 
   2006 -ifdef(TEST).
   2007 expect() ->
   2008 	?LET(E,
   2009 		[$1, $0, $0, $-,
   2010 			elements([$c, $C]), elements([$o, $O]), elements([$n, $N]),
   2011 			elements([$t, $T]), elements([$i, $I]), elements([$n, $N]),
   2012 			elements([$u, $U]), elements([$e, $E])],
   2013 		list_to_binary(E)).
   2014 
   2015 prop_parse_expect() ->
   2016 	?FORALL(E, expect(), continue =:= parse_expect(E)).
   2017 
   2018 parse_expect_test_() ->
   2019 	Tests = [
   2020 		<<"100-continue">>,
   2021 		<<"100-CONTINUE">>,
   2022 		<<"100-Continue">>,
   2023 		<<"100-CoNtInUe">>
   2024 	],
   2025 	[{V, fun() -> continue = parse_expect(V) end} || V <- Tests].
   2026 
   2027 parse_expect_error_test_() ->
   2028 	Tests = [
   2029 		<<>>,
   2030 		<<"   ">>,
   2031 		<<"200-OK">>,
   2032 		<<"Cookies">>
   2033 	],
   2034 	[{V, fun() -> {'EXIT', _} = (catch parse_expect(V)) end} || V <- Tests].
   2035 
   2036 horse_parse_expect() ->
   2037 	horse:repeat(200000,
   2038 		parse_expect(<<"100-continue">>)
   2039 	).
   2040 -endif.
   2041 
   2042 %% Expires header.
   2043 %%
   2044 %% Recipients must interpret invalid date formats as a date
   2045 %% in the past. The value "0" is commonly used.
   2046 
   2047 -spec parse_expires(binary()) -> calendar:datetime().
   2048 parse_expires(<<"0">>) ->
   2049 	{{1, 1, 1}, {0, 0, 0}};
   2050 parse_expires(Expires) ->
   2051 	try
   2052 		cow_date:parse_date(Expires)
   2053 	catch _:_ ->
   2054 		{{1, 1, 1}, {0, 0, 0}}
   2055 	end.
   2056 
   2057 -ifdef(TEST).
   2058 parse_expires_test_() ->
   2059 	Tests = [
   2060 		{<<"0">>, {{1, 1, 1}, {0, 0, 0}}},
   2061 		{<<"Thu, 01 Dec 1994 nope invalid">>, {{1, 1, 1}, {0, 0, 0}}},
   2062 		{<<"Thu, 01 Dec 1994 16:00:00 GMT">>, {{1994, 12, 1}, {16, 0, 0}}}
   2063 	],
   2064 	[{V, fun() -> R = parse_expires(V) end} || {V, R} <- Tests].
   2065 
   2066 horse_parse_expires_0() ->
   2067 	horse:repeat(200000,
   2068 		parse_expires(<<"0">>)
   2069 	).
   2070 
   2071 horse_parse_expires_invalid() ->
   2072 	horse:repeat(200000,
   2073 		parse_expires(<<"Thu, 01 Dec 1994 nope invalid">>)
   2074 	).
   2075 -endif.
   2076 
   2077 %% Host header.
   2078 %%
   2079 %% We only seek to have legal characters and separate the
   2080 %% host and port values. The number of segments in the host
   2081 %% or the size of each segment is not checked.
   2082 %%
   2083 %% There is no way to distinguish IPv4 addresses from regular
   2084 %% names until the last segment is reached therefore we do not
   2085 %% differentiate them.
   2086 %%
   2087 %% The following valid hosts are currently rejected: IPv6
   2088 %% addresses with a zone identifier; IPvFuture addresses;
   2089 %% and percent-encoded addresses.
   2090 
   2091 -spec parse_host(binary()) -> {binary(), 0..65535 | undefined}.
   2092 parse_host(<< $[, R/bits >>) ->
   2093 	ipv6_address(R, << $[ >>);
   2094 parse_host(Host) ->
   2095 	reg_name(Host, <<>>).
   2096 
   2097 ipv6_address(<< $] >>, IP) -> {<< IP/binary, $] >>, undefined};
   2098 ipv6_address(<< $], $:, Port/bits >>, IP) -> {<< IP/binary, $] >>, binary_to_integer(Port)};
   2099 ipv6_address(<< C, R/bits >>, IP) when ?IS_HEX(C) or (C =:= $:) or (C =:= $.) ->
   2100 	?LOWER(ipv6_address, R, IP).
   2101 
   2102 reg_name(<<>>, Name) -> {Name, undefined};
   2103 reg_name(<< $:, Port/bits >>, Name) -> {Name, binary_to_integer(Port)};
   2104 reg_name(<< C, R/bits >>, Name) when ?IS_URI_UNRESERVED(C) or ?IS_URI_SUB_DELIMS(C) ->
   2105 	?LOWER(reg_name, R, Name).
   2106 
   2107 -ifdef(TEST).
   2108 host_chars() -> "!$&'()*+,-.0123456789;=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~".
   2109 host() -> vector(1, 255, elements(host_chars())).
   2110 
   2111 host_port() ->
   2112 	?LET({Host, Port},
   2113 		{host(), oneof([undefined, integer(1, 65535)])},
   2114 		begin
   2115 			HostBin = list_to_binary(Host),
   2116 			{{?LOWER(HostBin), Port},
   2117 				case Port of
   2118 					undefined -> HostBin;
   2119 					_ -> << HostBin/binary, $:, (integer_to_binary(Port))/binary >>
   2120 				end}
   2121 		end).
   2122 
   2123 prop_parse_host() ->
   2124 	?FORALL({Res, Host}, host_port(), Res =:= parse_host(Host)).
   2125 
   2126 parse_host_test_() ->
   2127 	Tests = [
   2128 		{<<>>, {<<>>, undefined}},
   2129 		{<<"www.example.org:8080">>, {<<"www.example.org">>, 8080}},
   2130 		{<<"www.example.org">>, {<<"www.example.org">>, undefined}},
   2131 		{<<"192.0.2.1:8080">>, {<<"192.0.2.1">>, 8080}},
   2132 		{<<"192.0.2.1">>, {<<"192.0.2.1">>, undefined}},
   2133 		{<<"[2001:db8::1]:8080">>, {<<"[2001:db8::1]">>, 8080}},
   2134 		{<<"[2001:db8::1]">>, {<<"[2001:db8::1]">>, undefined}},
   2135 		{<<"[::ffff:192.0.2.1]:8080">>, {<<"[::ffff:192.0.2.1]">>, 8080}},
   2136 		{<<"[::ffff:192.0.2.1]">>, {<<"[::ffff:192.0.2.1]">>, undefined}}
   2137 	],
   2138 	[{V, fun() -> R = parse_host(V) end} || {V, R} <- Tests].
   2139 
   2140 horse_parse_host_blue_example_org() ->
   2141 	horse:repeat(200000,
   2142 		parse_host(<<"blue.example.org:8080">>)
   2143 	).
   2144 
   2145 horse_parse_host_ipv4() ->
   2146 	horse:repeat(200000,
   2147 		parse_host(<<"192.0.2.1:8080">>)
   2148 	).
   2149 
   2150 horse_parse_host_ipv6() ->
   2151 	horse:repeat(200000,
   2152 		parse_host(<<"[2001:db8::1]:8080">>)
   2153 	).
   2154 
   2155 horse_parse_host_ipv6_v4() ->
   2156 	horse:repeat(200000,
   2157 		parse_host(<<"[::ffff:192.0.2.1]:8080">>)
   2158 	).
   2159 -endif.
   2160 
   2161 %% HTTP2-Settings header.
   2162 
   2163 -spec parse_http2_settings(binary()) -> map().
   2164 parse_http2_settings(HTTP2Settings) ->
   2165 	cow_http2:parse_settings_payload(base64:decode(HTTP2Settings)).
   2166 
   2167 %% If-Match header.
   2168 
   2169 -spec parse_if_match(binary()) -> '*' | [etag()].
   2170 parse_if_match(<<"*">>) ->
   2171 	'*';
   2172 parse_if_match(IfMatch) ->
   2173 	nonempty(etag_list(IfMatch, [])).
   2174 
   2175 etag_list(<<>>, Acc) -> lists:reverse(Acc);
   2176 etag_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> etag_list(R, Acc);
   2177 etag_list(<< $W, $/, $", R/bits >>, Acc) -> etag(R, Acc, weak, <<>>);
   2178 etag_list(<< $", R/bits >>, Acc) -> etag(R, Acc, strong, <<>>).
   2179 
   2180 etag(<< $", R/bits >>, Acc, Strength, Tag) -> etag_list_sep(R, [{Strength, Tag}|Acc]);
   2181 etag(<< C, R/bits >>, Acc, Strength, Tag) when ?IS_ETAGC(C) -> etag(R, Acc, Strength, << Tag/binary, C >>).
   2182 
   2183 etag_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   2184 etag_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> etag_list_sep(R, Acc);
   2185 etag_list_sep(<< $,, R/bits >>, Acc) -> etag_list(R, Acc).
   2186 
   2187 -ifdef(TEST).
   2188 prop_parse_if_match() ->
   2189 	?FORALL(L,
   2190 		non_empty(list(etag())),
   2191 		begin
   2192 			<< _, IfMatch/binary >> = iolist_to_binary([[$,, T] || {_, T} <- L]),
   2193 			ResL = parse_if_match(IfMatch),
   2194 			CheckedL = [T =:= ResT || {{T, _}, ResT} <- lists:zip(L, ResL)],
   2195 			[true] =:= lists:usort(CheckedL)
   2196 		end).
   2197 
   2198 parse_if_match_test_() ->
   2199 	Tests = [
   2200 		{<<"\"xyzzy\"">>, [{strong, <<"xyzzy">>}]},
   2201 		{<<"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"">>,
   2202 			[{strong, <<"xyzzy">>}, {strong, <<"r2d2xxxx">>}, {strong, <<"c3piozzzz">>}]},
   2203 		{<<"*">>, '*'}
   2204 	],
   2205 	[{V, fun() -> R = parse_if_match(V) end} || {V, R} <- Tests].
   2206 
   2207 parse_if_match_error_test_() ->
   2208 	Tests = [
   2209 		<<>>
   2210 	],
   2211 	[{V, fun() -> {'EXIT', _} = (catch parse_if_match(V)) end} || V <- Tests].
   2212 
   2213 horse_parse_if_match() ->
   2214 	horse:repeat(200000,
   2215 		parse_if_match(<<"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"">>)
   2216 	).
   2217 -endif.
   2218 
   2219 %% If-Modified-Since header.
   2220 
   2221 -spec parse_if_modified_since(binary()) -> calendar:datetime().
   2222 parse_if_modified_since(IfModifiedSince) ->
   2223 	cow_date:parse_date(IfModifiedSince).
   2224 
   2225 -ifdef(TEST).
   2226 parse_if_modified_since_test_() ->
   2227 	Tests = [
   2228 		{<<"Sat, 29 Oct 1994 19:43:31 GMT">>, {{1994, 10, 29}, {19, 43, 31}}}
   2229 	],
   2230 	[{V, fun() -> R = parse_if_modified_since(V) end} || {V, R} <- Tests].
   2231 -endif.
   2232 
   2233 %% If-None-Match header.
   2234 
   2235 -spec parse_if_none_match(binary()) -> '*' | [etag()].
   2236 parse_if_none_match(<<"*">>) ->
   2237 	'*';
   2238 parse_if_none_match(IfNoneMatch) ->
   2239 	nonempty(etag_list(IfNoneMatch, [])).
   2240 
   2241 -ifdef(TEST).
   2242 parse_if_none_match_test_() ->
   2243 	Tests = [
   2244 		{<<"\"xyzzy\"">>, [{strong, <<"xyzzy">>}]},
   2245 		{<<"W/\"xyzzy\"">>, [{weak, <<"xyzzy">>}]},
   2246 		{<<"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"">>,
   2247 			[{strong, <<"xyzzy">>}, {strong, <<"r2d2xxxx">>}, {strong, <<"c3piozzzz">>}]},
   2248 		{<<"W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\"">>,
   2249 			[{weak, <<"xyzzy">>}, {weak, <<"r2d2xxxx">>}, {weak, <<"c3piozzzz">>}]},
   2250 		{<<"*">>, '*'}
   2251 	],
   2252 	[{V, fun() -> R = parse_if_none_match(V) end} || {V, R} <- Tests].
   2253 
   2254 parse_if_none_match_error_test_() ->
   2255 	Tests = [
   2256 		<<>>
   2257 	],
   2258 	[{V, fun() -> {'EXIT', _} = (catch parse_if_none_match(V)) end} || V <- Tests].
   2259 
   2260 horse_parse_if_none_match() ->
   2261 	horse:repeat(200000,
   2262 		parse_if_none_match(<<"W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\"">>)
   2263 	).
   2264 -endif.
   2265 
   2266 %% If-Range header.
   2267 
   2268 -spec parse_if_range(binary()) -> etag() | calendar:datetime().
   2269 parse_if_range(<< $W, $/, $", R/bits >>) ->
   2270 	etag(R, weak, <<>>);
   2271 parse_if_range(<< $", R/bits >>) ->
   2272 	etag(R, strong, <<>>);
   2273 parse_if_range(IfRange) ->
   2274 	cow_date:parse_date(IfRange).
   2275 
   2276 -ifdef(TEST).
   2277 parse_if_range_test_() ->
   2278 	Tests = [
   2279 		{<<"W/\"xyzzy\"">>, {weak, <<"xyzzy">>}},
   2280 		{<<"\"xyzzy\"">>, {strong, <<"xyzzy">>}},
   2281 		{<<"Sat, 29 Oct 1994 19:43:31 GMT">>, {{1994, 10, 29}, {19, 43, 31}}}
   2282 	],
   2283 	[{V, fun() -> R = parse_if_range(V) end} || {V, R} <- Tests].
   2284 
   2285 parse_if_range_error_test_() ->
   2286 	Tests = [
   2287 		<<>>
   2288 	],
   2289 	[{V, fun() -> {'EXIT', _} = (catch parse_if_range(V)) end} || V <- Tests].
   2290 
   2291 horse_parse_if_range_etag() ->
   2292 	horse:repeat(200000,
   2293 		parse_if_range(<<"\"xyzzy\"">>)
   2294 	).
   2295 
   2296 horse_parse_if_range_date() ->
   2297 	horse:repeat(200000,
   2298 		parse_if_range(<<"Sat, 29 Oct 1994 19:43:31 GMT">>)
   2299 	).
   2300 -endif.
   2301 
   2302 %% If-Unmodified-Since header.
   2303 
   2304 -spec parse_if_unmodified_since(binary()) -> calendar:datetime().
   2305 parse_if_unmodified_since(IfModifiedSince) ->
   2306 	cow_date:parse_date(IfModifiedSince).
   2307 
   2308 -ifdef(TEST).
   2309 parse_if_unmodified_since_test_() ->
   2310 	Tests = [
   2311 		{<<"Sat, 29 Oct 1994 19:43:31 GMT">>, {{1994, 10, 29}, {19, 43, 31}}}
   2312 	],
   2313 	[{V, fun() -> R = parse_if_unmodified_since(V) end} || {V, R} <- Tests].
   2314 -endif.
   2315 
   2316 %% Last-Modified header.
   2317 
   2318 -spec parse_last_modified(binary()) -> calendar:datetime().
   2319 parse_last_modified(LastModified) ->
   2320 	cow_date:parse_date(LastModified).
   2321 
   2322 -ifdef(TEST).
   2323 parse_last_modified_test_() ->
   2324 	Tests = [
   2325 		{<<"Tue, 15 Nov 1994 12:45:26 GMT">>, {{1994, 11, 15}, {12, 45, 26}}}
   2326 	],
   2327 	[{V, fun() -> R = parse_last_modified(V) end} || {V, R} <- Tests].
   2328 -endif.
   2329 
   2330 %% Link header.
   2331 
   2332 -spec parse_link(binary()) -> [cow_link:link()].
   2333 parse_link(Link) ->
   2334 	cow_link:parse_link(Link).
   2335 
   2336 %% Max-Forwards header.
   2337 
   2338 -spec parse_max_forwards(binary()) -> non_neg_integer().
   2339 parse_max_forwards(MaxForwards) ->
   2340 	I = binary_to_integer(MaxForwards),
   2341 	true = I >= 0,
   2342 	I.
   2343 
   2344 -ifdef(TEST).
   2345 prop_parse_max_forwards() ->
   2346 	?FORALL(
   2347 		X,
   2348 		non_neg_integer(),
   2349 		X =:= parse_max_forwards(integer_to_binary(X))
   2350 	).
   2351 
   2352 parse_max_forwards_test_() ->
   2353 	Tests = [
   2354 		{<<"0">>, 0},
   2355 		{<<"42">>, 42},
   2356 		{<<"69">>, 69},
   2357 		{<<"1337">>, 1337},
   2358 		{<<"1234567890">>, 1234567890}
   2359 	],
   2360 	[{V, fun() -> R = parse_max_forwards(V) end} || {V, R} <- Tests].
   2361 
   2362 parse_max_forwards_error_test_() ->
   2363 	Tests = [
   2364 		<<>>,
   2365 		<<"123, 123">>,
   2366 		<<"4.17">>
   2367 	],
   2368 	[{V, fun() -> {'EXIT', _} = (catch parse_max_forwards(V)) end} || V <- Tests].
   2369 -endif.
   2370 
   2371 %% Origin header.
   2372 
   2373 %% According to the RFC6454 we should generate
   2374 %% a fresh globally unique identifier and return that value if:
   2375 %% - URI does not use a hierarchical element as a naming authority
   2376 %%   or the URI is not an absolute URI
   2377 %% - the implementation doesn't support the protocol given by uri-scheme
   2378 %% Thus, erlang reference represents a GUID here.
   2379 %%
   2380 %% We only seek to have legal characters and separate the
   2381 %% host and port values. The number of segments in the host
   2382 %% or the size of each segment is not checked.
   2383 %%
   2384 %% There is no way to distinguish IPv4 addresses from regular
   2385 %% names until the last segment is reached therefore we do not
   2386 %% differentiate them.
   2387 %%
   2388 %% @todo The following valid hosts are currently rejected: IPv6
   2389 %% addresses with a zone identifier; IPvFuture addresses;
   2390 %% and percent-encoded addresses.
   2391 
   2392 -spec parse_origin(binary()) -> [{binary(), binary(), 0..65535} | reference()].
   2393 parse_origin(Origins) ->
   2394 	nonempty(origin_scheme(Origins, [])).
   2395 
   2396 origin_scheme(<<>>, Acc) -> Acc;
   2397 origin_scheme(<< "http://", R/bits >>, Acc) -> origin_host(R, Acc, <<"http">>);
   2398 origin_scheme(<< "https://", R/bits >>, Acc) -> origin_host(R, Acc, <<"https">>);
   2399 origin_scheme(<< C, R/bits >>, Acc) when ?IS_TOKEN(C)  -> origin_scheme(next_origin(R), [make_ref()|Acc]).
   2400 
   2401 origin_host(<< $[, R/bits >>, Acc, Scheme) -> origin_ipv6_address(R, Acc, Scheme, << $[ >>);
   2402 origin_host(Host, Acc, Scheme) -> origin_reg_name(Host, Acc, Scheme, <<>>).
   2403 
   2404 origin_ipv6_address(<< $] >>, Acc, Scheme, IP) ->
   2405 	lists:reverse([{Scheme, << IP/binary, $] >>, default_port(Scheme)}|Acc]);
   2406 origin_ipv6_address(<< $], $\s, R/bits >>, Acc, Scheme, IP) ->
   2407 	origin_scheme(R, [{Scheme, << IP/binary, $] >>, default_port(Scheme)}|Acc]);
   2408 origin_ipv6_address(<< $], $:, Port/bits >>, Acc, Scheme, IP) ->
   2409 	origin_port(Port, Acc, Scheme, << IP/binary, $] >>, <<>>);
   2410 origin_ipv6_address(<< C, R/bits >>, Acc, Scheme, IP) when ?IS_HEX(C) or (C =:= $:) or (C =:= $.) ->
   2411 	?LOWER(origin_ipv6_address, R, Acc, Scheme, IP).
   2412 
   2413 origin_reg_name(<<>>, Acc, Scheme, Name) ->
   2414 	lists:reverse([{Scheme, Name, default_port(Scheme)}|Acc]);
   2415 origin_reg_name(<< $\s, R/bits >>, Acc, Scheme, Name) ->
   2416 	origin_scheme(R, [{Scheme, Name, default_port(Scheme)}|Acc]);
   2417 origin_reg_name(<< $:, Port/bits >>, Acc, Scheme, Name) ->
   2418 	origin_port(Port, Acc, Scheme, Name, <<>>);
   2419 origin_reg_name(<< C, R/bits >>, Acc, Scheme, Name) when ?IS_URI_UNRESERVED(C) or ?IS_URI_SUB_DELIMS(C) ->
   2420 	?LOWER(origin_reg_name, R, Acc, Scheme, Name).
   2421 
   2422 origin_port(<<>>, Acc, Scheme, Host, Port) ->
   2423 	lists:reverse([{Scheme, Host, binary_to_integer(Port)}|Acc]);
   2424 origin_port(<< $\s, R/bits >>, Acc, Scheme, Host, Port) ->
   2425 	origin_scheme(R, [{Scheme, Host, binary_to_integer(Port)}|Acc]);
   2426 origin_port(<< C, R/bits >>, Acc, Scheme, Host, Port) when ?IS_DIGIT(C) ->
   2427 	origin_port(R, Acc, Scheme, Host, << Port/binary, C >>).
   2428 
   2429 next_origin(<<>>) -> <<>>;
   2430 next_origin(<< $\s, C, R/bits >>) when ?IS_TOKEN(C) -> << C, R/bits >>;
   2431 next_origin(<< C, R/bits >>) when ?IS_TOKEN(C) or (C =:= $:) or (C =:= $/) -> next_origin(R).
   2432 
   2433 default_port(<< "http" >>) -> 80;
   2434 default_port(<< "https" >>) -> 443.
   2435 
   2436 -ifdef(TEST).
   2437 scheme() -> oneof([<<"http">>, <<"https">>]).
   2438 
   2439 scheme_host_port() ->
   2440 	?LET({Scheme, Host, Port},
   2441 		{scheme(), host(), integer(1, 65535)},
   2442 		begin
   2443 			HostBin = list_to_binary(Host),
   2444 			{[{Scheme, ?LOWER(HostBin), Port}],
   2445 				case default_port(Scheme) of
   2446 					Port -> << Scheme/binary, "://", HostBin/binary>>;
   2447 					_ -> << Scheme/binary, "://", HostBin/binary, $:, (integer_to_binary(Port))/binary >>
   2448 				end}
   2449 		end).
   2450 
   2451 prop_parse_origin() ->
   2452 	?FORALL({Res, Origin}, scheme_host_port(), Res =:= parse_origin(Origin)).
   2453 
   2454 parse_origin_test_() ->
   2455 	Tests = [
   2456 		{<<"http://www.example.org:8080">>, [{<<"http">>, <<"www.example.org">>, 8080}]},
   2457 		{<<"http://www.example.org">>, [{<<"http">>, <<"www.example.org">>, 80}]},
   2458 		{<<"http://192.0.2.1:8080">>, [{<<"http">>, <<"192.0.2.1">>, 8080}]},
   2459 		{<<"http://192.0.2.1">>, [{<<"http">>, <<"192.0.2.1">>, 80}]},
   2460 		{<<"http://[2001:db8::1]:8080">>, [{<<"http">>, <<"[2001:db8::1]">>, 8080}]},
   2461 		{<<"http://[2001:db8::1]">>, [{<<"http">>, <<"[2001:db8::1]">>, 80}]},
   2462 		{<<"http://[::ffff:192.0.2.1]:8080">>, [{<<"http">>, <<"[::ffff:192.0.2.1]">>, 8080}]},
   2463 		{<<"http://[::ffff:192.0.2.1]">>, [{<<"http">>, <<"[::ffff:192.0.2.1]">>, 80}]},
   2464 		{<<"http://example.org https://blue.example.com:8080">>,
   2465 			[{<<"http">>, <<"example.org">>, 80},
   2466 			 {<<"https">>, <<"blue.example.com">>, 8080}]}
   2467 	],
   2468 	[{V, fun() -> R = parse_origin(V) end} || {V, R} <- Tests].
   2469 
   2470 parse_origin_reference_test_() ->
   2471 	Tests = [
   2472 		<<"null">>,
   2473 		<<"httpx://example.org:80">>,
   2474 		<<"httpx://example.org:80 null">>,
   2475 		<<"null null">>
   2476 	],
   2477 	[{V, fun() -> [true = is_reference(Ref) || Ref <- parse_origin(V)] end} || V <- Tests].
   2478 
   2479 parse_origin_error_test_() ->
   2480 	Tests = [
   2481 		<<>>,
   2482 		<<"null", $\t, "null">>,
   2483 		<<"null", $\s, $\s, "null">>
   2484 	],
   2485 	[{V, fun() -> {'EXIT', _} = (catch parse_origin(V)) end} || V <- Tests].
   2486 
   2487 horse_parse_origin_blue_example_org() ->
   2488 	horse:repeat(200000,
   2489 		parse_origin(<<"http://blue.example.org:8080">>)
   2490 	).
   2491 
   2492 horse_parse_origin_ipv4() ->
   2493 	horse:repeat(200000,
   2494 		parse_origin(<<"http://192.0.2.1:8080">>)
   2495 	).
   2496 
   2497 horse_parse_origin_ipv6() ->
   2498 	horse:repeat(200000,
   2499 		parse_origin(<<"http://[2001:db8::1]:8080">>)
   2500 	).
   2501 
   2502 horse_parse_origin_ipv6_v4() ->
   2503 	horse:repeat(200000,
   2504 		parse_origin(<<"http://[::ffff:192.0.2.1]:8080">>)
   2505 	).
   2506 
   2507 horse_parse_origin_null() ->
   2508 	horse:repeat(200000,
   2509 		parse_origin(<<"null">>)
   2510 	).
   2511 -endif.
   2512 
   2513 %% Pragma header.
   2514 %%
   2515 %% Legacy header kept for backward compatibility with HTTP/1.0 caches.
   2516 %% Only the "no-cache" directive was ever specified, and only for
   2517 %% request messages.
   2518 %%
   2519 %% We take a large shortcut in the parsing of this header, expecting
   2520 %% an exact match of "no-cache".
   2521 
   2522 -spec parse_pragma(binary()) -> cache | no_cache.
   2523 parse_pragma(<<"no-cache">>) -> no_cache;
   2524 parse_pragma(_) -> cache.
   2525 
   2526 %% Proxy-Authenticate header.
   2527 %%
   2528 %% Alias of parse_www_authenticate/1 due to identical syntax.
   2529 
   2530 -spec parse_proxy_authenticate(binary()) -> [{basic, binary()}
   2531 	| {bearer | digest | binary(), [{binary(), binary()}]}].
   2532 parse_proxy_authenticate(ProxyAuthenticate) ->
   2533 	parse_www_authenticate(ProxyAuthenticate).
   2534 
   2535 %% Proxy-Authorization header.
   2536 %%
   2537 %% Alias of parse_authorization/1 due to identical syntax.
   2538 
   2539 -spec parse_proxy_authorization(binary())
   2540 	-> {basic, binary(), binary()}
   2541 	| {bearer, binary()}
   2542 	| {digest, [{binary(), binary()}]}.
   2543 parse_proxy_authorization(ProxyAuthorization) ->
   2544 	parse_authorization(ProxyAuthorization).
   2545 
   2546 %% Range header.
   2547 
   2548 -spec parse_range(binary())
   2549 	-> {bytes, [{non_neg_integer(), non_neg_integer() | infinity} | neg_integer()]}
   2550 	| {binary(), binary()}.
   2551 parse_range(<<"bytes=", R/bits >>) ->
   2552 	bytes_range_set(R, []);
   2553 parse_range(<< C, R/bits >>) when ?IS_TOKEN(C) ->
   2554 	?LOWER(other_range_unit, R, <<>>).
   2555 
   2556 bytes_range_set(<<>>, Acc) -> {bytes, lists:reverse(Acc)};
   2557 bytes_range_set(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> bytes_range_set(R, Acc);
   2558 bytes_range_set(<< $-, C, R/bits >>, Acc) when ?IS_DIGIT(C) -> bytes_range_suffix_spec(R, Acc, C - $0);
   2559 bytes_range_set(<< C, R/bits >>, Acc) when ?IS_DIGIT(C) -> bytes_range_spec(R, Acc, C - $0).
   2560 
   2561 bytes_range_spec(<< $-, C, R/bits >>, Acc, First) when ?IS_DIGIT(C) -> bytes_range_spec_last(R, Acc, First, C - $0);
   2562 bytes_range_spec(<< $-, R/bits >>, Acc, First) -> bytes_range_set_sep(R, [{First, infinity}|Acc]);
   2563 bytes_range_spec(<< C, R/bits >>, Acc, First) when ?IS_DIGIT(C) -> bytes_range_spec(R, Acc, First * 10 + C - $0).
   2564 
   2565 bytes_range_spec_last(<< C, R/bits >>, Acc, First, Last) when ?IS_DIGIT(C) -> bytes_range_spec_last(R, Acc, First, Last * 10 + C - $0);
   2566 bytes_range_spec_last(R, Acc, First, Last) -> bytes_range_set_sep(R, [{First, Last}|Acc]).
   2567 
   2568 bytes_range_suffix_spec(<< C, R/bits >>, Acc, Suffix) when ?IS_DIGIT(C) -> bytes_range_suffix_spec(R, Acc, Suffix * 10 + C - $0);
   2569 bytes_range_suffix_spec(R, Acc, Suffix) -> bytes_range_set_sep(R, [-Suffix|Acc]).
   2570 
   2571 bytes_range_set_sep(<<>>, Acc) -> {bytes, lists:reverse(Acc)};
   2572 bytes_range_set_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> bytes_range_set_sep(R, Acc);
   2573 bytes_range_set_sep(<< $,, R/bits >>, Acc) -> bytes_range_set(R, Acc).
   2574 
   2575 other_range_unit(<< $=, C, R/bits >>, U) when ?IS_VCHAR(C) ->
   2576 	other_range_set(R, U, << C >>);
   2577 other_range_unit(<< C, R/bits >>, U) when ?IS_TOKEN(C) ->
   2578 	?LOWER(other_range_unit, R, U).
   2579 
   2580 other_range_set(<<>>, U, S) ->
   2581 	{U, S};
   2582 other_range_set(<< C, R/bits >>, U, S) when ?IS_VCHAR(C) ->
   2583 	other_range_set(R, U, << S/binary, C >>).
   2584 
   2585 -ifdef(TEST).
   2586 bytes_range() ->
   2587 	?LET(BytesSet,
   2588 		non_empty(list(oneof([
   2589 			?SUCHTHAT({First, Last}, {pos_integer(), pos_integer()}, First =< Last),
   2590 			{pos_integer(), infinity},
   2591 			?LET(I, pos_integer(), -I)
   2592 		]))),
   2593 		{{bytes, BytesSet}, begin
   2594 			<< _, Set/bits >> = iolist_to_binary([
   2595 				case Spec of
   2596 					{First, infinity} -> [$,, integer_to_binary(First), $-];
   2597 					{First, Last} -> [$,, integer_to_binary(First), $-, integer_to_binary(Last)];
   2598 					Suffix -> [$,, integer_to_binary(Suffix)]
   2599 				end || Spec <- BytesSet]),
   2600 			<<"bytes=", Set/binary >>
   2601 		end}).
   2602 
   2603 other_range() ->
   2604 	?LET(Range = {Unit, Set},
   2605 		{token(), ?LET(L, non_empty(list(vchar())), list_to_binary(L))},
   2606 		{Range, << Unit/binary, $=, Set/binary >>}).
   2607 
   2608 range() ->
   2609 	oneof([
   2610 		bytes_range(),
   2611 		other_range()
   2612 	]).
   2613 
   2614 prop_parse_range() ->
   2615 	?FORALL({Range, RangeBin},
   2616 		range(),
   2617 		begin
   2618 			Range2 = case Range of
   2619 				{bytes, _} -> Range;
   2620 				{Unit, Set} -> {?LOWER(Unit), Set}
   2621 			end,
   2622 			Range2 =:= parse_range(RangeBin)
   2623 		end).
   2624 
   2625 parse_range_test_() ->
   2626 	Tests = [
   2627 		{<<"bytes=0-499">>, {bytes, [{0, 499}]}},
   2628 		{<<"bytes=500-999">>, {bytes, [{500, 999}]}},
   2629 		{<<"bytes=-500">>, {bytes, [-500]}},
   2630 		{<<"bytes=9500-">>, {bytes, [{9500, infinity}]}},
   2631 		{<<"bytes=0-0,-1">>, {bytes, [{0, 0}, -1]}},
   2632 		{<<"bytes=500-600,601-999">>, {bytes, [{500, 600}, {601, 999}]}},
   2633 		{<<"bytes=500-700,601-999">>, {bytes, [{500, 700}, {601, 999}]}},
   2634 		{<<"books=I-III,V-IX">>, {<<"books">>, <<"I-III,V-IX">>}}
   2635 	],
   2636 	[{V, fun() -> R = parse_range(V) end} || {V, R} <- Tests].
   2637 
   2638 parse_range_error_test_() ->
   2639 	Tests = [
   2640 		<<>>
   2641 	],
   2642 	[{V, fun() -> {'EXIT', _} = (catch parse_range(V)) end} || V <- Tests].
   2643 
   2644 horse_parse_range_first_last() ->
   2645 	horse:repeat(200000,
   2646 		parse_range(<<"bytes=500-999">>)
   2647 	).
   2648 
   2649 horse_parse_range_infinity() ->
   2650 	horse:repeat(200000,
   2651 		parse_range(<<"bytes=9500-">>)
   2652 	).
   2653 
   2654 horse_parse_range_suffix() ->
   2655 	horse:repeat(200000,
   2656 		parse_range(<<"bytes=-500">>)
   2657 	).
   2658 
   2659 horse_parse_range_two() ->
   2660 	horse:repeat(200000,
   2661 		parse_range(<<"bytes=500-700,601-999">>)
   2662 	).
   2663 
   2664 horse_parse_range_other() ->
   2665 	horse:repeat(200000,
   2666 		parse_range(<<"books=I-III,V-IX">>)
   2667 	).
   2668 -endif.
   2669 
   2670 %% Retry-After header.
   2671 
   2672 -spec parse_retry_after(binary()) -> non_neg_integer() | calendar:datetime().
   2673 parse_retry_after(RetryAfter = << D, _/bits >>) when ?IS_DIGIT(D) ->
   2674 	I = binary_to_integer(RetryAfter),
   2675 	true = I >= 0,
   2676 	I;
   2677 parse_retry_after(RetryAfter) ->
   2678 	cow_date:parse_date(RetryAfter).
   2679 
   2680 -ifdef(TEST).
   2681 parse_retry_after_test_() ->
   2682 	Tests = [
   2683 		{<<"Fri, 31 Dec 1999 23:59:59 GMT">>, {{1999, 12, 31}, {23, 59, 59}}},
   2684 		{<<"120">>, 120}
   2685 	],
   2686 	[{V, fun() -> R = parse_retry_after(V) end} || {V, R} <- Tests].
   2687 
   2688 parse_retry_after_error_test_() ->
   2689 	Tests = [
   2690 		<<>>
   2691 	],
   2692 	[{V, fun() -> {'EXIT', _} = (catch parse_retry_after(V)) end} || V <- Tests].
   2693 
   2694 horse_parse_retry_after_date() ->
   2695 	horse:repeat(200000,
   2696 		parse_retry_after(<<"Fri, 31 Dec 1999 23:59:59 GMT">>)
   2697 	).
   2698 
   2699 horse_parse_retry_after_delay_seconds() ->
   2700 	horse:repeat(200000,
   2701 		parse_retry_after(<<"120">>)
   2702 	).
   2703 -endif.
   2704 
   2705 %% Sec-WebSocket-Accept header.
   2706 %%
   2707 %% The argument is returned without any processing. This value is
   2708 %% expected to be matched directly by the client so no parsing is
   2709 %% needed.
   2710 
   2711 -spec parse_sec_websocket_accept(binary()) -> binary().
   2712 parse_sec_websocket_accept(SecWebSocketAccept) ->
   2713 	SecWebSocketAccept.
   2714 
   2715 %% Sec-WebSocket-Extensions header.
   2716 
   2717 -spec parse_sec_websocket_extensions(binary()) -> [{binary(), [binary() | {binary(), binary()}]}].
   2718 parse_sec_websocket_extensions(SecWebSocketExtensions) ->
   2719 	nonempty(ws_extension_list(SecWebSocketExtensions, [])).
   2720 
   2721 ws_extension_list(<<>>, Acc) -> lists:reverse(Acc);
   2722 ws_extension_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> ws_extension_list(R, Acc);
   2723 ws_extension_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) -> ws_extension(R, Acc, << C >>).
   2724 
   2725 ws_extension(<< C, R/bits >>, Acc, E) when ?IS_TOKEN(C) -> ws_extension(R, Acc, << E/binary, C >>);
   2726 ws_extension(R, Acc, E) -> ws_extension_param_sep(R, Acc, E, []).
   2727 
   2728 ws_extension_param_sep(<<>>, Acc, E, P) -> lists:reverse([{E, lists:reverse(P)}|Acc]);
   2729 ws_extension_param_sep(<< $,, R/bits >>, Acc, E, P) -> ws_extension_list(R, [{E, lists:reverse(P)}|Acc]);
   2730 ws_extension_param_sep(<< $;, R/bits >>, Acc, E, P) -> ws_extension_before_param(R, Acc, E, P);
   2731 ws_extension_param_sep(<< C, R/bits >>, Acc, E, P) when ?IS_WS(C) -> ws_extension_param_sep(R, Acc, E, P).
   2732 
   2733 ws_extension_before_param(<< C, R/bits >>, Acc, E, P) when ?IS_WS(C) -> ws_extension_before_param(R, Acc, E, P);
   2734 ws_extension_before_param(<< C, R/bits >>, Acc, E, P) when ?IS_TOKEN(C) -> ws_extension_param(R, Acc, E, P, << C >>).
   2735 
   2736 ws_extension_param(<< $=, $", R/bits >>, Acc, E, P, K) -> ws_extension_quoted(R, Acc, E, P, K, <<>>);
   2737 ws_extension_param(<< $=, C, R/bits >>, Acc, E, P, K) when ?IS_TOKEN(C) -> ws_extension_value(R, Acc, E, P, K, << C >>);
   2738 ws_extension_param(<< C, R/bits >>, Acc, E, P, K) when ?IS_TOKEN(C) -> ws_extension_param(R, Acc, E, P, << K/binary, C >>);
   2739 ws_extension_param(R, Acc, E, P, K) -> ws_extension_param_sep(R, Acc, E, [K|P]).
   2740 
   2741 ws_extension_quoted(<< $", R/bits >>, Acc, E, P, K, V) -> ws_extension_param_sep(R, Acc, E, [{K, V}|P]);
   2742 ws_extension_quoted(<< $\\, C, R/bits >>, Acc, E, P, K, V) when ?IS_TOKEN(C) -> ws_extension_quoted(R, Acc, E, P, K, << V/binary, C >>);
   2743 ws_extension_quoted(<< C, R/bits >>, Acc, E, P, K, V) when ?IS_TOKEN(C) -> ws_extension_quoted(R, Acc, E, P, K, << V/binary, C >>).
   2744 
   2745 ws_extension_value(<< C, R/bits >>, Acc, E, P, K, V) when ?IS_TOKEN(C) -> ws_extension_value(R, Acc, E, P, K, << V/binary, C >>);
   2746 ws_extension_value(R, Acc, E, P, K, V) -> ws_extension_param_sep(R, Acc, E, [{K, V}|P]).
   2747 
   2748 -ifdef(TEST).
   2749 quoted_token() ->
   2750 	?LET(T,
   2751 		non_empty(list(frequency([
   2752 			{99, tchar()},
   2753 			{1, [$\\, tchar()]}
   2754 		]))),
   2755 		[$", T, $"]).
   2756 
   2757 ws_extension() ->
   2758 	?LET({E, PL},
   2759 		{token(), small_list({ows(), ows(), oneof([token(), {token(), oneof([token(), quoted_token()])}])})},
   2760 		{E, PL, iolist_to_binary([E,
   2761 			[case P of
   2762 				{OWS1, OWS2, {K, V}} -> [OWS1, $;, OWS2, K, $=, V];
   2763 				{OWS1, OWS2, K} -> [OWS1, $;, OWS2, K]
   2764 			end || P <- PL]
   2765 		])}).
   2766 
   2767 prop_parse_sec_websocket_extensions() ->
   2768 	?FORALL(L,
   2769 		vector(1, 50, ws_extension()),
   2770 		begin
   2771 			<< _, SecWebsocketExtensions/binary >> = iolist_to_binary([[$,, E] || {_, _, E} <- L]),
   2772 			ResL = parse_sec_websocket_extensions(SecWebsocketExtensions),
   2773 			CheckedL = [begin
   2774 				ExpectedPL = [case P of
   2775 					{_, _, {K, V}} -> {K, unquote(V)};
   2776 					{_, _, K} -> K
   2777 				end || P <- PL],
   2778 				E =:= ResE andalso ExpectedPL =:= ResPL
   2779 			end || {{E, PL, _}, {ResE, ResPL}} <- lists:zip(L, ResL)],
   2780 			[true] =:= lists:usort(CheckedL)
   2781 		end).
   2782 
   2783 parse_sec_websocket_extensions_test_() ->
   2784 	Tests = [
   2785 		{<<"foo">>, [{<<"foo">>, []}]},
   2786 		{<<"bar; baz=2">>, [{<<"bar">>, [{<<"baz">>, <<"2">>}]}]},
   2787 		{<<"foo, bar; baz=2">>, [{<<"foo">>, []}, {<<"bar">>, [{<<"baz">>, <<"2">>}]}]},
   2788 		{<<"deflate-stream">>, [{<<"deflate-stream">>, []}]},
   2789 		{<<"mux; max-channels=4; flow-control, deflate-stream">>,
   2790 			[{<<"mux">>, [{<<"max-channels">>, <<"4">>}, <<"flow-control">>]}, {<<"deflate-stream">>, []}]},
   2791 		{<<"private-extension">>, [{<<"private-extension">>, []}]}
   2792 	],
   2793 	[{V, fun() -> R = parse_sec_websocket_extensions(V) end} || {V, R} <- Tests].
   2794 
   2795 parse_sec_websocket_extensions_error_test_() ->
   2796 	Tests = [
   2797 		<<>>
   2798 	],
   2799 	[{V, fun() -> {'EXIT', _} = (catch parse_sec_websocket_extensions(V)) end}
   2800 		|| V <- Tests].
   2801 
   2802 horse_parse_sec_websocket_extensions() ->
   2803 	horse:repeat(200000,
   2804 		parse_sec_websocket_extensions(<<"mux; max-channels=4; flow-control, deflate-stream">>)
   2805 	).
   2806 -endif.
   2807 
   2808 %% Sec-WebSocket-Key header.
   2809 %%
   2810 %% The argument is returned without any processing. This value is
   2811 %% expected to be prepended to a static value, the result of which
   2812 %% hashed to form a new base64 value returned in Sec-WebSocket-Accept,
   2813 %% therefore no parsing is needed.
   2814 
   2815 -spec parse_sec_websocket_key(binary()) -> binary().
   2816 parse_sec_websocket_key(SecWebSocketKey) ->
   2817 	SecWebSocketKey.
   2818 
   2819 %% Sec-WebSocket-Protocol request header.
   2820 
   2821 -spec parse_sec_websocket_protocol_req(binary()) -> [binary()].
   2822 parse_sec_websocket_protocol_req(SecWebSocketProtocol) ->
   2823 	nonempty(token_list(SecWebSocketProtocol, [])).
   2824 
   2825 -ifdef(TEST).
   2826 parse_sec_websocket_protocol_req_test_() ->
   2827 	Tests = [
   2828 		{<<"chat, superchat">>, [<<"chat">>, <<"superchat">>]},
   2829 		{<<"Chat, SuperChat">>, [<<"Chat">>, <<"SuperChat">>]}
   2830 	],
   2831 	[{V, fun() -> R = parse_sec_websocket_protocol_req(V) end} || {V, R} <- Tests].
   2832 
   2833 parse_sec_websocket_protocol_req_error_test_() ->
   2834 	Tests = [
   2835 		<<>>
   2836 	],
   2837 	[{V, fun() -> {'EXIT', _} = (catch parse_sec_websocket_protocol_req(V)) end}
   2838 		|| V <- Tests].
   2839 
   2840 horse_parse_sec_websocket_protocol_req() ->
   2841 	horse:repeat(200000,
   2842 		parse_sec_websocket_protocol_req(<<"chat, superchat">>)
   2843 	).
   2844 -endif.
   2845 
   2846 %% Sec-Websocket-Protocol response header.
   2847 
   2848 -spec parse_sec_websocket_protocol_resp(binary()) -> binary().
   2849 parse_sec_websocket_protocol_resp(Protocol) ->
   2850 	true = <<>> =/= Protocol,
   2851 	ok = validate_token(Protocol),
   2852 	Protocol.
   2853 
   2854 -ifdef(TEST).
   2855 prop_parse_sec_websocket_protocol_resp() ->
   2856 	?FORALL(T,
   2857 		token(),
   2858 		T =:= parse_sec_websocket_protocol_resp(T)).
   2859 
   2860 parse_sec_websocket_protocol_resp_test_() ->
   2861 	Tests = [
   2862 		{<<"chat">>, <<"chat">>},
   2863 		{<<"CHAT">>, <<"CHAT">>}
   2864 	],
   2865 	[{V, fun() -> R = parse_sec_websocket_protocol_resp(V) end} || {V, R} <- Tests].
   2866 
   2867 parse_sec_websocket_protocol_resp_error_test_() ->
   2868 	Tests = [
   2869 		<<>>
   2870 	],
   2871 	[{V, fun() -> {'EXIT', _} = (catch parse_sec_websocket_protocol_resp(V)) end}
   2872 		|| V <- Tests].
   2873 
   2874 horse_parse_sec_websocket_protocol_resp() ->
   2875 	horse:repeat(200000,
   2876 		parse_sec_websocket_protocol_resp(<<"chat">>)
   2877 	).
   2878 -endif.
   2879 
   2880 %% Sec-WebSocket-Version request header.
   2881 
   2882 -spec parse_sec_websocket_version_req(binary()) -> websocket_version().
   2883 parse_sec_websocket_version_req(SecWebSocketVersion) when byte_size(SecWebSocketVersion) < 4 ->
   2884 	Version = binary_to_integer(SecWebSocketVersion),
   2885 	true = Version >= 0 andalso Version =< 255,
   2886 	Version.
   2887 
   2888 -ifdef(TEST).
   2889 prop_parse_sec_websocket_version_req() ->
   2890 	?FORALL(Version,
   2891 		integer(0, 255),
   2892 		Version =:= parse_sec_websocket_version_req(integer_to_binary(Version))).
   2893 
   2894 parse_sec_websocket_version_req_test_() ->
   2895 	Tests = [
   2896 		{<<"13">>, 13},
   2897 		{<<"25">>, 25}
   2898 	],
   2899 	[{V, fun() -> R = parse_sec_websocket_version_req(V) end} || {V, R} <- Tests].
   2900 
   2901 parse_sec_websocket_version_req_error_test_() ->
   2902 	Tests = [
   2903 		<<>>,
   2904 		<<" ">>,
   2905 		<<"7, 8, 13">>,
   2906 		<<"invalid">>
   2907 	],
   2908 	[{V, fun() -> {'EXIT', _} = (catch parse_sec_websocket_version_req(V)) end}
   2909 		|| V <- Tests].
   2910 
   2911 horse_parse_sec_websocket_version_req_13() ->
   2912 	horse:repeat(200000,
   2913 		parse_sec_websocket_version_req(<<"13">>)
   2914 	).
   2915 
   2916 horse_parse_sec_websocket_version_req_255() ->
   2917 	horse:repeat(200000,
   2918 		parse_sec_websocket_version_req(<<"255">>)
   2919 	).
   2920 -endif.
   2921 
   2922 %% Sec-WebSocket-Version response header.
   2923 
   2924 -spec parse_sec_websocket_version_resp(binary()) -> [websocket_version()].
   2925 parse_sec_websocket_version_resp(SecWebSocketVersion) ->
   2926 	nonempty(ws_version_list(SecWebSocketVersion, [])).
   2927 
   2928 ws_version_list(<<>>, Acc) -> lists:reverse(Acc);
   2929 ws_version_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> ws_version_list(R, Acc);
   2930 ws_version_list(<< C, R/bits >>, Acc) when ?IS_DIGIT(C) -> ws_version(R, Acc, C - $0).
   2931 
   2932 ws_version(<< C, R/bits >>, Acc, V) when ?IS_DIGIT(C) -> ws_version(R, Acc, V * 10 + C - $0);
   2933 ws_version(R, Acc, V) -> ws_version_list_sep(R, [V|Acc]).
   2934 
   2935 ws_version_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   2936 ws_version_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> ws_version_list_sep(R, Acc);
   2937 ws_version_list_sep(<< $,, R/bits >>, Acc) -> ws_version_list(R, Acc).
   2938 
   2939 -ifdef(TEST).
   2940 sec_websocket_version_resp() ->
   2941 	?LET(L,
   2942 		non_empty(list({ows(), ows(), integer(0, 255)})),
   2943 		begin
   2944 			<< _, SecWebSocketVersion/binary >> = iolist_to_binary(
   2945 				[[OWS1, $,, OWS2, integer_to_binary(V)] || {OWS1, OWS2, V} <- L]),
   2946 			{[V || {_, _, V} <- L], SecWebSocketVersion}
   2947 		end).
   2948 
   2949 prop_parse_sec_websocket_version_resp() ->
   2950 	?FORALL({L, SecWebSocketVersion},
   2951 		sec_websocket_version_resp(),
   2952 		L =:= parse_sec_websocket_version_resp(SecWebSocketVersion)).
   2953 
   2954 parse_sec_websocket_version_resp_test_() ->
   2955 	Tests = [
   2956 		{<<"13, 8, 7">>, [13, 8, 7]}
   2957 	],
   2958 	[{V, fun() -> R = parse_sec_websocket_version_resp(V) end} || {V, R} <- Tests].
   2959 
   2960 parse_sec_websocket_version_resp_error_test_() ->
   2961 	Tests = [
   2962 		<<>>
   2963 	],
   2964 	[{V, fun() -> {'EXIT', _} = (catch parse_sec_websocket_version_resp(V)) end}
   2965 		|| V <- Tests].
   2966 
   2967 horse_parse_sec_websocket_version_resp() ->
   2968 	horse:repeat(200000,
   2969 		parse_sec_websocket_version_resp(<<"13, 8, 7">>)
   2970 	).
   2971 -endif.
   2972 
   2973 %% Set-Cookie header.
   2974 
   2975 -spec parse_set_cookie(binary())
   2976 	-> {ok, binary(), binary(), cow_cookie:cookie_attrs()}
   2977 	| ignore.
   2978 parse_set_cookie(SetCookie) ->
   2979 	cow_cookie:parse_set_cookie(SetCookie).
   2980 
   2981 %% TE header.
   2982 %%
   2983 %% This function does not support parsing of transfer-parameter.
   2984 
   2985 -spec parse_te(binary()) -> {trailers | no_trailers, [{binary(), qvalue()}]}.
   2986 parse_te(TE) ->
   2987 	te_list(TE, no_trailers, []).
   2988 
   2989 te_list(<<>>, Trail, Acc) -> {Trail, lists:reverse(Acc)};
   2990 te_list(<< C, R/bits >>, Trail, Acc) when ?IS_WS_COMMA(C) -> te_list(R, Trail, Acc);
   2991 te_list(<< "trailers", R/bits >>, Trail, Acc) -> te(R, Trail, Acc, <<"trailers">>);
   2992 te_list(<< "compress", R/bits >>, Trail, Acc) -> te(R, Trail, Acc, <<"compress">>);
   2993 te_list(<< "deflate", R/bits >>, Trail, Acc) -> te(R, Trail, Acc, <<"deflate">>);
   2994 te_list(<< "gzip", R/bits >>, Trail, Acc) -> te(R, Trail, Acc, <<"gzip">>);
   2995 te_list(<< C, R/bits >>, Trail, Acc) when ?IS_TOKEN(C) ->
   2996 	?LOWER(te, R, Trail, Acc, <<>>).
   2997 
   2998 te(<<>>, _, Acc, <<"trailers">>) -> {trailers, lists:reverse(Acc)};
   2999 te(<< $,, R/bits >>, _, Acc, <<"trailers">>) -> te_list(R, trailers, Acc);
   3000 te(<< $;, R/bits >>, Trail, Acc, T) when T =/= <<"trailers">> -> te_before_weight(R, Trail, Acc, T);
   3001 te(<< C, R/bits >>, _, Acc, <<"trailers">>) when ?IS_WS(C) -> te_list_sep(R, trailers, Acc);
   3002 te(<< C, R/bits >>, Trail, Acc, T) when ?IS_TOKEN(C) ->
   3003 	?LOWER(te, R, Trail, Acc, T);
   3004 te(R, Trail, Acc, T) -> te_param_sep(R, Trail, Acc, T).
   3005 
   3006 te_param_sep(<<>>, Trail, Acc, T) -> {Trail, lists:reverse([{T, 1000}|Acc])};
   3007 te_param_sep(<< $,, R/bits >>, Trail, Acc, T) -> te_list(R, Trail, [{T, 1000}|Acc]);
   3008 te_param_sep(<< C, R/bits >>, Trail, Acc, T) when ?IS_WS(C) -> te_param_sep(R, Trail, Acc, T).
   3009 
   3010 te_before_weight(<< C, R/bits >>, Trail, Acc, T) when ?IS_WS(C) -> te_before_weight(R, Trail, Acc, T);
   3011 te_before_weight(<< $q, $=, R/bits >>, Trail, Acc, T) -> te_weight(R, Trail, Acc, T).
   3012 
   3013 te_weight(<< "1.000", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 1000}|Acc]);
   3014 te_weight(<< "1.00", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 1000}|Acc]);
   3015 te_weight(<< "1.0", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 1000}|Acc]);
   3016 te_weight(<< "1.", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 1000}|Acc]);
   3017 te_weight(<< "1", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 1000}|Acc]);
   3018 te_weight(<< "0.", A, B, C, R/bits >>, Trail, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B), ?IS_DIGIT(C) ->
   3019 	te_list_sep(R, Trail, [{T, (A - $0) * 100 + (B - $0) * 10 + (C - $0)}|Acc]);
   3020 te_weight(<< "0.", A, B, R/bits >>, Trail, Acc, T) when ?IS_DIGIT(A), ?IS_DIGIT(B) ->
   3021 	te_list_sep(R, Trail, [{T, (A - $0) * 100 + (B - $0) * 10}|Acc]);
   3022 te_weight(<< "0.", A, R/bits >>, Trail, Acc, T) when ?IS_DIGIT(A) ->
   3023 	te_list_sep(R, Trail, [{T, (A - $0) * 100}|Acc]);
   3024 te_weight(<< "0.", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 0}|Acc]);
   3025 te_weight(<< "0", R/bits >>, Trail, Acc, T) -> te_list_sep(R, Trail, [{T, 0}|Acc]).
   3026 
   3027 te_list_sep(<<>>, Trail, Acc) -> {Trail, lists:reverse(Acc)};
   3028 te_list_sep(<< C, R/bits >>, Trail, Acc) when ?IS_WS(C) -> te_list_sep(R, Trail, Acc);
   3029 te_list_sep(<< $,, R/bits >>, Trail, Acc) -> te_list(R, Trail, Acc).
   3030 
   3031 -ifdef(TEST).
   3032 te() ->
   3033 	?LET({Trail, L},
   3034 		{elements([trailers, no_trailers]),
   3035 			small_non_empty_list({?SUCHTHAT(T, token(), T =/= <<"trailers">>), weight()})},
   3036 		{Trail, L, begin
   3037 			L2 = case Trail of
   3038 				no_trailers -> L;
   3039 				trailers ->
   3040 					Rand = rand:uniform(length(L) + 1) - 1,
   3041 					{Before, After} = lists:split(Rand, L),
   3042 					Before ++ [{<<"trailers">>, undefined}|After]
   3043 			end,
   3044 			<< _, TE/binary >> = iolist_to_binary([case W of
   3045 				undefined -> [$,, T];
   3046 				_ -> [$,, T, <<";q=">>, qvalue_to_iodata(W)]
   3047 			end || {T, W} <- L2]),
   3048 			TE
   3049 		end}
   3050 	).
   3051 
   3052 prop_parse_te() ->
   3053 	?FORALL({Trail, L, TE},
   3054 		te(),
   3055 		begin
   3056 			{ResTrail, ResL} = parse_te(TE),
   3057 			CheckedL = [begin
   3058 				ResT =:= ?LOWER(T)
   3059 					andalso (ResW =:= W orelse (W =:= undefined andalso ResW =:= 1000))
   3060 			end || {{T, W}, {ResT, ResW}} <- lists:zip(L, ResL)],
   3061 			ResTrail =:= Trail andalso [true] =:= lists:usort(CheckedL)
   3062 		end).
   3063 
   3064 parse_te_test_() ->
   3065 	Tests = [
   3066 		{<<"deflate">>, {no_trailers, [{<<"deflate">>, 1000}]}},
   3067 		{<<>>, {no_trailers, []}},
   3068 		{<<"trailers, deflate;q=0.5">>, {trailers, [{<<"deflate">>, 500}]}}
   3069 	],
   3070 	[{V, fun() -> R = parse_te(V) end} || {V, R} <- Tests].
   3071 
   3072 horse_parse_te() ->
   3073 	horse:repeat(200000,
   3074 		parse_te(<<"trailers, deflate;q=0.5">>)
   3075 	).
   3076 -endif.
   3077 
   3078 %% Trailer header.
   3079 
   3080 -spec parse_trailer(binary()) -> [binary()].
   3081 parse_trailer(Trailer) ->
   3082 	nonempty(token_ci_list(Trailer, [])).
   3083 
   3084 -ifdef(TEST).
   3085 parse_trailer_test_() ->
   3086 	Tests = [
   3087 		{<<"Date, Content-MD5">>, [<<"date">>, <<"content-md5">>]}
   3088 	],
   3089 	[{V, fun() -> R = parse_trailer(V) end} || {V, R} <- Tests].
   3090 
   3091 parse_trailer_error_test_() ->
   3092 	Tests = [
   3093 		<<>>
   3094 	],
   3095 	[{V, fun() -> {'EXIT', _} = (catch parse_trailer(V)) end} || V <- Tests].
   3096 
   3097 horse_parse_trailer() ->
   3098 	horse:repeat(200000,
   3099 		parse_trailer(<<"Date, Content-MD5">>)
   3100 	).
   3101 -endif.
   3102 
   3103 %% Transfer-Encoding header.
   3104 %%
   3105 %% This function does not support parsing of transfer-parameter.
   3106 
   3107 -spec parse_transfer_encoding(binary()) -> [binary()].
   3108 parse_transfer_encoding(<<"chunked">>) ->
   3109 	[<<"chunked">>];
   3110 parse_transfer_encoding(TransferEncoding) ->
   3111 	nonempty(token_ci_list(TransferEncoding, [])).
   3112 
   3113 -ifdef(TEST).
   3114 prop_parse_transfer_encoding() ->
   3115 	?FORALL(L,
   3116 		non_empty(list(token())),
   3117 		begin
   3118 			<< _, TransferEncoding/binary >> = iolist_to_binary([[$,, C] || C <- L]),
   3119 			ResL = parse_transfer_encoding(TransferEncoding),
   3120 			CheckedL = [?LOWER(Co) =:= ResC || {Co, ResC} <- lists:zip(L, ResL)],
   3121 			[true] =:= lists:usort(CheckedL)
   3122 		end).
   3123 
   3124 parse_transfer_encoding_test_() ->
   3125 	Tests = [
   3126 		{<<"a , , , ">>, [<<"a">>]},
   3127 		{<<" , , , a">>, [<<"a">>]},
   3128 		{<<"a , , b">>, [<<"a">>, <<"b">>]},
   3129 		{<<"chunked">>, [<<"chunked">>]},
   3130 		{<<"chunked, something">>, [<<"chunked">>, <<"something">>]},
   3131 		{<<"gzip, chunked">>, [<<"gzip">>, <<"chunked">>]}
   3132 	],
   3133 	[{V, fun() -> R = parse_transfer_encoding(V) end} || {V, R} <- Tests].
   3134 
   3135 parse_transfer_encoding_error_test_() ->
   3136 	Tests = [
   3137 		<<>>,
   3138 		<<" ">>,
   3139 		<<" , ">>,
   3140 		<<",,,">>,
   3141 		<<"a b">>
   3142 	],
   3143 	[{V, fun() -> {'EXIT', _} = (catch parse_transfer_encoding(V)) end}
   3144 		|| V <- Tests].
   3145 
   3146 horse_parse_transfer_encoding_chunked() ->
   3147 	horse:repeat(200000,
   3148 		parse_transfer_encoding(<<"chunked">>)
   3149 	).
   3150 
   3151 horse_parse_transfer_encoding_custom() ->
   3152 	horse:repeat(200000,
   3153 		parse_transfer_encoding(<<"chunked, something">>)
   3154 	).
   3155 -endif.
   3156 
   3157 %% Upgrade header.
   3158 %%
   3159 %% It is unclear from the RFC whether the values here are
   3160 %% case sensitive.
   3161 %%
   3162 %% We handle them in a case insensitive manner because they
   3163 %% are described as case insensitive in the Websocket RFC.
   3164 
   3165 -spec parse_upgrade(binary()) -> [binary()].
   3166 parse_upgrade(Upgrade) ->
   3167 	nonempty(protocol_list(Upgrade, [])).
   3168 
   3169 protocol_list(<<>>, Acc) -> lists:reverse(Acc);
   3170 protocol_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> protocol_list(R, Acc);
   3171 protocol_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) ->
   3172 	?LOWER(protocol_name, R, Acc, <<>>).
   3173 
   3174 protocol_name(<< $/, C, R/bits >>, Acc, P) ->
   3175 	?LOWER(protocol_version, R, Acc, << P/binary, $/ >>);
   3176 protocol_name(<< C, R/bits >>, Acc, P) when ?IS_TOKEN(C) ->
   3177 	?LOWER(protocol_name, R, Acc, P);
   3178 protocol_name(R, Acc, P) -> protocol_list_sep(R, [P|Acc]).
   3179 
   3180 protocol_version(<< C, R/bits >>, Acc, P) when ?IS_TOKEN(C) ->
   3181 	?LOWER(protocol_version, R, Acc, P);
   3182 protocol_version(R, Acc, P) -> protocol_list_sep(R, [P|Acc]).
   3183 
   3184 protocol_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   3185 protocol_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> protocol_list_sep(R, Acc);
   3186 protocol_list_sep(<< $,, R/bits >>, Acc) -> protocol_list(R, Acc).
   3187 
   3188 -ifdef(TEST).
   3189 protocols() ->
   3190 	?LET(P,
   3191 		oneof([token(), [token(), $/, token()]]),
   3192 		iolist_to_binary(P)).
   3193 
   3194 prop_parse_upgrade() ->
   3195 	?FORALL(L,
   3196 		non_empty(list(protocols())),
   3197 		begin
   3198 			<< _, Upgrade/binary >> = iolist_to_binary([[$,, P] || P <- L]),
   3199 			ResL = parse_upgrade(Upgrade),
   3200 			CheckedL = [?LOWER(P) =:= ResP || {P, ResP} <- lists:zip(L, ResL)],
   3201 			[true] =:= lists:usort(CheckedL)
   3202 		end).
   3203 
   3204 parse_upgrade_test_() ->
   3205 	Tests = [
   3206 		{<<"HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11">>,
   3207 			[<<"http/2.0">>, <<"shttp/1.3">>, <<"irc/6.9">>, <<"rta/x11">>]},
   3208 		{<<"HTTP/2.0">>, [<<"http/2.0">>]}
   3209 	],
   3210 	[{V, fun() -> R = parse_upgrade(V) end} || {V, R} <- Tests].
   3211 
   3212 parse_upgrade_error_test_() ->
   3213 	Tests = [
   3214 		<<>>
   3215 	],
   3216 	[{V, fun() -> {'EXIT', _} = (catch parse_upgrade(V)) end}
   3217 		|| V <- Tests].
   3218 -endif.
   3219 
   3220 %% Variant-Key-06 (draft) header.
   3221 %%
   3222 %% The Variants header must be parsed first in order to know
   3223 %% the NumMembers argument as it is the number of members in
   3224 %% the Variants dictionary.
   3225 
   3226 -spec parse_variant_key(binary(), pos_integer()) -> [[binary()]].
   3227 parse_variant_key(VariantKey, NumMembers) ->
   3228 	List = cow_http_struct_hd:parse_list(VariantKey),
   3229 	[case Inner of
   3230 		{with_params, InnerList, #{}} ->
   3231 			NumMembers = length(InnerList),
   3232 			[case Item of
   3233 				{with_params, {token, Value}, #{}} -> Value;
   3234 				{with_params, {string, Value}, #{}} -> Value
   3235 			end || Item <- InnerList]
   3236 	end || Inner <- List].
   3237 
   3238 -ifdef(TEST).
   3239 parse_variant_key_test_() ->
   3240 	Tests = [
   3241 		{<<"(en)">>, 1, [[<<"en">>]]},
   3242 		{<<"(gzip fr)">>, 2, [[<<"gzip">>, <<"fr">>]]},
   3243 		{<<"(gzip fr), (\"identity\" fr)">>, 2, [[<<"gzip">>, <<"fr">>], [<<"identity">>, <<"fr">>]]},
   3244 		{<<"(\"gzip \" fr)">>, 2, [[<<"gzip ">>, <<"fr">>]]},
   3245 		{<<"(en br)">>, 2, [[<<"en">>, <<"br">>]]},
   3246 		{<<"(\"0\")">>, 1, [[<<"0">>]]},
   3247 		{<<"(silver), (\"bronze\")">>, 1, [[<<"silver">>], [<<"bronze">>]]},
   3248 		{<<"(some_person)">>, 1, [[<<"some_person">>]]},
   3249 		{<<"(gold europe)">>, 2, [[<<"gold">>, <<"europe">>]]}
   3250 	],
   3251 	[{V, fun() -> R = parse_variant_key(V, N) end} || {V, N, R} <- Tests].
   3252 
   3253 parse_variant_key_error_test_() ->
   3254 	Tests = [
   3255 		{<<"(gzip fr), (identity fr), (br fr oops)">>, 2}
   3256 	],
   3257 	[{V, fun() -> {'EXIT', _} = (catch parse_variant_key(V, N)) end} || {V, N} <- Tests].
   3258 -endif.
   3259 
   3260 -spec variant_key([[binary()]]) -> iolist().
   3261 %% We assume that the lists are of correct length.
   3262 variant_key(VariantKeys) ->
   3263 	cow_http_struct_hd:list([
   3264 		{with_params, [
   3265 			{with_params, {string, Value}, #{}}
   3266 		|| Value <- InnerList], #{}}
   3267 	|| InnerList <- VariantKeys]).
   3268 
   3269 -ifdef(TEST).
   3270 variant_key_identity_test_() ->
   3271 	Tests = [
   3272 		{1, [[<<"en">>]]},
   3273 		{2, [[<<"gzip">>, <<"fr">>]]},
   3274 		{2, [[<<"gzip">>, <<"fr">>], [<<"identity">>, <<"fr">>]]},
   3275 		{2, [[<<"gzip ">>, <<"fr">>]]},
   3276 		{2, [[<<"en">>, <<"br">>]]},
   3277 		{1, [[<<"0">>]]},
   3278 		{1, [[<<"silver">>], [<<"bronze">>]]},
   3279 		{1, [[<<"some_person">>]]},
   3280 		{2, [[<<"gold">>, <<"europe">>]]}
   3281 	],
   3282 	[{lists:flatten(io_lib:format("~p", [V])),
   3283 		fun() -> V = parse_variant_key(iolist_to_binary(variant_key(V)), N) end} || {N, V} <- Tests].
   3284 -endif.
   3285 
   3286 %% Variants-06 (draft) header.
   3287 
   3288 -spec parse_variants(binary()) -> [{binary(), [binary()]}].
   3289 parse_variants(Variants) ->
   3290 	{Dict0, Order} = cow_http_struct_hd:parse_dictionary(Variants),
   3291 	Dict = maps:map(fun(_, {with_params, List, #{}}) ->
   3292 		[case Item of
   3293 			{with_params, {token, Value}, #{}} -> Value;
   3294 			{with_params, {string, Value}, #{}} -> Value
   3295 		end || Item <- List]
   3296 	end, Dict0),
   3297 	[{Key, maps:get(Key, Dict)} || Key <- Order].
   3298 
   3299 -ifdef(TEST).
   3300 parse_variants_test_() ->
   3301 	Tests = [
   3302 		{<<"accept-language=(de en jp)">>, [{<<"accept-language">>, [<<"de">>, <<"en">>, <<"jp">>]}]},
   3303 		{<<"accept-encoding=(gzip)">>, [{<<"accept-encoding">>, [<<"gzip">>]}]},
   3304 		{<<"accept-encoding=()">>, [{<<"accept-encoding">>, []}]},
   3305 		{<<"accept-encoding=(gzip br), accept-language=(en fr)">>, [
   3306 			{<<"accept-encoding">>, [<<"gzip">>, <<"br">>]},
   3307 			{<<"accept-language">>, [<<"en">>, <<"fr">>]}
   3308 		]},
   3309 		{<<"accept-language=(en fr de), accept-encoding=(gzip br)">>, [
   3310 			{<<"accept-language">>, [<<"en">>, <<"fr">>, <<"de">>]},
   3311 			{<<"accept-encoding">>, [<<"gzip">>, <<"br">>]}
   3312 		]}
   3313 	],
   3314 	[{V, fun() -> R = parse_variants(V) end} || {V, R} <- Tests].
   3315 -endif.
   3316 
   3317 -spec variants([{binary(), [binary()]}]) -> iolist().
   3318 variants(Variants) ->
   3319 	cow_http_struct_hd:dictionary([
   3320 		{Key, {with_params, [
   3321 			{with_params, {string, Value}, #{}}
   3322 		|| Value <- List], #{}}}
   3323 	|| {Key, List} <- Variants]).
   3324 
   3325 -ifdef(TEST).
   3326 variants_identity_test_() ->
   3327 	Tests = [
   3328 		[{<<"accept-language">>, [<<"de">>, <<"en">>, <<"jp">>]}],
   3329 		[{<<"accept-encoding">>, [<<"gzip">>]}],
   3330 		[{<<"accept-encoding">>, []}],
   3331 		[
   3332 			{<<"accept-encoding">>, [<<"gzip">>, <<"br">>]},
   3333 			{<<"accept-language">>, [<<"en">>, <<"fr">>]}
   3334 		],
   3335 		[
   3336 			{<<"accept-language">>, [<<"en">>, <<"fr">>, <<"de">>]},
   3337 			{<<"accept-encoding">>, [<<"gzip">>, <<"br">>]}
   3338 		]
   3339 	],
   3340 	[{lists:flatten(io_lib:format("~p", [V])),
   3341 		fun() -> V = parse_variants(iolist_to_binary(variants(V))) end} || V <- Tests].
   3342 -endif.
   3343 
   3344 %% Vary header.
   3345 
   3346 -spec parse_vary(binary()) -> '*' | [binary()].
   3347 parse_vary(<<"*">>) ->
   3348 	'*';
   3349 parse_vary(Vary) ->
   3350 	nonempty(token_ci_list(Vary, [])).
   3351 
   3352 -ifdef(TEST).
   3353 parse_vary_test_() ->
   3354 	Tests = [
   3355 		{<<"*">>, '*'},
   3356 		{<<"Accept-Encoding">>, [<<"accept-encoding">>]},
   3357 		{<<"accept-encoding, accept-language">>, [<<"accept-encoding">>, <<"accept-language">>]}
   3358 	],
   3359 	[{V, fun() -> R = parse_vary(V) end} || {V, R} <- Tests].
   3360 
   3361 parse_vary_error_test_() ->
   3362 	Tests = [
   3363 		<<>>
   3364 	],
   3365 	[{V, fun() -> {'EXIT', _} = (catch parse_vary(V)) end} || V <- Tests].
   3366 -endif.
   3367 
   3368 %% WWW-Authenticate header.
   3369 %%
   3370 %% Unknown schemes are represented as the lowercase binary
   3371 %% instead of an atom. Unlike with parse_authorization/1,
   3372 %% we do not crash on unknown schemes.
   3373 %%
   3374 %% When parsing auth-params, we do not accept BWS characters around the "=".
   3375 
   3376 -spec parse_www_authenticate(binary()) -> [{basic, binary()}
   3377 	| {bearer | digest | binary(), [{binary(), binary()}]}].
   3378 parse_www_authenticate(Authenticate) ->
   3379 	nonempty(www_auth_list(Authenticate, [])).
   3380 
   3381 www_auth_list(<<>>, Acc) -> lists:reverse(Acc);
   3382 www_auth_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> www_auth_list(R, Acc);
   3383 www_auth_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) ->
   3384 	?LOWER(www_auth_scheme, R, Acc, <<>>).
   3385 
   3386 www_auth_basic_before_realm(<< C, R/bits >>, Acc) when ?IS_WS(C) -> www_auth_basic_before_realm(R, Acc);
   3387 www_auth_basic_before_realm(<< "realm=\"", R/bits >>, Acc) -> www_auth_basic(R, Acc, <<>>).
   3388 
   3389 www_auth_basic(<< $", R/bits >>, Acc, Realm) -> www_auth_list_sep(R, [{basic, Realm}|Acc]);
   3390 www_auth_basic(<< $\\, C, R/bits >>, Acc, Realm) when ?IS_VCHAR_OBS(C) -> www_auth_basic(R, Acc, << Realm/binary, C >>);
   3391 www_auth_basic(<< C, R/bits >>, Acc, Realm) when ?IS_VCHAR_OBS(C) -> www_auth_basic(R, Acc, << Realm/binary, C >>).
   3392 
   3393 www_auth_scheme(<< C, R/bits >>, Acc, Scheme) when ?IS_WS(C) ->
   3394 	case Scheme of
   3395 		<<"basic">> -> www_auth_basic_before_realm(R, Acc);
   3396 		<<"bearer">> -> www_auth_params_list(R, Acc, bearer, []);
   3397 		<<"digest">> -> www_auth_params_list(R, Acc, digest, []);
   3398 		_ -> www_auth_params_list(R, Acc, Scheme, [])
   3399 	end;
   3400 www_auth_scheme(<< C, R/bits >>, Acc, Scheme) when ?IS_TOKEN(C) ->
   3401 	?LOWER(www_auth_scheme, R, Acc, Scheme).
   3402 
   3403 www_auth_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   3404 www_auth_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> www_auth_list_sep(R, Acc);
   3405 www_auth_list_sep(<< $,, R/bits >>, Acc) -> www_auth_list(R, Acc).
   3406 
   3407 www_auth_params_list(<<>>, Acc, Scheme, Params) ->
   3408 	lists:reverse([{Scheme, lists:reverse(nonempty(Params))}|Acc]);
   3409 www_auth_params_list(<< C, R/bits >>, Acc, Scheme, Params) when ?IS_WS_COMMA(C) ->
   3410 	www_auth_params_list(R, Acc, Scheme, Params);
   3411 www_auth_params_list(<< "algorithm=", C, R/bits >>, Acc, Scheme, Params) when ?IS_TOKEN(C) ->
   3412 	www_auth_token(R, Acc, Scheme, Params, <<"algorithm">>, << C >>);
   3413 www_auth_params_list(<< "domain=\"", R/bits >>, Acc, Scheme, Params) ->
   3414 	www_auth_quoted(R, Acc, Scheme, Params, <<"domain">>, <<>>);
   3415 www_auth_params_list(<< "error=\"", R/bits >>, Acc, Scheme, Params) ->
   3416 	www_auth_quoted(R, Acc, Scheme, Params, <<"error">>, <<>>);
   3417 www_auth_params_list(<< "error_description=\"", R/bits >>, Acc, Scheme, Params) ->
   3418 	www_auth_quoted(R, Acc, Scheme, Params, <<"error_description">>, <<>>);
   3419 www_auth_params_list(<< "error_uri=\"", R/bits >>, Acc, Scheme, Params) ->
   3420 	www_auth_quoted(R, Acc, Scheme, Params, <<"error_uri">>, <<>>);
   3421 www_auth_params_list(<< "nonce=\"", R/bits >>, Acc, Scheme, Params) ->
   3422 	www_auth_quoted(R, Acc, Scheme, Params, <<"nonce">>, <<>>);
   3423 www_auth_params_list(<< "opaque=\"", R/bits >>, Acc, Scheme, Params) ->
   3424 	www_auth_quoted(R, Acc, Scheme, Params, <<"opaque">>, <<>>);
   3425 www_auth_params_list(<< "qop=\"", R/bits >>, Acc, Scheme, Params) ->
   3426 	www_auth_quoted(R, Acc, Scheme, Params, <<"qop">>, <<>>);
   3427 www_auth_params_list(<< "realm=\"", R/bits >>, Acc, Scheme, Params) ->
   3428 	www_auth_quoted(R, Acc, Scheme, Params, <<"realm">>, <<>>);
   3429 www_auth_params_list(<< "scope=\"", R/bits >>, Acc, Scheme, Params) ->
   3430 	www_auth_quoted(R, Acc, Scheme, Params, <<"scope">>, <<>>);
   3431 www_auth_params_list(<< "stale=false", R/bits >>, Acc, Scheme, Params) ->
   3432 	www_auth_params_list_sep(R, Acc, Scheme, [{<<"stale">>, <<"false">>}|Params]);
   3433 www_auth_params_list(<< "stale=true", R/bits >>, Acc, Scheme, Params) ->
   3434 	www_auth_params_list_sep(R, Acc, Scheme, [{<<"stale">>, <<"true">>}|Params]);
   3435 www_auth_params_list(<< C, R/bits >>, Acc, Scheme, Params) when ?IS_TOKEN(C) ->
   3436 	?LOWER(www_auth_param, R, Acc, Scheme, Params, <<>>).
   3437 
   3438 www_auth_param(<< $=, $", R/bits >>, Acc, Scheme, Params, K) ->
   3439 	www_auth_quoted(R, Acc, Scheme, Params, K, <<>>);
   3440 www_auth_param(<< $=, C, R/bits >>, Acc, Scheme, Params, K) when ?IS_TOKEN(C) ->
   3441 	www_auth_token(R, Acc, Scheme, Params, K, << C >>);
   3442 www_auth_param(<< C, R/bits >>, Acc, Scheme, Params, K) when ?IS_TOKEN(C) ->
   3443 	?LOWER(www_auth_param, R, Acc, Scheme, Params, K);
   3444 www_auth_param(R, Acc, Scheme, Params, NewScheme) ->
   3445 	www_auth_scheme(R, [{Scheme, lists:reverse(Params)}|Acc], NewScheme).
   3446 
   3447 www_auth_token(<< C, R/bits >>, Acc, Scheme, Params, K, V) when ?IS_TOKEN(C) ->
   3448 	www_auth_token(R, Acc, Scheme, Params, K, << V/binary, C >>);
   3449 www_auth_token(R, Acc, Scheme, Params, K, V) ->
   3450 	www_auth_params_list_sep(R, Acc, Scheme, [{K, V}|Params]).
   3451 
   3452 www_auth_quoted(<< $", R/bits >>, Acc, Scheme, Params, K, V) ->
   3453 	www_auth_params_list_sep(R, Acc, Scheme, [{K, V}|Params]);
   3454 www_auth_quoted(<< $\\, C, R/bits >>, Acc, Scheme, Params, K, V) when ?IS_VCHAR_OBS(C) ->
   3455 	www_auth_quoted(R, Acc, Scheme, Params, K, << V/binary, C >>);
   3456 www_auth_quoted(<< C, R/bits >>, Acc, Scheme, Params, K, V) when ?IS_VCHAR_OBS(C) ->
   3457 	www_auth_quoted(R, Acc, Scheme, Params, K, << V/binary, C >>).
   3458 
   3459 www_auth_params_list_sep(<<>>, Acc, Scheme, Params) ->
   3460 	lists:reverse([{Scheme, lists:reverse(Params)}|Acc]);
   3461 www_auth_params_list_sep(<< C, R/bits >>, Acc, Scheme, Params) when ?IS_WS(C) ->
   3462 	www_auth_params_list_sep(R, Acc, Scheme, Params);
   3463 www_auth_params_list_sep(<< $,, R/bits >>, Acc, Scheme, Params) ->
   3464 	www_auth_params_list_after_sep(R, Acc, Scheme, Params).
   3465 
   3466 www_auth_params_list_after_sep(<<>>, Acc, Scheme, Params) ->
   3467 	lists:reverse([{Scheme, lists:reverse(Params)}|Acc]);
   3468 www_auth_params_list_after_sep(<< C, R/bits >>, Acc, Scheme, Params) when ?IS_WS_COMMA(C) ->
   3469 	www_auth_params_list_after_sep(R, Acc, Scheme, Params);
   3470 www_auth_params_list_after_sep(R, Acc, Scheme, Params) ->
   3471 	www_auth_params_list(R, Acc, Scheme, Params).
   3472 
   3473 -ifdef(TEST).
   3474 parse_www_authenticate_test_() ->
   3475 	Tests = [
   3476 		{<<"Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\"">>,
   3477 			[{<<"newauth">>, [
   3478 				{<<"realm">>, <<"apps">>},
   3479 				{<<"type">>, <<"1">>},
   3480 				{<<"title">>, <<"Login to \"apps\"">>}]},
   3481 			{basic, <<"simple">>}]},
   3482 		%% Same test, different order.
   3483 		{<<"Basic realm=\"simple\", Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\"">>,
   3484 			[{basic, <<"simple">>},
   3485 			{<<"newauth">>, [
   3486 				{<<"realm">>, <<"apps">>},
   3487 				{<<"type">>, <<"1">>},
   3488 				{<<"title">>, <<"Login to \"apps\"">>}]}]},
   3489 		{<<"Bearer realm=\"example\"">>,
   3490 			[{bearer, [{<<"realm">>, <<"example">>}]}]},
   3491 		{<<"Bearer realm=\"example\", error=\"invalid_token\", error_description=\"The access token expired\"">>,
   3492 			[{bearer, [
   3493 				{<<"realm">>, <<"example">>},
   3494 				{<<"error">>, <<"invalid_token">>},
   3495 				{<<"error_description">>, <<"The access token expired">>}
   3496 			]}]},
   3497 		{<<"Basic realm=\"WallyWorld\"">>,
   3498 			[{basic, <<"WallyWorld">>}]},
   3499 		{<<"Digest realm=\"testrealm@host.com\", qop=\"auth,auth-int\", "
   3500 				"nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
   3501 				"opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"">>,
   3502 			[{digest, [
   3503 				{<<"realm">>, <<"testrealm@host.com">>},
   3504 				{<<"qop">>, <<"auth,auth-int">>},
   3505 				{<<"nonce">>, <<"dcd98b7102dd2f0e8b11d0f600bfb0c093">>},
   3506 				{<<"opaque">>, <<"5ccc069c403ebaf9f0171e9517f40e41">>}
   3507 			]}]}
   3508 	],
   3509 	[{V, fun() -> R = parse_www_authenticate(V) end} || {V, R} <- Tests].
   3510 
   3511 parse_www_authenticate_error_test_() ->
   3512 	Tests = [
   3513 		<<>>
   3514 	],
   3515 	[{V, fun() -> {'EXIT', _} = (catch parse_www_authenticate(V)) end} || V <- Tests].
   3516 
   3517 horse_parse_www_authenticate() ->
   3518 	horse:repeat(200000,
   3519 		parse_www_authenticate(<<"Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\"">>)
   3520 	).
   3521 -endif.
   3522 
   3523 %% X-Forwarded-For header.
   3524 %%
   3525 %% This header has no specification but *looks like* it is
   3526 %% a list of tokens.
   3527 %%
   3528 %% This header is deprecated in favor of the Forwarded header.
   3529 
   3530 -spec parse_x_forwarded_for(binary()) -> [binary()].
   3531 parse_x_forwarded_for(XForwardedFor) ->
   3532 	nonempty(nodeid_list(XForwardedFor, [])).
   3533 
   3534 -define(IS_NODEID_TOKEN(C),
   3535 	?IS_ALPHA(C) or ?IS_DIGIT(C)
   3536 		or (C =:= $:) or (C =:= $.) or (C =:= $_)
   3537 		or (C =:= $-) or (C =:= $[) or (C =:= $])).
   3538 
   3539 nodeid_list(<<>>, Acc) -> lists:reverse(Acc);
   3540 nodeid_list(<<C, R/bits>>, Acc) when ?IS_WS_COMMA(C) -> nodeid_list(R, Acc);
   3541 nodeid_list(<<C, R/bits>>, Acc) when ?IS_NODEID_TOKEN(C) -> nodeid(R, Acc, <<C>>).
   3542 
   3543 nodeid(<<C, R/bits>>, Acc, T) when ?IS_NODEID_TOKEN(C) -> nodeid(R, Acc, <<T/binary, C>>);
   3544 nodeid(R, Acc, T) -> nodeid_list_sep(R, [T|Acc]).
   3545 
   3546 nodeid_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   3547 nodeid_list_sep(<<C, R/bits>>, Acc) when ?IS_WS(C) -> nodeid_list_sep(R, Acc);
   3548 nodeid_list_sep(<<$,, R/bits>>, Acc) -> nodeid_list(R, Acc).
   3549 
   3550 -ifdef(TEST).
   3551 parse_x_forwarded_for_test_() ->
   3552 	Tests = [
   3553 		{<<"client, proxy1, proxy2">>,
   3554 			[<<"client">>, <<"proxy1">>, <<"proxy2">>]},
   3555 		{<<"128.138.243.150, unknown, 192.52.106.30">>,
   3556 			[<<"128.138.243.150">>, <<"unknown">>, <<"192.52.106.30">>]},
   3557 		%% Examples from Mozilla DN.
   3558 		{<<"2001:db8:85a3:8d3:1319:8a2e:370:7348">>,
   3559 			[<<"2001:db8:85a3:8d3:1319:8a2e:370:7348">>]},
   3560 		{<<"203.0.113.195">>,
   3561 			[<<"203.0.113.195">>]},
   3562 		{<<"203.0.113.195, 70.41.3.18, 150.172.238.178">>,
   3563 			[<<"203.0.113.195">>, <<"70.41.3.18">>, <<"150.172.238.178">>]},
   3564 		%% Examples from RFC7239 modified for x-forwarded-for.
   3565 		{<<"[2001:db8:cafe::17]:4711">>,
   3566 			[<<"[2001:db8:cafe::17]:4711">>]},
   3567 		{<<"192.0.2.43, 198.51.100.17">>,
   3568 			[<<"192.0.2.43">>, <<"198.51.100.17">>]},
   3569 		{<<"_hidden">>,
   3570 			[<<"_hidden">>]},
   3571 		{<<"192.0.2.43,[2001:db8:cafe::17],unknown">>,
   3572 			[<<"192.0.2.43">>, <<"[2001:db8:cafe::17]">>, <<"unknown">>]},
   3573 		{<<"192.0.2.43, [2001:db8:cafe::17], unknown">>,
   3574 			[<<"192.0.2.43">>, <<"[2001:db8:cafe::17]">>, <<"unknown">>]},
   3575 		{<<"192.0.2.43, 2001:db8:cafe::17">>,
   3576 			[<<"192.0.2.43">>, <<"2001:db8:cafe::17">>]},
   3577 		{<<"192.0.2.43, [2001:db8:cafe::17]">>,
   3578 			[<<"192.0.2.43">>, <<"[2001:db8:cafe::17]">>]}
   3579 	],
   3580 	[{V, fun() -> R = parse_x_forwarded_for(V) end} || {V, R} <- Tests].
   3581 
   3582 parse_x_forwarded_for_error_test_() ->
   3583 	Tests = [
   3584 		<<>>
   3585 	],
   3586 	[{V, fun() -> {'EXIT', _} = (catch parse_x_forwarded_for(V)) end} || V <- Tests].
   3587 -endif.
   3588 
   3589 %% Internal.
   3590 
   3591 %% Only return if the list is not empty.
   3592 nonempty(L) when L =/= [] -> L.
   3593 
   3594 %% Parse a list of case sensitive tokens.
   3595 token_list(<<>>, Acc) -> lists:reverse(Acc);
   3596 token_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> token_list(R, Acc);
   3597 token_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) -> token(R, Acc, << C >>).
   3598 
   3599 token(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> token(R, Acc, << T/binary, C >>);
   3600 token(R, Acc, T) -> token_list_sep(R, [T|Acc]).
   3601 
   3602 token_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   3603 token_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> token_list_sep(R, Acc);
   3604 token_list_sep(<< $,, R/bits >>, Acc) -> token_list(R, Acc).
   3605 
   3606 %% Parse a list of case insensitive tokens.
   3607 token_ci_list(<<>>, Acc) -> lists:reverse(Acc);
   3608 token_ci_list(<< C, R/bits >>, Acc) when ?IS_WS_COMMA(C) -> token_ci_list(R, Acc);
   3609 token_ci_list(<< C, R/bits >>, Acc) when ?IS_TOKEN(C) -> ?LOWER(token_ci, R, Acc, <<>>).
   3610 
   3611 token_ci(<< C, R/bits >>, Acc, T) when ?IS_TOKEN(C) -> ?LOWER(token_ci, R, Acc, T);
   3612 token_ci(R, Acc, T) -> token_ci_list_sep(R, [T|Acc]).
   3613 
   3614 token_ci_list_sep(<<>>, Acc) -> lists:reverse(Acc);
   3615 token_ci_list_sep(<< C, R/bits >>, Acc) when ?IS_WS(C) -> token_ci_list_sep(R, Acc);
   3616 token_ci_list_sep(<< $,, R/bits >>, Acc) -> token_ci_list(R, Acc).
   3617 
   3618 join_token_list([]) -> [];
   3619 join_token_list([H|T]) -> join_token_list(T, [H]).
   3620 
   3621 join_token_list([], Acc) -> lists:reverse(Acc);
   3622 join_token_list([H|T], Acc) -> join_token_list(T, [H,<<", ">>|Acc]).