You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by be...@apache.org on 2014/02/13 17:06:24 UTC
[29/50] mochiweb commit: updated refs/heads/import-upstream to 8eb1f22
tests for websocket handshake and frames parsing
Project: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/commit/2eb1c563
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/tree/2eb1c563
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/diff/2eb1c563
Branch: refs/heads/import-upstream
Commit: 2eb1c563ca934b53a935c3b96ff5fba135cab9f8
Parents: cef2055
Author: Łukasz Lalik <lu...@gmail.com>
Authored: Wed Dec 25 01:25:24 2013 +0100
Committer: Łukasz Lalik <lu...@gmail.com>
Committed: Wed Dec 25 01:25:24 2013 +0100
----------------------------------------------------------------------
src/mochiweb_websocket.erl | 65 +++++++++++++++++---------------
src/mochiweb_websocket_tests.erl | 70 +++++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/2eb1c563/src/mochiweb_websocket.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_websocket.erl b/src/mochiweb_websocket.erl
index d1cc4b4..12bf84a 100644
--- a/src/mochiweb_websocket.erl
+++ b/src/mochiweb_websocket.erl
@@ -28,45 +28,47 @@
-export([loop/4, upgrade_connection/1, request/4]).
-export([after_response/4, reentry/1, send/3]).
--define(REQUEST_RECV_TIMEOUT, 3000000). %% timeout waiting for request line
--define(HEADERS_RECV_TIMEOUT, 30000). %% timeout waiting for headers
-
--define(MAX_HEADERS, 1000).
--define(DEFAULTS, [{name, ?MODULE},
- {port, 8888}]).
-
loop(Socket, Body, State, WsVersion) ->
ok = mochiweb_socket:setopts(Socket, [{packet, 0}, {active, once}]),
proc_lib:hibernate(?MODULE, request, [Socket, Body, State, WsVersion]).
upgrade_connection(Req) ->
- % Headers for HYBI handshake
+ case make_handshake(Req) of
+ {Version, Response} ->
+ Req:respond(Response),
+ Version;
+
+ _ ->
+ mochiweb_socket:close(Req:get(socket)),
+ exit(normal)
+ end.
+
+make_handshake(Req) ->
SecKey = Req:get_header_value("sec-websocket-key"),
Sec1Key = Req:get_header_value("Sec-WebSocket-Key1"),
Sec2Key = Req:get_header_value("Sec-WebSocket-Key2"),
Origin = Req:get_header_value(origin),
-
if not (SecKey == undefined) ->
- hybi_handshake(Req, SecKey);
+ hybi_handshake(SecKey);
- (not (Sec1Key == undefined)) and (not (Sec2Key == undefined)) ->
- Body = Req:recv(8),
- hixie_handshake(Req, Sec1Key, Sec2Key, Body, Origin);
+ (not (Sec1Key == undefined)) and (not (Sec2Key == undefined)) ->
+ Host = Req:get_header_value("Host"),
+ Path = Req:get(path),
+ Body = Req:recv(8),
+ hixie_handshake(Host, Path, Sec1Key, Sec2Key, Body, Origin);
true ->
- mochiweb_socket:close(Req:get(socket)),
- exit(normal)
+ error
end.
-
-hybi_handshake(Req, SecKey) ->
+hybi_handshake(SecKey) ->
Challenge = handshake_key(SecKey),
- Req:respond({101, [{"Connection", "Upgrade"},
+ Response = {101, [{"Connection", "Upgrade"},
{"Upgrade", "websocket"},
- {"Sec-Websocket-Accept", Challenge}], ""}),
- hybi.
+ {"Sec-Websocket-Accept", Challenge}], ""},
+ {hybi, Response}.
-hixie_handshake(Req, Key1, Key2, Body, Origin) ->
+hixie_handshake(Host, Path, Key1, Key2, Body, Origin) ->
Ikey1 = [D || D <- Key1, $0 =< D, D =< $9],
Ikey2 = [D || D <- Key2, $0 =< D, D =< $9],
Blank1 = length([D || D <- Key1, D =:= 32]),
@@ -76,18 +78,14 @@ hixie_handshake(Req, Key1, Key2, Body, Origin) ->
Ckey = <<Part1:4/big-unsigned-integer-unit:8, Part2:4/big-unsigned-integer-unit:8, Body/binary>>,
Challenge = erlang:md5(Ckey),
- Location = lists:concat(["ws://",
- Req:get_header_value("Host"),
- Req:get(path)]),
+ Location = lists:concat(["ws://", Host, Path]),
- Req:respond({101, [{"Upgrade", "WebSocket"},
+ Response = {101, [{"Upgrade", "WebSocket"},
{"Connection", "Upgrade"},
{"Sec-WebSocket-Origin", Origin},
{"Sec-WebSocket-Location", Location}],
- Challenge}),
- hixie.
-
-
+ Challenge},
+ {hixie, Response}.
send(Socket, Payload, hybi) ->
Len = payload_length(iolist_size(Payload)),
@@ -121,6 +119,7 @@ request(Socket, Body, State, WsVersion) ->
M:F(Socket, Payload, State, WsVersion)
end,
+ io:format("Handle: ~p~n", [WsFrames]),
try parse_frames(Socket, WsFrames, []) of
Parsed -> process_frames(Parsed, Reply, [])
catch
@@ -302,3 +301,11 @@ handle_frame(<<255, Rest/binary>>, Buffer) ->
{Buffer, Rest};
handle_frame(<<H, T/binary>>, Buffer) ->
handle_frame(T, <<Buffer/binary, H>>).
+
+%%
+%% Tests
+%%
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-compile(export_all).
+-endif.
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/2eb1c563/src/mochiweb_websocket_tests.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_websocket_tests.erl b/src/mochiweb_websocket_tests.erl
new file mode 100644
index 0000000..272b188
--- /dev/null
+++ b/src/mochiweb_websocket_tests.erl
@@ -0,0 +1,70 @@
+-module(mochiweb_websocket_tests).
+-author('lukasz.lalik@zadane.pl').
+
+%% The MIT License (MIT)
+
+%% Copyright (c) 2012 Zadane.pl sp. z o.o.
+
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+make_handshake_for_correct_client_test() ->
+ %% Hybi handshake
+ Req1 = mochiweb_request:new(nil, 'GET', "/foo", {1, 1},
+ mochiweb_headers:make([{"Sec-WebSocket-Key", "Xn3fdKyc3qEXPuj2A3O+ZA=="}])),
+
+ {Version1, {HttpCode1, Headers1, _}} = mochiweb_websocket:make_handshake(Req1),
+ ?assertEqual(hybi, Version1),
+ ?assertEqual(101, HttpCode1),
+ ?assertEqual("Upgrade", proplists:get_value("Connection", Headers1)),
+ ?assertEqual(<<"BIFTHkJk4r5t8kuud82tZJaQsCE=">>, proplists:get_value("Sec-Websocket-Accept", Headers1)),
+
+ %% Hixie handshake
+ {Version2, {HttpCode2, Headers2, Body2}} = mochiweb_websocket:hixie_handshake(
+ "localhost", "/",
+ "33j284 9 z63 e 9 7",
+ "TF'3|6D12659H 7 70",
+ <<175,181,191,215,128,195,144,120>>,
+ "null"),
+ ?assertEqual(hixie, Version2),
+ ?assertEqual(101, HttpCode2),
+ ?assertEqual("null", proplists:get_value("Sec-WebSocket-Origin", Headers2)),
+ ?assertEqual("ws://localhost/", proplists:get_value("Sec-WebSocket-Location", Headers2)),
+ ?assertEqual(<<230,144,237,94,84,214,41,69,244,150,134,167,221,103,239,246>>, Body2).
+
+hybi_frames_decode_test() ->
+ Resp1 = mochiweb_websocket:parse_frames(nil, <<129,131,118,21,153,58,16,122,246>>, []),
+ ?assertEqual([{1, <<"foo">>}], Resp1),
+
+ Resp2 = mochiweb_websocket:parse_frames(nil, <<129,131,1,225,201,42,103,142,166,129,131,93,222,214,66,63,191,164>>, []),
+ ?assertEqual([{1, <<"foo">>}, {1, <<"bar">>}], Resp2).
+
+hixie_frames_decode_test() ->
+ Resp1 = mochiweb_websocket:handle_frames(<<>>, []),
+ ?assertEqual([], Resp1),
+
+ Resp2 = mochiweb_websocket:handle_frames(<<0,102,111,111,255>>, []),
+ ?assertEqual([<<"foo">>], Resp2),
+
+ Resp3 = mochiweb_websocket:handle_frames(<<0,102,111,111,255,0,98,97,114,255>>, []),
+ ?assertEqual([<<"foo">>, <<"bar">>], Resp3).
+
+-endif.