const MIN_DATA_FRAME_SIZE: usize = 3; // Minimal DATA frame size: 2 (header) + 1 (payload) const MAX_DATA_HEADER_SIZE_2: usize = (1 << 6) - 1; // Maximal amount of data with DATA frame header size 2 const MAX_DATA_HEADER_SIZE_2_LIMIT: usize = MAX_DATA_HEADER_SIZE_2 + 3; // 63 + 3 (size of the next buffer data frame header) const MAX_DATA_HEADER_SIZE_3: usize = (1 << 14) - 1; // Maximal amount of data with DATA frame header size 3 const MAX_DATA_HEADER_SIZE_3_LIMIT: usize = MAX_DATA_HEADER_SIZE_3 + 5; // 16383 + 5 (size of the next buffer data frame header) const MAX_DATA_HEADER_SIZE_5: usize = (1 << 30) - 1; // Maximal amount of data with DATA frame header size 3 const MAX_DATA_HEADER_SIZE_5_LIMIT: usize = MAX_DATA_HEADER_SIZE_5 + 9; // 1073741823 + 9 (size of the next buffer data frame header)
/// A HTTP message, request and response, consists of headers, optional data and an optional /// trailer header block. This state machine does not reflect what was already sent to the /// transport layer but only reflect what has been supplied to the `SendMessage`. It is /// represented by the following states: /// `WaitingForHeaders` - the headers have not been supplied yet. In this state only a /// request/response header can be added. When headers are supplied /// the state changes to `WaitingForData`. A response may contain /// multiple messages only if all but the last one are informational(1xx) /// responses. The informational responses can only contain headers, /// therefore after an informational response is received the state /// machine states in `WaitingForHeaders` state. /// `WaitingForData` - in this state, data and trailers can be supplied. This state means that /// a request or response header is already supplied. /// `TrailersSet` - trailers have been supplied. At this stage no more data or headers can be /// supply only a fin. /// `Done` - in this state no more data or headers can be added. This state is entered when the /// message is closed. #[derive(Debug, PartialEq)] enum MessageState {
WaitingForHeaders,
WaitingForData,
TrailersSet,
Done,
}
impl MessageState { fn new_headers(&mutself, headers: &[Header], message_type: MessageType) -> Res<()> { match &self { Self::WaitingForHeaders => { // This is only a debug assertion because we expect that application will // do the right thing here and performing the check costs.
debug_assert!(headers_valid(headers, message_type).is_ok()); match message_type {
MessageType::Request => {
*self = Self::WaitingForData;
}
MessageType::Response => { if !is_interim(headers)? {
*self = Self::WaitingForData;
}
}
}
Ok(())
} Self::WaitingForData => {
trailers_valid(headers)?;
*self = Self::TrailersSet;
Ok(())
} Self::TrailersSet | Self::Done => Err(Error::InvalidInput),
}
}
self.stream.send_buffer(conn)?; ifself.stream.has_buffered_data() { return Ok(0);
} let available = conn
.stream_avail_send_space(self.stream_id())
.map_err(|e| Error::map_stream_send_errors(&e.into()))?; if available < MIN_DATA_FRAME_SIZE { // Setting this once, instead of every time the available send space // is exhausted, would suffice. That said, function call should be // cheap, thus not worth optimizing.
conn.stream_set_writable_event_low_watermark( self.stream_id(),
NonZeroUsize::new(MIN_DATA_FRAME_SIZE).unwrap(),
)?; return Ok(0);
} let to_send = if available <= MAX_DATA_HEADER_SIZE_2_LIMIT { // 63 + 3
min(min(buf.len(), available - 2), MAX_DATA_HEADER_SIZE_2)
} elseif available <= MAX_DATA_HEADER_SIZE_3_LIMIT { // 16383 + 5
min(min(buf.len(), available - 3), MAX_DATA_HEADER_SIZE_3)
} elseif available <= MAX_DATA_HEADER_SIZE_5 { // 1073741823 + 9
min(min(buf.len(), available - 5), MAX_DATA_HEADER_SIZE_5_LIMIT)
} else {
min(buf.len(), available - 9)
};
fn stream_writable(&self) { if !self.stream.has_buffered_data() && !self.state.done() { // DataWritable is just a signal for an application to try to write more data, // if writing fails it is fine. Therefore we do not need to properly check // whether more credits are available on the transport layer. self.conn_events.data_writable(self.get_stream_info());
}
}
/// # Errors /// /// `InternalError` if an unexpected error occurred. /// `InvalidStreamId` if the stream does not exist, /// `AlreadyClosed` if the stream has already been closed. /// `TransportStreamDoesNotExist` if the transport stream does not exist (this may happen if /// `process_output` has not been called when needed, and HTTP3 layer has not picked up the /// info that the stream has been closed.) fn send(&mutself, conn: &mut Connection) -> Res<()> { let sent = Error::map_error(self.stream.send_buffer(conn), Error::HttpInternal(5))?;
qtrace!([self], "{} bytes sent", sent); if !self.stream.has_buffered_data() { ifself.state.done() {
Error::map_error(
conn.stream_close_send(self.stream_id()),
Error::HttpInternal(6),
)?;
qtrace!([self], "done sending request");
} else { // DataWritable is just a signal for an application to try to write more data, // if writing fails it is fine. Therefore we do not need to properly check // whether more credits are available on the transport layer. self.conn_events.data_writable(self.get_stream_info());
}
}
Ok(())
}
// SendMessage owns headers and sends them. It may also own data for the server side. // This method returns if they're still being sent. Request body (if any) is sent by // http client afterwards using `send_request_body` after receiving DataWritable event. fn has_data_to_send(&self) -> bool { self.stream.has_buffered_data()
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.