Packages
hackney
1.6.5
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/hackney_bstr.erl
%%% -*- erlang -*-
%%%
%%% This file is part of hackney_lib released under the Apache 2 license.
%%% See the NOTICE for more information.
%%%
-module(hackney_bstr).
-export([to_binary/1,
to_lower/1, to_upper/1,
char_to_lower/1, char_to_upper/1,
join/2,
to_hex/1,
token_ci/2, token/2,
list/2,
nonempty_list/2,
params/2,
parameterized_tokens/1,
whitespace/2,
digits/1, digits/2, digits/3,
alpha/2,
word/2,
trim/1]).
-export([quoted_string/2]).
to_binary(V) when is_list(V) ->
list_to_binary(V);
to_binary(V) when is_atom(V) ->
atom_to_binary(V, latin1);
to_binary(V) when is_integer(V) ->
list_to_binary(integer_to_list(V));
to_binary(V) when is_binary(V) ->
V.
%% @doc Convert a binary string to lowercase.
-spec to_lower(binary()) -> binary().
to_lower(L) when is_list(L) ->
to_lower(list_to_binary(L));
to_lower(L) ->
<< << (char_to_lower(C)) >> || << C >> <= L >>.
to_upper(L) when is_list(L) ->
to_upper(list_to_binary(L));
to_upper(U) ->
<< << (char_to_upper(C)) >> || << C >> <= U >>.
%% @doc Convert [A-Z] characters to lowercase.
%% @end
%% We gain noticeable speed by matching each value directly.
-spec char_to_lower(char()) -> char().
char_to_lower($A) -> $a;
char_to_lower($B) -> $b;
char_to_lower($C) -> $c;
char_to_lower($D) -> $d;
char_to_lower($E) -> $e;
char_to_lower($F) -> $f;
char_to_lower($G) -> $g;
char_to_lower($H) -> $h;
char_to_lower($I) -> $i;
char_to_lower($J) -> $j;
char_to_lower($K) -> $k;
char_to_lower($L) -> $l;
char_to_lower($M) -> $m;
char_to_lower($N) -> $n;
char_to_lower($O) -> $o;
char_to_lower($P) -> $p;
char_to_lower($Q) -> $q;
char_to_lower($R) -> $r;
char_to_lower($S) -> $s;
char_to_lower($T) -> $t;
char_to_lower($U) -> $u;
char_to_lower($V) -> $v;
char_to_lower($W) -> $w;
char_to_lower($X) -> $x;
char_to_lower($Y) -> $y;
char_to_lower($Z) -> $z;
char_to_lower(Ch) -> Ch.
%% @doc Convert [a-z] characters to uppercase.
-spec char_to_upper(char()) -> char().
char_to_upper($a) -> $A;
char_to_upper($b) -> $B;
char_to_upper($c) -> $C;
char_to_upper($d) -> $D;
char_to_upper($e) -> $E;
char_to_upper($f) -> $F;
char_to_upper($g) -> $G;
char_to_upper($h) -> $H;
char_to_upper($i) -> $I;
char_to_upper($j) -> $J;
char_to_upper($k) -> $K;
char_to_upper($l) -> $L;
char_to_upper($m) -> $M;
char_to_upper($n) -> $N;
char_to_upper($o) -> $O;
char_to_upper($p) -> $P;
char_to_upper($q) -> $Q;
char_to_upper($r) -> $R;
char_to_upper($s) -> $S;
char_to_upper($t) -> $T;
char_to_upper($u) -> $U;
char_to_upper($v) -> $V;
char_to_upper($w) -> $W;
char_to_upper($x) -> $X;
char_to_upper($y) -> $Y;
char_to_upper($z) -> $Z;
char_to_upper(Ch) -> Ch.
join([], _Separator) ->
<<>>;
join([S], _separator) ->
S;
join(L, Separator) ->
iolist_to_binary(join(lists:reverse(L), Separator, [])).
join([], _Separator, Acc) ->
Acc;
join([S | Rest], Separator, []) ->
join(Rest, Separator, [S]);
join([S | Rest], Separator, Acc) ->
join(Rest, Separator, [S, Separator | Acc]).
to_hex([]) ->
[];
to_hex(Bin) when is_binary(Bin) ->
to_hex(binary_to_list(Bin));
to_hex([H|T]) ->
[to_digit(H div 16), to_digit(H rem 16) | to_hex(T)].
to_digit(N) when N < 10 -> $0 + N;
to_digit(N) -> $a + N-10.
%% @doc Parse a case-insensitive token.
%%
%% Changes all characters to lowercase.
-spec token_ci(binary(), fun()) -> any().
token_ci(Data, Fun) ->
token(Data, Fun, ci, <<>>).
%% @doc Parse a token.
-spec token(binary(), fun()) -> any().
token(Data, Fun) ->
token(Data, Fun, cs, <<>>).
-spec token(binary(), fun(), ci | cs, binary()) -> any().
token(<<>>, Fun, _Case, Acc) ->
Fun(<<>>, Acc);
token(Data = << C, _Rest/binary >>, Fun, _Case, Acc)
when C =:= $(; C =:= $); C =:= $<; C =:= $>; C =:= $@;
C =:= $,; C =:= $;; C =:= $:; C =:= $\\; C =:= $";
C =:= $/; C =:= $[; C =:= $]; C =:= $?; C =:= $=;
C =:= ${; C =:= $}; C =:= $\s; C =:= $\t;
C < 32; C =:= 127 ->
Fun(Data, Acc);
token(<< C, Rest/binary >>, Fun, Case = ci, Acc) ->
C2 = char_to_lower(C),
token(Rest, Fun, Case, << Acc/binary, C2 >>);
token(<< C, Rest/binary >>, Fun, Case, Acc) ->
token(Rest, Fun, Case, << Acc/binary, C >>).
%% @doc Parse a non-empty list of the given type.
-spec nonempty_list(binary(), fun()) -> [any(), ...] | {error, badarg}.
nonempty_list(Data, Fun) ->
case list(Data, Fun, []) of
{error, badarg} -> {error, badarg};
[] -> {error, badarg};
L -> lists:reverse(L)
end.
%% @doc Parse a list of the given type.
-spec list(binary(), fun()) -> list() | {error, badarg}.
list(Data, Fun) ->
case list(Data, Fun, []) of
{error, badarg} -> {error, badarg};
L -> lists:reverse(L)
end.
-spec list(binary(), fun(), [binary()]) -> [any()] | {error, badarg}.
%% From the RFC:
%% <blockquote>Wherever this construct is used, null elements are allowed,
%% but do not contribute to the count of elements present.
%% That is, "(element), , (element) " is permitted, but counts
%% as only two elements. Therefore, where at least one element is required,
%% at least one non-null element MUST be present.</blockquote>
list(Data, Fun, Acc) ->
whitespace(Data,
fun (<<>>) -> Acc;
(<< $,, Rest/binary >>) -> list(Rest, Fun, Acc);
(Rest) -> Fun(Rest,
fun (D, I) -> whitespace(D,
fun (<<>>) -> [I|Acc];
(<< $,, R/binary >>) -> list(R, Fun,
[I|Acc]);
(_Any) -> {error, badarg}
end)
end)
end).
%% @doc Parse a list of parameters (a=b;c=d).
-spec params(binary(), fun()) -> any().
params(Data, Fun) ->
params(Data, Fun, []).
-spec params(binary(), fun(), [{binary(), binary()}]) -> any().
params(Data, Fun, Acc) ->
whitespace(Data,
fun (<< $;, Rest/binary >>) ->
param(Rest,
fun (Rest2, Attr, Value) ->
params(Rest2, Fun, [{Attr, Value}|Acc])
end);
(Rest) ->
Fun(Rest, lists:reverse(Acc))
end).
-spec param(binary(), fun()) -> any().
param(Data, Fun) ->
whitespace(Data,
fun (Rest) ->
token_ci(Rest,
fun (_Rest2, <<>>) -> {error, badarg};
(<< $=, Rest2/binary >>, Attr) ->
word(Rest2,
fun (Rest3, Value) ->
Fun(Rest3, Attr, Value)
end);
(_Rest2, _Attr) -> {error, badarg}
end)
end).
%% @doc Parse a non empty list of tokens followed with optional parameters.
-spec parameterized_tokens(binary()) -> any().
parameterized_tokens(Data) ->
nonempty_list(Data,
fun (D, Fun) ->
token(D,
fun (_Rest, <<>>) -> {error, badarg};
(Rest, Token) ->
parameterized_tokens_params(Rest,
fun (Rest2, Params) ->
Fun(Rest2, {Token, Params})
end, [])
end)
end).
-spec parameterized_tokens_params(binary(), fun(),
[binary() | {binary(), binary()}]) -> any().
parameterized_tokens_params(Data, Fun, Acc) ->
whitespace(Data,
fun (<< $;, Rest/binary >>) ->
parameterized_tokens_param(Rest,
fun (Rest2, Param) ->
parameterized_tokens_params(Rest2, Fun,
[Param|Acc])
end);
(Rest) ->
Fun(Rest, lists:reverse(Acc))
end).
-spec parameterized_tokens_param(binary(), fun()) -> any().
parameterized_tokens_param(Data, Fun) ->
whitespace(Data,
fun (Rest) ->
token(Rest,
fun (_Rest2, <<>>) ->
{error, badarg};
(<< $=, Rest2/binary >>, Attr) ->
word(Rest2,
fun (Rest3, Value) ->
Fun(Rest3, {Attr, Value})
end);
(Rest2, Attr) ->
Fun(Rest2, Attr)
end)
end).
%% @doc Skip whitespace.
-spec whitespace(binary(), fun()) -> any().
whitespace(<< C, Rest/binary >>, Fun)
when C =:= $\s; C =:= $\t ->
whitespace(Rest, Fun);
whitespace(Data, Fun) ->
Fun(Data).
%% @doc Parse a list of digits as a non negative integer.
-spec digits(binary()) -> non_neg_integer() | {error, badarg}.
digits(Data) ->
digits(Data,
fun (Rest, I) ->
whitespace(Rest,
fun (<<>>) ->
I;
(_Rest2) ->
{error, badarg}
end)
end).
-spec digits(binary(), fun()) -> any().
digits(<< C, Rest/binary >>, Fun)
when C >= $0, C =< $9 ->
digits(Rest, Fun, C - $0);
digits(_Data, _Fun) ->
{error, badarg}.
-spec digits(binary(), fun(), non_neg_integer()) -> any().
digits(<< C, Rest/binary >>, Fun, Acc)
when C >= $0, C =< $9 ->
digits(Rest, Fun, Acc * 10 + (C - $0));
digits(Data, Fun, Acc) ->
Fun(Data, Acc).
%% @doc Parse a list of case-insensitive alpha characters.
%%
%% Changes all characters to lowercase.
-spec alpha(binary(), fun()) -> any().
alpha(Data, Fun) ->
alpha(Data, Fun, <<>>).
-spec alpha(binary(), fun(), binary()) -> any().
alpha(<<>>, Fun, Acc) ->
Fun(<<>>, Acc);
alpha(<< C, Rest/binary >>, Fun, Acc)
when C >= $a andalso C =< $z;
C >= $A andalso C =< $Z ->
C2 = char_to_lower(C),
alpha(Rest, Fun, << Acc/binary, C2 >>);
alpha(Data, Fun, Acc) ->
Fun(Data, Acc).
%% @doc Parse either a token or a quoted string.
-spec word(binary(), fun()) -> any().
word(Data = << $", _/binary >>, Fun) ->
quoted_string(Data, Fun);
word(Data, Fun) ->
token(Data,
fun (_Rest, <<>>) -> {error, badarg};
(Rest, Token) -> Fun(Rest, Token)
end).
-spec trim(binary()) -> binary().
trim(Data) ->
re:replace(Data, "^\\s+|\\s+$", "", [{return, binary}, global]).
-spec quoted_string(binary(), fun()) -> any().
quoted_string(<< $", Rest/binary >>, Fun) ->
quoted_string(Rest, Fun, <<>>).
-spec quoted_string(binary(), fun(), binary()) -> any().
quoted_string(<<>>, _Fun, _Acc) ->
{error, badarg};
quoted_string(<< $", Rest/binary >>, Fun, Acc) ->
Fun(Rest, Acc);
quoted_string(<< $\\, C, Rest/binary >>, Fun, Acc) ->
quoted_string(Rest, Fun, << Acc/binary, C >>);
quoted_string(<< C, Rest/binary >>, Fun, Acc) ->
quoted_string(Rest, Fun, << Acc/binary, C >>).