Avoid prematurely unlinking streams in send_reset, in some cases. (#319)

Because `send_reset` called `recv_err`, which calls `reclaim_all_capacity`,
which eventually calls `transition(stream, ..)` -- all of which happens _before_
the RESET frame is enqueued -- it was possible for the stream to get unlinked
from the store (if there was any connection-level capacity to reassign). This
could then cause the stream to get "leaked" on drop/EOF since it would no longer
be iterated.

Fix this by delaying the call to `reclaim_all_capacity` _after_ enqueueing the
RESET frame.

A test demonstrating the issue is included.
This commit is contained in:
Geoffry Song
2018-10-16 11:59:22 -07:00
committed by Carl Lerche
parent 9bbbe7ebd5
commit ea8b8ac2fd
2 changed files with 79 additions and 1 deletions

View File

@@ -159,12 +159,17 @@ impl Send {
return;
}
self.recv_err(buffer, stream, counts);
// Clear all pending outbound frames.
// Note that we don't call `self.recv_err` because we want to enqueue
// the reset frame before transitioning the stream inside
// `reclaim_all_capacity`.
self.prioritize.clear_queue(buffer, stream);
let frame = frame::Reset::new(stream.id, reason);
trace!("send_reset -- queueing; frame={:?}", frame);
self.prioritize.queue_frame(frame.into(), buffer, stream, task);
self.prioritize.reclaim_all_capacity(stream, counts);
}
pub fn schedule_implicit_reset(