HTTP/2: Wait END_STREAM flag on half-closed(local) stream state
Recently, we found that some clients send HEADERS frame followed by an empty DATA frame with the END_STREAM flag even for GET requests.
HEADERSframe withEND_HEADERSflag- zero-length
DATAframe withEND_STREAMflag
Sometimes ATS closes the stream immediately after it sends DATA frame to the client, right after handling the HEADERS frame. In this case, ATS treats the zero-length DATA frame as a stream error because the stream is already closed.
However, this appears to be a bug. The spec[*1] says that an endpoint should keep the stream in the half-closed (local) state after sending END_STREAM flag and wait to receive END_STREAM flag from the peer before closing it.
With this change, ATS waits for the END_STREAM flag until the http.transaction_no_activity_timeout_in expires.
[*1] https://datatracker.ietf.org/doc/html/rfc9113#name-stream-states
The spec[*1] says that an endpoint should keep the stream in the half-closed (local) state after sending END_STREAM flag and wait to receive END_STREAM flag from the peer before closing it.
That's not true. Server can actively close the stream without waiting for END_STREAM if the server knows that receiving the rest of request is unnecessary. https://datatracker.ietf.org/doc/html/rfc9113#section-8.1-11
There is a way to close unnecessary streams cleanly. https://datatracker.ietf.org/doc/html/rfc9113#section-5.1-7.14.5 https://datatracker.ietf.org/doc/html/rfc9113#section-5.1-7.14.6
We should not retain resources to be used unnecessarily.
All right, we can close the stream by sending a RST_STREAM. It might be better for resource usage point of view.
It doesn't seem like the fundamental issue is fixed.
I have transaction_active_timeout_in: 1 and sending a POST request that continues over 1 second causes stream errors with error code STREAM_CLOSED.
Cherry-picked to 10.1.x branch