Skip to content

Commit

Permalink
apps: more eagerly attempt to write HTTP response stream data in quic…
Browse files Browse the repository at this point in the history
…he-server

Previously, the quiche-server HTTP/3 poll() loop would preference writing HTTP
response headers for all received requests ahead of any other data. Once
completed, no attempt to use remaining stream capacity was made. This had the
effect of deferring writing HTTP response content until the next time the read
loop was triggered. Especially noticeable when the path had a high RTT.

This change forces an attempt to write on any writable response streams
immediately after all response headers have been flushed.
  • Loading branch information
LPardue authored and ghedo committed Oct 9, 2024
1 parent 93074d5 commit 9ea2152
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
5 changes: 3 additions & 2 deletions apps/src/bin/quiche-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,9 @@ fn main() {
let http_conn = client.http_conn.as_mut().unwrap();
let partial_responses = &mut client.partial_responses;

// Handle writable streams.
for stream_id in conn.writable() {
// Visit all writable response streams to send any remaining HTTP
// content.
for stream_id in writable_response_streams(conn) {
http_conn.handle_writable(conn, partial_responses, stream_id);
}

Expand Down
28 changes: 26 additions & 2 deletions apps/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,12 @@ pub trait HttpConn {
);
}

pub fn writable_response_streams(
conn: &quiche::Connection,
) -> impl Iterator<Item = u64> {
conn.writable().filter(|id| id % 4 == 0)
}

/// Represents an HTTP/0.9 formatted request.
pub struct Http09Request {
url: url::Url,
Expand Down Expand Up @@ -675,7 +681,12 @@ impl HttpConn for Http09Conn {
&mut self, conn: &mut quiche::Connection,
partial_responses: &mut HashMap<u64, PartialResponse>, stream_id: u64,
) {
trace!("{} stream {} is writable", conn.trace_id(), stream_id);
debug!(
"{} response stream {} is writable with capacity {:?}",
conn.trace_id(),
stream_id,
conn.stream_capacity(stream_id)
);

if !partial_responses.contains_key(&stream_id) {
return;
Expand Down Expand Up @@ -1393,6 +1404,9 @@ impl HttpConn for Http3Conn {
index: &str, buf: &mut [u8],
) -> quiche::h3::Result<()> {
// Process HTTP stream-related events.
//
// This loops over any and all received HTTP requests and sends just the
// HTTP response headers.
loop {
match self.h3_conn.poll(conn) {
Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => {
Expand Down Expand Up @@ -1547,6 +1561,11 @@ impl HttpConn for Http3Conn {
}
}

// Visit all writable response streams to send HTTP content.
for stream_id in writable_response_streams(conn) {
self.handle_writable(conn, partial_responses, stream_id);
}

// Process datagram-related events.
while let Ok(len) = conn.dgram_recv(buf) {
let mut b = octets::Octets::with_slice(buf);
Expand Down Expand Up @@ -1587,7 +1606,12 @@ impl HttpConn for Http3Conn {
&mut self, conn: &mut quiche::Connection,
partial_responses: &mut HashMap<u64, PartialResponse>, stream_id: u64,
) {
debug!("{} stream {} is writable", conn.trace_id(), stream_id);
debug!(
"{} response stream {} is writable with capacity {:?}",
conn.trace_id(),
stream_id,
conn.stream_capacity(stream_id)
);

if !partial_responses.contains_key(&stream_id) {
return;
Expand Down

0 comments on commit 9ea2152

Please sign in to comment.