From 0ceafb1265f461e64d6953a7f978e2484fef7c95 Mon Sep 17 00:00:00 2001 From: Daniel White Date: Tue, 2 Dec 2014 11:44:37 +1100 Subject: [PATCH 1/6] Do not send 'Origin' header in handshake This is a header only intended to support for Web Origin security in browsers. Other clients are not required to include this header, and the current case complicates servers since it receiving 'ws://' or 'ws://' in the 'Origin' header is highly unusual. RFC 6455, Section 4.1, Client Requirements: > Additionally, if the client is a web browser, it supplies /origin/. RFC 6455, Section 4.2.1, Reading the Client's Opening Handshake: > Optionally, an |Origin| header field. This header field is sent by > all browser clients. A connection attempt lacking this header field > SHOULD NOT be interpreted as coming from a browser client. --- src/websocket_client.erl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/websocket_client.erl b/src/websocket_client.erl index ee9abdc..fc17e39 100644 --- a/src/websocket_client.erl +++ b/src/websocket_client.erl @@ -122,12 +122,11 @@ ws_client_init(Handler, Protocol, Host, Port, Path, Args, Opts) -> %% @doc Send http upgrade request and validate handshake response challenge -spec websocket_handshake(WSReq :: websocket_req:req(), [{string(), string()}]) -> {ok, binary()} | {error, term()}. websocket_handshake(WSReq, ExtraHeaders) -> - [Protocol, Path, Host, Key, Transport, Socket] = - websocket_req:get([protocol, path, host, key, transport, socket], WSReq), + [Path, Host, Key, Transport, Socket] = + websocket_req:get([path, host, key, transport, socket], WSReq), Handshake = ["GET ", Path, " HTTP/1.1\r\n" "Host: ", Host, "\r\n" "Connection: Upgrade\r\n" - "Origin: ", atom_to_binary(Protocol, utf8), "://", Host, "\r\n" "Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Key: ", Key, "\r\n" "Upgrade: websocket\r\n", From 449b2054083f2d33bc5a04e7a6245418b8cce0ba Mon Sep 17 00:00:00 2001 From: Matt Branton Date: Tue, 10 Mar 2015 14:36:43 -0400 Subject: [PATCH 2/6] Websocket start_link now accepts binary string as URL option. Fixed start_link spec to include binary option on URL --- src/websocket_client.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/websocket_client.erl b/src/websocket_client.erl index fc17e39..dd22d58 100644 --- a/src/websocket_client.erl +++ b/src/websocket_client.erl @@ -18,13 +18,15 @@ -type opts() :: [opt()]. %% @doc Start the websocket client --spec start_link(URL :: string(), Handler :: module(), HandlerArgs :: list()) -> +-spec start_link(URL :: string() | binary(), Handler :: module(), HandlerArgs :: list()) -> {ok, pid()} | {error, term()}. start_link(URL, Handler, HandlerArgs) -> start_link(URL, Handler, HandlerArgs, []). start_link(URL, Handler, HandlerArgs, AsyncStart) when is_boolean(AsyncStart) -> start_link(URL, Handler, HandlerArgs, [{async_start, AsyncStart}]); +start_link(URL, Handler, HandlerArgs, Opts) when is_binary(URL) -> + start_link(erlang:binary_to_list(URL), Handler, HandlerArgs, Opts); start_link(URL, Handler, HandlerArgs, Opts) when is_list(Opts) -> case http_uri:parse(URL, [{scheme_defaults, [{ws,80},{wss,443}]}]) of {ok, {Protocol, _, Host, Port, Path, Query}} -> From 2ef32459aa74a9a3540c40824d907fb80a9b82a0 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Wed, 20 May 2015 19:09:11 -0700 Subject: [PATCH 3/6] More accurate type spec for websocket_terminate, other minor cleanup --- src/websocket_client.erl | 22 +++++++++++++-------- src/websocket_client_handler.erl | 34 ++++++++++++++++++++++++++++---- src/websocket_req.erl | 9 +++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/websocket_client.erl b/src/websocket_client.erl index dd22d58..f2c9fb1 100644 --- a/src/websocket_client.erl +++ b/src/websocket_client.erl @@ -154,19 +154,19 @@ receive_handshake(Buffer, Transport, Socket) -> end. %% @doc Send frame to server +-spec send(websocket_req:frame(), websocket_req:req()) -> ok | {error, term()}. send(Frame, WSReq) -> Socket = websocket_req:socket(WSReq), Transport = websocket_req:transport(WSReq), Transport:send(Socket, encode_frame(Frame)). - %% @doc Main loop -spec websocket_loop(WSReq :: websocket_req:req(), HandlerState :: any(), Buffer :: binary()) -> ok. websocket_loop(WSReq, HandlerState, Buffer) -> receive - Message -> handle_websocket_message(WSReq, HandlerState, Buffer, Message) + Message -> handle_websocket_message(WSReq, HandlerState, Buffer, Message) end. handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> @@ -174,13 +174,10 @@ handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> websocket_req:get([handler, remaining, socket], WSReq), case Message of keepalive -> - case websocket_req:get([keepalive_timer], WSReq) of - [undefined] -> ok; - [OldTimer] -> erlang:cancel_timer(OldTimer) - end, + cancel_keepalive_timer(WSReq), ok = send({ping, <<>>}, WSReq), KATimer = erlang:send_after(websocket_req:keepalive(WSReq), self(), keepalive), - websocket_loop(websocket_req:set([{keepalive_timer,KATimer}], WSReq), HandlerState, Buffer); + websocket_loop(websocket_req:keepalive_timer(KATimer, WSReq), HandlerState, Buffer); {cast, Frame} -> ok = send(Frame, WSReq), websocket_loop(WSReq, HandlerState, Buffer); @@ -196,7 +193,6 @@ handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> websocket_req:opcode(WSReq), Remaining, Data, Buffer) end; Msg -> - Handler = websocket_req:handler(WSReq), try Handler:websocket_info(Msg, WSReq, HandlerState) of HandlerResponse -> handle_response(WSReq, HandlerResponse, Buffer) @@ -213,6 +209,16 @@ handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> end end. +-spec cancel_keepalive_timer(websocket_req:req()) -> ok. +cancel_keepalive_timer(WSReq) -> + case websocket_req:keepalive_timer(WSReq) of + undefined -> + ok; + OldTimer -> + erlang:cancel_timer(OldTimer), + ok + end. + -spec websocket_close(WSReq :: websocket_req:req(), HandlerState :: any(), Reason :: tuple()) -> ok. diff --git a/src/websocket_client_handler.erl b/src/websocket_client_handler.erl index d7ebd46..0ee4b18 100644 --- a/src/websocket_client_handler.erl +++ b/src/websocket_client_handler.erl @@ -2,7 +2,35 @@ -type state() :: any(). -type keepalive() :: integer(). --type close_type() :: normal | error | remote. + +-type close_reason() :: + % Either the local end was closed via a `{closed, Reason, State}` tuple + % returned from websocket_handle/3 or websocket_info/3, or the remote end + % was closed during graceful teardown of the connection via a close frame + % (see https://tools.ietf.org/html/rfc6455#section-5.5.1). + {normal, binary()} | + % The transport failed to send (see http://erlang.org/doc/man/gen_tcp.html#send-2 + % or http://erlang.org/doc/man/ssl.html#send-2) + {error, term()} | + % The remote end was closed due to a protocol error + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1002). + {error, badframe, binary()} | + % The remote end was closed due to an encoding error + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1007). + {error, badencoding, binary()} | + % The remote end was closed unexpectedly + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1011). + {error, handler, binary()} | + % The remote host closed the socket. + {remote, closed} | + % The remote end was closed for some other reason + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1). + {remote, integer(), binary()} | + % The remote host closed the socket. + % TODO: How is this different than `{remote, closed}`? + {remote, binary()} | + % The handler terminated unexpectedly in websocket_handle/3 or websocket_info/3. + term(). -callback init(list(), websocket_req:req()) -> {ok, state()} @@ -18,6 +46,4 @@ | {reply, websocket_req:frame(), state()} | {close, binary(), state()}. --callback websocket_terminate({close_type(), term()} | {close_type(), integer(), binary()}, - websocket_req:req(), state()) -> - ok. +-callback websocket_terminate(close_reason(), websocket_req:req(), state()) -> ok. diff --git a/src/websocket_req.erl b/src/websocket_req.erl index c5d5044..830679b 100644 --- a/src/websocket_req.erl +++ b/src/websocket_req.erl @@ -40,6 +40,7 @@ port/2, port/1, path/2, path/1, keepalive/2, keepalive/1, + keepalive_timer/2, keepalive_timer/1, socket/2, socket/1, transport/2, transport/1, handler/2, handler/1, @@ -134,6 +135,14 @@ keepalive(K, Req) -> Req#websocket_req{keepalive = K}. +-spec keepalive_timer(req()) -> undefined | reference(). +keepalive_timer(#websocket_req{keepalive_timer = K}) -> K. + +-spec keepalive_timer(reference(), req()) -> req(). +keepalive_timer(K, Req) -> + Req#websocket_req{keepalive_timer = K}. + + -spec socket(req()) -> inet:socket() | ssl:sslsocket(). socket(#websocket_req{socket = S}) -> S. From 0cfa2857e50d467c23b9e61d29e1c2c48a689e62 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Wed, 20 May 2015 19:09:11 -0700 Subject: [PATCH 4/6] More accurate type spec for websocket_terminate, other minor cleanup --- src/websocket_client_handler.erl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/websocket_client_handler.erl b/src/websocket_client_handler.erl index 0ee4b18..caf1688 100644 --- a/src/websocket_client_handler.erl +++ b/src/websocket_client_handler.erl @@ -3,6 +3,35 @@ -type state() :: any(). -type keepalive() :: integer(). +-type close_reason() :: + % Either the local end was closed via a `{closed, Reason, State}` tuple + % returned from websocket_handle/3 or websocket_info/3, or the remote end + % was closed during graceful teardown of the connection via a close frame + % (see https://tools.ietf.org/html/rfc6455#section-5.5.1). + {normal, binary()} | + % The transport failed to send (see http://erlang.org/doc/man/gen_tcp.html#send-2 + % or http://erlang.org/doc/man/ssl.html#send-2) + {error, term()} | + % The remote end was closed due to a protocol error + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1002). + {error, badframe, binary()} | + % The remote end was closed due to an encoding error + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1007). + {error, badencoding, binary()} | + % The remote end was closed unexpectedly + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1011). + {error, handler, binary()} | + % The remote host closed the socket. + {remote, closed} | + % The remote end was closed for some other reason + % (see https://tools.ietf.org/html/rfc6455#section-7.4.1). + {remote, integer(), binary()} | + % The remote host closed the socket. + % TODO: How is this different than `{remote, closed}`? + {remote, binary()} | + % The handler terminated unexpectedly in websocket_handle/3 or websocket_info/3. + term(). + -type close_reason() :: % Either the local end was closed via a `{closed, Reason, State}` tuple % returned from websocket_handle/3 or websocket_info/3, or the remote end From 699569ec8a80fceb6b092a28a0f2db61c1ded619 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Fri, 22 May 2015 21:31:11 +0100 Subject: [PATCH 5/6] Updated terminate typespec, cleanup, exit websocket process with non-normal code on error --- src/websocket_client.erl | 114 +++++++++++++++---------------- src/websocket_client_handler.erl | 78 ++++++--------------- 2 files changed, 76 insertions(+), 116 deletions(-) diff --git a/src/websocket_client.erl b/src/websocket_client.erl index f2c9fb1..ba08b89 100644 --- a/src/websocket_client.erl +++ b/src/websocket_client.erl @@ -2,8 +2,7 @@ %% @doc Erlang websocket client -module(websocket_client). --export([ - start_link/3, +-export([start_link/3, start_link/4, cast/2, send/2 @@ -182,7 +181,7 @@ handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> ok = send(Frame, WSReq), websocket_loop(WSReq, HandlerState, Buffer); {_Closed, Socket} -> - websocket_close(WSReq, HandlerState, {remote, closed}); + websocket_close(WSReq, HandlerState, remote); {_TransportType, Socket, Data} -> case Remaining of undefined -> @@ -194,18 +193,11 @@ handle_websocket_message(WSReq, HandlerState, Buffer, Message) -> end; Msg -> try Handler:websocket_info(Msg, WSReq, HandlerState) of - HandlerResponse -> - handle_response(WSReq, HandlerResponse, Buffer) - catch Class:Reason -> - error_logger:error_msg( - "** Websocket client ~p terminating in ~p/~p~n" - " for the reason ~p:~p~n" - "** Last message was ~p~n" - "** Handler state was ~p~n" - "** Stacktrace: ~p~n~n", - [Handler, websocket_info, 3, Class, Reason, Msg, HandlerState, - erlang:get_stacktrace()]), - websocket_close(WSReq, HandlerState, Reason) + HandlerResponse -> + handle_response(WSReq, HandlerResponse, Buffer) + catch + _:Reason -> + websocket_close(WSReq, HandlerState, {handler, Reason}) end end. @@ -224,16 +216,26 @@ cancel_keepalive_timer(WSReq) -> Reason :: tuple()) -> ok. websocket_close(WSReq, HandlerState, Reason) -> Handler = websocket_req:handler(WSReq), - try Handler:websocket_terminate(Reason, WSReq, HandlerState) - catch Class:Reason2 -> - error_logger:error_msg( - "** Websocket handler ~p terminating in ~p/~p~n" - " for the reason ~p:~p~n" + try Handler:websocket_terminate(Reason, WSReq, HandlerState) of + _ -> + case Reason of + normal -> ok; + _ -> error_info(Handler, Reason, HandlerState) + end, + exit(Reason) + catch + _:Reason2 -> + error_info(Handler, Reason2, HandlerState), + exit(Reason2) + end. + +error_info(Handler, Reason, State) -> + error_logger:error_msg( + "** Websocket handler ~p terminating~n" + "** for the reason ~p~n" "** Handler state was ~p~n" "** Stacktrace: ~p~n~n", - [Handler, websocket_terminate, 3, Class, Reason2, HandlerState, - erlang:get_stacktrace()]) - end. + [Handler, Reason, State, erlang:get_stacktrace()]). %% @doc Key sent in initial handshake -spec generate_ws_key() -> @@ -339,18 +341,24 @@ retrieve_frame(WSReq, HandlerState, Opcode, Len, Data, Buffer) -> end, case OpcodeName of close when byte_size(FullPayload) >= 2 -> - << CodeBin:2/binary, ClosePayload/binary >> = FullPayload, + << CodeBin:2/binary, _ClosePayload/binary >> = FullPayload, Code = binary:decode_unsigned(CodeBin), Reason = case Code of - 1000 -> {normal, ClosePayload}; - 1002 -> {error, badframe, ClosePayload}; - 1007 -> {error, badencoding, ClosePayload}; - 1011 -> {error, handler, ClosePayload}; - _ -> {remote, Code, ClosePayload} + % 1000 indicates a normal closure, meaning that the purpose for + % which the connection was established has been fulfilled. + 1000 -> normal; + + % 1001 indicates that an endpoint is "going away", such as a server + % going down or a browser having navigated away from a page. + 1001 -> normal; + + % See https://tools.ietf.org/html/rfc6455#section-7.4.1 + % for error code descriptions. + _ -> {remote, Code} end, websocket_close(WSReq, HandlerState, Reason); close -> - websocket_close(WSReq, HandlerState, {remote, <<>>}); + websocket_close(WSReq, HandlerState, remote); %% Non-control continuation frame _ when Opcode < 8, Continuation =/= undefined, Fin == 0 -> %% Append to previously existing continuation payloads and continue @@ -366,36 +374,21 @@ retrieve_frame(WSReq, HandlerState, Opcode, Len, Data, Buffer) -> try Handler:websocket_handle( {ContinuationOpcodeName, DefragPayload}, WSReq2, HandlerState) of - HandlerResponse -> - handle_response(websocket_req:remaining(undefined, WSReq1), - HandlerResponse, Rest) - catch Class:Reason -> - error_logger:error_msg( - "** Websocket client ~p terminating in ~p/~p~n" - " for the reason ~p:~p~n" - "** Websocket message was ~p~n" - "** Handler state was ~p~n" - "** Stacktrace: ~p~n~n", - [Handler, websocket_handle, 3, Class, Reason, {ContinuationOpcodeName, DefragPayload}, HandlerState, - erlang:get_stacktrace()]), - websocket_close(WSReq, HandlerState, Reason) + HandlerResponse -> + handle_response(websocket_req:remaining(undefined, WSReq1), + HandlerResponse, Rest) + catch _:Reason -> + websocket_close(WSReq, HandlerState, {handler, Reason}) end; _ -> try Handler:websocket_handle( {OpcodeName, FullPayload}, WSReq, HandlerState) of - HandlerResponse -> - handle_response(websocket_req:remaining(undefined, WSReq), - HandlerResponse, Rest) - catch Class:Reason -> - error_logger:error_msg( - "** Websocket client ~p terminating in ~p/~p~n" - " for the reason ~p:~p~n" - "** Handler state was ~p~n" - "** Stacktrace: ~p~n~n", - [Handler, websocket_handle, 3, Class, Reason, HandlerState, - erlang:get_stacktrace()]), - websocket_close(WSReq, HandlerState, Reason) + HandlerResponse -> + handle_response(websocket_req:remaining(undefined, WSReq), + HandlerResponse, Rest) + catch _:Reason -> + websocket_close(WSReq, HandlerState, {handler, Reason}) end end. @@ -407,11 +400,14 @@ handle_response(WSReq, {reply, Frame, HandlerState}, Buffer) -> %% we can still have more messages in buffer case websocket_req:remaining(WSReq) of %% buffer should not contain uncomplete messages - undefined -> retrieve_frame(WSReq, HandlerState, Buffer); + undefined -> + retrieve_frame(WSReq, HandlerState, Buffer); %% buffer contain uncomplete message that shouldnt be parsed - _ -> websocket_loop(WSReq, HandlerState, Buffer) + _ -> + websocket_loop(WSReq, HandlerState, Buffer) end; - Reason -> websocket_close(WSReq, HandlerState, Reason) + {error, Reason} -> + websocket_close(WSReq, HandlerState, {local, Reason}) end; handle_response(WSReq, {ok, HandlerState}, Buffer) -> %% we can still have more messages in buffer @@ -424,7 +420,7 @@ handle_response(WSReq, {ok, HandlerState}, Buffer) -> handle_response(WSReq, {close, Payload, HandlerState}, _) -> send({close, Payload}, WSReq), - websocket_close(WSReq, HandlerState, {normal, Payload}). + websocket_close(WSReq, HandlerState, normal). %% @doc Encodes the data with a header (including a masking key) and %% masks the data diff --git a/src/websocket_client_handler.erl b/src/websocket_client_handler.erl index caf1688..dba2058 100644 --- a/src/websocket_client_handler.erl +++ b/src/websocket_client_handler.erl @@ -4,62 +4,26 @@ -type keepalive() :: integer(). -type close_reason() :: - % Either the local end was closed via a `{closed, Reason, State}` tuple - % returned from websocket_handle/3 or websocket_info/3, or the remote end - % was closed during graceful teardown of the connection via a close frame - % (see https://tools.ietf.org/html/rfc6455#section-5.5.1). - {normal, binary()} | - % The transport failed to send (see http://erlang.org/doc/man/gen_tcp.html#send-2 - % or http://erlang.org/doc/man/ssl.html#send-2) - {error, term()} | - % The remote end was closed due to a protocol error - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1002). - {error, badframe, binary()} | - % The remote end was closed due to an encoding error - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1007). - {error, badencoding, binary()} | - % The remote end was closed unexpectedly - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1011). - {error, handler, binary()} | - % The remote host closed the socket. - {remote, closed} | - % The remote end was closed for some other reason - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1). - {remote, integer(), binary()} | - % The remote host closed the socket. - % TODO: How is this different than `{remote, closed}`? - {remote, binary()} | - % The handler terminated unexpectedly in websocket_handle/3 or websocket_info/3. - term(). - --type close_reason() :: - % Either the local end was closed via a `{closed, Reason, State}` tuple - % returned from websocket_handle/3 or websocket_info/3, or the remote end - % was closed during graceful teardown of the connection via a close frame - % (see https://tools.ietf.org/html/rfc6455#section-5.5.1). - {normal, binary()} | - % The transport failed to send (see http://erlang.org/doc/man/gen_tcp.html#send-2 - % or http://erlang.org/doc/man/ssl.html#send-2) - {error, term()} | - % The remote end was closed due to a protocol error - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1002). - {error, badframe, binary()} | - % The remote end was closed due to an encoding error - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1007). - {error, badencoding, binary()} | - % The remote end was closed unexpectedly - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1, status code 1011). - {error, handler, binary()} | - % The remote host closed the socket. - {remote, closed} | - % The remote end was closed for some other reason - % (see https://tools.ietf.org/html/rfc6455#section-7.4.1). - {remote, integer(), binary()} | - % The remote host closed the socket. - % TODO: How is this different than `{remote, closed}`? - {remote, binary()} | - % The handler terminated unexpectedly in websocket_handle/3 or websocket_info/3. - term(). + % Either: + % - The websocket was closed by a handler via a `{closed, Reason, State}` tuple + % returned from websocket_handle/3 or websocket_info/3. + % - A 'close' frame was received with code 1000 or 1001. + normal | + % The local end failed to send (see http://erlang.org/doc/man/gen_tcp.html#send-2 + % or http://erlang.org/doc/man/ssl.html#send-2). The second element in the + % tuple is the same term that was wrapped in an `{error, Reason}` tuple by + % `send/2`, i.e. `{error, closed}` will become `{local, closed}`, and not + % `{local, {error, closed}}`. + {local, term()} | + % The remote end either closed abruptly, or closed after sending a 'close' frame + % without a status code. + remote | + % The remote end closed with a status code (see https://tools.ietf.org/html/rfc6455#section-7.4.1). + {remote, integer()} | + % An asynchronous exception was raised during message handling, either in + % websocket_handle/3 or websocket_info/3. The term raised is passed as the + % second element in this tuple. + {handler, term()}. -callback init(list(), websocket_req:req()) -> {ok, state()} @@ -73,6 +37,6 @@ -callback websocket_info(any(), websocket_req:req(), state()) -> {ok, state()} | {reply, websocket_req:frame(), state()} - | {close, binary(), state()}. + | {close, binary(), state()}. -callback websocket_terminate(close_reason(), websocket_req:req(), state()) -> ok. From 9a6f65d05ebf2725d62fb19262b21f1805a59fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20S=C3=A6le?= Date: Mon, 6 Mar 2017 01:27:08 +0100 Subject: [PATCH 6/6] strong_rand_bytes --- src/websocket_client.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/websocket_client.erl b/src/websocket_client.erl index ba08b89..07489fc 100644 --- a/src/websocket_client.erl +++ b/src/websocket_client.erl @@ -241,7 +241,7 @@ error_info(Handler, Reason, State) -> -spec generate_ws_key() -> binary(). generate_ws_key() -> - base64:encode(crypto:rand_bytes(16)). + base64:encode(crypto:strong_rand_bytes(16)). %% @doc Validate handshake response challenge -spec validate_handshake(HandshakeResponse :: binary(), Key :: binary()) -> {ok, binary()} | {error, term()}. @@ -430,7 +430,7 @@ encode_frame({Type, Payload}) -> Opcode = websocket_req:name_to_opcode(Type), Len = iolist_size(Payload), BinLen = payload_length_to_binary(Len), - MaskingKeyBin = crypto:rand_bytes(4), + MaskingKeyBin = crypto:strong_rand_bytes(4), << MaskingKey:32 >> = MaskingKeyBin, Header = << 1:1, 0:3, Opcode:4, 1:1, BinLen/bits, MaskingKeyBin/bits >>, MaskedPayload = mask_payload(MaskingKey, Payload),