Browse Source

Fix a bug where final empty frames were ignored

When a final empty frame was queued and the data sent made
the window go to 0 and the remote end didn't increase the
window anymore, the final empty frame could get stuck in
the queue and never sent.

Also ensure that we never queue empty non-final data.
Loïc Hoguin 5 years ago
parent
commit
6baeb05bdb
1 changed files with 19 additions and 2 deletions
  1. 19 2
      src/cow_http2_machine.erl

+ 19 - 2
src/cow_http2_machine.erl

@@ -1218,6 +1218,17 @@ send_data(Stream0, State0) ->
 send_data_for_one_stream(Stream=#stream{local=nofin, local_buffer_size=0,
 		local_trailers=Trailers}, State, SendAcc) when Trailers =/= undefined ->
 	{ok, Stream, State, lists:reverse([{trailers, Trailers}|SendAcc])};
+send_data_for_one_stream(Stream=#stream{local=nofin, local_buffer=Q0, local_buffer_size=0},
+		State, SendAcc) ->
+	case queue:len(Q0) of
+		0 ->
+			{ok, Stream, State, lists:reverse(SendAcc)};
+		1 ->
+			%% We know there is a final empty data frame in the queue.
+			%% We need to mark the stream as complete.
+			{{value, {fin, 0, _}}, Q} = queue:out(Q0),
+			{ok, Stream#stream{local=fin, local_buffer=Q}, State, lists:reverse(SendAcc)}
+	end;
 send_data_for_one_stream(Stream=#stream{local=IsFin, local_window=StreamWindow,
 		local_buffer_size=BufferSize}, State=#http2_machine{local_window=ConnWindow}, SendAcc)
 		when ConnWindow =< 0; IsFin =:= fin; StreamWindow =< 0; BufferSize =:= 0 ->
@@ -1283,8 +1294,14 @@ queue_data(Stream=#stream{local_buffer=Q0, local_buffer_size=Size0}, IsFin, Data
 		{sendfile, _, Bytes, _} -> Bytes;
 		{data, Iolist} -> iolist_size(Iolist)
 	end,
-	Q = queue:In({IsFin, DataSize, Data}, Q0),
-	Stream#stream{local_buffer=Q, local_buffer_size=Size0 + DataSize}.
+	%% Never queue non-final empty data frames.
+	case {DataSize, IsFin} of
+		{0, nofin} ->
+			Stream;
+		_ ->
+			Q = queue:In({IsFin, DataSize, Data}, Q0),
+			Stream#stream{local_buffer=Q, local_buffer_size=Size0 + DataSize}
+	end.
 
 %% Public interface to update the flow control window.
 %%