aboutsummaryrefslogtreecommitdiffstats
path: root/test/req_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'test/req_SUITE.erl')
-rw-r--r--test/req_SUITE.erl80
1 files changed, 70 insertions, 10 deletions
diff --git a/test/req_SUITE.erl b/test/req_SUITE.erl
index c724dea..3a223d9 100644
--- a/test/req_SUITE.erl
+++ b/test/req_SUITE.erl
@@ -83,9 +83,23 @@ do_body(Method, Path, Headers0, Body, Config) ->
gun:close(ConnPid),
do_decode(RespHeaders, RespBody).
+do_body_error(Method, Path, Headers0, Body, Config) ->
+ ConnPid = gun_open(Config),
+ Headers = [{<<"accept-encoding">>, <<"gzip">>}|Headers0],
+ Ref = case Body of
+ <<>> -> gun:request(ConnPid, Method, Path, Headers);
+ _ -> gun:request(ConnPid, Method, Path, Headers, Body)
+ end,
+ {response, _, Status, RespHeaders} = gun:await(ConnPid, Ref),
+ gun:close(ConnPid),
+ {Status, RespHeaders}.
+
do_get(Path, Config) ->
+ do_get(Path, [], Config).
+
+do_get(Path, Headers, Config) ->
ConnPid = gun_open(Config),
- Ref = gun:get(ConnPid, Path, [{<<"accept-encoding">>, <<"gzip">>}]),
+ Ref = gun:get(ConnPid, Path, [{<<"accept-encoding">>, <<"gzip">>}|Headers]),
{response, IsFin, Status, RespHeaders} = gun:await(ConnPid, Ref),
{ok, RespBody} = case IsFin of
nofin -> gun:await_body(ConnPid, Ref);
@@ -178,13 +192,13 @@ method(Config) ->
do_method("/direct/method", Config).
do_method(Path, Config) ->
- <<"GET">> = do_body("GET", "/method", Config),
- <<>> = do_body("HEAD", "/method", Config),
- <<"OPTIONS">> = do_body("OPTIONS", "/method", Config),
- <<"PATCH">> = do_body("PATCH", "/method", Config),
- <<"POST">> = do_body("POST", "/method", Config),
- <<"PUT">> = do_body("PUT", "/method", Config),
- <<"ZZZZZZZZ">> = do_body("ZZZZZZZZ", "/method", Config),
+ <<"GET">> = do_body("GET", Path, Config),
+ <<>> = do_body("HEAD", Path, Config),
+ <<"OPTIONS">> = do_body("OPTIONS", Path, Config),
+ <<"PATCH">> = do_body("PATCH", Path, Config),
+ <<"POST">> = do_body("POST", Path, Config),
+ <<"PUT">> = do_body("PUT", Path, Config),
+ <<"ZZZZZZZZ">> = do_body("ZZZZZZZZ", Path, Config),
ok.
parse_cookies(Config) ->
@@ -197,6 +211,11 @@ parse_cookies(Config) ->
<<"[{<<\"cake\">>,<<\"strawberry\">>},{<<\"color\">>,<<\"blue\">>}]">>
= do_get_body("/parse_cookies",
[{<<"cookie">>, "cake=strawberry"}, {<<"cookie">>, "color=blue"}], Config),
+ %% Ensure parse errors result in a 400 response.
+ {400, _, _} = do_get("/parse_cookies",
+ [{<<"cookie">>, "bad name=strawberry"}], Config),
+ {400, _, _} = do_get("/parse_cookies",
+ [{<<"cookie">>, "goodname=strawberry\tmilkshake"}], Config),
ok.
parse_header(Config) ->
@@ -211,6 +230,9 @@ parse_header(Config) ->
<<"undefined">> = do_get_body("/args/parse_header/upgrade", Config),
%% Header in request and with default provided.
<<"100-continue">> = do_get_body("/args/parse_header/expect/100-continue", Config),
+ %% Ensure parse errors result in a 400 response.
+ {400, _, _} = do_get("/args/parse_header/accept",
+ [{<<"accept">>, "bad media type"}], Config),
ok.
parse_qs(Config) ->
@@ -218,6 +240,8 @@ parse_qs(Config) ->
<<"[]">> = do_get_body("/parse_qs", Config),
<<"[{<<\"abc\">>,true}]">> = do_get_body("/parse_qs?abc", Config),
<<"[{<<\"a\">>,<<\"b\">>},{<<\"c\">>,<<\"d e\">>}]">> = do_get_body("/parse_qs?a=b&c=d+e", Config),
+ %% Ensure parse errors result in a 400 response.
+ {400, _, _} = do_get("/parse_qs?%%%%%%%", Config),
ok.
path(Config) ->
@@ -389,6 +413,8 @@ read_urlencoded_body(Config) ->
ok = do_read_urlencoded_body_too_long("/crash/read_urlencoded_body/period", <<"abc">>, Config),
%% The timeout value is set too low on purpose to ensure a crash occurs.
ok = do_read_body_timeout("/opts/read_urlencoded_body/timeout", <<"abc">>, Config),
+ %% Ensure parse errors result in a 400 response.
+ {400, _} = do_body_error("POST", "/read_urlencoded_body", [], "%%%%%", Config),
ok.
%% We expect a crash.
@@ -398,7 +424,7 @@ do_read_urlencoded_body_too_large(Path, Body, Config) ->
{<<"content-length">>, integer_to_binary(iolist_size(Body))}
]),
gun:data(ConnPid, Ref, fin, Body),
- {response, _, 500, _} = gun:await(ConnPid, Ref),
+ {response, _, 413, _} = gun:await(ConnPid, Ref),
gun:close(ConnPid).
%% We expect a crash.
@@ -410,7 +436,14 @@ do_read_urlencoded_body_too_long(Path, Body, Config) ->
gun:data(ConnPid, Ref, nofin, Body),
timer:sleep(1100),
gun:data(ConnPid, Ref, fin, Body),
- {response, _, 500, _} = gun:await(ConnPid, Ref),
+ {response, _, 408, RespHeaders} = gun:await(ConnPid, Ref),
+ _ = case config(protocol, Config) of
+ http ->
+ %% 408 error responses should close HTTP/1.1 connections.
+ {_, <<"close">>} = lists:keyfind(<<"connection">>, 1, RespHeaders);
+ http2 ->
+ ok
+ end,
gun:close(ConnPid).
multipart(Config) ->
@@ -437,6 +470,33 @@ do_multipart(Path, Config) ->
} = LargeHeaders,
ok.
+multipart_error_headers(Config) ->
+ doc("Multipart request body with invalid part headers."),
+ ReqBody = [
+ "--deadbeef\r\nbad-header text/plain\r\n\r\nCowboy is an HTTP server.\r\n"
+ "--deadbeef--"
+ ],
+ %% Ensure parse errors result in a 400 response.
+ {400, _} = do_body_error("POST", "/multipart", [
+ {<<"content-type">>, <<"multipart/mixed; boundary=deadbeef">>}
+ ], ReqBody, Config),
+ ok.
+
+%% The function to parse the multipart body currently does not crash,
+%% as far as I can tell. There is therefore no test for it.
+
+multipart_missing_boundary(Config) ->
+ doc("Multipart request body without a boundary in the media type."),
+ ReqBody = [
+ "--deadbeef\r\nContent-Type: text/plain\r\n\r\nCowboy is an HTTP server.\r\n"
+ "--deadbeef--"
+ ],
+ %% Ensure parse errors result in a 400 response.
+ {400, _} = do_body_error("POST", "/multipart", [
+ {<<"content-type">>, <<"multipart/mixed">>}
+ ], ReqBody, Config),
+ ok.
+
read_part_skip_body(Config) ->
doc("Multipart request body skipping part bodies."),
LargeBody = iolist_to_binary(string:chars($a, 10000000)),