aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2018-11-21 17:39:12 +0100
committerLoïc Hoguin <[email protected]>2018-11-21 18:39:59 +0100
commit037b286aa85acaaf439011bd7d2ae38685ce2f2e (patch)
tree2879aa405283eb15385efa02b71e2689337cda2f /test
parent800a4890092ebd30551c49fdae606ed5182bfdb1 (diff)
downloadcowboy-037b286aa85acaaf439011bd7d2ae38685ce2f2e.tar.gz
cowboy-037b286aa85acaaf439011bd7d2ae38685ce2f2e.tar.bz2
cowboy-037b286aa85acaaf439011bd7d2ae38685ce2f2e.zip
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.
Diffstat (limited to 'test')
-rw-r--r--test/handlers/accept_callback_missing_h.erl15
-rw-r--r--test/handlers/content_types_accepted_h.erl9
-rw-r--r--test/handlers/content_types_provided_h.erl24
-rw-r--r--test/handlers/expires_h.erl28
-rw-r--r--test/handlers/last_modified_h.erl24
-rw-r--r--test/old_http_SUITE.erl137
-rw-r--r--test/rest_handler_SUITE.erl198
7 files changed, 291 insertions, 144 deletions
diff --git a/test/handlers/accept_callback_missing_h.erl b/test/handlers/accept_callback_missing_h.erl
new file mode 100644
index 0000000..c97f123
--- /dev/null
+++ b/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}.
diff --git a/test/handlers/content_types_accepted_h.erl b/test/handlers/content_types_accepted_h.erl
index 7aec1bb..b871dc8 100644
--- a/test/handlers/content_types_accepted_h.erl
+++ b/test/handlers/content_types_accepted_h.erl
@@ -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}.
@@ -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}.
diff --git a/test/handlers/content_types_provided_h.erl b/test/handlers/content_types_provided_h.erl
new file mode 100644
index 0000000..5220c19
--- /dev/null
+++ b/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}.
diff --git a/test/handlers/expires_h.erl b/test/handlers/expires_h.erl
new file mode 100644
index 0000000..87fcb14
--- /dev/null
+++ b/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.
diff --git a/test/handlers/last_modified_h.erl b/test/handlers/last_modified_h.erl
new file mode 100644
index 0000000..82893b3
--- /dev/null
+++ b/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.
diff --git a/test/old_http_SUITE.erl b/test/old_http_SUITE.erl
index 6dbd2d6..81bb36c 100644
--- a/test/old_http_SUITE.erl
+++ b/test/old_http_SUITE.erl
@@ -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.
-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",
@@ -171,87 +109,12 @@ rest_bad_content_type(Config) ->
{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">>},
diff --git a/test/rest_handler_SUITE.erl b/test/rest_handler_SUITE.erl
index 88d3554..b21dda6 100644
--- a/test/rest_handler_SUITE.erl
+++ b/test/rest_handler_SUITE.erl
@@ -39,6 +39,7 @@ end_per_group(Name, _) ->
init_dispatch(_) ->
cowboy_router:compile([{'_', [
{"/", rest_hello_h, []},
+ {"/accept_callback_missing", accept_callback_missing_h, []},
{"/charsets_provided", charsets_provided_h, []},
{"/charsets_provided_empty", charsets_provided_empty_h, []},
{"/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_h, []},
{"/content_types_accepted", content_types_accepted_h, []},
+ {"/content_types_provided", content_types_provided_h, []},
+ {"/expires", expires_h, []},
{"/if_range", if_range_h, []},
+ {"/last_modified", last_modified_h, []},
{"/provide_callback_missing", provide_callback_missing_h, []},
{"/provide_range_callback", provide_range_callback_h, []},
{"/range_satisfiable", range_satisfiable_h, []},
@@ -70,6 +74,16 @@ do_decode(Headers, Body) ->
%% 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) ->
doc("When a charset is matched explictly in content_types_provided, "
"that charset is used and the charsets_provided callback is ignored."),
@@ -281,26 +295,154 @@ content_types_accepted_ignore_multipart_boundary(Config) ->
{response, _, 204, _} = gun:await(ConnPid, Ref),
ok.
-error_on_malformed_if_match(Config) ->
- doc("A malformed If-Match header must result in a 400 response."),
+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:get(ConnPid, "/", [
+ Ref = gun:put(ConnPid, "/content_types_accepted?wildcard-param", [
{<<"accept-encoding">>, <<"gzip">>},
- {<<"if-match">>, <<"bad">>}
+ {<<"content-type">>, <<"text/plain">>}
]),
- {response, _, 400, _} = gun:await(ConnPid, Ref),
+ 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) ->
+ 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),
Ref = gun:get(ConnPid, "/", [
{<<"accept-encoding">>, <<"gzip">>},
- {<<"if-none-match">>, <<"bad">>}
+ {Name, <<"bad">>}
]),
{response, _, 400, _} = gun:await(ConnPid, Ref),
ok.
+expires_binary(Config) ->
+ 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),
+ Ref = gun:get(ConnPid, "/expires?binary", [
+ {<<"accept-encoding">>, <<"gzip">>}
+ ]),
+ {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.
+
if_range_etag_equal(Config) ->
doc("When the if-range header matches, a 206 partial content "
"response is expected for an otherwise valid range request. (RFC7233 3.2)"),
@@ -405,6 +547,50 @@ if_range_date_not_equal(Config) ->
false = lists:keyfind(<<"content-range">>, 1, Headers),
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) ->
doc("A 500 response must be sent when the ProvideCallback can't be called."),
ConnPid = gun_open(Config),