| 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<T = Bytes> { |
| stream_id: StreamId, |
| data: T, |
| flags: DataFlags, |
| pad_len: Option<u8>, |
| } |
| |
| #[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<T> Data<T> { |
| /// 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<F, U>(self, f: F) -> Data<U> |
| 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<Bytes> { |
| pub(crate) fn load(head: Head, mut payload: Bytes) -> Result<Self, Error> { |
| 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<T: Buf> Data<T> { |
| /// Encode the data frame into the `dst` buffer. |
| /// |
| /// # Panics |
| /// |
| /// Panics if `dst` cannot contain the data frame. |
| pub(crate) fn encode_chunk<U: BufMut>(&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<T> From<Data<T>> for Frame<T> { |
| fn from(src: Data<T>) -> Self { |
| Frame::Data(src) |
| } |
| } |
| |
| impl<T> fmt::Debug for Data<T> { |
| 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<DataFlags> 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() |
| } |
| } |