Improves symmetry with `WriteError::Stopped`. The proto layer can't
provide this behavior because it discards stream state, but we have
our own application-owned state and need to defer error reporting
sometimes anyway, so we might as well make this more intuitive.
Bi-directional streams might not be freed immediately on reading to
end or receiving a reset, and `StreamsState::stream_freed` already
performs the exact accounting required for this case when we call it
on entering Finished or Reset state.
We only queue MAX_STREAM_DATA when stream data is read by the
application, which never happens for stopped streams, but loss of
packets carrying previously sent MAX_STREAM_DATA frames could still
cause fresh ones to be queued unnecessarily. Filtering them out isn't
strictly necessary, but saves some space in the packet.
If frames are received out of order (e.g. due to packet loss) on a
stopped stream, the local `end` might be less than the high water mark
`Recv::end`. The previous code would set `Assembler::bytes_read` to
that incorrect lower value, potentially after it had previously taken
a higher value.
If `MAX_STREAM_DATA` frames are then queued for that stream (e.g. due
to retransmits prompted by packet loss), we might attempt to transmit
a smaller flow control credit than we had previously. This would cause
an underflow in the subtraction used to judge whether an increase in
flow control credit is worth sending, and violates the spec besides.
Because additional data on a stopped stream isn't useful, there's no
benefit to updating stream-level flow control at all, so we might as
well remove that path entirely. Connection-level flow control is still
maintained at the StreamsState level based on change in the stream's
high-water mark or determination of the final offset.
Exactly MTU-sized datagrams aren't necessarily transmitted often, if
ever. As a result, black hole detection could previously reset the MTU
regularly at any nonzero packet loss rate.
In `last_burst_was_suspicious`, if the last burst contains
non-suspicious packets, we bail out early. If it doesn't,
`largest_suspicious_packet_lost` is necessarily equal to
`largest_non_probe_lost`. No other code reads this field, so it is
redundant to `largest_non_probe_lost`.