diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/autobahn_SUITE.erl | 12 | ||||
-rwxr-xr-x | test/autobahn_SUITE_data/test.py | 4 | ||||
-rw-r--r-- | test/chunked_handler.erl | 6 | ||||
-rw-r--r-- | test/cover.spec | 1 | ||||
-rw-r--r-- | test/eunit_SUITE.erl | 31 | ||||
-rw-r--r-- | test/http_SUITE.erl | 282 | ||||
-rw-r--r-- | test/http_handler.erl | 4 | ||||
-rw-r--r-- | test/http_handler_echo_body.erl | 8 | ||||
-rw-r--r-- | test/http_handler_errors.erl | 4 | ||||
-rw-r--r-- | test/http_handler_init_shutdown.erl | 4 | ||||
-rw-r--r-- | test/http_handler_long_polling.erl | 4 | ||||
-rw-r--r-- | test/http_handler_loop_timeout.erl | 4 | ||||
-rw-r--r-- | test/http_handler_multipart.erl | 4 | ||||
-rw-r--r-- | test/http_handler_set_resp.erl | 4 | ||||
-rw-r--r-- | test/http_handler_stream_body.erl | 18 | ||||
-rw-r--r-- | test/rest_created_path_resource.erl | 35 | ||||
-rw-r--r-- | test/rest_patch_resource.erl | 34 | ||||
-rw-r--r-- | test/websocket_echo_handler.erl | 9 | ||||
-rw-r--r-- | test/websocket_handler.erl | 9 | ||||
-rw-r--r-- | test/websocket_handler_init_shutdown.erl | 9 | ||||
-rw-r--r-- | test/ws_SUITE.erl | 137 | ||||
-rw-r--r-- | test/ws_timeout_cancel_handler.erl | 9 | ||||
-rw-r--r-- | test/ws_timeout_hibernate_handler.erl | 9 |
23 files changed, 426 insertions, 215 deletions
diff --git a/test/autobahn_SUITE.erl b/test/autobahn_SUITE.erl index 9ae9d7a..61cf631 100644 --- a/test/autobahn_SUITE.erl +++ b/test/autobahn_SUITE.erl @@ -64,7 +64,7 @@ end_per_suite(_Config) -> init_per_group(autobahn, Config) -> Port = 33080, cowboy:start_http(autobahn, 100, [{port, Port}], [ - {dispatch, init_dispatch()} + {env, [{dispatch, init_dispatch()}]} ]), [{port, Port}|Config]. @@ -75,8 +75,8 @@ end_per_group(Listener, _Config) -> %% Dispatch configuration. init_dispatch() -> - [{[<<"localhost">>], [ - {[<<"echo">>], websocket_echo_handler, []}]}]. + cowboy_router:compile([{"localhost", [ + {"/echo", websocket_echo_handler, []}]}]). %% autobahn cases @@ -92,7 +92,7 @@ run_tests(Config) -> _ -> ok end, {ok, IndexHTML} = file:read_file(IndexFile), - case binary:match(IndexHTML, <<"Fail">>) of - {_, _} -> erlang:error(failed); - nomatch -> ok + case length(binary:matches(IndexHTML, <<"case_failed">>)) > 2 of + true -> erlang:error(failed); + false -> ok end. diff --git a/test/autobahn_SUITE_data/test.py b/test/autobahn_SUITE_data/test.py index c528c64..19c7669 100755 --- a/test/autobahn_SUITE_data/test.py +++ b/test/autobahn_SUITE_data/test.py @@ -10,7 +10,7 @@ AB_TESTS_PRIV = os.getenv("AB_TESTS_PRIV") VIRTUALENV_URL = 'https://raw.github.com/pypa/virtualenv/master/virtualenv.py' VIRTUALENV_BIN = os.path.join(AB_TESTS_ENV, "virtualenv.py") -PIP_BIN = os.path.join(AB_TESTS_ENV, "bin", "pip") +INSTALL_BIN = os.path.join(AB_TESTS_ENV, "bin", "easy_install") def activate_env(env): @@ -29,7 +29,7 @@ def install_env(env): subprocess.check_call(["curl", "-sS", VIRTUALENV_URL, "-o", VIRTUALENV_BIN]) subprocess.check_call(["python", VIRTUALENV_BIN, env]) activate_env(env) - subprocess.check_call([PIP_BIN, "install", "AutobahnTestSuite"]) + subprocess.check_call([INSTALL_BIN, "http://pypi.python.org/packages/2.7/a/autobahntestsuite/autobahntestsuite-0.5.2-py2.7.egg#md5=f7480d4ca6ce4954ac05f59778de4bda"]) def client_config(): """ diff --git a/test/chunked_handler.erl b/test/chunked_handler.erl index 38305fd..e486afe 100644 --- a/test/chunked_handler.erl +++ b/test/chunked_handler.erl @@ -2,16 +2,18 @@ -module(chunked_handler). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_Transport, http}, Req, _Opts) -> {ok, Req, undefined}. handle(Req, State) -> {ok, Req2} = cowboy_req:chunked_reply(200, Req), + timer:sleep(100), cowboy_req:chunk("chunked_handler\r\n", Req2), + timer:sleep(100), cowboy_req:chunk("works fine!", Req2), {ok, Req2, State}. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/cover.spec b/test/cover.spec new file mode 100644 index 0000000..9dba11c --- /dev/null +++ b/test/cover.spec @@ -0,0 +1 @@ +{incl_app, cowboy, details}. diff --git a/test/eunit_SUITE.erl b/test/eunit_SUITE.erl new file mode 100644 index 0000000..a460890 --- /dev/null +++ b/test/eunit_SUITE.erl @@ -0,0 +1,31 @@ +%% Copyright (c) 2013, Loïc Hoguin <[email protected]> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(eunit_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +%% ct. +-export([all/0]). + +%% Tests. +-export([eunit/1]). + +%% ct. + +all() -> + [eunit]. + +eunit(_) -> + ok = eunit:test({application, cowboy}). diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index c90e585..afe62c3 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2011-2012, Loïc Hoguin <[email protected]> +%% Copyright (c) 2011-2013, Loïc Hoguin <[email protected]> %% Copyright (c) 2011, Anthony Ramine <[email protected]> %% %% Permission to use, copy, modify, and/or distribute this software for any @@ -45,21 +45,26 @@ -export([nc_zero/1]). -export([onrequest/1]). -export([onrequest_reply/1]). +-export([onresponse_capitalize/1]). -export([onresponse_crash/1]). -export([onresponse_reply/1]). -export([pipeline/1]). -export([rest_bad_accept/1]). +-export([rest_created_path/1]). -export([rest_expires/1]). -export([rest_keepalive/1]). -export([rest_keepalive_post/1]). -export([rest_missing_get_callbacks/1]). -export([rest_missing_put_callbacks/1]). -export([rest_nodelete/1]). +-export([rest_patch/1]). -export([rest_resource_etags/1]). -export([rest_resource_etags_if_none_match/1]). -export([set_resp_body/1]). -export([set_resp_header/1]). -export([set_resp_overwrite/1]). +-export([slowloris/1]). +-export([slowloris2/1]). -export([static_attribute_etag/1]). -export([static_function_etag/1]). -export([static_mimetypes_function/1]). @@ -68,14 +73,24 @@ -export([static_test_file/1]). -export([static_test_file_css/1]). -export([stream_body_set_resp/1]). +-export([stream_body_set_resp_close/1]). -export([te_chunked/1]). +-export([te_chunked_chopped/1]). -export([te_chunked_delayed/1]). -export([te_identity/1]). %% ct. all() -> - [{group, http}, {group, https}, {group, onrequest}, {group, onresponse}]. + [ + {group, http}, + {group, https}, + {group, http_compress}, + {group, https_compress}, + {group, onrequest}, + {group, onresponse}, + {group, onresponse_capitalize} + ]. groups() -> Tests = [ @@ -98,17 +113,21 @@ groups() -> nc_zero, pipeline, rest_bad_accept, + rest_created_path, rest_expires, rest_keepalive, rest_keepalive_post, rest_missing_get_callbacks, rest_missing_put_callbacks, rest_nodelete, + rest_patch, rest_resource_etags, rest_resource_etags_if_none_match, set_resp_body, set_resp_header, set_resp_overwrite, + slowloris, + slowloris2, static_attribute_etag, static_function_etag, static_mimetypes_function, @@ -117,13 +136,17 @@ groups() -> static_test_file, static_test_file_css, stream_body_set_resp, + stream_body_set_resp_close, te_chunked, + te_chunked_chopped, te_chunked_delayed, te_identity ], [ {http, [], Tests}, {https, [], Tests}, + {http_compress, [], Tests}, + {https_compress, [], Tests}, {onrequest, [], [ onrequest, onrequest_reply @@ -131,11 +154,13 @@ groups() -> {onresponse, [], [ onresponse_crash, onresponse_reply + ]}, + {onresponse_capitalize, [], [ + onresponse_capitalize ]} ]. init_per_suite(Config) -> - application:start(inets), application:start(crypto), application:start(ranch), application:start(cowboy), @@ -145,7 +170,6 @@ end_per_suite(_Config) -> application:stop(cowboy), application:stop(ranch), application:stop(crypto), - application:stop(inets), ok. init_per_group(http, Config) -> @@ -153,7 +177,7 @@ init_per_group(http, Config) -> Transport = ranch_tcp, Config1 = init_static_dir(Config), {ok, _} = cowboy:start_http(http, 100, [{port, Port}], [ - {dispatch, init_dispatch(Config1)}, + {env, [{dispatch, init_dispatch(Config1)}]}, {max_keepalive, 50}, {timeout, 500} ]), @@ -172,18 +196,51 @@ init_per_group(https, Config) -> application:start(public_key), application:start(ssl), {ok, _} = cowboy:start_https(https, 100, Opts ++ [{port, Port}], [ - {dispatch, init_dispatch(Config1)}, + {env, [{dispatch, init_dispatch(Config1)}]}, {max_keepalive, 50}, {timeout, 500} ]), {ok, Client} = cowboy_client:init(Opts), [{scheme, <<"https">>}, {port, Port}, {opts, Opts}, {transport, Transport}, {client, Client}|Config1]; -init_per_group(onrequest, Config) -> +init_per_group(http_compress, Config) -> Port = 33082, Transport = ranch_tcp, + Config1 = init_static_dir(Config), + {ok, _} = cowboy:start_http(http_compress, 100, [{port, Port}], [ + {compress, true}, + {env, [{dispatch, init_dispatch(Config1)}]}, + {max_keepalive, 50}, + {timeout, 500} + ]), + {ok, Client} = cowboy_client:init([]), + [{scheme, <<"http">>}, {port, Port}, {opts, []}, + {transport, Transport}, {client, Client}|Config1]; +init_per_group(https_compress, Config) -> + Port = 33083, + Transport = ranch_ssl, + Opts = [ + {certfile, ?config(data_dir, Config) ++ "cert.pem"}, + {keyfile, ?config(data_dir, Config) ++ "key.pem"}, + {password, "cowboy"} + ], + Config1 = init_static_dir(Config), + application:start(public_key), + application:start(ssl), + {ok, _} = cowboy:start_https(https_compress, 100, Opts ++ [{port, Port}], [ + {compress, true}, + {env, [{dispatch, init_dispatch(Config1)}]}, + {max_keepalive, 50}, + {timeout, 500} + ]), + {ok, Client} = cowboy_client:init(Opts), + [{scheme, <<"https">>}, {port, Port}, {opts, Opts}, + {transport, Transport}, {client, Client}|Config1]; +init_per_group(onrequest, Config) -> + Port = 33084, + Transport = ranch_tcp, {ok, _} = cowboy:start_http(onrequest, 100, [{port, Port}], [ - {dispatch, init_dispatch(Config)}, + {env, [{dispatch, init_dispatch(Config)}]}, {max_keepalive, 50}, {onrequest, fun onrequest_hook/1}, {timeout, 500} @@ -192,25 +249,37 @@ init_per_group(onrequest, Config) -> [{scheme, <<"http">>}, {port, Port}, {opts, []}, {transport, Transport}, {client, Client}|Config]; init_per_group(onresponse, Config) -> - Port = 33083, + Port = 33085, Transport = ranch_tcp, {ok, _} = cowboy:start_http(onresponse, 100, [{port, Port}], [ - {dispatch, init_dispatch(Config)}, + {env, [{dispatch, init_dispatch(Config)}]}, {max_keepalive, 50}, {onresponse, fun onresponse_hook/4}, {timeout, 500} ]), {ok, Client} = cowboy_client:init([]), [{scheme, <<"http">>}, {port, Port}, {opts, []}, + {transport, Transport}, {client, Client}|Config]; +init_per_group(onresponse_capitalize, Config) -> + Port = 33086, + Transport = ranch_tcp, + {ok, _} = cowboy:start_http(onresponse_capitalize, 100, [{port, Port}], [ + {env, [{dispatch, init_dispatch(Config)}]}, + {max_keepalive, 50}, + {onresponse, fun onresponse_capitalize_hook/4}, + {timeout, 500} + ]), + {ok, Client} = cowboy_client:init([]), + [{scheme, <<"http">>}, {port, Port}, {opts, []}, {transport, Transport}, {client, Client}|Config]. -end_per_group(https, Config) -> +end_per_group(Group, Config) when Group =:= https; Group =:= https_compress -> cowboy:stop_listener(https), application:stop(ssl), application:stop(public_key), end_static_dir(Config), ok; -end_per_group(http, Config) -> +end_per_group(Group, Config) when Group =:= http; Group =:= http_compress -> cowboy:stop_listener(http), end_static_dir(Config); end_per_group(Name, _) -> @@ -220,54 +289,60 @@ end_per_group(Name, _) -> %% Dispatch configuration. init_dispatch(Config) -> - [ - {[<<"localhost">>], [ - {[<<"chunked_response">>], chunked_handler, []}, - {[<<"init_shutdown">>], http_handler_init_shutdown, []}, - {[<<"long_polling">>], http_handler_long_polling, []}, - {[<<"headers">>, <<"dupe">>], http_handler, + cowboy_router:compile([ + {"localhost", [ + {"/chunked_response", chunked_handler, []}, + {"/init_shutdown", http_handler_init_shutdown, []}, + {"/long_polling", http_handler_long_polling, []}, + {"/headers/dupe", http_handler, [{headers, [{<<"connection">>, <<"close">>}]}]}, - {[<<"set_resp">>, <<"header">>], http_handler_set_resp, + {"/set_resp/header", http_handler_set_resp, [{headers, [{<<"vary">>, <<"Accept">>}]}]}, - {[<<"set_resp">>, <<"overwrite">>], http_handler_set_resp, + {"/set_resp/overwrite", http_handler_set_resp, [{headers, [{<<"server">>, <<"DesireDrive/1.0">>}]}]}, - {[<<"set_resp">>, <<"body">>], http_handler_set_resp, + {"/set_resp/body", http_handler_set_resp, [{body, <<"A flameless dance does not equal a cycle">>}]}, - {[<<"stream_body">>, <<"set_resp">>], http_handler_stream_body, + {"/stream_body/set_resp", http_handler_stream_body, [{reply, set_resp}, {body, <<"stream_body_set_resp">>}]}, - {[<<"static">>, '...'], cowboy_static, + {"/stream_body/set_resp_close", + http_handler_stream_body, [ + {reply, set_resp_close}, + {body, <<"stream_body_set_resp_close">>}]}, + {"/static/[...]", cowboy_static, [{directory, ?config(static_dir, Config)}, {mimetypes, [{<<".css">>, [<<"text/css">>]}]}]}, - {[<<"static_mimetypes_function">>, '...'], cowboy_static, + {"/static_mimetypes_function/[...]", cowboy_static, [{directory, ?config(static_dir, Config)}, {mimetypes, {fun(Path, data) when is_binary(Path) -> [<<"text/html">>] end, data}}]}, - {[<<"handler_errors">>], http_handler_errors, []}, - {[<<"static_attribute_etag">>, '...'], cowboy_static, + {"/handler_errors", http_handler_errors, []}, + {"/static_attribute_etag/[...]", cowboy_static, [{directory, ?config(static_dir, Config)}, {etag, {attributes, [filepath, filesize, inode, mtime]}}]}, - {[<<"static_function_etag">>, '...'], cowboy_static, + {"/static_function_etag/[...]", cowboy_static, [{directory, ?config(static_dir, Config)}, {etag, {fun static_function_etag/2, etag_data}}]}, - {[<<"static_specify_file">>, '...'], cowboy_static, + {"/static_specify_file/[...]", cowboy_static, [{directory, ?config(static_dir, Config)}, {mimetypes, [{<<".css">>, [<<"text/css">>]}]}, {file, <<"test_file.css">>}]}, - {[<<"multipart">>], http_handler_multipart, []}, - {[<<"echo">>, <<"body">>], http_handler_echo_body, []}, - {[<<"bad_accept">>], rest_simple_resource, []}, - {[<<"simple">>], rest_simple_resource, []}, - {[<<"forbidden_post">>], rest_forbidden_resource, [true]}, - {[<<"simple_post">>], rest_forbidden_resource, [false]}, - {[<<"missing_get_callbacks">>], rest_missing_callbacks, []}, - {[<<"missing_put_callbacks">>], rest_missing_callbacks, []}, - {[<<"nodelete">>], rest_nodelete_resource, []}, - {[<<"resetags">>], rest_resource_etags, []}, - {[<<"rest_expires">>], rest_expires, []}, - {[<<"loop_timeout">>], http_handler_loop_timeout, []}, - {[], http_handler, []} + {"/multipart", http_handler_multipart, []}, + {"/echo/body", http_handler_echo_body, []}, + {"/bad_accept", rest_simple_resource, []}, + {"/simple", rest_simple_resource, []}, + {"/forbidden_post", rest_forbidden_resource, [true]}, + {"/simple_post", rest_forbidden_resource, [false]}, + {"/missing_get_callbacks", rest_missing_callbacks, []}, + {"/missing_put_callbacks", rest_missing_callbacks, []}, + {"/nodelete", rest_nodelete_resource, []}, + {"/patch", rest_patch_resource, []}, + {"/created_path", rest_created_path_resource, []}, + {"/resetags", rest_resource_etags, []}, + {"/rest_expires", rest_expires, []}, + {"/loop_timeout", http_handler_loop_timeout, []}, + {"/", http_handler, []} ]} - ]. + ]). init_static_dir(Config) -> Dir = filename:join(?config(priv_dir, Config), "static"), @@ -408,10 +483,16 @@ check_status(Config) -> {Ret, URL} end || {Status, URL} <- Tests]. -%% @todo Convert to cowboy_client. chunked_response(Config) -> - {ok, {{"HTTP/1.1", 200, "OK"}, _, "chunked_handler\r\nworks fine!"}} - = httpc:request(binary_to_list(build_url("/chunked_response", Config))). + Client = ?config(client, Config), + {ok, Client2} = cowboy_client:request(<<"GET">>, + build_url("/chunked_response", Config), Client), + {ok, 200, Headers, Client3} = cowboy_client:response(Client2), + true = lists:keymember(<<"transfer-encoding">>, 1, Headers), + {ok, Transport, Socket} = cowboy_client:transport(Client3), + {ok, <<"11\r\nchunked_handler\r\n\r\nB\r\nworks fine!\r\n0\r\n\r\n">>} + = Transport:recv(Socket, 44, 1000), + {error, closed} = cowboy_client:response(Client3). %% Check if sending requests whose size is around the MTU breaks something. echo_body(Config) -> @@ -503,8 +584,8 @@ http10_hostless(Config) -> ranch:start_listener(Name, 5, ?config(transport, Config), ?config(opts, Config) ++ [{port, Port10}], cowboy_protocol, [ - {dispatch, [{'_', [ - {[<<"http1.0">>, <<"hostless">>], http_handler, []}]}]}, + {env, [{dispatch, cowboy_router:compile([ + {'_', [{"/http1.0/hostless", http_handler, []}]}])}]}, {max_keepalive, 50}, {timeout, 500}] ), @@ -517,7 +598,8 @@ keepalive_max(Config) -> URL = build_url("/", Config), ok = keepalive_max_loop(Client, URL, 50). -keepalive_max_loop(_, _, 0) -> +keepalive_max_loop(Client, _, 0) -> + {error, closed} = cowboy_client:response(Client), ok; keepalive_max_loop(Client, URL, N) -> Headers = [{<<"connection">>, <<"keep-alive">>}], @@ -536,7 +618,8 @@ keepalive_nl(Config) -> URL = build_url("/", Config), ok = keepalive_nl_loop(Client, URL, 10). -keepalive_nl_loop(_, _, 0) -> +keepalive_nl_loop(Client, _, 0) -> + {error, closed} = cowboy_client:response(Client), ok; keepalive_nl_loop(Client, URL, N) -> Headers = [{<<"connection">>, <<"keep-alive">>}], @@ -619,6 +702,21 @@ onrequest_hook(Req) -> Req3 end. +onresponse_capitalize(Config) -> + Client = ?config(client, Config), + {ok, Client2} = cowboy_client:request(<<"GET">>, + build_url("/", Config), Client), + {ok, Transport, Socket} = cowboy_client:transport(Client2), + {ok, Data} = Transport:recv(Socket, 0, 1000), + false = nomatch =:= binary:match(Data, <<"Content-Length">>). + +%% Hook for the above onresponse_capitalize test. +onresponse_capitalize_hook(Status, Headers, Body, Req) -> + Headers2 = [{cowboy_bstr:capitalize_token(N), V} + || {N, V} <- Headers], + {ok, Req2} = cowboy_req:reply(Status, Headers2, Body, Req), + Req2. + onresponse_crash(Config) -> Client = ?config(client, Config), {ok, Client2} = cowboy_client:request(<<"GET">>, @@ -668,6 +766,18 @@ rest_bad_accept(Config) -> Client), {ok, 400, _, _} = cowboy_client:response(Client2). +rest_created_path(Config) -> + Headers = [{<<"content-type">>, <<"text/plain">>}], + Body = <<"Whatever">>, + Client = ?config(client, Config), + URL = build_url("/created_path", Config), + {ok, Client2} = cowboy_client:request(<<"POST">>, URL, Headers, + Body, Client), + {ok, 303, ResHeaders, _} = cowboy_client:response(Client2), + {<<"location">>, _Location} = + lists:keyfind(<<"location">>, 1, ResHeaders), + ok. + rest_expires(Config) -> Client = ?config(client, Config), {ok, Client2} = cowboy_client:request(<<"GET">>, @@ -742,6 +852,21 @@ rest_nodelete(Config) -> build_url("/nodelete", Config), Client), {ok, 500, _, _} = cowboy_client:response(Client2). +rest_patch(Config) -> + Tests = [ + {204, [{<<"content-type">>, <<"text/plain">>}], <<"whatever">>}, + {422, [{<<"content-type">>, <<"text/plain">>}], <<"false">>}, + {400, [{<<"content-type">>, <<"text/plain">>}], <<"halt">>}, + {415, [{<<"content-type">>, <<"application/json">>}], <<"bad_content_type">>} + ], + Client = ?config(client, Config), + _ = [begin + {ok, Client2} = cowboy_client:request(<<"PATCH">>, + build_url("/patch", Config), Headers, Body, Client), + {ok, Status, _, _} = cowboy_client:response(Client2), + ok + end || {Status, Headers, Body} <- Tests]. + rest_resource_get_etag(Config, Type) -> rest_resource_get_etag(Config, Type, []). @@ -806,6 +931,34 @@ set_resp_overwrite(Config) -> {<<"server">>, <<"DesireDrive/1.0">>} = lists:keyfind(<<"server">>, 1, Headers). +slowloris(Config) -> + Client = ?config(client, Config), + Transport = ?config(transport, Config), + {ok, Client2} = cowboy_client:connect( + Transport, "localhost", ?config(port, Config), Client), + try + [begin + {ok, _} = cowboy_client:raw_request([C], Client2), + receive after 25 -> ok end + end || C <- "GET / HTTP/1.1\r\nHost: localhost\r\n" + "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US)\r\n" + "Cookie: name=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n\r\n"], + error(failure) + catch error:{badmatch, _} -> + ok + end. + +slowloris2(Config) -> + Client = ?config(client, Config), + Transport = ?config(transport, Config), + {ok, Client2} = cowboy_client:connect( + Transport, "localhost", ?config(port, Config), Client), + {ok, _} = cowboy_client:raw_request("GET / HTTP/1.1\r\n", Client2), + receive after 300 -> ok end, + {ok, _} = cowboy_client:raw_request("Host: localhost\r\n", Client2), + receive after 300 -> ok end, + {ok, 408, _, _} = cowboy_client:response(Client2). + static_attribute_etag(Config) -> Client = ?config(client, Config), {ok, Client2} = cowboy_client:request(<<"GET">>, @@ -892,6 +1045,22 @@ stream_body_set_resp(Config) -> {ok, <<"stream_body_set_resp">>, _} = cowboy_client:response_body(Client3). +stream_body_set_resp_close(Config) -> + Client = ?config(client, Config), + {ok, Client2} = cowboy_client:request(<<"GET">>, + build_url("/stream_body/set_resp_close", Config), Client), + {ok, 200, _, Client3} = cowboy_client:response(Client2), + {ok, Transport, Socket} = cowboy_client:transport(Client3), + case element(7, Client3) of + <<"stream_body_set_resp_close">> -> + ok; + Buffer -> + {ok, Rest} = Transport:recv(Socket, 26 - byte_size(Buffer), 1000), + <<"stream_body_set_resp_close">> = << Buffer/binary, Rest/binary >>, + ok + end, + {error, closed} = Transport:recv(Socket, 0, 1000). + te_chunked(Config) -> Client = ?config(client, Config), Body = list_to_binary(io_lib:format("~p", [lists:seq(1, 100)])), @@ -903,6 +1072,21 @@ te_chunked(Config) -> {ok, 200, _, Client3} = cowboy_client:response(Client2), {ok, Body, _} = cowboy_client:response_body(Client3). +te_chunked_chopped(Config) -> + Client = ?config(client, Config), + Body = list_to_binary(io_lib:format("~p", [lists:seq(1, 100)])), + Body2 = iolist_to_binary(body_to_chunks(50, Body, [])), + {ok, Client2} = cowboy_client:request(<<"GET">>, + build_url("/echo/body", Config), + [{<<"transfer-encoding">>, <<"chunked">>}], Client), + {ok, Transport, Socket} = cowboy_client:transport(Client2), + _ = [begin + ok = Transport:send(Socket, << C >>), + ok = timer:sleep(10) + end || << C >> <= Body2], + {ok, 200, _, Client3} = cowboy_client:response(Client2), + {ok, Body, _} = cowboy_client:response_body(Client3). + te_chunked_delayed(Config) -> Client = ?config(client, Config), Body = list_to_binary(io_lib:format("~p", [lists:seq(1, 100)])), diff --git a/test/http_handler.erl b/test/http_handler.erl index e569adb..e1f1665 100644 --- a/test/http_handler.erl +++ b/test/http_handler.erl @@ -2,7 +2,7 @@ -module(http_handler). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). -record(state, {headers, body}). @@ -15,5 +15,5 @@ handle(Req, State=#state{headers=Headers, body=Body}) -> {ok, Req2} = cowboy_req:reply(200, Headers, Body, Req), {ok, Req2, State}. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/http_handler_echo_body.erl b/test/http_handler_echo_body.erl index e4b1ee0..31595d5 100644 --- a/test/http_handler_echo_body.erl +++ b/test/http_handler_echo_body.erl @@ -2,18 +2,18 @@ -module(http_handler_echo_body). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_, http}, Req, _) -> {ok, Req, undefined}. handle(Req, State) -> - {true, Req1} = cowboy_req:has_body(Req), - {ok, Body, Req2} = cowboy_req:body(Req1), + true = cowboy_req:has_body(Req), + {ok, Body, Req2} = cowboy_req:body(Req), {Size, Req3} = cowboy_req:body_length(Req2), Size = byte_size(Body), {ok, Req4} = cowboy_req:reply(200, [], Body, Req3), {ok, Req4, State}. -terminate(_, _) -> +terminate(_, _, _) -> ok. diff --git a/test/http_handler_errors.erl b/test/http_handler_errors.erl index 30cbaeb..2d1066c 100644 --- a/test/http_handler_errors.erl +++ b/test/http_handler_errors.erl @@ -2,7 +2,7 @@ -module(http_handler_errors). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_Transport, http}, Req, _Opts) -> {Case, Req1} = cowboy_req:qs_val(<<"case">>, Req), @@ -36,5 +36,5 @@ handle(Req, <<"handle_after_reply">> = Case) -> {ok, _Req1} = cowboy_req:reply(200, [], "http_handler_crashes", Req), erlang:error(Case). -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/http_handler_init_shutdown.erl b/test/http_handler_init_shutdown.erl index edea1a0..fd01983 100644 --- a/test/http_handler_init_shutdown.erl +++ b/test/http_handler_init_shutdown.erl @@ -2,7 +2,7 @@ -module(http_handler_init_shutdown). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_Transport, http}, Req, _Opts) -> {ok, Req2} = cowboy_req:reply(<<"666 Init Shutdown Testing">>, @@ -13,5 +13,5 @@ handle(Req, State) -> {ok, Req2} = cowboy_req:reply(200, [], "Hello world!", Req), {ok, Req2, State}. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/http_handler_long_polling.erl b/test/http_handler_long_polling.erl index d61d697..763e1fe 100644 --- a/test/http_handler_long_polling.erl +++ b/test/http_handler_long_polling.erl @@ -2,7 +2,7 @@ -module(http_handler_long_polling). -behaviour(cowboy_http_handler). --export([init/3, handle/2, info/3, terminate/2]). +-export([init/3, handle/2, info/3, terminate/3]). init({_Transport, http}, Req, _Opts) -> erlang:send_after(500, self(), timeout), @@ -18,5 +18,5 @@ info(timeout, Req, State) -> erlang:send_after(500, self(), timeout), {loop, Req, State - 1, hibernate}. -terminate(_Req, _State) -> +terminate({normal, shutdown}, _, _) -> ok. diff --git a/test/http_handler_loop_timeout.erl b/test/http_handler_loop_timeout.erl index c9bb15f..0155b1e 100644 --- a/test/http_handler_loop_timeout.erl +++ b/test/http_handler_loop_timeout.erl @@ -2,7 +2,7 @@ -module(http_handler_loop_timeout). -behaviour(cowboy_loop_handler). --export([init/3, info/3, terminate/2]). +-export([init/3, info/3, terminate/3]). init({_, http}, Req, _) -> erlang:send_after(1000, self(), error_timeout), @@ -12,5 +12,5 @@ info(error_timeout, Req, State) -> {ok, Req2} = cowboy_req:reply(500, Req), {ok, Req2, State}. -terminate(_, _) -> +terminate({normal, timeout}, _, _) -> ok. diff --git a/test/http_handler_multipart.erl b/test/http_handler_multipart.erl index 850574f..8209535 100644 --- a/test/http_handler_multipart.erl +++ b/test/http_handler_multipart.erl @@ -2,7 +2,7 @@ -module(http_handler_multipart). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_Transport, http}, Req, []) -> {ok, Req, {}}. @@ -12,7 +12,7 @@ handle(Req, State) -> {ok, Req3} = cowboy_req:reply(200, [], term_to_binary(Result), Req2), {ok, Req3, State}. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. acc_multipart(Req) -> diff --git a/test/http_handler_set_resp.erl b/test/http_handler_set_resp.erl index 70ddf79..d00d72a 100644 --- a/test/http_handler_set_resp.erl +++ b/test/http_handler_set_resp.erl @@ -2,7 +2,7 @@ -module(http_handler_set_resp). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). init({_Transport, http}, Req, Opts) -> Headers = proplists:get_value(headers, Opts, []), @@ -27,5 +27,5 @@ handle(Req, State) -> end end. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/http_handler_stream_body.erl b/test/http_handler_stream_body.erl index feb4f78..5e42fa7 100644 --- a/test/http_handler_stream_body.erl +++ b/test/http_handler_stream_body.erl @@ -2,7 +2,7 @@ -module(http_handler_stream_body). -behaviour(cowboy_http_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3, handle/2, terminate/3]). -record(state, {headers, body, reply}). @@ -12,13 +12,17 @@ init({_Transport, http}, Req, Opts) -> Reply = proplists:get_value(reply, Opts), {ok, Req, #state{headers=Headers, body=Body, reply=Reply}}. -handle(Req, State=#state{headers=_Headers, body=Body, reply=set_resp}) -> - {ok, Transport, Socket} = cowboy_req:transport(Req), - SFun = fun() -> Transport:send(Socket, Body), sent end, - SLen = iolist_size(Body), - Req2 = cowboy_req:set_resp_body_fun(SLen, SFun, Req), +handle(Req, State=#state{headers=_Headers, body=Body, reply=Reply}) -> + SFun = fun(Socket, Transport) -> Transport:send(Socket, Body) end, + Req2 = case Reply of + set_resp -> + SLen = iolist_size(Body), + cowboy_req:set_resp_body_fun(SLen, SFun, Req); + set_resp_close -> + cowboy_req:set_resp_body_fun(SFun, Req) + end, {ok, Req3} = cowboy_req:reply(200, Req2), {ok, Req3, State}. -terminate(_Req, _State) -> +terminate(_, _, _) -> ok. diff --git a/test/rest_created_path_resource.erl b/test/rest_created_path_resource.erl new file mode 100644 index 0000000..5ad8cfc --- /dev/null +++ b/test/rest_created_path_resource.erl @@ -0,0 +1,35 @@ +-module(rest_created_path_resource). +-export([init/3]). +-export([allowed_methods/2]). +-export([content_types_provided/2]). +-export([get_text_plain/2]). +-export([post_is_create/2]). +-export([content_types_accepted/2]). +-export([post_text_plain/2]). +-export([created_path/2]). + +init(_Transport, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +allowed_methods(Req, State) -> +{[<<"HEAD">>, <<"GET">>, <<"POST">>], Req, State}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. + +get_text_plain(Req, State) -> + {<<"This is REST!">>, Req, State}. + +post_is_create(Req, State) -> + {true, Req, State}. + +content_types_accepted(Req, State) -> + {[{{<<"text">>, <<"plain">>, []}, post_text_plain}], Req, State}. + +post_text_plain(Req, State) -> + {true, Req, State}. + +created_path(Req, State) -> + {<<"/created">>, Req, State}. + + diff --git a/test/rest_patch_resource.erl b/test/rest_patch_resource.erl new file mode 100644 index 0000000..e265f6f --- /dev/null +++ b/test/rest_patch_resource.erl @@ -0,0 +1,34 @@ +-module(rest_patch_resource). +-export([init/3, allowed_methods/2, content_types_provided/2, get_text_plain/2, + content_types_accepted/2, patch_text_plain/2]). + +init(_Transport, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +allowed_methods(Req, State) -> + {[<<"HEAD">>, <<"GET">>, <<"PATCH">>], Req, State}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. + +get_text_plain(Req, State) -> + {<<"This is REST!">>, Req, State}. + +content_types_accepted(Req, State) -> + case cowboy_req:method(Req) of + {<<"PATCH">>, Req0} -> + {[{{<<"text">>, <<"plain">>, []}, patch_text_plain}], Req0, State}; + {_, Req0} -> + {[], Req0, State} + end. + +patch_text_plain(Req, State) -> + case cowboy_req:body(Req) of + {ok, <<"halt">>, Req0} -> + {ok, Req1} = cowboy_req:reply(400, Req0), + {halt, Req1, State}; + {ok, <<"false">>, Req0} -> + {false, Req0, State}; + {ok, _Body, Req0} -> + {true, Req0, State} + end. diff --git a/test/websocket_echo_handler.erl b/test/websocket_echo_handler.erl index 926b51d..21b0116 100644 --- a/test/websocket_echo_handler.erl +++ b/test/websocket_echo_handler.erl @@ -1,21 +1,14 @@ %% Feel free to use, reuse and abuse the code in this file. -module(websocket_echo_handler). --behaviour(cowboy_http_handler). -behaviour(cowboy_websocket_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3]). -export([websocket_init/3, websocket_handle/3, websocket_info/3, websocket_terminate/3]). init(_Any, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. -handle(_Req, _State) -> - exit(badarg). - -terminate(_Req, _State) -> - exit(badarg). - websocket_init(_TransportName, Req, _Opts) -> Req2 = cowboy_req:compact(Req), {ok, Req2, undefined}. diff --git a/test/websocket_handler.erl b/test/websocket_handler.erl index caf4828..a9863ae 100644 --- a/test/websocket_handler.erl +++ b/test/websocket_handler.erl @@ -1,21 +1,14 @@ %% Feel free to use, reuse and abuse the code in this file. -module(websocket_handler). --behaviour(cowboy_http_handler). -behaviour(cowboy_websocket_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3]). -export([websocket_init/3, websocket_handle/3, websocket_info/3, websocket_terminate/3]). init(_Any, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. -handle(_Req, _State) -> - exit(badarg). - -terminate(_Req, _State) -> - exit(badarg). - websocket_init(_TransportName, Req, _Opts) -> erlang:start_timer(1000, self(), <<"websocket_init">>), Req2 = cowboy_req:compact(Req), diff --git a/test/websocket_handler_init_shutdown.erl b/test/websocket_handler_init_shutdown.erl index 5fdfba3..7ccea05 100644 --- a/test/websocket_handler_init_shutdown.erl +++ b/test/websocket_handler_init_shutdown.erl @@ -1,21 +1,14 @@ %% Feel free to use, reuse and abuse the code in this file. -module(websocket_handler_init_shutdown). --behaviour(cowboy_http_handler). -behaviour(cowboy_websocket_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3]). -export([websocket_init/3, websocket_handle/3, websocket_info/3, websocket_terminate/3]). init(_Any, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. -handle(_Req, _State) -> - exit(badarg). - -terminate(_Req, _State) -> - exit(badarg). - websocket_init(_TransportName, Req, _Opts) -> {ok, Req2} = cowboy_req:reply(403, Req), {shutdown, Req2}. diff --git a/test/ws_SUITE.erl b/test/ws_SUITE.erl index 34befda..06d4b3e 100644 --- a/test/ws_SUITE.erl +++ b/test/ws_SUITE.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2011, Loïc Hoguin <[email protected]> +%% Copyright (c) 2011-2013, Loïc Hoguin <[email protected]> %% %% Permission to use, copy, modify, and/or distribute this software for any %% purpose with or without fee is hereby granted, provided that the above @@ -63,7 +63,6 @@ groups() -> [{ws, [], BaseTests}]. init_per_suite(Config) -> - application:start(inets), application:start(crypto), application:start(ranch), application:start(cowboy), @@ -73,13 +72,12 @@ end_per_suite(_Config) -> application:stop(cowboy), application:stop(ranch), application:stop(crypto), - application:stop(inets), ok. init_per_group(ws, Config) -> Port = 33080, cowboy:start_http(ws, 100, [{port, Port}], [ - {dispatch, init_dispatch()} + {env, [{dispatch, init_dispatch()}]} ]), [{port, Port}|Config]. @@ -90,42 +88,39 @@ end_per_group(Listener, _Config) -> %% Dispatch configuration. init_dispatch() -> - [ - {[<<"localhost">>], [ - {[<<"websocket">>], websocket_handler, []}, - {[<<"ws_echo_handler">>], websocket_echo_handler, []}, - {[<<"ws_init_shutdown">>], websocket_handler_init_shutdown, []}, - {[<<"ws_send_many">>], ws_send_many_handler, [ + cowboy_router:compile([ + {"localhost", [ + {"/websocket", websocket_handler, []}, + {"/ws_echo_handler", websocket_echo_handler, []}, + {"/ws_init_shutdown", websocket_handler_init_shutdown, []}, + {"/ws_send_many", ws_send_many_handler, [ {sequence, [ {text, <<"one">>}, {text, <<"two">>}, {text, <<"seven!">>}]} ]}, - {[<<"ws_send_close">>], ws_send_many_handler, [ + {"/ws_send_close", ws_send_many_handler, [ {sequence, [ {text, <<"send">>}, close, {text, <<"won't be received">>}]} ]}, - {[<<"ws_send_close_payload">>], ws_send_many_handler, [ + {"/ws_send_close_payload", ws_send_many_handler, [ {sequence, [ {text, <<"send">>}, {close, 1001, <<"some text!">>}, {text, <<"won't be received">>}]} ]}, - {[<<"ws_timeout_hibernate">>], ws_timeout_hibernate_handler, []}, - {[<<"ws_timeout_cancel">>], ws_timeout_cancel_handler, []}, - {[<<"ws_upgrade_with_opts">>], ws_upgrade_with_opts_handler, + {"/ws_timeout_hibernate", ws_timeout_hibernate_handler, []}, + {"/ws_timeout_cancel", ws_timeout_cancel_handler, []}, + {"/ws_upgrade_with_opts", ws_upgrade_with_opts_handler, <<"failure">>} ]} - ]. + ]). %% ws and wss. -%% This test makes sure the code works even if we wait for a reply -%% before sending the third challenge key in the GET body. -%% -%% This ensures that Cowboy will work fine with proxies on hixie. +%% We do not support hixie76 anymore. ws0(Config) -> {port, Port} = lists:keyfind(port, 1, Config), {ok, Socket} = gen_tcp:connect("localhost", Port, @@ -140,34 +135,8 @@ ws0(Config) -> "Sec-Websocket-Key2: 1711 M;4\\74 80<6\r\n" "\r\n"), {ok, Handshake} = gen_tcp:recv(Socket, 0, 6000), - {ok, {http_response, {1, 1}, 101, "WebSocket Protocol Handshake"}, 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-location", "ws://localhost/websocket"} - = lists:keyfind("sec-websocket-location", 1, Headers), - {"sec-websocket-origin", "http://localhost"} - = lists:keyfind("sec-websocket-origin", 1, Headers), - ok = gen_tcp:send(Socket, <<15,245,8,18,2,204,133,33>>), - {ok, Body} = gen_tcp:recv(Socket, 0, 6000), - <<169,244,191,103,146,33,149,59,74,104,67,5,99,118,171,236>> = Body, - ok = gen_tcp:send(Socket, << 0, "client_msg", 255 >>), - {ok, << 0, "client_msg", 255 >>} = gen_tcp:recv(Socket, 0, 6000), - {ok, << 0, "websocket_init", 255 >>} = gen_tcp:recv(Socket, 0, 6000), - {ok, << 0, "websocket_handle", 255 >>} = gen_tcp:recv(Socket, 0, 6000), - {ok, << 0, "websocket_handle", 255 >>} = gen_tcp:recv(Socket, 0, 6000), - {ok, << 0, "websocket_handle", 255 >>} = gen_tcp:recv(Socket, 0, 6000), - %% We try to send another HTTP request to make sure - %% the server closed the request. - ok = gen_tcp:send(Socket, [ - << 255, 0 >>, %% Close websocket command. - "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" %% Server should ignore it. - ]), - {ok, << 255, 0 >>} = gen_tcp:recv(Socket, 0, 6000), - {error, closed} = gen_tcp:recv(Socket, 0, 6000), - ok. + {ok, {http_response, {1, 1}, 400, _}, _} + = erlang:decode_packet(http, Handshake, []). ws8(Config) -> {port, Port} = lists:keyfind(port, 1, Config), @@ -203,9 +172,9 @@ ws8(Config) -> = gen_tcp:recv(Socket, 0, 6000), {ok, << 1:1, 0:3, 1:4, 0:1, 16:7, "websocket_handle" >>} = gen_tcp:recv(Socket, 0, 6000), - ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 0:8 >>), %% ping + ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 1:1, 0:7, 0:32 >>), %% ping {ok, << 1:1, 0:3, 10:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), %% pong - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -254,7 +223,7 @@ ws8_single_bytes(Config) -> ok = gen_tcp:send(Socket, << 16#81 >>), %% send one byte ok = timer:sleep(100), %% sleep for a period ok = gen_tcp:send(Socket, << 16#85 >>), %% send another and so on - ok = timer:sleep(100), + ok = timer:sleep(100), ok = gen_tcp:send(Socket, << 16#37 >>), ok = timer:sleep(100), ok = gen_tcp:send(Socket, << 16#fa >>), @@ -282,9 +251,9 @@ ws8_single_bytes(Config) -> = gen_tcp:recv(Socket, 0, 6000), {ok, << 1:1, 0:3, 1:4, 0:1, 16:7, "websocket_handle" >>} = gen_tcp:recv(Socket, 0, 6000), - ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 0:8 >>), %% ping + ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 1:1, 0:7, 0:32 >>), %% ping {ok, << 1:1, 0:3, 10:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), %% pong - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -317,7 +286,7 @@ ws13(Config) -> {ok, << 1:1, 0:3, 1:4, 0:1, 5:7, "Hello" >>} = gen_tcp:recv(Socket, 0, 6000), %% binary (empty) - ok = gen_tcp:send(Socket, << 1:1, 0:3, 2:4, 0:8 >>), + ok = gen_tcp:send(Socket, << 1:1, 0:3, 2:4, 1:1, 0:7, 0:32 >>), {ok, << 1:1, 0:3, 2:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), %% binary ok = gen_tcp:send(Socket, << 16#82, 16#85, 16#37, 16#fa, 16#21, 16#3d, @@ -333,9 +302,9 @@ ws13(Config) -> = gen_tcp:recv(Socket, 0, 6000), {ok, << 1:1, 0:3, 1:4, 0:1, 16:7, "websocket_handle" >>} = gen_tcp:recv(Socket, 0, 6000), - ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 0:8 >>), %% ping + ok = gen_tcp:send(Socket, << 1:1, 0:3, 9:4, 1:1, 0:7, 0:32 >>), %% ping {ok, << 1:1, 0:3, 10:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), %% pong - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -425,7 +394,7 @@ ws_send_many(Config) -> << 1:1, 0:3, 1:4, 0:1, 3:7, "one", 1:1, 0:3, 1:4, 0:1, 3:7, "two", 1:1, 0:3, 1:4, 0:1, 6:7, "seven!" >> = Many, - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -479,8 +448,7 @@ ws_text_fragments(Config) -> << 16#9f >>, << 16#4d >>, << 16#51 >>, << 16#58 >>]), {ok, << 1:1, 0:3, 1:4, 0:1, 15:7, "HelloHelloHello" >>} = gen_tcp:recv(Socket, 0, 6000), - - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -507,7 +475,7 @@ ws_timeout_hibernate(Config) -> {'Upgrade', "websocket"} = lists:keyfind('Upgrade', 1, Headers), {"sec-websocket-accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="} = lists:keyfind("sec-websocket-accept", 1, Headers), - {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), + {ok, << 1:1, 0:3, 8:4, 0:1, 2:7, 1000:16 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -534,7 +502,7 @@ ws_timeout_cancel(Config) -> {'Upgrade', "websocket"} = lists:keyfind('Upgrade', 1, Headers), {"sec-websocket-accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="} = lists:keyfind("sec-websocket-accept", 1, Headers), - {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), + {ok, << 1:1, 0:3, 8:4, 0:1, 2:7, 1000:16 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -547,41 +515,28 @@ ws_timeout_reset(Config) -> "GET /ws_timeout_cancel HTTP/1.1\r\n" "Host: localhost\r\n" "Connection: Upgrade\r\n" - "Upgrade: WebSocket\r\n" - "Origin: http://localhost\r\n" - "Sec-Websocket-Key1: Y\" 4 1Lj!957b8@0H756!i\r\n" - "Sec-Websocket-Key2: 1711 M;4\\74 80<6\r\n" + "Upgrade: websocket\r\n" + "Sec-WebSocket-Origin: http://localhost\r\n" + "Sec-Websocket-Version: 13\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" "\r\n"]), {ok, Handshake} = gen_tcp:recv(Socket, 0, 6000), - {ok, {http_response, {1, 1}, 101, "WebSocket Protocol Handshake"}, Rest} + {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-location", "ws://localhost/ws_timeout_cancel"} - = lists:keyfind("sec-websocket-location", 1, Headers), - {"sec-websocket-origin", "http://localhost"} - = lists:keyfind("sec-websocket-origin", 1, Headers), - ok = gen_tcp:send(Socket, <<15,245,8,18,2,204,133,33>>), - {ok, Body} = gen_tcp:recv(Socket, 0, 6000), - <<169,244,191,103,146,33,149,59,74,104,67,5,99,118,171,236>> = Body, - ok = gen_tcp:send(Socket, << 0, "msg sent", 255 >>), - {ok, << 0, "msg sent", 255 >>} - = gen_tcp:recv(Socket, 0, 6000), - ok = timer:sleep(500), - ok = gen_tcp:send(Socket, << 0, "msg sent", 255 >>), - {ok, << 0, "msg sent", 255 >>} - = gen_tcp:recv(Socket, 0, 6000), - ok = timer:sleep(500), - ok = gen_tcp:send(Socket, << 0, "msg sent", 255 >>), - {ok, << 0, "msg sent", 255 >>} - = gen_tcp:recv(Socket, 0, 6000), - ok = timer:sleep(500), - ok = gen_tcp:send(Socket, << 0, "msg sent", 255 >>), - {ok, << 0, "msg sent", 255 >>} - = gen_tcp:recv(Socket, 0, 6000), - {ok, << 255, 0 >>} = gen_tcp:recv(Socket, 0, 6000), + {'Upgrade', "websocket"} = lists:keyfind('Upgrade', 1, Headers), + {"sec-websocket-accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="} + = lists:keyfind("sec-websocket-accept", 1, Headers), + [begin + ok = gen_tcp:send(Socket, << 16#81, 16#85, 16#37, 16#fa, 16#21, 16#3d, + 16#7f, 16#9f, 16#4d, 16#51, 16#58 >>), + {ok, << 1:1, 0:3, 1:4, 0:1, 5:7, "Hello" >>} + = gen_tcp:recv(Socket, 0, 6000), + ok = timer:sleep(500) + end || _ <- [1, 2, 3, 4]], + {ok, << 1:1, 0:3, 8:4, 0:1, 2:7, 1000:16 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. @@ -609,7 +564,7 @@ ws_upgrade_with_opts(Config) -> = lists:keyfind("sec-websocket-accept", 1, Headers), {ok, Response} = gen_tcp:recv(Socket, 9, 6000), << 1:1, 0:3, 1:4, 0:1, 7:7, "success" >> = Response, - ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>), %% close + ok = gen_tcp:send(Socket, << 1:1, 0:3, 8:4, 1:1, 0:7, 0:32 >>), %% close {ok, << 1:1, 0:3, 8:4, 0:8 >>} = gen_tcp:recv(Socket, 0, 6000), {error, closed} = gen_tcp:recv(Socket, 0, 6000), ok. diff --git a/test/ws_timeout_cancel_handler.erl b/test/ws_timeout_cancel_handler.erl index ee75d9b..68b0468 100644 --- a/test/ws_timeout_cancel_handler.erl +++ b/test/ws_timeout_cancel_handler.erl @@ -1,21 +1,14 @@ %% Feel free to use, reuse and abuse the code in this file. -module(ws_timeout_cancel_handler). --behaviour(cowboy_http_handler). -behaviour(cowboy_websocket_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3]). -export([websocket_init/3, websocket_handle/3, websocket_info/3, websocket_terminate/3]). init(_Any, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. -handle(_Req, _State) -> - exit(badarg). - -terminate(_Req, _State) -> - exit(badarg). - websocket_init(_TransportName, Req, _Opts) -> erlang:start_timer(500, self(), should_not_cancel_timer), {ok, Req, undefined, 1000}. diff --git a/test/ws_timeout_hibernate_handler.erl b/test/ws_timeout_hibernate_handler.erl index ac6ee4f..41b9edd 100644 --- a/test/ws_timeout_hibernate_handler.erl +++ b/test/ws_timeout_hibernate_handler.erl @@ -1,21 +1,14 @@ %% Feel free to use, reuse and abuse the code in this file. -module(ws_timeout_hibernate_handler). --behaviour(cowboy_http_handler). -behaviour(cowboy_websocket_handler). --export([init/3, handle/2, terminate/2]). +-export([init/3]). -export([websocket_init/3, websocket_handle/3, websocket_info/3, websocket_terminate/3]). init(_Any, _Req, _Opts) -> {upgrade, protocol, cowboy_websocket}. -handle(_Req, _State) -> - exit(badarg). - -terminate(_Req, _State) -> - exit(badarg). - websocket_init(_TransportName, Req, _Opts) -> {ok, Req, undefined, 1000, hibernate}. |