-
Notifications
You must be signed in to change notification settings - Fork 267
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update WebSockets implementation to support RFC 6455
This change allows websocket connections to be set up between browsers and the yaws server. RFC 6455 for WebSocket connections is supported, in addition to the hybi working group RFC drafts 10 to 17. The quickest way to try this out is by compiling yaws as usual, then visiting /websockets_example.yaws at the default local installation host. This can be done using Google Chrome 14+, Firefox 7+ or any other browser supporting WebSocket version 8 or above. Information about getting started with WebSockets using this implementation is given in /websockets.yaws. This drops support for the older draft RFCs, specifically those of the hixie working group which were previously supported by yaws but are significantly different from the hybi working group's specification. The interface for using WebSocket with yaws has changed somewhat. Instead of spawning a websocket owner process which maintains a server loop such as that shown in the old websockets_endpoint.yaws, the application developer now implements a callback module such as those in src/basic_echo_callback.erl or src/advanced_echo_callback.erl -- the difference being that the advanced callback style is only necessary if you need advanced features of WebSocket such as fragmented messages. One suggested way to deploy your callback module and its dependencies is as part of an application in an OTP release, with yaws as a dependency. Rebar can be used to build the dependencies, fetch and build yaws, and create a release which will ensure the modules are in the path of the runtime system. Most behaviour tested by the Autobahn test suite 0.43 pass when configured to connect to the /websockets_autobahn_endpoint.yaws and /websockets_example_endpoint.yaws over an unencrypted connection. Significantly, websocket connection closing is not implemented and the socket is left to be cleaned up by the Runtime System when either the connection is lost or the owning processes dies. Secondly, certain cases where websocket frames are fragmented within UTF-8 code points cause the check for valid text type messages to incorrectly fail the connection. Subprotocols are not currently supported. Augment yaws.tex with a new WebSocket Protocol chapter (Steve Vinoski).
- Loading branch information
Showing
11 changed files
with
854 additions
and
269 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
%%%============================================================== | ||
%%% compiled using erlc -I include src/advanced_echo_callback.erl | ||
%%%============================================================== | ||
|
||
-module(advanced_echo_callback). | ||
|
||
-export([handle_message/2]). | ||
|
||
-include("yaws_api.hrl"). | ||
|
||
%% define callback state to accumulate a fragmented WS message | ||
%% which we echo back when all fragments are in, returning to | ||
%% initial state. | ||
-record(state, {frag_type = none, % fragment type | ||
acc = <<>>}). % accumulate fragment data | ||
|
||
%% start of a fragmented message | ||
handle_message(#ws_frame_info{fin=0, | ||
opcode=FragType, | ||
data=Data}, | ||
#state{frag_type=none, acc = <<>>}) -> | ||
{noreply, #state{frag_type=FragType, acc=Data}}; | ||
|
||
%% non-final continuation of a fragmented message | ||
handle_message(#ws_frame_info{fin=0, | ||
data=Data, | ||
opcode=continuation}, | ||
#state{frag_type = FragType, acc = Acc}) -> | ||
{noreply, #state{frag_type=FragType, acc = <<Acc/binary,Data/binary>>}}; | ||
|
||
%% end of text fragmented message | ||
handle_message(#ws_frame_info{fin=1, | ||
opcode=continuation, | ||
data=Data}, | ||
#state{frag_type=text, acc=Acc}) -> | ||
Unfragged = <<Acc/binary, Data/binary>>, | ||
{reply, {text, Unfragged}, #state{frag_type=none, acc = <<>>}}; | ||
|
||
%% one full non-fragmented message | ||
handle_message(#ws_frame_info{opcode=text, data=Data}, State) -> | ||
{reply, {text, Data}, State}; | ||
|
||
%% end of binary fragmented message | ||
handle_message(#ws_frame_info{fin=1, | ||
opcode=continuation, | ||
data=Data}, | ||
#state{frag_type=binary, acc=Acc}) -> | ||
Unfragged = <<Acc/binary, Data/binary>>, | ||
io:format("echoing back binary message~n",[]), | ||
{reply, {binary, Unfragged}, #state{frag_type=none, acc = <<>>}}; | ||
|
||
%% one full non-fragmented binary message | ||
handle_message(#ws_frame_info{opcode=binary, | ||
data=Data}, | ||
State) -> | ||
io:format("echoing back binary message~n",[]), | ||
{reply, {binary, Data}, State}; | ||
|
||
handle_message(#ws_frame_info{opcode=ping, | ||
data=Data}, | ||
State) -> | ||
io:format("replying pong to ping~n",[]), | ||
{reply, {pong, Data}, State}; | ||
|
||
handle_message(#ws_frame_info{opcode=pong}, State) -> | ||
%% A response to an unsolicited pong frame is not expected. | ||
%% http://tools.ietf.org/html/\ | ||
%% draft-ietf-hybi-thewebsocketprotocol-08#section-4 | ||
io:format("ignoring unsolicited pong~n",[]), | ||
{noreply, State}; | ||
|
||
handle_message(#ws_frame_info{}=FrameInfo, State) -> | ||
io:format("WS Endpoint Unhandled message: ~p~n~p~n", [FrameInfo, State]), | ||
{close, {error, {unhandled_message, FrameInfo}}}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
%%%=========================================================== | ||
%%% compiled using erlc -I include src/basic_echo_callback.erl | ||
%%%=========================================================== | ||
|
||
-module(basic_echo_callback). | ||
|
||
%% Export for websocket callbacks | ||
-export([handle_message/1]). | ||
|
||
%% Export for apply | ||
-export([say_hi/1]). | ||
|
||
handle_message({text, <<"bye">>}) -> | ||
io:format("User said bye.~n", []), | ||
{close, normal}; | ||
|
||
handle_message({text, <<"something">>}) -> | ||
io:format("Some action without a reply~n", []), | ||
noreply; | ||
|
||
handle_message({text, <<"say hi later">>}) -> | ||
io:format("saying hi in 3s.~n", []), | ||
timer:apply_after(3000, ?MODULE, say_hi, [self()]), | ||
{reply, {text, <<"I'll say hi in a bit...">>}}; | ||
|
||
handle_message({text, Message}) -> | ||
io:format("basic echo handler got ~p~n", [Message]), | ||
{reply, {text, <<Message/binary>>}}; | ||
|
||
handle_message({binary, Message}) -> | ||
{reply, {binary, Message}}. | ||
|
||
|
||
say_hi(Pid) -> | ||
io:format("asynchronous greeting~n", []), | ||
yaws_api:websocket_send(Pid, {text, <<"hi there!">>}). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.