Files
geef/src/geef_pkt.erl
Carlos Martín Nieto 370acd05ce More correct spec for pkt
2013-06-05 00:33:11 +02:00

79 lines
2.0 KiB
Erlang

-module(geef_pkt).
-export([line/1, parse/1, parse_request/1]).
-include("geef_records.hrl").
-define(SHA_LEN, 40).
-spec line(iolist()) -> iolist().
line([]) ->
[];
line(Text) ->
% prefix's own size + text size + LF
Len = 4 + iolist_size(Text) + 1,
Prefix = io_lib:format("~4.16.0b", [Len]),
[Prefix, Text, "\n"].
-spec parse(iolist()) -> {{want | have, geef_oid()}, binary()} | {error, ebufs}.
parse(In) ->
case unpack(In) of
Err = {error, ebufs} ->
Err;
{Len, Rest} ->
parse_pkt(Rest, Len)
end.
-spec parse_request(iolist()) -> geef_request().
parse_request(In) ->
case unpack(In) of
Err = {error, ebufs} ->
Err;
{_, Line} ->
%% Split it into request, host, rest (should be empty)
[S, H, _] = binary:split(Line, <<0:8>>, [global]),
{Service, Path} = service_path(S),
<<"host=", Host/binary>> = H,
{ok, #geef_request{service=Service, path=Path, host=Host}}
end.
service_path(<<"git-upload-pack ", Path/binary>>) ->
{upload_pack, Path};
service_path(<<"git-receive-pack ", Path/binary>>) ->
{receive_pack, Path}.
-spec unpack(iolist()) -> {error, ebufs} | {non_neg_integer(), binary()}.
unpack(In) ->
<<BLen:4/binary, Rest/binary>> = iolist_to_binary(In),
Len = binary_to_integer(BLen, 16),
do_unpack(Len, Rest).
do_unpack(0, Rest) ->
{0, Rest};
do_unpack(Len, Rest) when Len - 4 > size(Rest) ->
{error, ebufs};
do_unpack(Len, Rest) ->
{Len - 4, Rest}.
parse_pkt(In, 0) ->
{flush, In};
parse_pkt(In, Len) ->
{Type, NameLen, Rest0} = pkt_type(In),
LenLF = Len - NameLen, % lets us optionally clean the LF
{Pkt, Rest1} = case Type of
done ->
{done, Rest0};
_ ->
<<Sha:?SHA_LEN/binary, R/binary>> = Rest0,
{{Type, geef_oid:parse(Sha)}, R}
end,
<<_:LenLF/binary, Rest/binary>> = Rest1,
{Pkt, Rest}.
pkt_type(<<"have ", Rest/binary>>) ->
{have, 5 + ?SHA_LEN, Rest};
pkt_type(<<"want ", Rest/binary>>) ->
{want, 5 + ?SHA_LEN, Rest};
pkt_type(<<"done", Rest/binary>>) ->
{done, 4, Rest}.