use crate::frame::{util, Error, Frame, Head, Kind, StreamId}; use bytes::{Buf, BufMut, Bytes}; use std::fmt; /// Data frame /// /// Data frames convey arbitrary, variable-length sequences of octets associated /// with a stream. One or more DATA frames are used, for instance, to carry HTTP /// request or response payloads. #[derive(Eq, PartialEq)] pub struct Data { stream_id: StreamId, data: T, flags: DataFlags, pad_len: Option, } #[derive(Copy, Clone, Default, Eq, PartialEq)] struct DataFlags(u8); const END_STREAM: u8 = 0x1; const PADDED: u8 = 0x8; const ALL: u8 = END_STREAM | PADDED; impl Data { /// Creates a new DATA frame. pub fn new(stream_id: StreamId, payload: T) -> Self { assert!(!stream_id.is_zero()); Data { stream_id, data: payload, flags: DataFlags::default(), pad_len: None, } } /// Returns the stream identifier that this frame is associated with. /// /// This cannot be a zero stream identifier. pub fn stream_id(&self) -> StreamId { self.stream_id } /// Gets the value of the `END_STREAM` flag for this frame. /// /// If true, this frame is the last that the endpoint will send for the /// identified stream. /// /// Setting this flag causes the stream to enter one of the "half-closed" /// states or the "closed" state (Section 5.1). pub fn is_end_stream(&self) -> bool { self.flags.is_end_stream() } /// Sets the value for the `END_STREAM` flag on this frame. pub fn set_end_stream(&mut self, val: bool) { if val { self.flags.set_end_stream(); } else { self.flags.unset_end_stream(); } } /// Returns whether the `PADDED` flag is set on this frame. #[cfg(feature = "unstable")] pub fn is_padded(&self) -> bool { self.flags.is_padded() } /// Sets the value for the `PADDED` flag on this frame. #[cfg(feature = "unstable")] pub fn set_padded(&mut self) { self.flags.set_padded(); } /// Returns a reference to this frame's payload. /// /// This does **not** include any padding that might have been originally /// included. pub fn payload(&self) -> &T { &self.data } /// Returns a mutable reference to this frame's payload. /// /// This does **not** include any padding that might have been originally /// included. pub fn payload_mut(&mut self) -> &mut T { &mut self.data } /// Consumes `self` and returns the frame's payload. /// /// This does **not** include any padding that might have been originally /// included. pub fn into_payload(self) -> T { self.data } pub(crate) fn head(&self) -> Head { Head::new(Kind::Data, self.flags.into(), self.stream_id) } pub(crate) fn map(self, f: F) -> Data where F: FnOnce(T) -> U, { Data { stream_id: self.stream_id, data: f(self.data), flags: self.flags, pad_len: self.pad_len, } } } impl Data { pub(crate) fn load(head: Head, mut payload: Bytes) -> Result { let flags = DataFlags::load(head.flag()); // The stream identifier must not be zero if head.stream_id().is_zero() { return Err(Error::InvalidStreamId); } let pad_len = if flags.is_padded() { let len = util::strip_padding(&mut payload)?; Some(len) } else { None }; Ok(Data { stream_id: head.stream_id(), data: payload, flags, pad_len, }) } } impl Data { /// Encode the data frame into the `dst` buffer. /// /// # Panics /// /// Panics if `dst` cannot contain the data frame. pub(crate) fn encode_chunk(&mut self, dst: &mut U) { let len = self.data.remaining(); assert!(dst.remaining_mut() >= len); self.head().encode(len, dst); dst.put(&mut self.data); } } impl From> for Frame { fn from(src: Data) -> Self { Frame::Data(src) } } impl fmt::Debug for Data { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut f = fmt.debug_struct("Data"); f.field("stream_id", &self.stream_id); if !self.flags.is_empty() { f.field("flags", &self.flags); } if let Some(ref pad_len) = self.pad_len { f.field("pad_len", pad_len); } // `data` bytes purposefully excluded f.finish() } } // ===== impl DataFlags ===== impl DataFlags { fn load(bits: u8) -> DataFlags { DataFlags(bits & ALL) } fn is_empty(&self) -> bool { self.0 == 0 } fn is_end_stream(&self) -> bool { self.0 & END_STREAM == END_STREAM } fn set_end_stream(&mut self) { self.0 |= END_STREAM } fn unset_end_stream(&mut self) { self.0 &= !END_STREAM } fn is_padded(&self) -> bool { self.0 & PADDED == PADDED } #[cfg(feature = "unstable")] fn set_padded(&mut self) { self.0 |= PADDED } } impl From for u8 { fn from(src: DataFlags) -> u8 { src.0 } } impl fmt::Debug for DataFlags { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { util::debug_flags(fmt, self.0) .flag_if(self.is_end_stream(), "END_STREAM") .flag_if(self.is_padded(), "PADDED") .finish() } }