aboutsummaryrefslogtreecommitdiffstats
path: root/test/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'test/handlers')
-rw-r--r--test/handlers/content_types_provided_h.erl5
-rw-r--r--test/handlers/crash_h.erl3
-rw-r--r--test/handlers/read_body_h.erl15
-rw-r--r--test/handlers/resp_h.erl17
-rw-r--r--test/handlers/stream_hello_h.erl15
-rw-r--r--test/handlers/ws_ignore.erl20
-rw-r--r--test/handlers/ws_set_options_commands_h.erl19
-rw-r--r--test/handlers/wt_echo_h.erl103
8 files changed, 193 insertions, 4 deletions
diff --git a/test/handlers/content_types_provided_h.erl b/test/handlers/content_types_provided_h.erl
index 5220c19..397026b 100644
--- a/test/handlers/content_types_provided_h.erl
+++ b/test/handlers/content_types_provided_h.erl
@@ -11,9 +11,14 @@
init(Req, Opts) ->
{cowboy_rest, Req, Opts}.
+content_types_provided(Req=#{qs := <<"invalid-type">>}, State) ->
+ ct_helper:ignore(cowboy_rest, normalize_content_types, 2),
+ {[{{'*', '*', '*'}, get_text_plain}], Req, State};
content_types_provided(Req=#{qs := <<"wildcard-param">>}, State) ->
{[{{<<"text">>, <<"plain">>, '*'}, get_text_plain}], Req, State}.
+get_text_plain(Req=#{qs := <<"invalid-type">>}, State) ->
+ {<<"invalid-type">>, Req, State};
get_text_plain(Req=#{qs := <<"wildcard-param">>}, State) ->
{_, _, Param} = maps:get(media_type, Req),
Body = if
diff --git a/test/handlers/crash_h.erl b/test/handlers/crash_h.erl
index b687aba..57d4d85 100644
--- a/test/handlers/crash_h.erl
+++ b/test/handlers/crash_h.erl
@@ -7,6 +7,9 @@
-export([init/2]).
-spec init(_, _) -> no_return().
+init(_, external_exit) ->
+ ct_helper:ignore(?MODULE, init, 2),
+ exit(self(), ct_helper_ignore);
init(_, no_reply) ->
ct_helper:ignore(?MODULE, init, 2),
error(crash);
diff --git a/test/handlers/read_body_h.erl b/test/handlers/read_body_h.erl
new file mode 100644
index 0000000..a0de3b3
--- /dev/null
+++ b/test/handlers/read_body_h.erl
@@ -0,0 +1,15 @@
+%% This module reads the request body fully and send a 204 response.
+
+-module(read_body_h).
+
+-export([init/2]).
+
+init(Req0, Opts) ->
+ {ok, Req} = read_body(Req0),
+ {ok, cowboy_req:reply(200, #{}, Req), Opts}.
+
+read_body(Req0) ->
+ case cowboy_req:read_body(Req0) of
+ {ok, _, Req} -> {ok, Req};
+ {more, _, Req} -> read_body(Req)
+ end.
diff --git a/test/handlers/resp_h.erl b/test/handlers/resp_h.erl
index aae9eb9..d1c46e0 100644
--- a/test/handlers/resp_h.erl
+++ b/test/handlers/resp_h.erl
@@ -43,12 +43,27 @@ do(<<"set_resp_headers">>, Req0, Opts) ->
<<"content-encoding">> => <<"compress">>
}, Req0),
{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
+do(<<"set_resp_headers_list">>, Req0, Opts) ->
+ Req = cowboy_req:set_resp_headers([
+ {<<"content-type">>, <<"text/plain">>},
+ {<<"test-header">>, <<"one">>},
+ {<<"content-encoding">>, <<"compress">>},
+ {<<"test-header">>, <<"two">>}
+ ], Req0),
+ {ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
do(<<"set_resp_headers_cookie">>, Req0, Opts) ->
ct_helper:ignore(cowboy_req, set_resp_headers, 2),
Req = cowboy_req:set_resp_headers(#{
<<"set-cookie">> => <<"name=value">>
}, Req0),
{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
+do(<<"set_resp_headers_list_cookie">>, Req0, Opts) ->
+ ct_helper:ignore(cowboy_req, set_resp_headers_list, 3),
+ Req = cowboy_req:set_resp_headers([
+ {<<"set-cookie">>, <<"name=value">>},
+ {<<"set-cookie">>, <<"name2=value2">>}
+ ], Req0),
+ {ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
do(<<"set_resp_headers_http11">>, Req0, Opts) ->
Req = cowboy_req:set_resp_headers(#{
<<"connection">> => <<"custom-header, close">>,
@@ -182,6 +197,7 @@ do(<<"reply2">>, Req0, Opts) ->
<<"twice">> ->
ct_helper:ignore(cowboy_req, reply, 4),
Req1 = cowboy_req:reply(200, Req0),
+ timer:sleep(100),
cowboy_req:reply(200, Req1);
Status ->
cowboy_req:reply(binary_to_integer(Status), Req0)
@@ -245,6 +261,7 @@ do(<<"stream_reply2">>, Req0, Opts) ->
<<"twice">> ->
ct_helper:ignore(cowboy_req, stream_reply, 3),
Req1 = cowboy_req:stream_reply(200, Req0),
+ timer:sleep(100),
%% We will crash here so the body shouldn't be sent.
Req = cowboy_req:stream_reply(200, Req1),
stream_body(Req),
diff --git a/test/handlers/stream_hello_h.erl b/test/handlers/stream_hello_h.erl
new file mode 100644
index 0000000..e67e220
--- /dev/null
+++ b/test/handlers/stream_hello_h.erl
@@ -0,0 +1,15 @@
+%% This module is the fastest way of producing a Hello world!
+
+-module(stream_hello_h).
+
+-export([init/3]).
+-export([terminate/3]).
+
+init(_, _, State) ->
+ {[
+ {response, 200, #{<<"content-length">> => <<"12">>}, <<"Hello world!">>},
+ stop
+ ], State}.
+
+terminate(_, _, _) ->
+ ok.
diff --git a/test/handlers/ws_ignore.erl b/test/handlers/ws_ignore.erl
new file mode 100644
index 0000000..9fe3322
--- /dev/null
+++ b/test/handlers/ws_ignore.erl
@@ -0,0 +1,20 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+-module(ws_ignore).
+
+-export([init/2]).
+-export([websocket_handle/2]).
+-export([websocket_info/2]).
+
+init(Req, _) ->
+ {cowboy_websocket, Req, undefined, #{
+ compress => true
+ }}.
+
+websocket_handle({text, <<"CHECK">>}, State) ->
+ {[{text, <<"CHECK">>}], State};
+websocket_handle(_Frame, State) ->
+ {[], State}.
+
+websocket_info(_Info, State) ->
+ {[], State}.
diff --git a/test/handlers/ws_set_options_commands_h.erl b/test/handlers/ws_set_options_commands_h.erl
index 88d4e72..1ab0af4 100644
--- a/test/handlers/ws_set_options_commands_h.erl
+++ b/test/handlers/ws_set_options_commands_h.erl
@@ -11,10 +11,21 @@ init(Req, RunOrHibernate) ->
{cowboy_websocket, Req, RunOrHibernate,
#{idle_timeout => infinity}}.
-websocket_handle(Frame={text, <<"idle_timeout_short">>}, State=run) ->
- {[{set_options, #{idle_timeout => 500}}, Frame], State};
-websocket_handle(Frame={text, <<"idle_timeout_short">>}, State=hibernate) ->
- {[{set_options, #{idle_timeout => 500}}, Frame], State, hibernate}.
+%% Set the idle_timeout option dynamically.
+websocket_handle({text, <<"idle_timeout_short">>}, State=run) ->
+ {[{set_options, #{idle_timeout => 500}}], State};
+websocket_handle({text, <<"idle_timeout_short">>}, State=hibernate) ->
+ {[{set_options, #{idle_timeout => 500}}], State, hibernate};
+%% Set the max_frame_size option dynamically.
+websocket_handle({text, <<"max_frame_size_small">>}, State=run) ->
+ {[{set_options, #{max_frame_size => 1000}}], State};
+websocket_handle({text, <<"max_frame_size_small">>}, State=hibernate) ->
+ {[{set_options, #{max_frame_size => 1000}}], State, hibernate};
+%% We just echo binary frames.
+websocket_handle(Frame={binary, _}, State=run) ->
+ {[Frame], State};
+websocket_handle(Frame={binary, _}, State=hibernate) ->
+ {[Frame], State, hibernate}.
websocket_info(_Info, State) ->
{[], State}.
diff --git a/test/handlers/wt_echo_h.erl b/test/handlers/wt_echo_h.erl
new file mode 100644
index 0000000..5198565
--- /dev/null
+++ b/test/handlers/wt_echo_h.erl
@@ -0,0 +1,103 @@
+%% This module echoes client events back,
+%% including creating new streams.
+
+-module(wt_echo_h).
+-behavior(cowboy_webtransport).
+
+-export([init/2]).
+-export([webtransport_handle/2]).
+-export([webtransport_info/2]).
+-export([terminate/3]).
+
+%% -define(DEBUG, 1).
+-ifdef(DEBUG).
+-define(LOG(Fmt, Args), ct:pal(Fmt, Args)).
+-else.
+-define(LOG(Fmt, Args), _ = Fmt, _ = Args, ok).
+-endif.
+
+init(Req0, _) ->
+ ?LOG("WT init ~p~n", [Req0]),
+ Req = case cowboy_req:parse_header(<<"wt-available-protocols">>, Req0) of
+ undefined ->
+ Req0;
+ [Protocol|_] ->
+ cowboy_req:set_resp_header(<<"wt-protocol">>, cow_http_hd:wt_protocol(Protocol), Req0)
+ end,
+ {cowboy_webtransport, Req, #{}}.
+
+webtransport_handle(Event = {stream_open, StreamID, bidi}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ {[], Streams#{StreamID => bidi}};
+webtransport_handle(Event = {stream_open, StreamID, unidi}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ OpenStreamRef = make_ref(),
+ {[{open_stream, OpenStreamRef, unidi, <<>>}], Streams#{
+ StreamID => {unidi_remote, OpenStreamRef},
+ OpenStreamRef => {unidi_local, StreamID}}};
+webtransport_handle(Event = {opened_stream_id, OpenStreamRef, OpenStreamID}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ case Streams of
+ #{OpenStreamRef := bidi} ->
+ {[], maps:remove(OpenStreamRef, Streams#{
+ OpenStreamID => bidi
+ })};
+ #{OpenStreamRef := {unidi_local, RemoteStreamID}} ->
+ #{RemoteStreamID := {unidi_remote, OpenStreamRef}} = Streams,
+ {[], maps:remove(OpenStreamRef, Streams#{
+ RemoteStreamID => {unidi_remote, OpenStreamID},
+ OpenStreamID => {unidi_local, RemoteStreamID}
+ })}
+ end;
+webtransport_handle(Event = {stream_data, StreamID, _IsFin, <<"TEST:", Test/bits>>}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ case Test of
+ <<"open_bidi">> ->
+ OpenStreamRef = make_ref(),
+ {[{open_stream, OpenStreamRef, bidi, <<>>}],
+ Streams#{OpenStreamRef => bidi}};
+ <<"initiate_close">> ->
+ {[initiate_close], Streams};
+ <<"close">> ->
+ {[close], Streams};
+ <<"close_app_code">> ->
+ {[{close, 1234567890}], Streams};
+ <<"close_app_code_msg">> ->
+ {[{close, 1234567890, <<"onetwothreefourfivesixseveneightnineten">>}], Streams};
+ <<"event_pid:", EventPidBin/bits>> ->
+ {[{send, StreamID, nofin, <<"event_pid_received">>}],
+ Streams#{event_pid => binary_to_term(EventPidBin)}}
+ end;
+webtransport_handle(Event = {stream_data, StreamID, IsFin, Data}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ case Streams of
+ #{StreamID := bidi} ->
+ {[{send, StreamID, IsFin, Data}], Streams};
+ #{StreamID := {unidi_remote, Ref}} when is_reference(Ref) ->
+ %% The stream isn't ready. We try again later.
+ erlang:send_after(100, self(), {try_again, Event}),
+ {[], Streams};
+ #{StreamID := {unidi_remote, LocalStreamID}} ->
+ {[{send, LocalStreamID, IsFin, Data}], Streams}
+ end;
+webtransport_handle(Event = {datagram, Data}, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ {[{send, datagram, Data}], Streams};
+webtransport_handle(Event = close_initiated, Streams) ->
+ ?LOG("WT handle ~p~n", [Event]),
+ {[{send, datagram, <<"TEST:close_initiated">>}], Streams};
+webtransport_handle(Event, Streams) ->
+ ?LOG("WT handle ignore ~p~n", [Event]),
+ {[], Streams}.
+
+webtransport_info({try_again, Event}, Streams) ->
+ ?LOG("WT try_again ~p", [Event]),
+ webtransport_handle(Event, Streams).
+
+terminate(Reason, Req, State=#{event_pid := EventPid}) ->
+ ?LOG("WT terminate ~0p~n~0p~n~0p", [Reason, Req, State]),
+ EventPid ! {'$wt_echo_h', terminate, Reason, Req, State},
+ ok;
+terminate(Reason, Req, State) ->
+ ?LOG("WT terminate ~0p~n~0p~n~0p", [Reason, Req, State]),
+ ok.