use super::super::control::{
Http2Goaway, Http2Ping, Http2PriorityFrame, Http2RstStream, Http2WindowIncrement,
Http2WindowUpdate,
};
use super::super::error::Http2BuildError;
use super::super::frame::Http2Frame;
use super::super::priority::Http2Priority;
use super::super::settings::{Http2Setting, Http2Settings};
use super::super::types::{Http2ErrorCode, Http2FrameType, Http2StreamId};
use super::raw::{FRAME_HEADER_LENGTH, MAXIMUM_PAYLOAD, write_frame_envelope};
pub struct Http2SettingsBuilder<'a, 'b> {
buffer: &'a mut [u8],
flags: u8,
settings: &'b [Http2Setting],
}
impl<'a, 'b> Http2SettingsBuilder<'a, 'b> {
pub fn new(buffer: &'a mut [u8], flags: u8, settings: &'b [Http2Setting]) -> Self {
Self {
buffer,
flags,
settings,
}
}
pub fn build(self) -> Result<Http2Settings<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2Settings<'a>, Http2BuildError> {
for setting in self.settings.iter().copied() {
if !setting.has_valid_intrinsic_value() {
return Err(Http2BuildError::InvalidSettingValue {
id: setting.id(),
value: setting.value(),
});
}
}
let payload_length =
self.settings
.len()
.checked_mul(6)
.ok_or(Http2BuildError::PayloadTooLarge {
maximum: maximum_payload.min(MAXIMUM_PAYLOAD),
actual: self.settings.len(),
})?;
if self.flags & 0x1 != 0 && payload_length != 0 {
return Err(Http2BuildError::SettingsAckPayload {
actual: payload_length,
});
}
let bytes = write_frame_envelope(
self.buffer,
payload_length,
Http2FrameType::SETTINGS,
self.flags,
Http2StreamId::new(0),
maximum_payload,
)?;
for (index, setting) in self.settings.iter().copied().enumerate() {
let offset = FRAME_HEADER_LENGTH + index * 6;
bytes[offset..offset + 2].copy_from_slice(&setting.id().raw().to_be_bytes());
bytes[offset + 2..offset + 6].copy_from_slice(&setting.value().to_be_bytes());
}
Ok(Http2Settings::from_validated(Http2Frame::from_validated(
bytes,
)))
}
}
pub struct Http2GoawayBuilder<'a, 'b> {
buffer: &'a mut [u8],
flags: u8,
last_stream_id: Http2StreamId,
error_code: Http2ErrorCode,
additional_debug_data: &'b [u8],
}
impl<'a, 'b> Http2GoawayBuilder<'a, 'b> {
pub fn new(
buffer: &'a mut [u8],
flags: u8,
last_stream_id: Http2StreamId,
error_code: Http2ErrorCode,
additional_debug_data: &'b [u8],
) -> Self {
Self {
buffer,
flags,
last_stream_id,
error_code,
additional_debug_data,
}
}
pub fn build(self) -> Result<Http2Goaway<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2Goaway<'a>, Http2BuildError> {
if self.last_stream_id.has_reserved_bit() {
return Err(Http2BuildError::ReservedLastStreamId);
}
let payload_length = self.additional_debug_data.len().checked_add(8).ok_or(
Http2BuildError::PayloadTooLarge {
maximum: maximum_payload.min(MAXIMUM_PAYLOAD),
actual: self.additional_debug_data.len(),
},
)?;
let bytes = write_frame_envelope(
self.buffer,
payload_length,
Http2FrameType::GOAWAY,
self.flags,
Http2StreamId::new(0),
maximum_payload,
)?;
bytes[FRAME_HEADER_LENGTH..FRAME_HEADER_LENGTH + 4]
.copy_from_slice(&self.last_stream_id.raw().to_be_bytes());
bytes[FRAME_HEADER_LENGTH + 4..FRAME_HEADER_LENGTH + 8]
.copy_from_slice(&self.error_code.raw().to_be_bytes());
bytes[FRAME_HEADER_LENGTH + 8..].copy_from_slice(self.additional_debug_data);
Ok(Http2Goaway::from_validated(
Http2Frame::from_validated(bytes),
self.last_stream_id,
self.error_code,
))
}
}
pub struct Http2PriorityFrameBuilder<'a> {
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
priority: Http2Priority,
}
impl<'a> Http2PriorityFrameBuilder<'a> {
pub fn new(
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
priority: Http2Priority,
) -> Self {
Self {
buffer,
stream_id,
flags,
priority,
}
}
pub fn build(self) -> Result<Http2PriorityFrame<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2PriorityFrame<'a>, Http2BuildError> {
validate_required_stream_id(self.stream_id)?;
let bytes = write_frame_envelope(
self.buffer,
5,
Http2FrameType::PRIORITY,
self.flags,
self.stream_id,
maximum_payload,
)?;
bytes[FRAME_HEADER_LENGTH..FRAME_HEADER_LENGTH + 4]
.copy_from_slice(&self.priority.raw_dependency().to_be_bytes());
bytes[FRAME_HEADER_LENGTH + 4] = self.priority.weight();
Ok(Http2PriorityFrame::from_validated(
Http2Frame::from_validated(bytes),
self.priority,
))
}
}
pub struct Http2RstStreamBuilder<'a> {
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
error_code: Http2ErrorCode,
}
impl<'a> Http2RstStreamBuilder<'a> {
pub fn new(
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
error_code: Http2ErrorCode,
) -> Self {
Self {
buffer,
stream_id,
flags,
error_code,
}
}
pub fn build(self) -> Result<Http2RstStream<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2RstStream<'a>, Http2BuildError> {
validate_required_stream_id(self.stream_id)?;
let bytes = write_frame_envelope(
self.buffer,
4,
Http2FrameType::RST_STREAM,
self.flags,
self.stream_id,
maximum_payload,
)?;
bytes[FRAME_HEADER_LENGTH..].copy_from_slice(&self.error_code.raw().to_be_bytes());
Ok(Http2RstStream::from_validated(
Http2Frame::from_validated(bytes),
self.error_code,
))
}
}
pub struct Http2PingBuilder<'a, 'b> {
buffer: &'a mut [u8],
flags: u8,
opaque_data: &'b [u8; 8],
}
impl<'a, 'b> Http2PingBuilder<'a, 'b> {
pub fn new(buffer: &'a mut [u8], flags: u8, opaque_data: &'b [u8; 8]) -> Self {
Self {
buffer,
flags,
opaque_data,
}
}
pub fn build(self) -> Result<Http2Ping<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2Ping<'a>, Http2BuildError> {
let bytes = write_frame_envelope(
self.buffer,
8,
Http2FrameType::PING,
self.flags,
Http2StreamId::new(0),
maximum_payload,
)?;
bytes[FRAME_HEADER_LENGTH..].copy_from_slice(self.opaque_data);
let opaque_data = bytes[FRAME_HEADER_LENGTH..].try_into().map_err(|_| {
Http2BuildError::BufferTooShort {
required: FRAME_HEADER_LENGTH + 8,
available: bytes.len(),
}
})?;
Ok(Http2Ping::from_validated(
Http2Frame::from_validated(bytes),
opaque_data,
))
}
}
pub struct Http2WindowUpdateBuilder<'a> {
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
increment: Http2WindowIncrement,
}
impl<'a> Http2WindowUpdateBuilder<'a> {
pub fn new(
buffer: &'a mut [u8],
stream_id: Http2StreamId,
flags: u8,
increment: Http2WindowIncrement,
) -> Self {
Self {
buffer,
stream_id,
flags,
increment,
}
}
pub fn build(self) -> Result<Http2WindowUpdate<'a>, Http2BuildError> {
self.build_with_maximum(MAXIMUM_PAYLOAD)
}
pub fn build_with_maximum(
self,
maximum_payload: usize,
) -> Result<Http2WindowUpdate<'a>, Http2BuildError> {
if self.stream_id.has_reserved_bit() {
return Err(Http2BuildError::ReservedStreamId);
}
if self.increment.has_reserved_bit() {
return Err(Http2BuildError::ReservedWindowIncrement);
}
if self.increment.value() == 0 {
return Err(Http2BuildError::ZeroWindowIncrement);
}
let bytes = write_frame_envelope(
self.buffer,
4,
Http2FrameType::WINDOW_UPDATE,
self.flags,
self.stream_id,
maximum_payload,
)?;
bytes[FRAME_HEADER_LENGTH..].copy_from_slice(&self.increment.raw().to_be_bytes());
Ok(Http2WindowUpdate::from_validated(
Http2Frame::from_validated(bytes),
self.increment,
))
}
}
fn validate_required_stream_id(stream_id: Http2StreamId) -> Result<(), Http2BuildError> {
if stream_id.value() == 0 {
return Err(Http2BuildError::ZeroStreamId);
}
if stream_id.has_reserved_bit() {
return Err(Http2BuildError::ReservedStreamId);
}
Ok(())
}