From a631d27b53ccb4da2c4fcca86087053a5a518e46 Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Sat, 23 May 2026 17:07:41 +0200 Subject: [PATCH 1/2] Add HTTP/2 machine timeout message cleanup regression test --- src/cow_http2_machine.erl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/cow_http2_machine.erl b/src/cow_http2_machine.erl index 26350b0..609a249 100644 --- a/src/cow_http2_machine.erl +++ b/src/cow_http2_machine.erl @@ -270,6 +270,31 @@ terminate(#http2_machine{preface_timer=PTRef, settings_timer=STRef}) -> _ -> erlang:cancel_timer(STRef, [{async, true}, {info, false}]) end. +-ifdef(TEST). + +terminate_removes_stray_timeout_messages_test() -> + PTRef = erlang:start_timer(5000, self(), {?MODULE, undefined, preface_timeout}), + STRef = erlang:start_timer(5000, self(), {?MODULE, undefined, settings_timeout}), + PTMsg = {timeout, PTRef, {?MODULE, undefined, preface_timeout}}, + STMsg = {timeout, STRef, {?MODULE, undefined, settings_timeout}}, + self() ! PTMsg, + self() ! STMsg, + terminate(#http2_machine{preface_timer=PTRef, settings_timer=STRef}), + [] = collect_timeout_messages(PTRef, STRef), + ok. + +collect_timeout_messages(PTRef, STRef) -> + receive + {timeout, PTRef, {?MODULE, undefined, preface_timeout}} -> + [preface_timeout|collect_timeout_messages(PTRef, STRef)]; + {timeout, STRef, {?MODULE, undefined, settings_timeout}} -> + [settings_timeout|collect_timeout_messages(PTRef, STRef)] + after 0 -> + [] + end. + +-endif. + -spec init_stream(binary(), State) -> {ok, cow_http2:streamid(), State} when State::http2_machine(). init_stream(Method, State=#http2_machine{mode=client, local_streamid=LocalStreamID, From b527a73d8a9e2d209588e6d45e96b2ba73c8fc9d Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Sat, 23 May 2026 17:08:04 +0200 Subject: [PATCH 2/2] Remove stray HTTP/2 machine timeout messages on terminate --- src/cow_http2_machine.erl | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/cow_http2_machine.erl b/src/cow_http2_machine.erl index 609a249..0ca9c2e 100644 --- a/src/cow_http2_machine.erl +++ b/src/cow_http2_machine.erl @@ -261,13 +261,22 @@ setting_from_opt(Settings, Opts, OptName, SettingName, Default) -> -spec terminate(State::http2_machine()) -> ok. terminate(#http2_machine{preface_timer=PTRef, settings_timer=STRef}) -> - _ = case PTRef of - undefined -> ok; - _ -> erlang:cancel_timer(PTRef, [{async, true}, {info, false}]) - end, - _ = case STRef of - undefined -> ok; - _ -> erlang:cancel_timer(STRef, [{async, true}, {info, false}]) + cancel_timeout(PTRef), + cancel_timeout(STRef). + +cancel_timeout(TRef) -> + ok = case TRef of + undefined -> + ok; + _ -> + %% Do a synchronous cancel and remove the message if any + %% to avoid receiving stray messages. + _ = erlang:cancel_timer(TRef, [{async, false}, {info, false}]), + receive + {timeout, TRef, _} -> ok + after 0 -> + ok + end end. -ifdef(TEST).