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

