mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Move many old HTTP test cases to the rest_handler test suite
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.
This commit is contained in:
parent
800a489009
commit
037b286aa8
8 changed files with 298 additions and 146 deletions
|
@ -479,7 +479,12 @@ content_types_provided(Req, State) ->
|
||||||
State3 = State2#state{content_types_p=CTP2},
|
State3 = State2#state{content_types_p=CTP2},
|
||||||
try cowboy_req:parse_header(<<"accept">>, Req2) of
|
try cowboy_req:parse_header(<<"accept">>, Req2) of
|
||||||
undefined ->
|
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(
|
languages_provided(
|
||||||
Req2#{media_type => PMT},
|
Req2#{media_type => PMT},
|
||||||
State3#state{content_type_a=HeadCTP});
|
State3#state{content_type_a=HeadCTP});
|
||||||
|
|
15
test/handlers/accept_callback_missing_h.erl
Normal file
15
test/handlers/accept_callback_missing_h.erl
Normal file
|
@ -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}.
|
|
@ -7,6 +7,7 @@
|
||||||
-export([allowed_methods/2]).
|
-export([allowed_methods/2]).
|
||||||
-export([content_types_accepted/2]).
|
-export([content_types_accepted/2]).
|
||||||
-export([put_multipart_mixed/2]).
|
-export([put_multipart_mixed/2]).
|
||||||
|
-export([put_text_plain/2]).
|
||||||
|
|
||||||
init(Req, Opts) ->
|
init(Req, Opts) ->
|
||||||
{cowboy_rest, Req, Opts}.
|
{cowboy_rest, Req, Opts}.
|
||||||
|
@ -17,7 +18,13 @@ allowed_methods(Req, State) ->
|
||||||
content_types_accepted(Req=#{qs := <<"multipart">>}, State) ->
|
content_types_accepted(Req=#{qs := <<"multipart">>}, State) ->
|
||||||
{[
|
{[
|
||||||
{{<<"multipart">>, <<"mixed">>, [{<<"v">>, <<"1">>}]}, put_multipart_mixed}
|
{{<<"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) ->
|
put_multipart_mixed(Req, State) ->
|
||||||
{true, Req, State}.
|
{true, Req, State}.
|
||||||
|
|
||||||
|
put_text_plain(Req0, State) ->
|
||||||
|
{ok, _, Req} = cowboy_req:read_body(Req0),
|
||||||
|
{true, Req, State}.
|
||||||
|
|
24
test/handlers/content_types_provided_h.erl
Normal file
24
test/handlers/content_types_provided_h.erl
Normal file
|
@ -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
test/handlers/expires_h.erl
Normal file
28
test/handlers/expires_h.erl
Normal file
|
@ -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
test/handlers/last_modified_h.erl
Normal file
24
test/handlers/last_modified_h.erl
Normal file
|
@ -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.
|
|
@ -100,70 +100,8 @@ 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.
|
%% 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) ->
|
rest_bad_content_type(Config) ->
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
Ref = gun:patch(ConnPid, "/bad_content_type",
|
Ref = gun:patch(ConnPid, "/bad_content_type",
|
||||||
|
@ -171,87 +109,12 @@ rest_bad_content_type(Config) ->
|
||||||
{response, fin, 415, _} = gun:await(ConnPid, Ref),
|
{response, fin, 415, _} = gun:await(ConnPid, Ref),
|
||||||
ok.
|
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) ->
|
rest_nodelete(Config) ->
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
Ref = gun:delete(ConnPid, "/nodelete"),
|
Ref = gun:delete(ConnPid, "/nodelete"),
|
||||||
{response, fin, 500, _} = gun:await(ConnPid, Ref),
|
{response, fin, 500, _} = gun:await(ConnPid, Ref),
|
||||||
ok.
|
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) ->
|
rest_patch(Config) ->
|
||||||
Tests = [
|
Tests = [
|
||||||
{204, [{<<"content-type">>, <<"text/plain">>}], <<"whatever">>},
|
{204, [{<<"content-type">>, <<"text/plain">>}], <<"whatever">>},
|
||||||
|
|
|
@ -39,6 +39,7 @@ end_per_group(Name, _) ->
|
||||||
init_dispatch(_) ->
|
init_dispatch(_) ->
|
||||||
cowboy_router:compile([{'_', [
|
cowboy_router:compile([{'_', [
|
||||||
{"/", rest_hello_h, []},
|
{"/", rest_hello_h, []},
|
||||||
|
{"/accept_callback_missing", accept_callback_missing_h, []},
|
||||||
{"/charsets_provided", charsets_provided_h, []},
|
{"/charsets_provided", charsets_provided_h, []},
|
||||||
{"/charsets_provided_empty", charsets_provided_empty_h, []},
|
{"/charsets_provided_empty", charsets_provided_empty_h, []},
|
||||||
{"/charset_in_content_types_provided",
|
{"/charset_in_content_types_provided",
|
||||||
|
@ -48,7 +49,10 @@ init_dispatch(_) ->
|
||||||
{"/charset_in_content_types_provided_implicit_no_callback",
|
{"/charset_in_content_types_provided_implicit_no_callback",
|
||||||
charset_in_content_types_provided_implicit_no_callback_h, []},
|
charset_in_content_types_provided_implicit_no_callback_h, []},
|
||||||
{"/content_types_accepted", content_types_accepted_h, []},
|
{"/content_types_accepted", content_types_accepted_h, []},
|
||||||
|
{"/content_types_provided", content_types_provided_h, []},
|
||||||
|
{"/expires", expires_h, []},
|
||||||
{"/if_range", if_range_h, []},
|
{"/if_range", if_range_h, []},
|
||||||
|
{"/last_modified", last_modified_h, []},
|
||||||
{"/provide_callback_missing", provide_callback_missing_h, []},
|
{"/provide_callback_missing", provide_callback_missing_h, []},
|
||||||
{"/provide_range_callback", provide_range_callback_h, []},
|
{"/provide_range_callback", provide_range_callback_h, []},
|
||||||
{"/range_satisfiable", range_satisfiable_h, []},
|
{"/range_satisfiable", range_satisfiable_h, []},
|
||||||
|
@ -70,6 +74,16 @@ do_decode(Headers, Body) ->
|
||||||
|
|
||||||
%% Tests.
|
%% Tests.
|
||||||
|
|
||||||
|
accept_callback_missing(Config) ->
|
||||||
|
doc("A 500 response must be sent when the AcceptCallback can't be called."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:put(ConnPid, "/accept_callback_missing", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>},
|
||||||
|
{<<"content-type">>, <<"text/plain">>}
|
||||||
|
], <<"Missing!">>),
|
||||||
|
{response, fin, 500, _} = gun:await(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
charset_in_content_types_provided(Config) ->
|
charset_in_content_types_provided(Config) ->
|
||||||
doc("When a charset is matched explictly in content_types_provided, "
|
doc("When a charset is matched explictly in content_types_provided, "
|
||||||
"that charset is used and the charsets_provided callback is ignored."),
|
"that charset is used and the charsets_provided callback is ignored."),
|
||||||
|
@ -281,24 +295,152 @@ content_types_accepted_ignore_multipart_boundary(Config) ->
|
||||||
{response, _, 204, _} = gun:await(ConnPid, Ref),
|
{response, _, 204, _} = gun:await(ConnPid, Ref),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
content_types_accepted_wildcard_param_no_content_type_param(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_accepted callback, a content-type header "
|
||||||
|
"with no parameters must be accepted."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:put(ConnPid, "/content_types_accepted?wildcard-param", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>},
|
||||||
|
{<<"content-type">>, <<"text/plain">>}
|
||||||
|
]),
|
||||||
|
gun:data(ConnPid, Ref, fin, "Hello world!"),
|
||||||
|
{response, fin, 204, _} = gun:await(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
content_types_accepted_wildcard_param_content_type_with_param(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_accepted callback, a content-type header "
|
||||||
|
"with a parameter must be accepted."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:put(ConnPid, "/content_types_accepted?wildcard-param", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>},
|
||||||
|
{<<"content-type">>, <<"text/plain; charset=utf-8">>}
|
||||||
|
]),
|
||||||
|
gun:data(ConnPid, Ref, fin, "Hello world!"),
|
||||||
|
{response, fin, 204, _} = gun:await(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
content_types_provided_wildcard_param_no_accept_param(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_provided callback, an accept header "
|
||||||
|
"with no parameters must be accepted."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/content_types_provided?wildcard-param", [
|
||||||
|
{<<"accept">>, <<"text/plain">>},
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, _} = gun:await(ConnPid, Ref),
|
||||||
|
{ok, <<"[]">>} = gun:await_body(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
content_types_provided_wildcard_param_accept_with_param(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_provided callback, an accept header "
|
||||||
|
"with a parameter must be accepted."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/content_types_provided?wildcard-param", [
|
||||||
|
{<<"accept">>, <<"text/plain;level=1">>},
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, _} = gun:await(ConnPid, Ref),
|
||||||
|
{ok, <<"level=1">>} = gun:await_body(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
content_types_provided_wildcard_param_accept_with_param_and_qvalue(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_provided callback, an accept header "
|
||||||
|
"with two media types containing parameters including a "
|
||||||
|
"q-value must be accepted. The q-value determines which."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref1 = gun:get(ConnPid, "/content_types_provided?wildcard-param", [
|
||||||
|
{<<"accept">>, <<"text/plain;level=1;q=0.8, text/plain;level=2;q=0.5">>},
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, _} = gun:await(ConnPid, Ref1),
|
||||||
|
{ok, <<"level=1">>} = gun:await_body(ConnPid, Ref1),
|
||||||
|
Ref2 = gun:get(ConnPid, "/content_types_provided?wildcard-param", [
|
||||||
|
{<<"accept">>, <<"text/plain;level=1;q=0.5, text/plain;level=2;q=0.8">>},
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, _} = gun:await(ConnPid, Ref2),
|
||||||
|
{ok, <<"level=2">>} = gun:await_body(ConnPid, Ref2),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
content_types_provided_wildcard_param_no_accept_header(Config) ->
|
||||||
|
doc("When a wildcard is returned for parameters from the "
|
||||||
|
"content_types_provided callback, the lack of accept header "
|
||||||
|
"results in the first media type returned being accepted. "
|
||||||
|
"The wildcard must however not be present in the media_type "
|
||||||
|
"value added to the Req object."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/content_types_provided?wildcard-param", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, _} = gun:await(ConnPid, Ref),
|
||||||
|
{ok, <<"[]">>} = gun:await_body(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
error_on_malformed_accept(Config) ->
|
||||||
|
doc("A malformed Accept header must result in a 400 response."),
|
||||||
|
do_error_on_malformed_header(Config, <<"accept">>).
|
||||||
|
|
||||||
error_on_malformed_if_match(Config) ->
|
error_on_malformed_if_match(Config) ->
|
||||||
doc("A malformed If-Match header must result in a 400 response."),
|
doc("A malformed If-Match header must result in a 400 response."),
|
||||||
|
do_error_on_malformed_header(Config, <<"if-match">>).
|
||||||
|
|
||||||
|
error_on_malformed_if_none_match(Config) ->
|
||||||
|
doc("A malformed If-None-Match header must result in a 400 response."),
|
||||||
|
do_error_on_malformed_header(Config, <<"if-none-match">>).
|
||||||
|
|
||||||
|
do_error_on_malformed_header(Config, Name) ->
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
Ref = gun:get(ConnPid, "/", [
|
Ref = gun:get(ConnPid, "/", [
|
||||||
{<<"accept-encoding">>, <<"gzip">>},
|
{<<"accept-encoding">>, <<"gzip">>},
|
||||||
{<<"if-match">>, <<"bad">>}
|
{Name, <<"bad">>}
|
||||||
]),
|
]),
|
||||||
{response, _, 400, _} = gun:await(ConnPid, Ref),
|
{response, _, 400, _} = gun:await(ConnPid, Ref),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
error_on_malformed_if_none_match(Config) ->
|
expires_binary(Config) ->
|
||||||
doc("A malformed If-None-Match header must result in a 400 response."),
|
doc("The expires header can also be given as a binary "
|
||||||
|
"to indicate a date in the past. (RFC7234 5.3)"),
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
Ref = gun:get(ConnPid, "/", [
|
Ref = gun:get(ConnPid, "/expires?binary", [
|
||||||
{<<"accept-encoding">>, <<"gzip">>},
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
{<<"if-none-match">>, <<"bad">>}
|
|
||||||
]),
|
]),
|
||||||
{response, _, 400, _} = gun:await(ConnPid, Ref),
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
{_, <<"0">>} = lists:keyfind(<<"expires">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
expires_missing(Config) ->
|
||||||
|
doc("The expires header must not be sent when the callback is not exported."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/expires?missing", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
false = lists:keyfind(<<"expires">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
expires_tuple(Config) ->
|
||||||
|
doc("The expires header can be given as a date tuple. (RFC7234 5.3)"),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/expires?tuple", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
{_, <<"Fri, 21 Sep 2012 22:36:14 GMT">>} = lists:keyfind(<<"expires">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
expires_undefined(Config) ->
|
||||||
|
doc("The expires header must not be sent when undefined is returned."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/expires?undefined", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
false = lists:keyfind(<<"expires">>, 1, Headers),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
if_range_etag_equal(Config) ->
|
if_range_etag_equal(Config) ->
|
||||||
|
@ -405,6 +547,50 @@ if_range_date_not_equal(Config) ->
|
||||||
false = lists:keyfind(<<"content-range">>, 1, Headers),
|
false = lists:keyfind(<<"content-range">>, 1, Headers),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
last_modified(Config) ->
|
||||||
|
doc("The last-modified header can be given as a date tuple. (RFC7232 2.2)"),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/last_modified?tuple", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
{_, <<"Fri, 21 Sep 2012 22:36:14 GMT">>} = lists:keyfind(<<"last-modified">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
last_modified_missing(Config) ->
|
||||||
|
doc("The last-modified header must not be sent when the callback is not exported."),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/last_modified?missing", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, _, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
false = lists:keyfind(<<"last-modified">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
options_missing(Config) ->
|
||||||
|
doc("A successful OPTIONS request to a simple handler results in "
|
||||||
|
"a 200 OK response with the allow header set. (RFC7231 4.3.7)"),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:options(ConnPid, "/", [
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, fin, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
{_, <<"HEAD, GET, OPTIONS">>} = lists:keyfind(<<"allow">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
provide_callback(Config) ->
|
||||||
|
doc("A successful GET request to a simple handler results in "
|
||||||
|
"a 200 OK response with the content-type set. (RFC7231 4.3.1, RFC7231 6.3.1)"),
|
||||||
|
ConnPid = gun_open(Config),
|
||||||
|
Ref = gun:get(ConnPid, "/", [
|
||||||
|
{<<"accept">>, <<"*/*">>},
|
||||||
|
{<<"accept-encoding">>, <<"gzip">>}
|
||||||
|
]),
|
||||||
|
{response, nofin, 200, Headers} = gun:await(ConnPid, Ref),
|
||||||
|
{_, <<"text/plain">>} = lists:keyfind(<<"content-type">>, 1, Headers),
|
||||||
|
{ok, <<"This is REST!">>} = gun:await_body(ConnPid, Ref),
|
||||||
|
ok.
|
||||||
|
|
||||||
provide_callback_missing(Config) ->
|
provide_callback_missing(Config) ->
|
||||||
doc("A 500 response must be sent when the ProvideCallback can't be called."),
|
doc("A 500 response must be sent when the ProvideCallback can't be called."),
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue