91
91
parent :: undefined | pid (),
92
92
ref :: ranch :ref (),
93
93
socket = undefined :: inet :socket () | {pid (), cowboy_stream :streamid ()} | undefined ,
94
- transport = undefined :: module () | undefined ,
94
+ transport :: module () | { data_delivery , stream_handlers | relay } ,
95
95
opts = #{} :: opts (),
96
96
active = true :: boolean (),
97
97
handler :: module (),
@@ -149,7 +149,7 @@ upgrade(Req, Env, Handler, HandlerState) ->
149
149
% % @todo Immediately crash if a response has already been sent.
150
150
upgrade (Req0 = #{version := Version }, Env , Handler , HandlerState , Opts ) ->
151
151
FilteredReq = case maps :get (req_filter , Opts , undefined ) of
152
- undefined -> maps :with ([method , version , scheme , host , port , path , qs , peer ], Req0 );
152
+ undefined -> maps :with ([method , version , scheme , host , port , path , qs , peer , streamid ], Req0 );
153
153
FilterFun -> FilterFun (Req0 )
154
154
end ,
155
155
Utf8State = case maps :get (validate_utf8 , Opts , true ) of
@@ -273,12 +273,28 @@ websocket_handshake(State=#state{key=Key},
273
273
% % For HTTP/2 we do not let the process die, we instead keep it
274
274
% % for the Websocket stream. This is because in HTTP/2 we only
275
275
% % have a stream, it doesn't take over the whole connection.
276
- websocket_handshake (State , Req = #{ref := Ref , pid := Pid , streamid := StreamID },
276
+ % %
277
+ % % There are two methods of delivering data to the Websocket session:
278
+ % % - 'stream_handlers' is the default and makes the data go
279
+ % % through stream handlers just like when reading a request body;
280
+ % % - 'relay' is a new method where data is sent as a message as
281
+ % % soon as it is received from the socket in a DATA frame.
282
+ websocket_handshake (State = # state {opts = Opts },
283
+ Req = #{ref := Ref , pid := Pid , streamid := StreamID },
277
284
HandlerState , _Env ) ->
278
285
% % @todo We don't want date and server headers.
279
286
Headers = cowboy_req :response_headers (#{}, Req ),
280
- Pid ! {{Pid , StreamID }, {switch_protocol , Headers , ? MODULE , {State , HandlerState }}},
281
- takeover (Pid , Ref , {Pid , StreamID }, undefined , #{}, <<>>,
287
+ DataDelivery = maps :get (data_delivery , Opts , stream_handlers ),
288
+ ModState = #{
289
+ data_delivery => DataDelivery ,
290
+ % % For relay data_delivery. The flow is a hint and may
291
+ % % not be used by the underlying protocol.
292
+ data_delivery_pid => self (),
293
+ data_delivery_flow => maps :get (data_delivery_flow , Opts , 131072 )
294
+ },
295
+ Pid ! {{Pid , StreamID }, {switch_protocol , Headers , ? MODULE , ModState }},
296
+ % % @todo We can't call the normal takeover because it tries to parse.
297
+ takeover (Pid , Ref , {Pid , StreamID }, {data_delivery , DataDelivery }, #{}, <<>>,
282
298
{State , HandlerState }).
283
299
284
300
% % Connection process.
@@ -311,7 +327,7 @@ takeover(Parent, Ref, Socket, Transport, Opts, Buffer,
311
327
_ -> ranch :remove_connection (Ref )
312
328
end ,
313
329
Messages = case Transport of
314
- undefined -> undefined ;
330
+ { data_delivery , _ } -> undefined ;
315
331
_ -> Transport :messages ()
316
332
end ,
317
333
State = set_idle_timeout (State0 # state {parent = Parent ,
@@ -355,13 +371,14 @@ after_init(State, HandlerState, ParseState) ->
355
371
% % immediately but there might still be data to be processed in
356
372
% % the message queue.
357
373
358
- setopts_active (# state {transport = undefined }) ->
374
+ setopts_active (# state {transport = { data_delivery , _ } }) ->
359
375
ok ;
360
376
setopts_active (# state {socket = Socket , transport = Transport , opts = Opts }) ->
361
377
N = maps :get (active_n , Opts , 1 ),
362
378
Transport :setopts (Socket , [{active , N }]).
363
379
364
- maybe_read_body (# state {socket = Stream = {Pid , _ }, transport = undefined , active = true }) ->
380
+ maybe_read_body (# state {transport = {data_delivery , stream_handlers },
381
+ socket = Stream = {Pid , _ }, active = true }) ->
365
382
% % @todo Keep Ref around.
366
383
ReadBodyRef = make_ref (),
367
384
Pid ! {Stream , {read_body , self (), ReadBodyRef , auto , infinity }},
@@ -374,10 +391,11 @@ active(State) ->
374
391
maybe_read_body (State ),
375
392
State # state {active = true }.
376
393
377
- passive (State = # state {transport = undefined }) ->
394
+ passive (State = # state {transport = { data_delivery , _ } }) ->
378
395
% % Unfortunately we cannot currently cancel read_body.
379
396
% % But that's OK, we will just stop reading the body
380
397
% % after the next message.
398
+ % % @todo We can't stop relay data_delivery currently.
381
399
State # state {active = false };
382
400
passive (State = # state {socket = Socket , transport = Transport , messages = Messages }) ->
383
401
Transport :setopts (Socket , [{active , false }]),
@@ -454,6 +472,10 @@ loop(State=#state{parent=Parent, socket=Socket, messages=Messages,
454
472
{request_body , _Ref , fin , _ , Data } ->
455
473
maybe_read_body (State ),
456
474
parse (? reset_idle_timeout (State ), HandlerState , ParseState , Data );
475
+ % % @todo It would be better to check StreamID.
476
+ % % @todo We must ensure that IsFin=fin is handled like a socket close?
477
+ {'$cowboy_stream_data' , {Pid , _StreamID }, _IsFin , Data } when Pid =:= Parent ->
478
+ parse (? reset_idle_timeout (State ), HandlerState , ParseState , Data );
457
479
% % Timeouts.
458
480
{timeout , TRef , ? MODULE } ->
459
481
tick_idle_timeout (State , HandlerState , ParseState );
@@ -662,9 +684,14 @@ commands([Frame|Tail], State, Data0) ->
662
684
commands (Tail , State , Data )
663
685
end .
664
686
665
- transport_send (# state {socket = Stream = {Pid , _ }, transport = undefined }, IsFin , Data ) ->
687
+ transport_send (# state {transport = {data_delivery , stream_handlers },
688
+ socket = Stream = {Pid , _ }}, IsFin , Data ) ->
666
689
Pid ! {Stream , {data , IsFin , Data }},
667
690
ok ;
691
+ transport_send (# state {transport = {data_delivery , relay },
692
+ socket = Stream = {Pid , _ }}, IsFin , Data ) ->
693
+ Pid ! {'$cowboy_stream_data' , Stream , IsFin , Data },
694
+ ok ;
668
695
transport_send (# state {socket = Socket , transport = Transport }, _ , Data ) ->
669
696
Transport :send (Socket , Data ).
670
697
0 commit comments