Skip to content

Commit 7062967

Browse files
committed
WIP close
1 parent af1692b commit 7062967

5 files changed

Lines changed: 74 additions & 3 deletions

File tree

src/cowboy_http3.erl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,10 @@ terminate_stream(State=#state{streams=Streams0, children=Children0},
10471047
Children = cowboy_children:shutdown(Children0, StreamID),
10481048
stream_linger(State#state{streams=Streams, children=Children}, StreamID).
10491049

1050+
%% We must dereference the stream state when WebTransport is in use.
1051+
terminate_stream_handler(State, StreamID, Reason,
1052+
{cowboy_webtransport, #{stream_state := StreamState}}) ->
1053+
terminate_stream_handler(State, StreamID, Reason, StreamState);
10501054
terminate_stream_handler(#state{opts=Opts}, StreamID, Reason, StreamState) ->
10511055
try
10521056
cowboy_stream:terminate(StreamID, Reason, StreamState)

src/cowboy_rest.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,5 +1622,6 @@ error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class,
16221622
erlang:raise(Class, Reason, Stacktrace).
16231623

16241624
terminate(Req, #state{handler=Handler, handler_state=HandlerState}) ->
1625+
%% @todo I don't think the result is used anywhere?
16251626
Result = cowboy_handler:terminate(normal, Req, HandlerState, Handler),
16261627
{ok, Req, Result}.

src/cowboy_webtransport.erl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ upgrade(Req=#{version := 'HTTP/3', pid := Pid, streamid := StreamID}, Env, Handl
105105
%% Use 501 Not Implemented to mirror the recommendation in
106106
%% by RFC9220 3 (WebSockets Upgrade over HTTP/3).
107107
false ->
108+
%% @todo I don't think terminate will be called.
108109
{ok, cowboy_req:reply(501, Req), Env}
109110
end.
110111

@@ -212,7 +213,7 @@ commands([Command={close, _, _}|Tail], State, _, Acc) ->
212213
%% @todo set_options (to increase number of streams? data amounts? or a flow command?)
213214
%% @todo shutdown_reason if useful.
214215

215-
terminate(State, HandlerState, Reason) ->
216+
terminate(State=#state{req=Req}, HandlerState, Reason) ->
216217
%cowboy_stream:terminate(StreamID, Reason, StreamState)
217218
%% @todo This terminate is at the connection level.
218219
% handler_terminate(State, HandlerState, Reason),
@@ -223,7 +224,8 @@ terminate(State, HandlerState, Reason) ->
223224
% exit(normal).
224225
%handler_terminate(#state{handler=Handler, req=Req}, HandlerState, Reason) ->
225226
% cowboy_handler:terminate(Reason, Req, HandlerState, Handler).
226-
ok.
227+
%% @todo I think we must call terminate ourselves.
228+
{ok, Req, Reason}.
227229

228230

229231

test/draft_h3_webtransport_SUITE.erl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,32 @@ datagrams(Config) ->
246246

247247
%% An HTTP/3 GOAWAY frame is also a signal to applications to initiate shutdown for all WebTransport sessions. (4.6)
248248

249+
%% @todo Currently receipt of a GOAWAY frame immediately ends the connection.
250+
%% We want to allow WT sessions to gracefully shut down before that.
251+
%goaway_client(Config) ->
252+
% doc("The HTTP/3 client can initiate the close of all WT sessions "
253+
% "by sending a GOAWAY frame. (draft_webtrans_http3 4.6)"),
254+
% %% Connect to the WebTransport server.
255+
% #{
256+
% conn := Conn,
257+
% connect_stream_ref := ConnectStreamRef,
258+
% session_id := SessionID
259+
% } = do_webtransport_connect(Config),
260+
% %% Open a control stream and send a GOAWAY frame.
261+
% {ok, ControlRef} = quicer:start_stream(Conn,
262+
% #{open_flag => ?QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL}),
263+
% {ok, SettingsBin, _HTTP3Machine0} = cow_http3_machine:init(client, #{}),
264+
% {ok, _} = quicer:send(ControlRef, [
265+
% <<0>>, %% CONTROL stream.
266+
% SettingsBin,
267+
% <<7>>, %% GOAWAY frame.
268+
% cow_http3:encode_int(1),
269+
% cow_http3:encode_int(0)
270+
% ]),
271+
% %% Receive a datagram indicating processing by the WT handler.
272+
% {datagram, SessionID, <<"TEST:close_initiated">>} = do_receive_datagram(Conn),
273+
% ok.
274+
249275
drain_wt_session_client(Config) ->
250276
doc("The WT client can initiate the close of a single session. "
251277
"(draft_webtrans_http3 4.6)"),
@@ -403,18 +429,54 @@ drain_wt_session_continue_server(Config) ->
403429
%% * a CLOSE_WEBTRANSPORT_SESSION capsule is either sent or received.
404430
%% (6)
405431

432+
%% @todo connect_stream_closed_cleanly_client
433+
%% @todo connect_stream_closed_abruptly_client
434+
%% @todo close_wt_session_client
435+
436+
close_wt_session_server(Config) ->
437+
doc("The WT server can close a single session. (draft_webtrans_http3 4.6)"),
438+
%% Connect to the WebTransport server.
439+
#{
440+
conn := Conn,
441+
connect_stream_ref := ConnectStreamRef,
442+
session_id := SessionID
443+
} = do_webtransport_connect(Config),
444+
%% Create a bidi stream, send a special instruction to make it initiate the close.
445+
{ok, LocalStreamRef} = quicer:start_stream(Conn, #{}),
446+
{ok, _} = quicer:send(LocalStreamRef, <<1:2, 16#41:14, 0:2, SessionID:6, "TEST:close">>),
447+
%% Receive the CLOSE_WEBTRANSPORT_SESSION capsule on the CONNECT stream.
448+
CloseWTSessionCapsule = cow_capsule:close_wt_session(0, <<>>),
449+
{fin, CloseWTSessionCapsule} = do_receive_data(ConnectStreamRef),
450+
ok.
451+
406452
%% Upon learning that the session has been terminated, the endpoint MUST reset the send side and abort reading on the receive side of all of the streams associated with the session (see Section 2.4 of [RFC9000]) using the WEBTRANSPORT_SESSION_GONE error code; it MUST NOT send any new datagrams or open any new streams. (6)
407453

454+
%% @todo wt_session_gone_client/server
455+
408456
%% To terminate a session with a detailed error message, an application MAY send an HTTP capsule [HTTP-DATAGRAM] of type CLOSE_WEBTRANSPORT_SESSION (0x2843). (6)
457+
%% @todo close_wt_session_client/server
409458

410459
%% Application Error Message: A UTF-8 encoded error message string provided by the application closing the session. The message takes up the remainder of the capsule, and its length MUST NOT exceed 1024 bytes. (6)
411460

461+
%% @todo close_wt_session_app_code_msg_client
462+
463+
%% @todo
464+
%close_wt_session_app_code_server(Config) ->
465+
% error(todo).
466+
%close_wt_session_app_code_msg_server(Config) ->
467+
% error(todo).
468+
412469
%% An endpoint that sends a CLOSE_WEBTRANSPORT_SESSION capsule MUST immediately send a FIN. The endpoint MAY send a STOP_SENDING to indicate it is no longer reading from the CONNECT stream. The recipient MUST either close or reset the stream in response. (6)
470+
%% @todo close_wt_session_server_fin
471+
%% @todo The part about close/reset should be tested in close_wt_session_client.
413472

414473
%% If any additional stream data is received on the CONNECT stream after receiving a CLOSE_WEBTRANSPORT_SESSION capsule, the stream MUST be reset with code H3_MESSAGE_ERROR. (6)
474+
%% @todo close_wt_session_followed_by_data
415475

416476
%% Cleanly terminating a CONNECT stream without a CLOSE_WEBTRANSPORT_SESSION capsule SHALL be semantically equivalent to terminating it with a CLOSE_WEBTRANSPORT_SESSION capsule that has an error code of 0 and an empty error string. (6)
477+
%% @todo connect_stream_closed_app_code_0_empty_msg
417478

479+
%% @todo This one is about gracefully closing HTTP/3 connection with WT sessions.
418480
%% the endpoint SHOULD wait until all CONNECT streams have been closed by the peer before sending the CONNECTION_CLOSE (6)
419481

420482
%% Helpers.

test/handlers/wt_echo_h.erl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ webtransport_handle(Event = {stream_data, _StreamID, _IsFin, <<"TEST:", Test/bit
5050
{[{open_stream, OpenStreamRef, bidi, <<>>}],
5151
Streams#{OpenStreamRef => bidi}};
5252
<<"initiate_close">> ->
53-
{[initiate_close], Streams}
53+
{[initiate_close], Streams};
54+
<<"close">> ->
55+
{[close], Streams}
5456
end;
5557
webtransport_handle(Event = {stream_data, StreamID, IsFin, Data}, Streams) ->
5658
ct:pal("WT handle ~p~n", [Event]),

0 commit comments

Comments
 (0)