Current section
Files
Jump to
Current section
Files
src/accept_encoding_header.erl
-module(accept_encoding_header).
-export([parse/1,
negotiate/2]).
-include("accept.hrl").
%%====================================================================
%% Public API
%%====================================================================
-spec parse(AcceptString) -> Result when
AcceptString :: binary() | string (),
Result :: [content_coding()].
parse(AcceptString) ->
accept_parser:map_options(fun parse_content_coding/1, AcceptString).
negotiate(undefined, Alternatives) ->
case Alternatives of
[H|_] -> H;
_ -> Alternatives
end;
negotiate([], _) ->
identity;
negotiate(Header, Alternatives) ->
CCs = parse(Header),
Alts = lists:map(fun (Alt) ->
{A, Tag} = accept_neg:alt_tag(Alt),
PA = parse_content_coding(accept_parser:ensure_string(A)),
%% list of Alt-CC scores
AltCCScores = lists:map(fun (CC) ->
{score_alt(CC, PA), CC}
end,
CCs),
%% best Content Coding match for this Alternative
[{Score, BCC} | _] = accept_neg:sort_scored(AltCCScores),
case Score of
0 ->
{-1, Tag};
_ ->
#content_coding{q = BCCQ} = BCC,
{BCCQ, Tag}
end
end,
Alternatives),
{Q, Tag} = accept_neg:find_preferred_best(Alts),
case Q of
Q when Q =< 0 -> fallback_to_identity(CCs);
_ -> Tag
end.
%%====================================================================
%% Private Parts
%%====================================================================
parse_content_coding(#accept_option{option=Coding,
q=Q,
params=Params}) ->
%% RFC [https://tools.ietf.org/html/rfc7230#section-4] says
%% that params are allowed only for 'not standard' coding
%% this can be good TODO item
#content_coding{coding = Coding,
q = Q,
params = Params};
parse_content_coding(String) ->
parse_content_coding(accept_parser:parse_option(String)).
fallback_to_identity(CCs) ->
%% "identity is always valid
%% unless identity; q=0 or *;q=0
identity_fallback(CCs, ["identity", "*"]).
identity_fallback(_, []) ->
identity;
identity_fallback(CCs, [C|R]) ->
case lists:keyfind(C, #content_coding.coding, CCs) of
#content_coding{q = 0} ->
undefined;
#content_coding{} ->
identity;
false ->
identity_fallback(CCs, R)
end.
score_alt(#content_coding{coding = Coding,
params = CCParams},
#content_coding{coding = Coding,
params = AltParams}) ->
4 + accept_neg:score_params(CCParams, AltParams);
score_alt(#content_coding{coding = "*"},
_) ->
4;
score_alt(_, _) ->
0.