154 lines
4.8 KiB
Erlang
154 lines
4.8 KiB
Erlang
|
%%%=============================================================================
|
||
|
%%% @copyright (C) 1999-2014, Erlang Solutions Ltd
|
||
|
%%% @author Diana Corbacho <diana.corbacho@erlang-solutions.com>
|
||
|
%%% @doc
|
||
|
%%% @end
|
||
|
%%%=============================================================================
|
||
|
-module(http_eqc_encoding).
|
||
|
-copyright("2014, Erlang Solutions Ltd.").
|
||
|
|
||
|
-export([add_content_length/2,
|
||
|
add_transfer_encoding/2,
|
||
|
body/1]).
|
||
|
|
||
|
-export([build_valid_response/4,
|
||
|
build_cookie/1,
|
||
|
build_expires_date/1,
|
||
|
expires_datetime/1]).
|
||
|
|
||
|
%%==============================================================================
|
||
|
%% API
|
||
|
%%==============================================================================
|
||
|
add_content_length(Headers, <<>>) ->
|
||
|
Headers;
|
||
|
add_content_length(Headers, Body) ->
|
||
|
ContentLength = list_to_binary(integer_to_list(byte_size(Body))),
|
||
|
[{<<"Content-Length">>, ContentLength} | Headers].
|
||
|
|
||
|
body({_, <<$1, _, _>>, _}) ->
|
||
|
<<>>;
|
||
|
body({_, <<$2,$0,$4>>, _}) ->
|
||
|
<<>>;
|
||
|
body({_, <<$3,$0,$4>>, _}) ->
|
||
|
<<>>;
|
||
|
body(_) ->
|
||
|
http_eqc_gen:body().
|
||
|
|
||
|
add_transfer_encoding(Headers, <<>>) ->
|
||
|
Headers;
|
||
|
add_transfer_encoding(Headers, Encoding) ->
|
||
|
lists:keystore(<<"Transfer-Encoding">>, 1,
|
||
|
remove_transfer_encoding(Headers),
|
||
|
{<<"Transfer-Encoding">>, Encoding}).
|
||
|
|
||
|
build_valid_response({HttpVersion, StatusCode, Reason}, Headers, Cookies, Body) ->
|
||
|
SL = [HttpVersion, sp(), StatusCode, sp(), Reason, crlf()],
|
||
|
HS = [[Name, colon(), Value, crlf()] || {Name, Value} <- Headers],
|
||
|
CS = [[Name, colon(), build_cookie(Cookie), crlf()] || {Name, Cookie} <- Cookies],
|
||
|
[SL, HS ++ CS, crlf(), build_body(Body)].
|
||
|
|
||
|
build_cookie({{K, V}, Avs}) ->
|
||
|
CookiePair = [K, eq(), V],
|
||
|
CookieAvs = build_cookie_avs(Avs),
|
||
|
CookiePair ++ CookieAvs.
|
||
|
|
||
|
build_expires_date({rfc1123date, {Wkday, Date1, Time}}) ->
|
||
|
Date = build_date(Date1),
|
||
|
BTime = build_time(Time),
|
||
|
[Wkday, $,, $\s, Date, $\s, BTime, $\s, "GMT"];
|
||
|
build_expires_date({rfc850date, {Weekday, Date2, Time}}) ->
|
||
|
Date = build_date(Date2),
|
||
|
BTime = build_time(Time),
|
||
|
[Weekday, $,, $\s, Date, $\s, BTime, $\s, "GMT"];
|
||
|
build_expires_date({asctimedate, {Wkday, Date3, Time, Year}}) ->
|
||
|
BTime = build_time(Time),
|
||
|
Date = build_date(Date3),
|
||
|
[Wkday, $\s, Date, $\s, BTime, $\s, Year].
|
||
|
|
||
|
expires_datetime({rfc1123date, {_, {date1, {Day, Month, Year}}, {H, M, S}}}) ->
|
||
|
{{st_to_int(Year), month(Month), st_to_int(Day)},
|
||
|
{st_to_int(H), st_to_int(M), st_to_int(S)}};
|
||
|
expires_datetime({rfc850date, {_, {date2, {Day, Month, Year}}, {H, M, S}}}) ->
|
||
|
{{to_year(Year), month(Month), st_to_int(Day)},
|
||
|
{st_to_int(H), st_to_int(M), st_to_int(S)}};
|
||
|
expires_datetime({asctimedate, {_, {date3, {Day, Month}}, {H, M, S}, Year}}) ->
|
||
|
{{st_to_int(Year), month(Month), st_to_int(Day)},
|
||
|
{st_to_int(H), st_to_int(M), st_to_int(S)}};
|
||
|
expires_datetime(undefined) ->
|
||
|
undefined.
|
||
|
%%==============================================================================
|
||
|
%% Internal functions
|
||
|
%%==============================================================================
|
||
|
remove_transfer_encoding(Headers) ->
|
||
|
lists:filter(fun({H, _}) -> H =/= <<"Transfer-Encoding">> end, Headers).
|
||
|
|
||
|
build_body(Body) when is_binary(Body) ->
|
||
|
Body;
|
||
|
build_body(List) ->
|
||
|
list_to_binary(
|
||
|
io_lib:format("~s0\r\n\r\n",
|
||
|
[[io_lib:format("~s\r\n~s\r\n",
|
||
|
[erlang:integer_to_list(Nat, 16), Body])
|
||
|
|| {Nat, Body} <- List]])).
|
||
|
|
||
|
build_cookie_avs(Avs) ->
|
||
|
build_cookie_avs(Avs, []).
|
||
|
|
||
|
build_cookie_avs([{<<"Expires">> = K, Date} | Rest], Acc) ->
|
||
|
V = build_expires_date(Date),
|
||
|
build_cookie_avs(Rest, [[semicolon(), sp(), K, eq(), V] | Acc]);
|
||
|
build_cookie_avs([{K, V} | Rest], Acc) ->
|
||
|
build_cookie_avs(Rest, [[semicolon(), sp(), K, eq(), V] | Acc]);
|
||
|
build_cookie_avs([K | Rest], Acc) ->
|
||
|
build_cookie_avs(Rest, [[semicolon(), sp(), K] | Acc]);
|
||
|
build_cookie_avs([], Acc) ->
|
||
|
Acc.
|
||
|
|
||
|
build_date({date1, {Day, Month, Year}}) ->
|
||
|
[Day, $\s, Month, $\s, Year];
|
||
|
build_date({date2, {Day, Month, Year}}) ->
|
||
|
[Day, $-, Month, $-, Year];
|
||
|
build_date({date3, {Day, Month}}) ->
|
||
|
[Month, $\s, Day].
|
||
|
|
||
|
build_time({H, M, S}) ->
|
||
|
[H, $:, M, $:, S].
|
||
|
|
||
|
colon() ->
|
||
|
<<$:>>.
|
||
|
|
||
|
semicolon() ->
|
||
|
<<$;>>.
|
||
|
|
||
|
sp() ->
|
||
|
<<$\s>>.
|
||
|
|
||
|
crlf() ->
|
||
|
<<$\r,$\n>>.
|
||
|
|
||
|
eq() ->
|
||
|
<<$=>>.
|
||
|
|
||
|
months() ->
|
||
|
[{"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4},
|
||
|
{"May", 5}, {"Jun", 6}, {"Jul", 7}, {"Aug", 8},
|
||
|
{"Sep", 9}, {"Oct", 10}, {"Nov", 11}, {"Dec", 12}].
|
||
|
|
||
|
st_to_int(L) ->
|
||
|
list_to_integer(L).
|
||
|
|
||
|
month(Month) ->
|
||
|
proplists:get_value(Month, months()).
|
||
|
|
||
|
to_year(Year) when length(Year) == 4 ->
|
||
|
st_to_int(Year);
|
||
|
to_year(Year) ->
|
||
|
IntY = list_to_integer(Year),
|
||
|
{Y, _, _} = date(),
|
||
|
case (2000 + IntY - Y) > 50 of
|
||
|
true ->
|
||
|
1900 + IntY;
|
||
|
false ->
|
||
|
2000 + IntY
|
||
|
end.
|