-
Notifications
You must be signed in to change notification settings - Fork 882
h3: add support for streaming HEADERS sends with new functions #2148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Calls to send_request(), send_response(), send_response_with_priority(), and send_additional_headers() can fail with a StreamBlocked error indicating lack of underlying transport capacity. When this occurs, applications ar expected to retry the operation when the stream is later reported as writable. However, certain conditions could mean that sufficient capacity might never be made available, effectively permenantly blocking header sends. The root cause of this problem was the choice to enforce that a HEADERS frame is always sent (buffered into a quiche stream) in whole. This change adds new variants of the header sending functions that support a streaming send design. These will produce a HEADERS frame that can be sent in whole or in part, depending on available capacity. When a frame is only partly sent, applications are notified and can resume sending using the new continue_partial_headers() method, once the stream is writable. While headers are being streamed, other operations that would cause an HTTP/3 frame to be sent on the stream are prevented. HEADERS frames must be sent completly before other operations are successful. Applications do not need to manage the partial HEADERS buffer, this is dealt with inside quiche.
| match conn.stream_writable(stream_id, overhead + header_block.len()) { | ||
| Ok(true) => (), | ||
| stream.outgoing_frame_header = frame_header; | ||
| stream.outgoing_frame_header_off = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: when streaming mode is false, don't set these
| } | ||
| stream.outgoing_frame_payload = frame_payload; | ||
| stream.outgoing_frame_payload_off = 0; | ||
| stream.fin_after_outgoing_frame = fin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: when streaming mode is false, don't set these
|
|
||
| match conn.stream_send(stream_id, &stream.outgoing_frame_header, false) { | ||
| Ok(v) => | ||
| if v != stream.outgoing_frame_header.len() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: only do this when streaming mode is true
| stream.fin_after_outgoing_frame, | ||
| ) { | ||
| Ok(v) => | ||
| if v != stream.outgoing_frame_payload.len() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: only do this when streaming mode is true
3c78e8c to
468a67e
Compare
|
It's probably a good idea to keep the old functions and add new ones like this PR. With #2147 the functions' contract would change but not their signature, so code using them would still compile which could lead to unexpected errors and bugs down the line. I'd probably add a you can avoid the code duplication if you add private implementations of your functions like: |
|
Closing this in favor of #2153 |
NB: this is an alternative to #2147, it adds streaming to new functions in order to keep previous behaviour. New functions names can be bikeshedded.
Calls to send_request(), send_response(), send_response_with_priority(),
and send_additional_headers() can fail with a StreamBlocked
error indicating lack of underlying transport capacity. When this
occurs, applications ar expected to retry the operation when
the stream is later reported as writable.
However, certain conditions could mean that sufficient capacity
might never be made available, effectively permenantly blocking
header sends. The root cause of this problem was the choice to enforce
that a HEADERS frame is always sent (buffered into a quiche stream)
in whole.
This change adds new variants of the header sending functions that
support a streaming send design. These will produce a HEADERS frame
that can be sent in whole or in part, depending on available capacity.
When a frame is only partly sent, applications are notified and
can resume sending using the new continue_partial_headers()
method, once the stream is writable.
While headers are being streamed, other operations that
would cause an HTTP/3 frame to be sent on the stream are
prevented. HEADERS frames must be sent completly before
other operations are successful.
Applications do not need to manage the partial HEADERS
buffer, this is dealt with inside quiche.