Hi,

On Wed, Jan 16, 2019 at 10:32:00AM +0300, Wert wrote:
> How to reproduce:
> 1. Start browser-download (content-disposition: attachment) of some big file 
> through H2
> * Tested with 1Gb file and several Chrome-versions (67-)
> 2. Make reload
> 3. Process with this connection would stay, transfer everything successfully 
> and even send to log info about code-200 full-size transfer without any 
> termination flags
> 4. Chrome would show "Network error" at the end of transfer
> 
> Versions:
> 1.8.17 - it happens in all cases
> #c4d56e5 - looks like it happens only in some conditions, but just because 
> there is another bug that makes old processes stay much longer than with 
> 1.8.17
> 
> Fix:
> For 1.8.17 I just disabled condition "if (sess && unlikely(sess->fe->state == 
> PR_STSTOPPED))" leading to h2c_send_goaway_error() in mux_h2.c:2330
> It is not correct way and probably breaks something else, but fixes this

I understand what's happening. And it is caused by the H2 state machine
which does not have provisions for something equivalent to the LAST_ACK
TCP state. A stream is closed as soon as the END_STREAM flag has been
seen in both directions. Thus during such a reload, we end up with a
connection which doesn't have any stream anymore but still bytes in
flight for the last stream(s). Since we have a reload in progress, we
know the process is waiting for old connections to leave, thus we close
this idle and unused connection. The problem is that the client is still
sending WINDOW_UPDATES for the data it receives, and that these ones will
cause a TCP RST to be emitted. Depending on the packet ordering on the
path and on the remote TCP stack, this can lead to truncated responses,
or even in a client reporting an error after it correctly gets everything.

I'd like to study the possibility to introduce an equivalent of the LAST_ACK
state for streams. In theory it should not be very difficult but in practice
it's tricky because frames are not really ACKed, the client sends us more
budget to send more data, so we never exactly know when all data were received
on the other end, though it serves as a hint. Ideally we could consider that
we can watch the window increments only and compare them to the amount of
data sent.

I think it's something I'll bring to the IETF HTTP working group, because
it could actually serve to address another issue related to priorities
which are sometimes incorrectly re-attached when streams disappear.

For the short term however I don't have any solution to this, and tricks
such as the one above are indeed risky, you may face connections which
never die :-/

Best regards,
Willy

Reply via email to