Skip to content

Commit 6165fc4

Browse files
committed
Make building SSE events more closely match the spec
Also add many more tests.
1 parent 6ccef1c commit 6165fc4

1 file changed

Lines changed: 61 additions & 3 deletions

File tree

src/cow_sse.erl

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ event_comment(_) ->
301301
[].
302302

303303
event_id(#{id := ID}) ->
304-
nomatch = binary:match(iolist_to_binary(ID), <<"\n">>),
304+
nomatch = binary:match(iolist_to_binary(ID),
305+
[<<"\r\n">>, <<"\r">>, <<"\n">>]),
305306
[<<"id: ">>, ID, $\n];
306307
event_id(_) ->
307308
[].
@@ -311,7 +312,8 @@ event_name(#{event := Name0}) ->
311312
is_atom(Name0) -> atom_to_binary(Name0, utf8);
312313
true -> iolist_to_binary(Name0)
313314
end,
314-
nomatch = binary:match(Name, <<"\n">>),
315+
nomatch = binary:match(Name,
316+
[<<"\r\n">>, <<"\r">>, <<"\n">>]),
315317
[<<"event: ">>, Name, $\n];
316318
event_name(_) ->
317319
[].
@@ -327,7 +329,8 @@ event_retry(_) ->
327329
[].
328330

329331
prefix_lines(IoData, Prefix) ->
330-
Lines = binary:split(iolist_to_binary(IoData), <<"\n">>, [global]),
332+
Lines = binary:split(iolist_to_binary(IoData),
333+
[<<"\r\n">>, <<"\r">>, <<"\n">>], [global]),
331334
[[Prefix, <<": ">>, Line, $\n] || Line <- Lines].
332335

333336
-ifdef(TEST).
@@ -345,5 +348,60 @@ event_test() ->
345348
_ = event(#{retry => 5000}),
346349
_ = event(#{event => "test", data => "test"}),
347350
_ = event(#{id => "test", event => "test", data => "test"}),
351+
_ = event(#{data => "test\r\ntest"}),
352+
_ = event(#{data => "test\rtest\r"}),
353+
_ = event(#{data => "test\ntest"}),
348354
ok.
355+
356+
event_error_test() ->
357+
{'EXIT', _} = (catch event(#{id => "test\n"})),
358+
{'EXIT', _} = (catch event(#{id => "test\r"})),
359+
{'EXIT', _} = (catch event(#{id => "test\r\n"})),
360+
{'EXIT', _} = (catch event(#{event => "test\n"})),
361+
{'EXIT', _} = (catch event(#{event => "test\r"})),
362+
{'EXIT', _} = (catch event(#{event => "test\r\n"})),
363+
ok.
364+
365+
identity_test_() ->
366+
Tests = [
367+
#{data => <<"hello">>},
368+
#{event => <<"update">>, data => <<"hello">>},
369+
#{id => <<"42">>, data => <<"hello">>},
370+
#{data => <<"a\nb">>},
371+
#{data => <<"multi\nline\ndata">>},
372+
#{event => <<"update">>, data => <<"hello">>},
373+
#{id => <<"abc">>, data => <<"x">>},
374+
#{comment => <<"c1">>, data => <<"d1">>, event => <<"e1">>, id => <<"i1">>},
375+
#{data => <<>>},
376+
#{data => <<"data with trailing newline\n">>},
377+
#{data => <<"\n">>},
378+
#{data => <<"\n\n">>},
379+
#{data => <<"">>, id => <<"1">>},
380+
#{data => <<"z">>},
381+
#{id => <<"17">>},
382+
#{data => << <<$a>> || _ <- lists:seq(1,200) >>},
383+
#{data => <<"こんにちは世界">>},
384+
#{retry => 30000, data => <<"reconnect">>}
385+
],
386+
[{lists:flatten(io_lib:format("~0p", [V])),
387+
fun() -> true = do_identity_result(V) =:= do_identity_build_parse(V) end}
388+
|| V <- Tests].
389+
390+
do_identity_build_parse(Event) ->
391+
{event, Parsed, _} = parse(iolist_to_binary(event(Event)), init()),
392+
case Parsed of
393+
#{data := Data} -> Parsed#{data => iolist_to_binary(Data)};
394+
_ -> Parsed
395+
end.
396+
397+
do_identity_result(E=#{id := ID}) when map_size(E) =:= 1 ->
398+
#{
399+
last_event_id => ID
400+
};
401+
do_identity_result(Event) ->
402+
#{
403+
event_type => maps:get(event, Event, <<"message">>),
404+
data => maps:get(data, Event, <<>>),
405+
last_event_id => maps:get(id, Event, <<>>)
406+
}.
349407
-endif.

0 commit comments

Comments
 (0)