Skip to content

Instantly share code, notes, and snippets.

@puzza007
Created November 2, 2011 16:21
Show Gist options
  • Save puzza007/1334088 to your computer and use it in GitHub Desktop.
Save puzza007/1334088 to your computer and use it in GitHub Desktop.
-module(badger).
-export([encoding/1]).
-spec encoding(binary()) -> gzip | compress | deflate | identity.
encoding(AcceptEncoding) ->
EncodingList = encoding_list(AcceptEncoding),
{Enc, _} =
lists:foldl(fun({E, Q}, {MaxEnc, MaxQval}) ->
E1 = encoding_map(E),
if Q > MaxQval andalso E1 =/= unknown ->
{E1, Q};
true ->
{MaxEnc, MaxQval}
end
end,
{identity, 0},
EncodingList),
Enc.
-spec encoding_map(binary()) -> gzip | compress | deflate | identity | unknown.
encoding_map(<<"gzip">>) -> gzip;
encoding_map(<<"compress">>) -> compress;
encoding_map(<<"deflate">>) -> deflate;
encoding_map(<<"identity">>) -> identity;
encoding_map(_) -> unknown.
-spec encoding_list(binary()) -> [{binary(), non_neg_integer()}].
encoding_list(AcceptEncoding) when is_binary(AcceptEncoding) ->
[parse_qval(X) || X <- binary:split(AcceptEncoding, <<",">>, [global])].
-spec parse_qval(binary()) -> {binary(), non_neg_integer()}.
parse_qval(S) when is_binary(S) ->
S1 = binary:replace(S, <<" ">>, <<"">>, [global]),
parse_qval(<<>>, S1).
-spec parse_qval(binary(), binary()) -> {binary(), non_neg_integer()}.
parse_qval(<<>>, <<>>) ->
{<<"identity">>, 1000};
parse_qval(A, <<";q=", Q/binary>>) ->
{A, parse_qvalue(Q)};
parse_qval(A, <<"">>) ->
{A, 1000};
parse_qval(A, <<C, T/binary>>) ->
parse_qval(<<A/binary, C>>, T).
-define(DIGIT(X), (X >= $0 andalso X =< $9)).
-spec parse_qvalue(binary()) -> non_neg_integer().
parse_qvalue(<<"0">>) ->
0;
parse_qvalue(<<"0.">>) ->
0;
parse_qvalue(<<"1">>) ->
1000;
parse_qvalue(<<"1.">>) ->
1000;
parse_qvalue(<<"1.0">>) ->
1000;
parse_qvalue(<<"1.00">>) ->
1000;
parse_qvalue(<<"1.000">>) ->
1000;
parse_qvalue(<<"0.", D1, D2, D3>>)
when ?DIGIT(D1) andalso ?DIGIT(D2) andalso ?DIGIT(D3) ->
list_to_integer([D1, D2, D3]);
parse_qvalue(<<"0.", D1, D2>>)
when ?DIGIT(D1) andalso ?DIGIT(D2) ->
list_to_integer([D1, D2, $0]);
parse_qvalue(<<"0.", D1>>)
when ?DIGIT(D1) ->
list_to_integer([D1, $0, $0]);
parse_qvalue(_) ->
%% error
0.
-include_lib("eunit/include/eunit.hrl").
encoding_list_test() ->
[{<<"identity">>, 1000}] = encoding_list(<<"">>),
[{<<"identity">>, 0}] = encoding_list(<<"identity;q=0">>),
[{<<"identity">>, 0}] = encoding_list(<<"identity ;q=0">>),
[{<<"identity">>, 0}] = encoding_list(<<" identity; q =0 ">>),
[{<<"identity">>, 0}] = encoding_list(<<"identity ; q = 0">>),
[{<<"identity">>, 0}] =
encoding_list(<<"identity ; q= 0.0">>),
[{<<"gzip">>, 1000}, {<<"deflate">>, 1000}, {<<"identity">>, 0}] =
encoding_list(<<"gzip,deflate,identity;q=0.0">>),
[{<<"deflate">>, 1000}, {<<"gzip">>, 1000}, {<<"identity">>, 0}] =
encoding_list(<<"deflate,gzip,identity;q=0.0">>),
[{<<"gzip">>, 1000}, {<<"deflate">>, 1000}, {<<"gzip">>, 1000},
{<<"identity">>, 0}] =
encoding_list(<<"gzip,deflate,gzip,identity;q=0">>),
[{<<"gzip">>, 1000}, {<<"deflate">>, 1000}, {<<"identity">>, 0}] =
encoding_list(<<"gzip, deflate , identity; q=0.0">>),
[{<<"gzip">>, 1000}, {<<"deflate">>, 1000}, {<<"identity">>, 0}] =
encoding_list(<<"gzip; q=1, deflate;q=1.0, identity;q=0.0">>),
[{<<"gzip">>, 500}, {<<"deflate">>, 1000},
{<<"identity">>, 0}] =
encoding_list(<<"gzip; q=0.5, deflate;q=1.0, identity;q=0">>),
[{<<"gzip">>, 500}, {<<"deflate">>, 1000},
{<<"identity">>, 0}] =
encoding_list(<<"gzip; q=0.5, deflate , identity;q=0.0">>),
[{<<"gzip">>, 500}, {<<"deflate">>, 800},
{<<"identity">>, 0}] =
encoding_list(<<"gzip; q=0.5, deflate;q=0.8, identity;q=0.0">>),
[{<<"gzip">>, 500}, {<<"deflate">>, 1000},
{<<"identity">>, 1000}] =
encoding_list(<<"gzip; q=0.5,deflate,identity">>),
[{<<"gzip">>, 500}, {<<"deflate">>, 1000}, {<<"identity">>, 1000},
{<<"identity">>, 1000}] =
encoding_list(<<"gzip; q=0.5,deflate,identity, identity ">>),
ok.
encoding_test() ->
identity = encoding(<<"">>),
identity = encoding(<<"BadEncoding">>),
identity = encoding(<<"identity;q=0">>),
identity = encoding(<<"BadEncoding;q=0">>),
identity = encoding(<<"identity ;q=0">>),
identity = encoding(<<"BadEncoding ;q=0">>),
identity = encoding(<<" identity; q =0 ">>),
identity = encoding(<<"identity ; q = 0">>),
identity = encoding(<<"identity ; q= 0.0">>),
gzip = encoding(<<"gzip,deflate,identity;q=0.0">>),
deflate = encoding(<<"deflate,gzip,identity;q=0.0">>),
gzip = encoding(<<"gzip,deflate,gzip,identity;q=0">>),
gzip = encoding(<<"gzip, deflate , identity; q=0.0">>),
gzip = encoding(<<"gzip; q=1, deflate;q=1.0, identity;q=0.0">>),
gzip = encoding(<<"BadEncoding, gzip; q=1, deflate;q=1.0, identity;q=0.0">>),
deflate = encoding(<<"gzip; q=0.5, deflate;q=1.0, identity;q=0">>),
deflate = encoding(<<"gzip; q=0.5, deflate , identity;q=0.0">>),
deflate = encoding(<<"gzip; q=0.5, deflate;q=0.8, identity;q=0.0">>),
deflate = encoding(<<"gzip; q=0.5,deflate,identity">>),
deflate = encoding(<<"gzip; q=0.5,deflate,identity, identity ">>),
deflate = encoding(<<"BadEncoding, gzip; q=0.5,deflate,identity, identity ">>),
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment