Packages
🐑 a fluffy Gleam web server
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/ewe@internal@gramps@websocket.erl
-module(ewe@internal@gramps@websocket).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ewe/internal/gramps/websocket.gleam").
-export([text_frame/1, binary_frame/1, match_data_frame/3, decode_frame/2, apply_mask/2, encode_close_frame/2, encode_continuation_frame/3, apply_deflate/2, apply_inflate/2, encode_text_frame/3, encode_binary_frame/3, encode_ping_frame/2, encode_pong_frame/2, decode_many_frames/3, decode_many_frames_result/3, aggregate_frames/4, make_client_key/0, has_deflate/1, get_context_takeovers/1, parse_websocket_key/1]).
-export_type([data_frame/0, close_reason/0, control_frame/0, frame/0, frame_parse_error/0, parsed_frame/0, compression/0, many_frames_parse_error/0, sha_hash/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-opaque data_frame() :: {text_frame, bitstring()} |
{binary_frame, bitstring()} |
{compressed_text_frame, bitstring()} |
{compressed_binary_frame, bitstring()}.
-type close_reason() :: not_provided |
{normal, bitstring()} |
{going_away, bitstring()} |
{protocol_error, bitstring()} |
{unexpected_data_type, bitstring()} |
{inconsistent_data_type, bitstring()} |
{policy_violation, bitstring()} |
{message_too_big, bitstring()} |
{missing_extensions, bitstring()} |
{unexpected_condition, bitstring()} |
{custom_close_reason, integer(), bitstring()}.
-type control_frame() :: {close_frame, close_reason()} |
{ping_frame, bitstring()} |
{pong_frame, bitstring()}.
-type frame() :: {data, data_frame()} |
{control, control_frame()} |
{continuation, integer(), bitstring()}.
-type frame_parse_error() :: {need_more_data, bitstring()} | invalid_frame.
-type parsed_frame() :: {complete, frame()} | {incomplete, frame()}.
-type compression() :: compressed | uncompressed.
-type many_frames_parse_error() :: {need_more_data_accumulated,
list(parsed_frame()),
bitstring()} |
contains_invalid_frame.
-type sha_hash() :: sha.
-file("src/ewe/internal/gramps/websocket.gleam", 24).
?DOC(false).
-spec text_frame(bitstring()) -> data_frame().
text_frame(Payload) ->
{text_frame, Payload}.
-file("src/ewe/internal/gramps/websocket.gleam", 28).
?DOC(false).
-spec binary_frame(bitstring()) -> data_frame().
binary_frame(Payload) ->
{binary_frame, Payload}.
-file("src/ewe/internal/gramps/websocket.gleam", 32).
?DOC(false).
-spec match_data_frame(
data_frame(),
fun((bitstring(), boolean()) -> KIC),
fun((bitstring(), boolean()) -> KIC)
) -> KIC.
match_data_frame(Data_frame, On_text, On_binary) ->
case Data_frame of
{text_frame, Payload} ->
On_text(Payload, false);
{compressed_text_frame, Payload@1} ->
On_text(Payload@1, true);
{binary_frame, Payload@2} ->
On_binary(Payload@2, false);
{compressed_binary_frame, Payload@3} ->
On_binary(Payload@3, true)
end.
-file("src/ewe/internal/gramps/websocket.gleam", 88).
?DOC(false).
-spec create_repeating_mask(bitstring(), integer()) -> bitstring().
create_repeating_mask(Mask_key, Size) ->
case Size of
1 ->
_pipe = gleam_stdlib:bit_array_slice(Mask_key, 0, Size),
gleam@result:unwrap(_pipe, <<>>);
2 ->
_pipe = gleam_stdlib:bit_array_slice(Mask_key, 0, Size),
gleam@result:unwrap(_pipe, <<>>);
3 ->
_pipe = gleam_stdlib:bit_array_slice(Mask_key, 0, Size),
gleam@result:unwrap(_pipe, <<>>);
4 ->
_pipe = gleam_stdlib:bit_array_slice(Mask_key, 0, Size),
gleam@result:unwrap(_pipe, <<>>);
_ ->
Repetitions = Size div 4,
Remainder = Size rem 4,
Base = begin
_pipe@1 = gleam@list:repeat(Mask_key, Repetitions),
gleam_stdlib:bit_array_concat(_pipe@1)
end,
case Remainder of
0 ->
Base;
N ->
Partial = begin
_pipe@2 = gleam_stdlib:bit_array_slice(Mask_key, 0, N),
gleam@result:unwrap(_pipe@2, <<>>)
end,
<<Base/bitstring, Partial/bitstring>>
end
end.
-file("src/ewe/internal/gramps/websocket.gleam", 79).
?DOC(false).
-spec mask_data(bitstring(), list(bitstring())) -> bitstring().
mask_data(Data, Masks) ->
{M1@1, M2@1, M3@1, M4@1} = case Masks of
[M1, M2, M3, M4] -> {M1, M2, M3, M4};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/gramps/websocket"/utf8>>,
function => <<"mask_data"/utf8>>,
line => 80,
value => _assert_fail,
start => 2058,
'end' => 2093,
pattern_start => 2069,
pattern_end => 2085})
end,
Mask_key = <<M1@1/bitstring,
M2@1/bitstring,
M3@1/bitstring,
M4@1/bitstring>>,
Payload_size = erlang:byte_size(Data),
Full_mask = create_repeating_mask(Mask_key, Payload_size),
crypto:exor(Data, Full_mask).
-file("src/ewe/internal/gramps/websocket.gleam", 118).
?DOC(false).
-spec decode_frame(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context())
) -> {ok, {parsed_frame(), bitstring()}} | {error, frame_parse_error()}.
decode_frame(Message, Context) ->
case Message of
<<Complete:1,
Compressed:1,
Rsv2:1,
Rsv3:1,
Opcode:4/integer,
Masked:1,
Payload_length:7/integer,
Rest/bitstring>> ->
Compressed@1 = Compressed =:= 1,
Masked@1 = Masked =:= 1,
gleam@bool:guard(
Compressed@1 andalso gleam@option:is_none(Context),
{error, invalid_frame},
fun() ->
gleam@bool:guard(
(Rsv2 =:= 1) orelse (Rsv3 =:= 1),
{error, invalid_frame},
fun() ->
gleam@bool:guard(
begin
Is_control_frame = (Opcode >= 8) andalso (Opcode
=< 10),
Is_fragmented = Complete =:= 0,
Is_control_frame andalso Is_fragmented
end,
{error, invalid_frame},
fun() ->
Payload_size = case Payload_length of
126 ->
16;
127 ->
64;
_ ->
0
end,
Maybe_pair = case {Masked@1, Rest} of
{true,
<<Length:Payload_size/integer,
Mask1:1/binary,
Mask2:1/binary,
Mask3:1/binary,
Mask4:1/binary,
Rest@1/bitstring>>} ->
Payload_byte_size = case Length of
0 ->
Payload_length;
N ->
N
end,
case {erlang:byte_size(Rest@1) >= Payload_byte_size,
Rest@1} of
{true,
<<Payload:Payload_byte_size/binary,
Remaining/bitstring>>} ->
Data = mask_data(
Payload,
[Mask1,
Mask2,
Mask3,
Mask4]
),
{ok, {Data, Remaining}};
{_, _} ->
{error,
{need_more_data,
Message}}
end;
{true, _} ->
{error, {need_more_data, Message}};
{false,
<<Length@1:Payload_size/integer,
Rest@2/bitstring>>} ->
Payload_byte_size@1 = case Length@1 of
0 ->
Payload_length;
N@1 ->
N@1
end,
case Rest@2 of
<<Payload@1:Payload_byte_size@1/binary,
Rest@3/bitstring>> ->
{ok, {Payload@1, Rest@3}};
_ ->
{error,
{need_more_data,
Message}}
end;
{_, _} ->
{error, invalid_frame}
end,
gleam@result:'try'(
Maybe_pair,
fun(_use0) ->
{Data@1, Rest@4} = _use0,
_pipe = case Opcode of
0 ->
{ok,
{continuation,
Payload_size,
Data@1}};
1 ->
case Compressed@1 of
true ->
{ok,
{data,
{compressed_text_frame,
Data@1}}};
false ->
{ok,
{data,
{text_frame,
Data@1}}}
end;
2 ->
case Compressed@1 of
true ->
{ok,
{data,
{compressed_binary_frame,
Data@1}}};
false ->
{ok,
{data,
{binary_frame,
Data@1}}}
end;
8 ->
case Data@1 of
<<>> ->
{ok,
{control,
{close_frame,
not_provided}}};
<<Code:16,
Rest@5/bitstring>> ->
gleam@bool:guard(
not gleam@bit_array:is_utf8(
Rest@5
),
{error,
invalid_frame},
fun() ->
case Code of
1000 ->
{ok,
{control,
{close_frame,
{normal,
Rest@5}}}};
1001 ->
{ok,
{control,
{close_frame,
{going_away,
Rest@5}}}};
1002 ->
{ok,
{control,
{close_frame,
{protocol_error,
Rest@5}}}};
1003 ->
{ok,
{control,
{close_frame,
{unexpected_data_type,
Rest@5}}}};
1007 ->
{ok,
{control,
{close_frame,
{inconsistent_data_type,
Rest@5}}}};
1008 ->
{ok,
{control,
{close_frame,
{policy_violation,
Rest@5}}}};
1009 ->
{ok,
{control,
{close_frame,
{message_too_big,
Rest@5}}}};
1010 ->
{ok,
{control,
{close_frame,
{missing_extensions,
Rest@5}}}};
1011 ->
{ok,
{control,
{close_frame,
{unexpected_condition,
Rest@5}}}};
Code@1 when (Code@1 >= 3000) andalso (Code@1 =< 4999) ->
{ok,
{control,
{close_frame,
{custom_close_reason,
Code@1,
Rest@5}}}};
_ ->
{error,
invalid_frame}
end
end
);
_ ->
{error,
invalid_frame}
end;
9 ->
{ok,
{control,
{ping_frame, Data@1}}};
10 ->
{ok,
{control,
{pong_frame, Data@1}}};
_ ->
{error, invalid_frame}
end,
gleam@result:'try'(
_pipe,
fun(Frame) -> case Complete of
1 ->
{ok,
{{complete,
Frame},
Rest@4}};
0 ->
{ok,
{{incomplete,
Frame},
Rest@4}};
_ ->
{error,
invalid_frame}
end end
)
end
)
end
)
end
)
end
);
_ ->
{error, {need_more_data, Message}}
end.
-file("src/ewe/internal/gramps/websocket.gleam", 378).
?DOC(false).
-spec make_length(integer()) -> bitstring().
make_length(Length) ->
case Length of
Length@1 when Length@1 > 65535 ->
<<127:7, Length@1:64/integer>>;
Length@2 when Length@2 >= 126 ->
<<126:7, Length@2:16/integer>>;
_ ->
<<Length:7>>
end.
-file("src/ewe/internal/gramps/websocket.gleam", 391).
?DOC(false).
-spec make_frame(
integer(),
integer(),
bitstring(),
compression(),
gleam@option:option(bitstring())
) -> gleam@bytes_tree:bytes_tree().
make_frame(Opcode, Length, Payload, Compressed, Mask) ->
Length_section = make_length(Length),
Masked = case gleam@option:is_some(Mask) of
true ->
1;
false ->
0
end,
Mask_key = gleam@option:unwrap(Mask, <<>>),
Compressed@1 = case Compressed of
compressed ->
1;
uncompressed ->
0
end,
_pipe = <<1:1,
Compressed@1:1,
0:2,
Opcode:4,
Masked:1,
Length_section/bitstring,
Mask_key/bitstring,
Payload/bitstring>>,
gleam@bytes_tree:from_bit_array(_pipe).
-file("src/ewe/internal/gramps/websocket.gleam", 425).
?DOC(false).
-spec apply_mask(bitstring(), gleam@option:option(bitstring())) -> bitstring().
apply_mask(Data, Mask) ->
case Mask of
{some, Mask@1} ->
{Mask1@1, Mask2@1, Mask3@1, Mask4@1} = case Mask@1 of
<<Mask1:1/binary,
Mask2:1/binary,
Mask3:1/binary,
Mask4:1/binary>> -> {Mask1, Mask2, Mask3, Mask4};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/gramps/websocket"/utf8>>,
function => <<"apply_mask"/utf8>>,
line => 428,
value => _assert_fail,
start => 12052,
'end' => 12197,
pattern_start => 12063,
pattern_end => 12190})
end,
mask_data(Data, [Mask1@1, Mask2@1, Mask3@1, Mask4@1]);
none ->
Data
end.
-file("src/ewe/internal/gramps/websocket.gleam", 298).
?DOC(false).
-spec encode_frame(frame(), compression(), gleam@option:option(bitstring())) -> gleam@bytes_tree:bytes_tree().
encode_frame(Frame, Compressed, Mask) ->
case Frame of
{data, {text_frame, Payload}} ->
Payload_length = erlang:byte_size(Payload),
make_frame(1, Payload_length, Payload, Compressed, Mask);
{data, {compressed_text_frame, Payload}} ->
Payload_length = erlang:byte_size(Payload),
make_frame(1, Payload_length, Payload, Compressed, Mask);
{data, {binary_frame, Payload@1}} ->
Payload_length@1 = erlang:byte_size(Payload@1),
make_frame(2, Payload_length@1, Payload@1, Compressed, Mask);
{data, {compressed_binary_frame, Payload@1}} ->
Payload_length@1 = erlang:byte_size(Payload@1),
make_frame(2, Payload_length@1, Payload@1, Compressed, Mask);
{control, {close_frame, Reason}} ->
{Payload_length@2, Payload@2} = case Reason of
not_provided ->
{0, <<>>};
{going_away, Body} ->
Payload_size = erlang:byte_size(Body) + 2,
{Payload_size, <<1001:16, Body/bitstring>>};
{inconsistent_data_type, Body@1} ->
Payload_size@1 = erlang:byte_size(Body@1) + 2,
{Payload_size@1, <<1007:16, Body@1/bitstring>>};
{message_too_big, Body@2} ->
Payload_size@2 = erlang:byte_size(Body@2) + 2,
{Payload_size@2, <<1009:16, Body@2/bitstring>>};
{missing_extensions, Body@3} ->
Payload_size@3 = erlang:byte_size(Body@3) + 2,
{Payload_size@3, <<1010:16, Body@3/bitstring>>};
{normal, Body@4} ->
Payload_size@4 = erlang:byte_size(Body@4) + 2,
{Payload_size@4, <<1000:16, Body@4/bitstring>>};
{policy_violation, Body@5} ->
Payload_size@5 = erlang:byte_size(Body@5) + 2,
{Payload_size@5, <<1008:16, Body@5/bitstring>>};
{protocol_error, Body@6} ->
Payload_size@6 = erlang:byte_size(Body@6) + 2,
{Payload_size@6, <<1002:16, Body@6/bitstring>>};
{unexpected_condition, Body@7} ->
Payload_size@7 = erlang:byte_size(Body@7) + 2,
{Payload_size@7, <<1011:16, Body@7/bitstring>>};
{unexpected_data_type, Body@8} ->
Payload_size@8 = erlang:byte_size(Body@8) + 2,
{Payload_size@8, <<1003:16, Body@8/bitstring>>};
{custom_close_reason, Code, Body@9} ->
Payload_size@9 = erlang:byte_size(Body@9) + 2,
Code@1 = case Code < 5000 of
true ->
Code;
false ->
1000
end,
{Payload_size@9, <<Code@1:16, Body@9/bitstring>>}
end,
make_frame(
8,
Payload_length@2,
apply_mask(Payload@2, Mask),
Compressed,
Mask
);
{control, {pong_frame, Payload@3}} ->
Payload_length@3 = erlang:byte_size(Payload@3),
make_frame(10, Payload_length@3, Payload@3, Compressed, Mask);
{control, {ping_frame, Payload@4}} ->
Payload_length@4 = erlang:byte_size(Payload@4),
make_frame(9, Payload_length@4, Payload@4, Compressed, Mask);
{continuation, Length, Payload@5} ->
make_frame(0, Length, Payload@5, Compressed, Mask)
end.
-file("src/ewe/internal/gramps/websocket.gleam", 274).
?DOC(false).
-spec encode_close_frame(close_reason(), gleam@option:option(bitstring())) -> gleam@bytes_tree:bytes_tree().
encode_close_frame(Reason, Mask) ->
encode_frame({control, {close_frame, Reason}}, uncompressed, Mask).
-file("src/ewe/internal/gramps/websocket.gleam", 289).
?DOC(false).
-spec encode_continuation_frame(
bitstring(),
integer(),
gleam@option:option(bitstring())
) -> gleam@bytes_tree:bytes_tree().
encode_continuation_frame(Data, Total_size, Mask) ->
Payload = apply_mask(Data, Mask),
encode_frame({continuation, Total_size, Payload}, uncompressed, Mask).
-file("src/ewe/internal/gramps/websocket.gleam", 440).
?DOC(false).
-spec apply_deflate(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context())
) -> bitstring().
apply_deflate(Data, Context) ->
case Context of
{some, Context@1} ->
ewe@internal@gramps@websocket@compression:deflate(Context@1, Data);
_ ->
Data
end.
-file("src/ewe/internal/gramps/websocket.gleam", 447).
?DOC(false).
-spec apply_inflate(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context())
) -> bitstring().
apply_inflate(Data, Context) ->
case Context of
{some, Context@1} ->
ewe@internal@gramps@websocket@compression:inflate(Context@1, Data);
_ ->
Data
end.
-file("src/ewe/internal/gramps/websocket.gleam", 454).
?DOC(false).
-spec to_frame(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context()),
gleam@option:option(bitstring()),
fun((bitstring()) -> KIW),
fun((KIW) -> frame())
) -> gleam@bytes_tree:bytes_tree().
to_frame(Data, Context, Mask, Create_inner_frame, Create_frame) ->
Frame = begin
_pipe = Data,
_pipe@1 = apply_deflate(_pipe, Context),
_pipe@2 = apply_mask(_pipe@1, Mask),
_pipe@3 = Create_inner_frame(_pipe@2),
Create_frame(_pipe@3)
end,
Compress = case Context of
{some, _} ->
compressed;
_ ->
uncompressed
end,
encode_frame(Frame, Compress, Mask).
-file("src/ewe/internal/gramps/websocket.gleam", 258).
?DOC(false).
-spec encode_text_frame(
binary(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context()),
gleam@option:option(bitstring())
) -> gleam@bytes_tree:bytes_tree().
encode_text_frame(Data, Context, Mask) ->
to_frame(
gleam_stdlib:identity(Data),
Context,
Mask,
fun(Field@0) -> {text_frame, Field@0} end,
fun(Field@0) -> {data, Field@0} end
).
-file("src/ewe/internal/gramps/websocket.gleam", 266).
?DOC(false).
-spec encode_binary_frame(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context()),
gleam@option:option(bitstring())
) -> gleam@bytes_tree:bytes_tree().
encode_binary_frame(Data, Context, Mask) ->
to_frame(
Data,
Context,
Mask,
fun(Field@0) -> {binary_frame, Field@0} end,
fun(Field@0) -> {data, Field@0} end
).
-file("src/ewe/internal/gramps/websocket.gleam", 281).
?DOC(false).
-spec encode_ping_frame(bitstring(), gleam@option:option(bitstring())) -> gleam@bytes_tree:bytes_tree().
encode_ping_frame(Data, Mask) ->
to_frame(
Data,
none,
Mask,
fun(Field@0) -> {ping_frame, Field@0} end,
fun(Field@0) -> {control, Field@0} end
).
-file("src/ewe/internal/gramps/websocket.gleam", 285).
?DOC(false).
-spec encode_pong_frame(bitstring(), gleam@option:option(bitstring())) -> gleam@bytes_tree:bytes_tree().
encode_pong_frame(Data, Mask) ->
to_frame(
Data,
none,
Mask,
fun(Field@0) -> {pong_frame, Field@0} end,
fun(Field@0) -> {control, Field@0} end
).
-file("src/ewe/internal/gramps/websocket.gleam", 474).
?DOC(false).
-spec decode_many_frames(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context()),
list(parsed_frame())
) -> {list(parsed_frame()), bitstring()}.
decode_many_frames(Data, Context, Frames) ->
case decode_frame(Data, Context) of
{ok, {Frame, <<>>}} ->
{lists:reverse([Frame | Frames]), <<>>};
{ok, {Frame@1, Rest}} ->
decode_many_frames(Rest, Context, [Frame@1 | Frames]);
{error, {need_more_data, Rest@1}} ->
{lists:reverse(Frames), Rest@1};
{error, invalid_frame} ->
{lists:reverse(Frames), Data}
end.
-file("src/ewe/internal/gramps/websocket.gleam", 492).
?DOC(false).
-spec decode_many_frames_result(
bitstring(),
gleam@option:option(ewe@internal@gramps@websocket@compression:context()),
list(parsed_frame())
) -> {ok, {list(parsed_frame()), bitstring()}} |
{error, many_frames_parse_error()}.
decode_many_frames_result(Data, Context, Frames) ->
case decode_frame(Data, Context) of
{ok, {Frame, <<>>}} ->
{ok, {lists:reverse([Frame | Frames]), <<>>}};
{ok, {Frame@1, Rest}} ->
decode_many_frames_result(Rest, Context, [Frame@1 | Frames]);
{error, {need_more_data, Rest@1}} ->
{error, {need_more_data_accumulated, lists:reverse(Frames), Rest@1}};
{error, invalid_frame} ->
{error, contains_invalid_frame}
end.
-file("src/ewe/internal/gramps/websocket.gleam", 507).
?DOC(false).
-spec aggregate_frames(
list(parsed_frame()),
gleam@option:option({frame(), list(bitstring())}),
list(frame()),
gleam@option:option(ewe@internal@gramps@websocket@compression:context())
) -> {ok, list(frame())} | {error, nil}.
aggregate_frames(Frames, Accumulated, Joined, Context) ->
case {Frames, Accumulated} of
{[], _} ->
{ok, lists:reverse(Joined)};
{[{complete, {data, {compressed_text_frame, Data}}} | Rest], none} ->
case Context of
{some, Ctx} ->
Decompressed = ewe@internal@gramps@websocket@compression:inflate(
Ctx,
Data
),
case gleam@bit_array:is_utf8(Decompressed) of
true ->
Final_frame = {data, {text_frame, Decompressed}},
aggregate_frames(
Rest,
none,
[Final_frame | Joined],
Context
);
false ->
{error, nil}
end;
none ->
{error, nil}
end;
{[{complete, {data, {compressed_binary_frame, Data@1}}} | Rest@1], none} ->
case Context of
{some, Ctx@1} ->
Decompressed@1 = ewe@internal@gramps@websocket@compression:inflate(
Ctx@1,
Data@1
),
Final_frame@1 = {data, {binary_frame, Decompressed@1}},
aggregate_frames(
Rest@1,
none,
[Final_frame@1 | Joined],
Context
);
none ->
{error, nil}
end;
{[{complete, {data, {text_frame, Data@2}}} | Rest@2], none} ->
case gleam@bit_array:is_utf8(Data@2) of
true ->
aggregate_frames(
Rest@2,
none,
[{data, {text_frame, Data@2}} | Joined],
Context
);
false ->
{error, nil}
end;
{[{complete, {data, {binary_frame, Data@3}}} | Rest@3], none} ->
aggregate_frames(
Rest@3,
none,
[{data, {binary_frame, Data@3}} | Joined],
Context
);
{[{complete, {continuation, _, _}} | _], none} ->
{error, nil};
{[{complete, Frame} | Rest@4], none} ->
aggregate_frames(Rest@4, none, [Frame | Joined], Context);
{[{incomplete, Frame@1} | Rest@5], none} ->
Initial_payload = case Frame@1 of
{data, {text_frame, Payload}} ->
Payload;
{data, {binary_frame, Payload@1}} ->
Payload@1;
{data, {compressed_text_frame, Payload@2}} ->
Payload@2;
{data, {compressed_binary_frame, Payload@3}} ->
Payload@3;
{continuation, _, Payload@4} ->
Payload@4;
{control, _} ->
<<>>
end,
aggregate_frames(
Rest@5,
{some, {Frame@1, [Initial_payload]}},
Joined,
Context
);
{[{complete, {continuation, _, Data@4}} | Rest@6],
{some, {Initial_frame, Payloads}}} ->
All_payloads = begin
_pipe = [Data@4 | Payloads],
lists:reverse(_pipe)
end,
Final_payload = gleam_stdlib:bit_array_concat(All_payloads),
case Initial_frame of
{data, {compressed_text_frame, _}} ->
case Context of
{some, Ctx@2} ->
Decompressed@2 = ewe@internal@gramps@websocket@compression:inflate(
Ctx@2,
Final_payload
),
case gleam@bit_array:is_utf8(Decompressed@2) of
true ->
Final_frame@2 = {data,
{text_frame, Decompressed@2}},
aggregate_frames(
Rest@6,
none,
[Final_frame@2 | Joined],
Context
);
false ->
{error, nil}
end;
none ->
{error, nil}
end;
{data, {compressed_binary_frame, _}} ->
case Context of
{some, Ctx@3} ->
Decompressed@3 = ewe@internal@gramps@websocket@compression:inflate(
Ctx@3,
Final_payload
),
Final_frame@3 = {data,
{binary_frame, Decompressed@3}},
aggregate_frames(
Rest@6,
none,
[Final_frame@3 | Joined],
Context
);
none ->
{error, nil}
end;
{data, {text_frame, _}} ->
case gleam@bit_array:is_utf8(Final_payload) of
true ->
Final_frame@4 = {data, {text_frame, Final_payload}},
aggregate_frames(
Rest@6,
none,
[Final_frame@4 | Joined],
Context
);
false ->
{error, nil}
end;
{data, {binary_frame, _}} ->
Final_frame@5 = {data, {binary_frame, Final_payload}},
aggregate_frames(
Rest@6,
none,
[Final_frame@5 | Joined],
Context
);
{control, _} ->
{error, nil};
{continuation, _, _} ->
{error, nil}
end;
{[{incomplete, {continuation, _, Data@5}} | Rest@7],
{some, {Initial_frame@1, Payloads@1}}} ->
aggregate_frames(
Rest@7,
{some, {Initial_frame@1, [Data@5 | Payloads@1]}},
Joined,
Context
);
{_, _} ->
{error, nil}
end.
-file("src/ewe/internal/gramps/websocket.gleam", 643).
?DOC(false).
-spec make_client_key() -> binary().
make_client_key() ->
Bytes = crypto:strong_rand_bytes(16),
gleam_stdlib:base64_encode(Bytes, true).
-file("src/ewe/internal/gramps/websocket.gleam", 665).
?DOC(false).
-spec has_deflate(list(binary())) -> boolean().
has_deflate(Extensions) ->
gleam@list:any(
Extensions,
fun(Str) -> Str =:= <<"permessage-deflate"/utf8>> end
).
-file("src/ewe/internal/gramps/websocket.gleam", 669).
?DOC(false).
-spec get_context_takeovers(list(binary())) -> ewe@internal@gramps@websocket@compression:context_takeover().
get_context_takeovers(Extensions) ->
No_client_context_takeover = gleam@list:any(
Extensions,
fun(Str) -> Str =:= <<"client_no_context_takeover"/utf8>> end
),
No_server_context_takeover = gleam@list:any(
Extensions,
fun(Str@1) -> Str@1 =:= <<"server_no_context_takeover"/utf8>> end
),
{context_takeover, No_client_context_takeover, No_server_context_takeover}.
-file("src/ewe/internal/gramps/websocket.gleam", 652).
?DOC(false).
-spec parse_websocket_key(binary()) -> binary().
parse_websocket_key(Key) ->
_pipe = Key,
_pipe@1 = gleam@string:append(
_pipe,
<<"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"/utf8>>
),
_pipe@2 = crypto:hash(sha, _pipe@1),
base64:encode(_pipe@2).