Skip to content

Commit

Permalink
Merge pull request #940 from erlang-ls/939-do-not-depend-on-cowlib
Browse files Browse the repository at this point in the history
[#939] Do not depend on the cowlib dependency
  • Loading branch information
robertoaloi authored Mar 13, 2021
2 parents e410de2 + a7e62dc commit f2f3cd8
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
1 change: 0 additions & 1 deletion apps/els_core/src/els_core.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
stdlib,
ranch,
jsx,
cowlib,
yamerl,
redbug
]},
Expand Down
125 changes: 125 additions & 0 deletions apps/els_core/src/els_http_utils.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
%% =============================================================================
%% Extracted version of cowlib:parse_headers/1 function
%% =============================================================================
%% The main reasons for the fork:
%% * OTP does not have an equivalent for the function
%% * The cowlib app is significant in size and including it as a dependency
%% seems overkill
%% =============================================================================
%% Copyright (c) 2013-2020, Loïc Hoguin <[email protected]>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
%%==============================================================================
-module(els_http_utils).

-compile(nowarn_missing_spec).

-export([ parse_headers/1 ]).

-define(LOWER(Function, Rest, A0, Acc),
case C of
$A -> Function(Rest, A0, << Acc/binary, $a >>);
$B -> Function(Rest, A0, << Acc/binary, $b >>);
$C -> Function(Rest, A0, << Acc/binary, $c >>);
$D -> Function(Rest, A0, << Acc/binary, $d >>);
$E -> Function(Rest, A0, << Acc/binary, $e >>);
$F -> Function(Rest, A0, << Acc/binary, $f >>);
$G -> Function(Rest, A0, << Acc/binary, $g >>);
$H -> Function(Rest, A0, << Acc/binary, $h >>);
$I -> Function(Rest, A0, << Acc/binary, $i >>);
$J -> Function(Rest, A0, << Acc/binary, $j >>);
$K -> Function(Rest, A0, << Acc/binary, $k >>);
$L -> Function(Rest, A0, << Acc/binary, $l >>);
$M -> Function(Rest, A0, << Acc/binary, $m >>);
$N -> Function(Rest, A0, << Acc/binary, $n >>);
$O -> Function(Rest, A0, << Acc/binary, $o >>);
$P -> Function(Rest, A0, << Acc/binary, $p >>);
$Q -> Function(Rest, A0, << Acc/binary, $q >>);
$R -> Function(Rest, A0, << Acc/binary, $r >>);
$S -> Function(Rest, A0, << Acc/binary, $s >>);
$T -> Function(Rest, A0, << Acc/binary, $t >>);
$U -> Function(Rest, A0, << Acc/binary, $u >>);
$V -> Function(Rest, A0, << Acc/binary, $v >>);
$W -> Function(Rest, A0, << Acc/binary, $w >>);
$X -> Function(Rest, A0, << Acc/binary, $x >>);
$Y -> Function(Rest, A0, << Acc/binary, $y >>);
$Z -> Function(Rest, A0, << Acc/binary, $z >>);
C -> Function(Rest, A0, << Acc/binary, C >>)
end).

%% @doc Parse the list of headers.
-spec parse_headers(binary()) -> {[{binary(), binary()}], binary()}.
parse_headers(Data) ->
parse_header(Data, []).

-spec parse_header(binary(), [{binary(), binary()}]) ->
{[{binary(), binary()}], binary()}.
parse_header(<< $\r, $\n, Rest/bits >>, Acc) ->
{lists:reverse(Acc), Rest};
parse_header(Data, Acc) ->
parse_hd_name(Data, Acc, <<>>).

-spec parse_hd_name(binary(), [{binary(), binary()}], binary()) ->
{[{binary(), binary()}], binary()}.
parse_hd_name(<< C, Rest/bits >>, Acc, SoFar) ->
case C of
$: -> parse_hd_before_value(Rest, Acc, SoFar);
$\s -> parse_hd_name_ws(Rest, Acc, SoFar);
$\t -> parse_hd_name_ws(Rest, Acc, SoFar);
_ -> ?LOWER(parse_hd_name, Rest, Acc, SoFar)
end.

-spec parse_hd_name_ws(binary(), [{binary(), binary()}], binary()) ->
{[{binary(), binary()}], binary()}.
parse_hd_name_ws(<< C, Rest/bits >>, Acc, Name) ->
case C of
$: -> parse_hd_before_value(Rest, Acc, Name);
$\s -> parse_hd_name_ws(Rest, Acc, Name);
$\t -> parse_hd_name_ws(Rest, Acc, Name)
end.

-spec parse_hd_before_value(binary(), [{binary(), binary()}], binary()) ->
{[{binary(), binary()}], binary()}.
parse_hd_before_value(<< $\s, Rest/bits >>, Acc, Name) ->
parse_hd_before_value(Rest, Acc, Name);
parse_hd_before_value(<< $\t, Rest/bits >>, Acc, Name) ->
parse_hd_before_value(Rest, Acc, Name);
parse_hd_before_value(Data, Acc, Name) ->
parse_hd_value(Data, Acc, Name, <<>>).

-spec parse_hd_value(binary(), [{binary(), binary()}], binary(), binary()) ->
{[{binary(), binary()}], binary()}.
parse_hd_value(<< $\r, Rest/bits >>, Acc, Name, SoFar) ->
case Rest of
<< $\n, C, Rest2/bits >> when C =:= $\s; C =:= $\t ->
parse_hd_value(Rest2, Acc, Name, << SoFar/binary, C >>);
<< $\n, Rest2/bits >> ->
Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
parse_header(Rest2, [{Name, Value}|Acc])
end;
parse_hd_value(<< C, Rest/bits >>, Acc, Name, SoFar) ->
parse_hd_value(Rest, Acc, Name, << SoFar/binary, C >>).

-spec clean_value_ws_end(binary(), number()) -> binary().
%% This function has been copied from cowboy_http.
clean_value_ws_end(_, -1) ->
<<>>;
clean_value_ws_end(Value, N) ->
case binary:at(Value, N) of
$\s -> clean_value_ws_end(Value, N - 1);
$\t -> clean_value_ws_end(Value, N - 1);
_ ->
S = N + 1,
<< Value2:S/binary, _/bits >> = Value,
Value2
end.
2 changes: 1 addition & 1 deletion apps/els_core/src/els_jsonrpc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ split(Data, DecodeOpts) ->

-spec split(binary(), [any()], [map()]) -> {[map()], binary()}.
split(Data, DecodeOpts, Responses) ->
try cow_http:parse_headers(Data) of
try els_http_utils:parse_headers(Data) of
{Headers, Data1} ->
BinLength = proplists:get_value(<<"content-length">>, Headers),
Length = binary_to_integer(BinLength),
Expand Down
1 change: 0 additions & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

{deps, [ {ranch, "1.7.1"}
, {jsx, "3.0.0"}
, {cowlib, "2.10.1"}
, {redbug, "2.0.6"}
, {yamerl, "0.8.1"}
, {docsh, "0.7.2"}
Expand Down
3 changes: 0 additions & 3 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{"1.2.0",
[{<<"bucs">>,{pkg,<<"bucs">>,<<"1.0.16">>},1},
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.10.1">>},0},
{<<"docsh">>,{pkg,<<"docsh">>,<<"0.7.2">>},0},
{<<"elvis_core">>,{pkg,<<"elvis_core">>,<<"1.1.1">>},0},
{<<"ephemeral">>,{pkg,<<"ephemeral">>,<<"2.0.4">>},0},
Expand All @@ -19,7 +18,6 @@
[
{pkg_hash,[
{<<"bucs">>, <<"D69A4CD6D1238CD1ADC5C95673DBDE0F8459A5DBB7D746516434D8C6D935E96F">>},
{<<"cowlib">>, <<"5442EB6B4EB1EB7F34DF38145ECB59BA15932FA6465C1C10DC47C7EB91DEA8CD">>},
{<<"docsh">>, <<"F893D5317A0E14269DD7FE79CF95FB6B9BA23513DA0480EC6E77C73221CAE4F2">>},
{<<"elvis_core">>, <<"EB7864CE4BC87D13FBF1C222A82230A4C3D327C21080B73E97FC6343C3A5264D">>},
{<<"ephemeral">>, <<"B3E57886ADD5D90C82FE3880F5954978222A122CB8BAA123667401BBAAEC51D6">>},
Expand All @@ -37,7 +35,6 @@
{<<"zipper">>, <<"3CCB4F14B97C06B2749B93D8B6C204A1ECB6FAFC6050CACC3B93B9870C05952A">>}]},
{pkg_hash_ext,[
{<<"bucs">>, <<"FF6A5C72A500AD7AEC1EE3BA164AE3C450EADEE898B0D151E1FACA18AC8D0D62">>},
{<<"cowlib">>, <<"9B4271E10228E6877199F1D698EAA3B32E69AE82CC68E1443C5CA8E774089A44">>},
{<<"docsh">>, <<"4E7DB461BB07540D2BC3D366B8513F0197712D0495BB85744F367D3815076134">>},
{<<"elvis_core">>, <<"391C95BAA49F2718D7FB498BCF08046DDFC202CF0AAB63B2E439271485C9DC42">>},
{<<"ephemeral">>, <<"4B293D80F75F9C4575FF4B9C8E889A56802F40B018BF57E74F19644EFEE6C850">>},
Expand Down

0 comments on commit f2f3cd8

Please sign in to comment.