160 lines
4.3 KiB
Rust
160 lines
4.3 KiB
Rust
use crate::hpack;
|
|
|
|
use bytes::Bytes;
|
|
|
|
use std::fmt;
|
|
|
|
/// A helper macro that unpacks a sequence of 4 bytes found in the buffer with
|
|
/// the given identifier, starting at the given offset, into the given integer
|
|
/// type. Obviously, the integer type should be able to support at least 4
|
|
/// bytes.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// let buf: [u8; 4] = [0, 0, 0, 1];
|
|
/// assert_eq!(1u32, unpack_octets_4!(buf, 0, u32));
|
|
/// ```
|
|
#[macro_escape]
|
|
macro_rules! unpack_octets_4 {
|
|
// TODO: Get rid of this macro
|
|
($buf:expr, $offset:expr, $tip:ty) => {
|
|
(($buf[$offset + 0] as $tip) << 24)
|
|
| (($buf[$offset + 1] as $tip) << 16)
|
|
| (($buf[$offset + 2] as $tip) << 8)
|
|
| (($buf[$offset + 3] as $tip) << 0)
|
|
};
|
|
}
|
|
|
|
mod data;
|
|
mod go_away;
|
|
mod head;
|
|
mod headers;
|
|
mod ping;
|
|
mod priority;
|
|
mod reason;
|
|
mod reset;
|
|
mod settings;
|
|
mod stream_id;
|
|
mod util;
|
|
mod window_update;
|
|
|
|
pub use self::data::Data;
|
|
pub use self::go_away::GoAway;
|
|
pub use self::head::{Head, Kind};
|
|
pub use self::headers::{
|
|
parse_u64, Continuation, Headers, Pseudo, PushPromise, PushPromiseHeaderError,
|
|
};
|
|
pub use self::ping::Ping;
|
|
pub use self::priority::{Priority, StreamDependency};
|
|
pub use self::reason::Reason;
|
|
pub use self::reset::Reset;
|
|
pub use self::settings::Settings;
|
|
pub use self::stream_id::{StreamId, StreamIdOverflow};
|
|
pub use self::window_update::WindowUpdate;
|
|
|
|
// Re-export some constants
|
|
|
|
pub use self::settings::{
|
|
DEFAULT_INITIAL_WINDOW_SIZE, DEFAULT_MAX_FRAME_SIZE, DEFAULT_SETTINGS_HEADER_TABLE_SIZE,
|
|
MAX_INITIAL_WINDOW_SIZE, MAX_MAX_FRAME_SIZE,
|
|
};
|
|
|
|
pub type FrameSize = u32;
|
|
|
|
pub const HEADER_LEN: usize = 9;
|
|
|
|
#[derive(Eq, PartialEq)]
|
|
pub enum Frame<T = Bytes> {
|
|
Data(Data<T>),
|
|
Headers(Headers),
|
|
Priority(Priority),
|
|
PushPromise(PushPromise),
|
|
Settings(Settings),
|
|
Ping(Ping),
|
|
GoAway(GoAway),
|
|
WindowUpdate(WindowUpdate),
|
|
Reset(Reset),
|
|
}
|
|
|
|
impl<T> Frame<T> {
|
|
pub fn map<F, U>(self, f: F) -> Frame<U>
|
|
where
|
|
F: FnOnce(T) -> U,
|
|
{
|
|
use self::Frame::*;
|
|
|
|
match self {
|
|
Data(frame) => frame.map(f).into(),
|
|
Headers(frame) => frame.into(),
|
|
Priority(frame) => frame.into(),
|
|
PushPromise(frame) => frame.into(),
|
|
Settings(frame) => frame.into(),
|
|
Ping(frame) => frame.into(),
|
|
GoAway(frame) => frame.into(),
|
|
WindowUpdate(frame) => frame.into(),
|
|
Reset(frame) => frame.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> fmt::Debug for Frame<T> {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
use self::Frame::*;
|
|
|
|
match *self {
|
|
Data(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
Headers(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
Priority(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
PushPromise(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
Settings(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
Ping(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
GoAway(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
WindowUpdate(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
Reset(ref frame) => fmt::Debug::fmt(frame, fmt),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Errors that can occur during parsing an HTTP/2 frame.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum Error {
|
|
/// A length value other than 8 was set on a PING message.
|
|
BadFrameSize,
|
|
|
|
/// The padding length was larger than the frame-header-specified
|
|
/// length of the payload.
|
|
TooMuchPadding,
|
|
|
|
/// An invalid setting value was provided
|
|
InvalidSettingValue,
|
|
|
|
/// An invalid window update value
|
|
InvalidWindowUpdateValue,
|
|
|
|
/// The payload length specified by the frame header was not the
|
|
/// value necessary for the specific frame type.
|
|
InvalidPayloadLength,
|
|
|
|
/// Received a payload with an ACK settings frame
|
|
InvalidPayloadAckSettings,
|
|
|
|
/// An invalid stream identifier was provided.
|
|
///
|
|
/// This is returned if a SETTINGS or PING frame is received with a stream
|
|
/// identifier other than zero.
|
|
InvalidStreamId,
|
|
|
|
/// A request or response is malformed.
|
|
MalformedMessage,
|
|
|
|
/// An invalid stream dependency ID was provided
|
|
///
|
|
/// This is returned if a HEADERS or PRIORITY frame is received with an
|
|
/// invalid stream identifier.
|
|
InvalidDependencyId,
|
|
|
|
/// Failed to perform HPACK decoding
|
|
Hpack(hpack::DecoderError),
|
|
}
|