Add new option 'ws_frame' to allow using binary frames
This commit is contained in:
		
							parent
							
								
									67defca8de
								
							
						
					
					
						commit
						eb28fc068a
					
				|  | @ -29,12 +29,14 @@ | |||
| -export([send/2]). | ||||
| -export([close/3]). | ||||
| 
 | ||||
| -record(state, {pid, type}). | ||||
| 
 | ||||
| %% Websocket. | ||||
| 
 | ||||
| init(_, _Req, _Opts) -> | ||||
|     {upgrade, protocol, cowboy_websocket}. | ||||
| 
 | ||||
| websocket_init(_TransportName, Req, _Opts) -> | ||||
| websocket_init(_TransportName, Req, [{type, FrameType}]) -> | ||||
|     {Peername, _} = cowboy_req:peer(Req), | ||||
|     [Socket, Transport] = cowboy_req:get([socket, transport], Req), | ||||
|     {ok, Sockname} = Transport:sockname(Socket), | ||||
|  | @ -42,23 +44,25 @@ websocket_init(_TransportName, Req, _Opts) -> | |||
|         {peername, Peername}, | ||||
|         {sockname, Sockname}]}, | ||||
|     {ok, _Sup, Pid} = rabbit_ws_sup:start_client({Conn}), | ||||
|     {ok, Req, Pid}. | ||||
|     {ok, Req, #state{pid=Pid, type=FrameType}}. | ||||
| 
 | ||||
| websocket_handle({text, Data}, Req, State = Pid) -> | ||||
| websocket_handle({text, Data}, Req, State=#state{pid=Pid}) -> | ||||
|     rabbit_ws_client:sockjs_msg(Pid, Data), | ||||
|     {ok, Req, State}; | ||||
| websocket_handle({binary, Data}, Req, State = Pid) -> | ||||
| websocket_handle({binary, Data}, Req, State=#state{pid=Pid}) -> | ||||
|     rabbit_ws_client:sockjs_msg(Pid, Data), | ||||
|     {ok, Req, State}; | ||||
| websocket_handle(_Frame, Req, State) -> | ||||
|     {ok, Req, State}. | ||||
| 
 | ||||
| websocket_info({send, Frame}, Req, State) -> | ||||
| websocket_info({send, Msg}, Req, State=#state{type=FrameType}) -> | ||||
|     {reply, {FrameType, Msg}, Req, State}; | ||||
| websocket_info(Frame = {close, _, _}, Req, State) -> | ||||
|     {reply, Frame, Req, State}; | ||||
| websocket_info(_Info, Req, State) -> | ||||
|     {ok, Req, State}. | ||||
| 
 | ||||
| websocket_terminate(_Reason, _Req, _State = Pid) -> | ||||
| websocket_terminate(_Reason, _Req, #state{pid=Pid}) -> | ||||
|     rabbit_ws_client:sockjs_closed(Pid), | ||||
|     ok. | ||||
| 
 | ||||
|  | @ -77,9 +81,9 @@ info({?MODULE, _, Info}) -> | |||
|     Info. | ||||
| 
 | ||||
| send(Data, {?MODULE, Pid, _}) -> | ||||
|     Pid ! {send, {text, Data}}, | ||||
|     Pid ! {send, Data}, | ||||
|     ok. | ||||
| 
 | ||||
| close(Code, Reason, {?MODULE, Pid, _}) -> | ||||
|     Pid ! {send, {close, Code, Reason}}, | ||||
|     Pid ! {close, Code, Reason}, | ||||
|     ok. | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ init() -> | |||
|             {[{port, Port0}|TCPConf0], Port0} | ||||
|     end, | ||||
| 
 | ||||
|     WsFrame = get_env(ws_frame, text), | ||||
|     CowboyOpts = get_env(cowboy_opts, []), | ||||
| 
 | ||||
|     SockjsOpts = get_env(sockjs_opts, []) ++ [{logger, fun logger/3}], | ||||
|  | @ -44,7 +45,7 @@ init() -> | |||
|                     <<"/stomp">>, fun service_stomp/3, {}, SockjsOpts), | ||||
|     VhostRoutes = [ | ||||
|         {"/stomp/[...]", sockjs_cowboy_handler, SockjsState}, | ||||
|         {"/ws", rabbit_ws_handler, undefined} | ||||
|         {"/ws", rabbit_ws_handler, [{type, WsFrame}]} | ||||
|     ], | ||||
|     Routes = cowboy_router:compile([{'_',  VhostRoutes}]), % any vhost | ||||
|     NbAcceptors = get_env(nb_acceptors, 100), | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
|          {ssl_config, []}, | ||||
|          {nb_acceptors, 100}, | ||||
|          {cowboy_opts, []}, | ||||
|          {sockjs_opts, []}]}, | ||||
|          {sockjs_opts, []}, | ||||
|          {ws_frame, text}]}, | ||||
|   {applications, [kernel, stdlib, rabbit, rabbitmq_stomp, cowboy, sockjs]} | ||||
|  ]}. | ||||
|  |  | |||
|  | @ -58,6 +58,50 @@ pubsub_test() -> | |||
|     ok. | ||||
| 
 | ||||
| 
 | ||||
| raw_send_binary(WS, Command, Headers) -> | ||||
|     raw_send_binary(WS, Command, Headers, <<>>). | ||||
| raw_send_binary(WS, Command, Headers, Body) -> | ||||
|     Frame = stomp:marshal(Command, Headers, Body), | ||||
|     rfc6455_client:send_binary(WS, Frame). | ||||
| 
 | ||||
| raw_recv_binary(WS) -> | ||||
|     {binary, P} = rfc6455_client:recv(WS), | ||||
|     stomp:unmarshal(P). | ||||
| 
 | ||||
| 
 | ||||
| pubsub_binary_test() -> | ||||
|     %% Set frame type to binary and restart the web stomp application. | ||||
|     ok = application:set_env(rabbitmq_web_stomp, ws_frame, binary), | ||||
|     ok = application:stop(rabbitmq_web_stomp), | ||||
|     ok = cowboy:stop_listener(http), | ||||
|     ok = application:start(rabbitmq_web_stomp), | ||||
| 
 | ||||
|     WS = rfc6455_client:new("ws://127.0.0.1:15674/ws", self()), | ||||
|     {ok, _} = rfc6455_client:open(WS), | ||||
|     ok = raw_send(WS, "CONNECT", [{"login","guest"}, {"passcode", "guest"}]), | ||||
| 
 | ||||
|     {<<"CONNECTED">>, _, <<>>} = raw_recv_binary(WS), | ||||
| 
 | ||||
|     Dst = "/topic/test-" ++ stomp:list_to_hex(binary_to_list(crypto:rand_bytes(8))), | ||||
| 
 | ||||
|     ok = raw_send(WS, "SUBSCRIBE", [{"destination", Dst}, | ||||
|                                     {"id", "s0"}]), | ||||
| 
 | ||||
|     ok = raw_send(WS, "SEND", [{"destination", Dst}, | ||||
|                               {"content-length", "3"}], <<"a\x00a">>), | ||||
| 
 | ||||
|     {<<"MESSAGE">>, H, <<"a\x00a">>} = raw_recv_binary(WS), | ||||
|     Dst = binary_to_list(proplists:get_value(<<"destination">>, H)), | ||||
| 
 | ||||
|     {close, _} = rfc6455_client:close(WS), | ||||
| 
 | ||||
|     %% Set frame type back to text and restart the web stomp application. | ||||
|     ok = application:set_env(rabbitmq_web_stomp, ws_frame, text), | ||||
|     ok = application:stop(rabbitmq_web_stomp), | ||||
|     ok = cowboy:stop_listener(http), | ||||
|     ok = application:start(rabbitmq_web_stomp). | ||||
| 
 | ||||
| 
 | ||||
| disconnect_test() -> | ||||
|     WS = rfc6455_client:new("ws://127.0.0.1:15674/ws", self()), | ||||
|     {ok, _} = rfc6455_client:open(WS), | ||||
|  |  | |||
|  | @ -52,6 +52,8 @@ recv(WS) -> | |||
|     receive | ||||
|         {rfc6455, recv, WS, Payload} -> | ||||
|             {ok, Payload}; | ||||
|         {rfc6455, recv_binary, WS, Payload} -> | ||||
|             {binary, Payload}; | ||||
|         {rfc6455, close, WS, R} -> | ||||
|             {close, R} | ||||
|     end. | ||||
|  | @ -60,6 +62,10 @@ send(WS, IoData) -> | |||
|     WS ! {send, IoData}, | ||||
|     ok. | ||||
| 
 | ||||
| send_binary(WS, IoData) -> | ||||
|     WS ! {send_binary, IoData}, | ||||
|     ok. | ||||
| 
 | ||||
| close(WS) -> | ||||
|     close(WS, {1000, ""}). | ||||
| 
 | ||||
|  | @ -130,6 +136,9 @@ do_recv2(State = #state{phase = Phase, socket = Socket, ppid = PPid}, R) -> | |||
|         {1, 1, Payload, Rest} -> | ||||
|             PPid ! {rfc6455, recv, self(), Payload}, | ||||
|             State#state{data = Rest}; | ||||
|         {1, 2, Payload, Rest} -> | ||||
|             PPid ! {rfc6455, recv_binary, self(), Payload}, | ||||
|             State#state{data = Rest}; | ||||
|         {1, 8, Payload, _Rest} -> | ||||
|             WsReason = case Payload of | ||||
|                            <<WC:16, WR/binary>> -> {WC, WR}; | ||||
|  | @ -167,6 +176,10 @@ do_send(State = #state{socket = Socket}, Payload) -> | |||
|     gen_tcp:send(Socket, encode_frame(1, 1, Payload)), | ||||
|     State. | ||||
| 
 | ||||
| do_send_binary(State = #state{socket = Socket}, Payload) -> | ||||
|     gen_tcp:send(Socket, encode_frame(1, 2, Payload)), | ||||
|     State. | ||||
| 
 | ||||
| do_close(State = #state{socket = Socket}, {Code, Reason}) -> | ||||
|     Payload = iolist_to_binary([<<Code:16>>, Reason]), | ||||
|     gen_tcp:send(Socket, encode_frame(1, 8, Payload)), | ||||
|  | @ -181,6 +194,8 @@ loop(State = #state{socket = Socket, ppid = PPid, data = Data, | |||
|             loop(do_recv(State1)); | ||||
|         {send, Payload} when Phase == open -> | ||||
|             loop(do_send(State, Payload)); | ||||
|         {send_binary, Payload} when Phase == open -> | ||||
|             loop(do_send_binary(State, Payload)); | ||||
|         {tcp_closed, Socket} -> | ||||
|             die(Socket, PPid, {1006, "Connection closed abnormally"}, normal); | ||||
|         {close, WsReason} when Phase == open -> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue