mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Add more frame types available in websocket replies
We can now reply empty close, ping and pong frames, or close frames with a payload. This means that we can send a frame and then close the connection in a single operation. If a close packet is sent, the connection is closed immediately, even if there was frames that remained to be sent. Cowboy will silently drop any extra frames in the list given as a reply.
This commit is contained in:
parent
3e0e507311
commit
067958abd2
4 changed files with 140 additions and 27 deletions
|
@ -30,6 +30,8 @@
|
|||
-export([ws8_init_shutdown/1]).
|
||||
-export([ws8_single_bytes/1]).
|
||||
-export([ws13/1]).
|
||||
-export([ws_send_close/1]).
|
||||
-export([ws_send_close_payload/1]).
|
||||
-export([ws_send_many/1]).
|
||||
-export([ws_text_fragments/1]).
|
||||
-export([ws_timeout_hibernate/1]).
|
||||
|
@ -46,6 +48,8 @@ groups() ->
|
|||
ws8_init_shutdown,
|
||||
ws8_single_bytes,
|
||||
ws13,
|
||||
ws_send_close,
|
||||
ws_send_close_payload,
|
||||
ws_send_many,
|
||||
ws_text_fragments,
|
||||
ws_timeout_hibernate
|
||||
|
@ -85,7 +89,24 @@ init_dispatch() ->
|
|||
{[<<"websocket">>], websocket_handler, []},
|
||||
{[<<"ws_echo_handler">>], websocket_echo_handler, []},
|
||||
{[<<"ws_init_shutdown">>], websocket_handler_init_shutdown, []},
|
||||
{[<<"ws_send_many">>], ws_send_many_handler, []},
|
||||
{[<<"ws_send_many">>], ws_send_many_handler, [
|
||||
{sequence, [
|
||||
{text, <<"one">>},
|
||||
{text, <<"two">>},
|
||||
{text, <<"seven!">>}]}
|
||||
]},
|
||||
{[<<"ws_send_close">>], ws_send_many_handler, [
|
||||
{sequence, [
|
||||
{text, <<"send">>},
|
||||
close,
|
||||
{text, <<"won't be received">>}]}
|
||||
]},
|
||||
{[<<"ws_send_close_payload">>], ws_send_many_handler, [
|
||||
{sequence, [
|
||||
{text, <<"send">>},
|
||||
{close, <<"some text!">>},
|
||||
{text, <<"won't be received">>}]}
|
||||
]},
|
||||
{[<<"ws_timeout_hibernate">>], ws_timeout_hibernate_handler, []}
|
||||
]}
|
||||
].
|
||||
|
@ -310,6 +331,64 @@ ws13(Config) ->
|
|||
{error, closed} = gen_tcp:recv(Socket, 0, 6000),
|
||||
ok.
|
||||
|
||||
ws_send_close(Config) ->
|
||||
{port, Port} = lists:keyfind(port, 1, Config),
|
||||
{ok, Socket} = gen_tcp:connect("localhost", Port,
|
||||
[binary, {active, false}, {packet, raw}]),
|
||||
ok = gen_tcp:send(Socket, [
|
||||
"GET /ws_send_close HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Sec-WebSocket-Origin: http://localhost\r\n"
|
||||
"Sec-WebSocket-Version: 8\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"\r\n"]),
|
||||
{ok, Handshake} = gen_tcp:recv(Socket, 0, 6000),
|
||||
{ok, {http_response, {1, 1}, 101, "Switching Protocols"}, Rest}
|
||||
= erlang:decode_packet(http, Handshake, []),
|
||||
[Headers, <<>>] = websocket_headers(
|
||||
erlang:decode_packet(httph, Rest, []), []),
|
||||
{'Connection', "Upgrade"} = lists:keyfind('Connection', 1, Headers),
|
||||
{'Upgrade', "websocket"} = lists:keyfind('Upgrade', 1, Headers),
|
||||
{"sec-websocket-accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="}
|
||||
= lists:keyfind("sec-websocket-accept", 1, Headers),
|
||||
%% We catch all frames at once and check them directly.
|
||||
{ok, Many} = gen_tcp:recv(Socket, 8, 6000),
|
||||
<< 1:1, 0:3, 1:4, 0:1, 4:7, "send",
|
||||
1:1, 0:3, 8:4, 0:8 >> = Many,
|
||||
{error, closed} = gen_tcp:recv(Socket, 0, 6000),
|
||||
ok.
|
||||
|
||||
ws_send_close_payload(Config) ->
|
||||
{port, Port} = lists:keyfind(port, 1, Config),
|
||||
{ok, Socket} = gen_tcp:connect("localhost", Port,
|
||||
[binary, {active, false}, {packet, raw}]),
|
||||
ok = gen_tcp:send(Socket, [
|
||||
"GET /ws_send_close_payload HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Sec-WebSocket-Origin: http://localhost\r\n"
|
||||
"Sec-WebSocket-Version: 8\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"\r\n"]),
|
||||
{ok, Handshake} = gen_tcp:recv(Socket, 0, 6000),
|
||||
{ok, {http_response, {1, 1}, 101, "Switching Protocols"}, Rest}
|
||||
= erlang:decode_packet(http, Handshake, []),
|
||||
[Headers, <<>>] = websocket_headers(
|
||||
erlang:decode_packet(httph, Rest, []), []),
|
||||
{'Connection', "Upgrade"} = lists:keyfind('Connection', 1, Headers),
|
||||
{'Upgrade', "websocket"} = lists:keyfind('Upgrade', 1, Headers),
|
||||
{"sec-websocket-accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="}
|
||||
= lists:keyfind("sec-websocket-accept", 1, Headers),
|
||||
%% We catch all frames at once and check them directly.
|
||||
{ok, Many} = gen_tcp:recv(Socket, 18, 6000),
|
||||
<< 1:1, 0:3, 1:4, 0:1, 4:7, "send",
|
||||
1:1, 0:3, 8:4, 0:1, 10:7, "some text!" >> = Many,
|
||||
{error, closed} = gen_tcp:recv(Socket, 0, 6000),
|
||||
ok.
|
||||
|
||||
ws_send_many(Config) ->
|
||||
{port, Port} = lists:keyfind(port, 1, Config),
|
||||
{ok, Socket} = gen_tcp:connect("localhost", Port,
|
||||
|
|
|
@ -12,20 +12,16 @@
|
|||
init(_Any, _Req, _Opts) ->
|
||||
{upgrade, protocol, cowboy_websocket}.
|
||||
|
||||
websocket_init(_TransportName, Req, _Opts) ->
|
||||
websocket_init(_TransportName, Req, Sequence) ->
|
||||
Req2 = cowboy_req:compact(Req),
|
||||
erlang:send_after(10, self(), send_many),
|
||||
{ok, Req2, undefined}.
|
||||
{ok, Req2, Sequence}.
|
||||
|
||||
websocket_handle(_Frame, Req, State) ->
|
||||
{ok, Req, State}.
|
||||
|
||||
websocket_info(send_many, Req, State) ->
|
||||
{reply, [
|
||||
{text, <<"one">>},
|
||||
{text, <<"two">>},
|
||||
{text, <<"seven!">>}
|
||||
], Req, State}.
|
||||
websocket_info(send_many, Req, State = [{sequence, Sequence}]) ->
|
||||
{reply, Sequence, Req, State}.
|
||||
|
||||
websocket_terminate(_Reason, _Req, _State) ->
|
||||
ok.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue