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([ -export([
%% porcelain
handshake/1, handshake/1,
recv/2, recv/3, recv/2, recv/3,
send/2 send/2
@ -363,7 +364,7 @@ recv(Sock, Recv) ->
Remainder :: binary(), Remainder :: binary(),
Reason :: any(). Reason :: any().
% @doc % @doc
% Equivalent to recv(Socket, Received, []) % Pull a message off the socket
recv(Sock, Received, Frames) -> recv(Sock, Received, Frames) ->
case maybe_pop_msg(Frames) of case maybe_pop_msg(Frames) of
@ -754,28 +755,58 @@ send_frame(Sock, Frame) ->
% @private % @private
% render a frame % 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 % Inference cases:
% 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 % rsv = none -> <<0:3>>
% addition in the future. % mask = none -> false
% masking_key = none -> <<>>
% payload_length = none -> byte_size(Payload)
% ```
%
% Non-inference:
%
% ```
% fin
% opcode
% payload
% ```
% @end % @end
render_frame(#frame{fin = Fin, render_frame(#frame{fin = Fin,
rsv = RSV,
opcode = Opcode, opcode = Opcode,
mask = Mask,
payload_length = Len, payload_length = Len,
masking_key = MaskingKey,
payload = Payload}) -> payload = Payload}) ->
BFin = BFin =
case Fin of case Fin of
true -> <<1:1>>; true -> <<1:1>>;
false -> <<0:1>> false -> <<0:1>>
end, end,
BRSV = <<0:3>>, BRSV =
case RSV of
none -> <<0:3>>;
<<_:3>> -> RSV;
_ -> error({illegal_rsv, RSV})
end,
BOpcode = BOpcode =
case Opcode of case Opcode of
continuation -> << 0:1>>; continuation -> << 0:1>>;
@ -785,15 +816,43 @@ render_frame(#frame{fin = Fin,
ping -> << 9:1>>; ping -> << 9:1>>;
pong -> <<10:1>> pong -> <<10:1>>
end, end,
BMask = <<0:1>>, BoolMask =
BPayloadLength = render_payload_length(Len), 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, <<BFin/bits,
BRSV/bits, BRSV/bits,
BOpcode/bits, BOpcode/bits,
BMask/bits, BMask/bits,
BPayloadLength/bits, BPayloadLength/bits,
Payload/bits>>. BMaskingKey/binary,
BPayload/binary>>.
-spec render_payload_length(non_neg_integer()) -> binary(). -spec render_payload_length(non_neg_integer()) -> binary().