Skip to content

Commit

Permalink
Move many old HTTP test cases to the rest_handler test suite
Browse files Browse the repository at this point in the history
A bug was fixed in cowboy_rest where when content_types_provided
returned a media type with a wildcard as first in the list, and
a request comes in without an accept header, then the media_type
value in the Req object would contain '*' instead of [] for the
parameters.
  • Loading branch information
essen committed Nov 21, 2018
1 parent 800a489 commit 037b286
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 145 deletions.
7 changes: 6 additions & 1 deletion src/cowboy_rest.erl
Expand Up @@ -479,7 +479,12 @@ content_types_provided(Req, State) ->
State3 = State2#state{content_types_p=CTP2},
try cowboy_req:parse_header(<<"accept">>, Req2) of
undefined ->
{PMT, _Fun} = HeadCTP = hd(CTP2),
{PMT0, _Fun} = HeadCTP = hd(CTP2),
%% We replace the wildcard by an empty list of parameters.
PMT = case PMT0 of
{Type, SubType, '*'} -> {Type, SubType, []};
_ -> PMT0
end,
languages_provided(
Req2#{media_type => PMT},
State3#state{content_type_a=HeadCTP});
Expand Down
15 changes: 15 additions & 0 deletions test/handlers/accept_callback_missing_h.erl
@@ -0,0 +1,15 @@
-module(accept_callback_missing_h).

-export([init/2]).
-export([allowed_methods/2]).
-export([content_types_accepted/2]).

init(Req, State) ->
{cowboy_rest, Req, State}.

allowed_methods(Req, State) ->
{[<<"PUT">>], Req, State}.

content_types_accepted(Req, State) ->
ct_helper_error_h:ignore(cowboy_rest, process_content_type, 3),
{[{<<"text/plain">>, accept}], Req, State}.
9 changes: 8 additions & 1 deletion test/handlers/content_types_accepted_h.erl
Expand Up @@ -7,6 +7,7 @@
-export([allowed_methods/2]).
-export([content_types_accepted/2]).
-export([put_multipart_mixed/2]).
-export([put_text_plain/2]).

init(Req, Opts) ->
{cowboy_rest, Req, Opts}.
Expand All @@ -17,7 +18,13 @@ allowed_methods(Req, State) ->
content_types_accepted(Req=#{qs := <<"multipart">>}, State) ->
{[
{{<<"multipart">>, <<"mixed">>, [{<<"v">>, <<"1">>}]}, put_multipart_mixed}
], Req, State}.
], Req, State};
content_types_accepted(Req=#{qs := <<"wildcard-param">>}, State) ->
{[{{<<"text">>, <<"plain">>, '*'}, put_text_plain}], Req, State}.

put_multipart_mixed(Req, State) ->
{true, Req, State}.

put_text_plain(Req0, State) ->
{ok, _, Req} = cowboy_req:read_body(Req0),
{true, Req, State}.
24 changes: 24 additions & 0 deletions test/handlers/content_types_provided_h.erl
@@ -0,0 +1,24 @@
%% This module has different content_types_provided values
%% and/or sends a different response body depending on the
%% query string.

-module(content_types_provided_h).

-export([init/2]).
-export([content_types_provided/2]).
-export([get_text_plain/2]).

init(Req, Opts) ->
{cowboy_rest, Req, Opts}.

content_types_provided(Req=#{qs := <<"wildcard-param">>}, State) ->
{[{{<<"text">>, <<"plain">>, '*'}, get_text_plain}], Req, State}.

get_text_plain(Req=#{qs := <<"wildcard-param">>}, State) ->
{_, _, Param} = maps:get(media_type, Req),
Body = if
Param =:= [] -> <<"[]">>;
Param =/= [] ->
iolist_to_binary([[Key, $=, Value] || {Key, Value} <- Param])
end,
{Body, Req, State}.
28 changes: 28 additions & 0 deletions test/handlers/expires_h.erl
@@ -0,0 +1,28 @@
%% This module sends a different expires value
%% depending on the query string.

-module(expires_h).

-export([init/2]).
-export([content_types_provided/2]).
-export([get_text_plain/2]).
-export([expires/2]).

init(Req, Opts) ->
{cowboy_rest, Req, Opts}.

content_types_provided(Req, State) ->
{[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}.

get_text_plain(Req, State) ->
{<<"This is REST!">>, Req, State}.

expires(Req=#{qs := <<"tuple">>}, State) ->
{{{2012, 9, 21}, {22, 36, 14}}, Req, State};
expires(Req=#{qs := <<"binary">>}, State) ->
{<<"0">>, Req, State};
expires(Req=#{qs := <<"undefined">>}, State) ->
{undefined, Req, State};
%% Simulate the callback being missing in other cases.
expires(#{qs := <<"missing">>}, _) ->
no_call.
24 changes: 24 additions & 0 deletions test/handlers/last_modified_h.erl
@@ -0,0 +1,24 @@
%% This module sends a different last-modified value
%% depending on the query string.

-module(last_modified_h).

-export([init/2]).
-export([content_types_provided/2]).
-export([get_text_plain/2]).
-export([last_modified/2]).

init(Req, Opts) ->
{cowboy_rest, Req, Opts}.

content_types_provided(Req, State) ->
{[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}.

get_text_plain(Req, State) ->
{<<"This is REST!">>, Req, State}.

last_modified(Req=#{qs := <<"tuple">>}, State) ->
{{{2012, 9, 21}, {22, 36, 14}}, Req, State};
%% Simulate the callback being missing in other cases.
last_modified(#{qs := <<"missing">>}, _) ->
no_call.
137 changes: 0 additions & 137 deletions test/old_http_SUITE.erl
Expand Up @@ -100,158 +100,21 @@ init_dispatch(_) ->
]}
]).

%% Convenience functions.

do_get(Path, Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, Path),
{response, _, Status, _} = gun:await(ConnPid, Ref),
gun:close(ConnPid),
Status.

%% Tests.

check_status(Config) ->
Tests = [
{200, "/simple"}
],
_ = [{Status, URL} = begin
Ret = do_get(URL, Config),
{Ret, URL}
end || {Status, URL} <- Tests].

rest_param_all(Config) ->
ConnPid = gun_open(Config),
%% Accept without param.
Ref1 = gun:get(ConnPid, "/param_all",
[{<<"accept">>, <<"text/plain">>}]),
{response, nofin, 200, _} = gun:await(ConnPid, Ref1),
{ok, <<"[]">>} = gun:await_body(ConnPid, Ref1),
%% Accept with param.
Ref2 = gun:get(ConnPid, "/param_all",
[{<<"accept">>, <<"text/plain;level=1">>}]),
{response, nofin, 200, _} = gun:await(ConnPid, Ref2),
{ok, <<"level=1">>} = gun:await_body(ConnPid, Ref2),
%% Accept with param and quality.
Ref3 = gun:get(ConnPid, "/param_all",
[{<<"accept">>, <<"text/plain;level=1;q=0.8, text/plain;level=2;q=0.5">>}]),
{response, nofin, 200, _} = gun:await(ConnPid, Ref3),
{ok, <<"level=1">>} = gun:await_body(ConnPid, Ref3),
Ref4 = gun:get(ConnPid, "/param_all",
[{<<"accept">>, <<"text/plain;level=1;q=0.5, text/plain;level=2;q=0.8">>}]),
{response, nofin, 200, _} = gun:await(ConnPid, Ref4),
{ok, <<"level=2">>} = gun:await_body(ConnPid, Ref4),
%% Without Accept.
Ref5 = gun:get(ConnPid, "/param_all"),
{response, nofin, 200, _} = gun:await(ConnPid, Ref5),
{ok, <<"'*'">>} = gun:await_body(ConnPid, Ref5),
%% Content-Type without param.
Ref6 = gun:put(ConnPid, "/param_all",
[{<<"content-type">>, <<"text/plain">>}]),
gun:data(ConnPid, Ref6, fin, "Hello world!"),
{response, fin, 204, _} = gun:await(ConnPid, Ref6),
%% Content-Type with param.
Ref7 = gun:put(ConnPid, "/param_all",
[{<<"content-type">>, <<"text/plain; charset=utf-8">>}]),
gun:data(ConnPid, Ref7, fin, "Hello world!"),
{response, fin, 204, _} = gun:await(ConnPid, Ref7),
ok.

rest_bad_accept(Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, "/bad_accept",
[{<<"accept">>, <<"1">>}]),
{response, fin, 400, _} = gun:await(ConnPid, Ref),
ok.

rest_bad_content_type(Config) ->
ConnPid = gun_open(Config),
Ref = gun:patch(ConnPid, "/bad_content_type",
[{<<"content-type">>, <<"text/plain, text/html">>}], <<"Whatever">>),
{response, fin, 415, _} = gun:await(ConnPid, Ref),
ok.

rest_expires(Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, "/rest_expires"),
{response, nofin, 200, Headers} = gun:await(ConnPid, Ref),
{_, Expires} = lists:keyfind(<<"expires">>, 1, Headers),
{_, LastModified} = lists:keyfind(<<"last-modified">>, 1, Headers),
Expires = LastModified = <<"Fri, 21 Sep 2012 22:36:14 GMT">>,
ok.

rest_expires_binary(Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, "/rest_expires_binary"),
{response, nofin, 200, Headers} = gun:await(ConnPid, Ref),
{_, <<"0">>} = lists:keyfind(<<"expires">>, 1, Headers),
ok.

rest_last_modified_undefined(Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, "/simple",
[{<<"if-modified-since">>, <<"Fri, 21 Sep 2012 22:36:14 GMT">>}]),
{response, nofin, 200, _} = gun:await(ConnPid, Ref),
ok.

rest_keepalive(Config) ->
ConnPid = gun_open(Config),
Refs = [gun:get(ConnPid, "/simple") || _ <- lists:seq(1, 10)],
_ = [begin
{response, nofin, 200, Headers} = gun:await(ConnPid, Ref),
false = lists:keymember(<<"connection">>, 1, Headers)
end || Ref <- Refs],
ok.

rest_keepalive_post(Config) ->
ConnPid = gun_open(Config),
Refs = [begin
Ref1 = gun:post(ConnPid, "/forbidden_post", [
{<<"content-type">>, <<"text/plain">>},
{<<"content-length">>, <<"12">>}
]),
gun:data(ConnPid, Ref1, fin, "Hello world!"),
Ref2 = gun:post(ConnPid, "/simple_post", [
{<<"content-type">>, <<"text/plain">>},
{<<"content-length">>, <<"12">>}
]),
gun:data(ConnPid, Ref2, fin, "Hello world!"),
{Ref1, Ref2}
end || _ <- lists:seq(1, 5)],
_ = [begin
{response, fin, 403, Headers1} = gun:await(ConnPid, Ref1),
false = lists:keymember(<<"connection">>, 1, Headers1),
{response, fin, 303, Headers2} = gun:await(ConnPid, Ref2),
false = lists:keymember(<<"connection">>, 1, Headers2)
end || {Ref1, Ref2} <- Refs],
ok.

rest_missing_get_callbacks(Config) ->
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, "/missing_get_callbacks"),
{response, fin, 500, _} = gun:await(ConnPid, Ref),
ok.

rest_missing_put_callbacks(Config) ->
ConnPid = gun_open(Config),
Ref = gun:put(ConnPid, "/missing_put_callbacks",
[{<<"content-type">>, <<"application/json">>}], <<"{}">>),
{response, fin, 500, _} = gun:await(ConnPid, Ref),
ok.

rest_nodelete(Config) ->
ConnPid = gun_open(Config),
Ref = gun:delete(ConnPid, "/nodelete"),
{response, fin, 500, _} = gun:await(ConnPid, Ref),
ok.

rest_options_default(Config) ->
ConnPid = gun_open(Config),
Ref = gun:options(ConnPid, "/rest_empty_resource"),
{response, fin, 200, Headers} = gun:await(ConnPid, Ref),
{_, <<"HEAD, GET, OPTIONS">>} = lists:keyfind(<<"allow">>, 1, Headers),
ok.

rest_patch(Config) ->
Tests = [
{204, [{<<"content-type">>, <<"text/plain">>}], <<"whatever">>},
Expand Down

0 comments on commit 037b286

Please sign in to comment.