11
11
12
12
-export ([ws_client_init /7 ]).
13
13
14
+ -type opt () :: {async_start , boolean ()}
15
+ | {extra_headers , [{string () | binary (), string () | binary ()}]}
16
+ .
17
+
18
+ -type opts () :: [opt ()].
19
+
14
20
% % @doc Start the websocket client
15
- -spec start_link (URL :: string (), Handler :: module (), Args :: list ()) ->
21
+ -spec start_link (URL :: string (), Handler :: module (), HandlerArgs :: list ()) ->
16
22
{ok , pid ()} | {error , term ()}.
17
- start_link (URL , Handler , Args ) ->
18
- start_link (URL , Handler , Args , true ).
23
+ start_link (URL , Handler , HandlerArgs ) ->
24
+ start_link (URL , Handler , HandlerArgs , [] ).
19
25
20
- start_link (URL , Handler , Args , AsyncStart ) ->
26
+ start_link (URL , Handler , HandlerArgs , AsyncStart ) when is_boolean (AsyncStart ) ->
27
+ start_link (URL , Handler , HandlerArgs , [{async_start , AsyncStart }]);
28
+ start_link (URL , Handler , HandlerArgs , Opts ) when is_list (Opts ) ->
21
29
case http_uri :parse (URL , [{scheme_defaults , [{ws ,80 },{wss ,443 }]}]) of
22
30
{ok , {Protocol , _ , Host , Port , Path , Query }} ->
23
31
proc_lib :start_link (? MODULE , ws_client_init ,
24
- [Handler , Protocol , Host , Port , Path ++ Query , Args , AsyncStart ]);
32
+ [Handler , Protocol , Host , Port , Path ++ Query , HandlerArgs , Opts ]);
25
33
{error , _ } = Error ->
26
34
Error
27
35
end .
@@ -36,9 +44,9 @@ cast(Client, Frame) ->
36
44
% % @doc Create socket, execute handshake, and enter loop
37
45
-spec ws_client_init (Handler :: module (), Protocol :: websocket_req :protocol (),
38
46
Host :: string (), Port :: inet :port_number (), Path :: string (),
39
- Args :: list (), AsyncStart :: boolean ()) ->
47
+ Args :: list (), Opts :: opts ()) ->
40
48
no_return ().
41
- ws_client_init (Handler , Protocol , Host , Port , Path , Args , AsyncStart ) ->
49
+ ws_client_init (Handler , Protocol , Host , Port , Path , Args , Opts ) ->
42
50
Transport = case Protocol of
43
51
wss ->
44
52
ssl ;
@@ -76,11 +84,13 @@ ws_client_init(Handler, Protocol, Host, Port, Path, Args, AsyncStart) ->
76
84
Handler ,
77
85
generate_ws_key ()
78
86
),
79
- case websocket_handshake (WSReq ) of
87
+ ExtraHeaders = proplists :get_value (extra_headers , Opts , []),
88
+ case websocket_handshake (WSReq , ExtraHeaders ) of
80
89
{error , _ } = HandshakeError ->
81
90
proc_lib :init_ack (HandshakeError ),
82
91
exit (normal );
83
92
{ok , Buffer } ->
93
+ AsyncStart = proplists :get_value (async_start , Opts , true ),
84
94
AsyncStart andalso proc_lib :init_ack ({ok , self ()}),
85
95
{ok , HandlerState , KeepAlive } = case Handler :init (Args , WSReq ) of
86
96
{ok , HS } ->
@@ -110,8 +120,8 @@ ws_client_init(Handler, Protocol, Host, Port, Path, Args, AsyncStart) ->
110
120
end .
111
121
112
122
% % @doc Send http upgrade request and validate handshake response challenge
113
- -spec websocket_handshake (WSReq :: websocket_req :req ()) -> {ok , binary ()} | {error , term ()}.
114
- websocket_handshake (WSReq ) ->
123
+ -spec websocket_handshake (WSReq :: websocket_req :req (), [{ string (), string ()}] ) -> {ok , binary ()} | {error , term ()}.
124
+ websocket_handshake (WSReq , ExtraHeaders ) ->
115
125
[Protocol , Path , Host , Key , Transport , Socket ] =
116
126
websocket_req :get ([protocol , path , host , key , transport , socket ], WSReq ),
117
127
Handshake = [" GET " , Path , " HTTP/1.1\r\n "
@@ -120,7 +130,8 @@ websocket_handshake(WSReq) ->
120
130
" Origin: " , atom_to_binary (Protocol , utf8 ), " ://" , Host , " \r\n "
121
131
" Sec-WebSocket-Version: 13\r\n "
122
132
" Sec-WebSocket-Key: " , Key , " \r\n "
123
- " Upgrade: websocket\r\n "
133
+ " Upgrade: websocket\r\n " ,
134
+ [ [Header , " : " , Value , " \r\n " ] || {Header , Value } <- ExtraHeaders ],
124
135
" \r\n " ],
125
136
Transport :send (Socket , Handshake ),
126
137
{ok , HandshakeResponse } = receive_handshake (<<>>, Transport , Socket ),
0 commit comments