painting bike shed

This commit is contained in:
Peter Harpending 2025-10-21 14:55:51 -07:00
parent 4509a328a8
commit 7ed8b12c4e

View File

@ -10,6 +10,7 @@
]).
-export([
%% porcelain
handshake/1,
recv/2, recv/3,
send/2
@ -363,7 +364,7 @@ recv(Sock, Recv) ->
Remainder :: binary(),
Reason :: any().
% @doc
% Equivalent to recv(Socket, Received, [])
% Pull a message off the socket
recv(Sock, Received, Frames) ->
case maybe_pop_msg(Frames) of
@ -754,28 +755,58 @@ send_frame(Sock, Frame) ->
% @private
% render a frame
%
% RSV is always <<0:3>> in rendered frame
% All fields in a `#frame{}` record have default values of `none`.
%
% TODO: this doesn't check/do masking
% ```erlang
% -record(frame,
% {fin = none :: none | boolean(),
% rsv = none :: none | <<_:3>>,
% opcode = none :: none | opcode(),
% mask = none :: none | boolean(),
% payload_length = none :: none | non_neg_integer(),
% masking_key = none :: none | <<>> | <<_:32>>,
% payload = none :: none | binary()}).
% ```
%
% Given a value of `none`, some of these fields are inferred, some cannot be
% inferred.
%
% This is a non-issue as long as this is only used for rendering messages sent
% from server to client (unmasked per protocol). However, for debugging
% purposes, a user of this library might want to test how frames render with
% masking. This functionality is not currently supported, but is a planned
% addition in the future.
% Inference cases:
%
% ```
% rsv = none -> <<0:3>>
% mask = none -> false
% masking_key = none -> <<>>
% payload_length = none -> byte_size(Payload)
% ```
%
% Non-inference:
%
% ```
% fin
% opcode
% payload
% ```
% @end
render_frame(#frame{fin = Fin,
rsv = RSV,
opcode = Opcode,
mask = Mask,
payload_length = Len,
masking_key = MaskingKey,
payload = Payload}) ->
BFin =
case Fin of
true -> <<1:1>>;
false -> <<0:1>>
end,
BRSV = <<0:3>>,
BRSV =
case RSV of
none -> <<0:3>>;
<<_:3>> -> RSV;
_ -> error({illegal_rsv, RSV})
end,
BOpcode =
case Opcode of
continuation -> << 0:1>>;
@ -785,15 +816,43 @@ render_frame(#frame{fin = Fin,
ping -> << 9:1>>;
pong -> <<10:1>>
end,
BMask = <<0:1>>,
BPayloadLength = render_payload_length(Len),
BoolMask =
case Mask of
none -> false;
false -> false;
true -> true
end,
BMask =
case BoolMask of
true -> <<1:1>>;
false -> <<0:1>>
end,
IntPayloadLength =
case Len of
none -> byte_size(Payload);
_ -> Len
end,
BPayloadLength = render_payload_length(IntPayloadLength),
BMaskingKey =
case {BoolMask, MaskingKey} of
{false, none} -> <<>>;
{false, <<>>} -> <<>>;
{true, <<BKey:4/bytes>>} -> BKey;
{false, _} -> error({not_masking_but_have_masking_key, {Mask, MaskingKey}});
{true, _} -> error({illegal_masking_key, MaskingKey})
end,
% failure case here is same as error case just above, so no need to worry
% about cryptic "illegal frame" message
%
% masking = unmasking, so `maybe_unmask` is a bit of a misnomer
{ok, BPayload} = maybe_unmask(#frame{}, BoolMask, BMaskingKey, Payload),
<<BFin/bits,
BRSV/bits,
BOpcode/bits,
BMask/bits,
BPayloadLength/bits,
Payload/bits>>.
BMaskingKey/binary,
BPayload/binary>>.
-spec render_payload_length(non_neg_integer()) -> binary().