Browse Source

Merge branch 'issue-114-tests' of https://github.com/klaar/cowboy into gracefully-handle-crashes

Conflicts:
	test/http_SUITE.erl
Loïc Hoguin 13 years ago
parent
commit
5095c27c65
2 changed files with 115 additions and 4 deletions
  1. 75 4
      test/http_SUITE.erl
  2. 40 0
      test/http_handler_errors.erl

+ 75 - 4
test/http_SUITE.erl

@@ -23,8 +23,9 @@
 	pipeline/1, raw/1, set_resp_header/1, set_resp_overwrite/1,
 	pipeline/1, raw/1, set_resp_header/1, set_resp_overwrite/1,
 	set_resp_body/1, stream_body_set_resp/1, response_as_req/1,
 	set_resp_body/1, stream_body_set_resp/1, response_as_req/1,
 	static_mimetypes_function/1]). %% http.
 	static_mimetypes_function/1]). %% http.
--export([http_200/1, http_404/1, file_200/1, file_403/1,
-	dir_403/1, file_404/1, file_400/1]). %% http and https.
+-export([http_200/1, http_404/1, handler_errors/1,
+	file_200/1, file_403/1, dir_403/1, file_404/1,
+	file_400/1]). %% http and https.
 -export([http_10_hostless/1]). %% misc.
 -export([http_10_hostless/1]). %% misc.
 -export([rest_simple/1, rest_keepalive/1]). %% rest.
 -export([rest_simple/1, rest_keepalive/1]). %% rest.
 
 
@@ -34,8 +35,8 @@ all() ->
 	[{group, http}, {group, https}, {group, misc}, {group, rest}].
 	[{group, http}, {group, https}, {group, misc}, {group, rest}].
 
 
 groups() ->
 groups() ->
-	BaseTests = [http_200, http_404, file_200, file_403, dir_403, file_404,
-		file_400],
+	BaseTests = [http_200, http_404, handler_errors,
+		file_200, file_403, dir_403, file_404, file_400],
 	[{http, [], [chunked_response, headers_dupe, headers_huge,
 	[{http, [], [chunked_response, headers_dupe, headers_huge,
 		keepalive_nl, max_keepalive, nc_rand, nc_zero, pipeline, raw,
 		keepalive_nl, max_keepalive, nc_rand, nc_zero, pipeline, raw,
 		set_resp_header, set_resp_overwrite,
 		set_resp_header, set_resp_overwrite,
@@ -134,6 +135,7 @@ init_http_dispatch(Config) ->
 				[{directory, ?config(static_dir, Config)},
 				[{directory, ?config(static_dir, Config)},
 				 {mimetypes, {fun(Path, data) when is_binary(Path) ->
 				 {mimetypes, {fun(Path, data) when is_binary(Path) ->
 					[<<"text/html">>] end, data}}]},
 					[<<"text/html">>] end, data}}]},
+			{[<<"handler_errors">>], http_handler_errors, []},
 			{[], http_handler, []}
 			{[], http_handler, []}
 		]}
 		]}
 	].
 	].
@@ -295,6 +297,40 @@ raw_req(Packet, Config) ->
 	gen_tcp:close(Socket),
 	gen_tcp:close(Socket),
 	{Packet, Res}.
 	{Packet, Res}.
 
 
+%% Send a raw request. Return the response code and the full response.
+raw_resp(Request, Config) ->
+   	{port, Port} = lists:keyfind(port, 1, Config),
+	Transport = case ?config(scheme, Config) of
+		"http" -> gen_tcp;
+		"https" -> ssl
+	end,
+	{ok, Socket} = Transport:connect("localhost", Port,
+		[binary, {active, false}, {packet, raw}]),
+	ok = Transport:send(Socket, Request),
+	{StatusCode,  Response} = case recv_loop(Transport, Socket, <<>>) of
+		{ok, << "HTTP/1.1 ", Str:24/bits, _Rest/bits >> = Bin} ->
+			{list_to_integer(binary_to_list(Str)), Bin};
+		{ok, Bin} ->
+			{badresp, Bin};
+		{error, Reason} ->
+			{Reason, <<>>}
+	end,
+	Transport:close(Socket),
+	{Response, StatusCode}.
+
+recv_loop(Transport, Socket, Acc) ->
+	case Transport:recv(Socket, 0, 6000) of
+		{ok, Data} ->
+			recv_loop(Transport, Socket, <<Acc/binary, Data/binary>>);
+		{error, closed} ->
+			ok = Transport:close(Socket),
+			{ok, Acc};
+		{error, Reason} ->
+			{error, Reason}
+	end.
+
+
+
 raw(Config) ->
 raw(Config) ->
 	Huge = [$0 || _N <- lists:seq(1, 5000)],
 	Huge = [$0 || _N <- lists:seq(1, 5000)],
 	Tests = [
 	Tests = [
@@ -386,6 +422,41 @@ static_mimetypes_function(Config) ->
 		httpc:request(TestURL),
 		httpc:request(TestURL),
 	"text/html" = ?config("content-type", Headers1).
 	"text/html" = ?config("content-type", Headers1).
 
 
+handler_errors(Config) ->
+	Request = fun(Case) ->
+		raw_resp(["GET /handler_errors?case=", Case, " HTTP/1.1\r\n",
+		 "Host: localhost\r\n\r\n"], Config) end,
+
+	{_Packet1, 500} = Request("init_before_reply"),
+
+	{Packet2, 200} = Request("init_after_reply"),
+	nomatch = binary:match(Packet2, <<"HTTP/1.1 500">>),
+
+	{Packet3, 200} = Request("init_reply_handle_error"),
+	nomatch = binary:match(Packet3, <<"HTTP/1.1 500">>),
+
+	{_Packet4, 500} = Request("handle_before_reply"),
+
+	{Packet5, 200} = Request("handle_after_reply"),
+	nomatch = binary:match(Packet5, <<"HTTP/1.1 500">>),
+
+	{Packet6, 200} = raw_resp([
+		"GET / HTTP/1.1\r\n",
+		"Host: localhost\r\n",
+		"Connection: keep-alive\r\n\r\n",
+		"GET /handler_errors?case=handle_after_reply\r\n",
+		"Host: localhost\r\n\r\n"], Config),
+	nomatch = binary:match(Packet6, <<"HTTP/1.1 500">>),
+
+	{Packet7, 200} = raw_resp([
+		"GET / HTTP/1.1\r\n",
+		"Host: localhost\r\n",
+		"Connection: keep-alive\r\n\r\n",
+		"GET /handler_errors?case=handle_before_reply HTTP/1.1\r\n",
+		"Host: localhost\r\n\r\n"], Config),
+	{{_, _}, _} = {binary:match(Packet7, <<"HTTP/1.1 500">>), Packet7},
+
+	done.
 
 
 %% http and https.
 %% http and https.
 
 

+ 40 - 0
test/http_handler_errors.erl

@@ -0,0 +1,40 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+-module(http_handler_errors).
+-behaviour(cowboy_http_handler).
+-export([init/3, handle/2, terminate/2]).
+
+init({_Transport, http}, Req, _Opts) ->
+    {Case, Req1} = cowboy_http_req:qs_val(<<"case">>, Req),
+    case_init(Case, Req1).
+
+case_init(<<"init_before_reply">> = Case, _Req) ->
+    erlang:error(Case);
+
+case_init(<<"init_after_reply">> = Case, Req) ->
+    {ok, _Req1} = cowboy_http_req:reply(200, [], "http_handler_crashes", Req),
+    erlang:error(Case);
+
+case_init(<<"init_reply_handle_error">> = Case, Req) ->
+    {ok, Req1} = cowboy_http_req:reply(200, [], "http_handler_crashes", Req),
+    {ok, Req1, Case};
+
+case_init(<<"handle_before_reply">> = Case, Req) ->
+    {ok, Req, Case};
+
+case_init(<<"handle_after_reply">> = Case, Req) ->
+    {ok, Req, Case}.
+
+
+handle(_Req, <<"init_reply_handle_error">> = Case) ->
+    erlang:error(Case);
+
+handle(_Req, <<"handle_before_reply">> = Case) ->
+    erlang:error(Case);
+
+handle(Req, <<"handle_after_reply">> = Case) ->
+    {ok, _Req1} = cowboy_http_req:reply(200, [], "http_handler_crashes", Req),
+    erlang:error(Case).
+
+terminate(_Req, _State) ->
+	ok.