// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0 > or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT >, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt::{Debug, Write
as _};
use neqo_common::{Buffer, Decoder, Encoder};
use neqo_transport::StreamId;
use nss::random;
use crate ::{Error, Priority, PushId, Res, frames::reader::FrameDecoder, settings::HSet
tings};
#[ derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HFrameType(pub u64);
impl HFrameType {
pub const DATA: Self = Self (0 x0);
pub const HEADERS: Self = Self (0 x1);
pub const CANCEL_PUSH: Self = Self (0 x3);
pub const SETTINGS: Self = Self (0 x4);
pub const PUSH_PROMISE: Self = Self (0 x5);
pub const GOAWAY: Self = Self (0 x7);
pub const MAX_PUSH_ID: Self = Self (0 xd);
pub const PRIORITY_UPDATE_REQUEST: Self = Self (0 xf0700);
pub const PRIORITY_UPDATE_PUSH: Self = Self (0 xf0701);
/// See <https://www.rfc-editor.org/rfc/rfc9114.html#section-11.2.1 > for these reserved types.
pub const RESERVED: &[Self ] = &[Self (0 x2), Self (0 x6), Self (0 x8), Self (0 x9)];
}
impl From<HFrameType> for u64 {
fn from(t: HFrameType) -> Self {
t.0
}
}
// data for DATA frame is not read into HFrame::Data.
#[ derive(PartialEq, Eq, Debug)]
pub enum HFrame {
Data {
len: u64, // length of the data
},
Headers {
header_block: Vec<u8>,
},
CancelPush {
push_id: PushId,
},
Settings {
settings: HSettings,
},
PushPromise {
push_id: PushId,
header_block: Vec<u8>,
},
Goaway {
stream_id: StreamId,
},
MaxPushId {
push_id: PushId,
},
Grease,
PriorityUpdateRequest {
element_id: u64,
priority: Priority,
},
PriorityUpdatePush {
element_id: u64,
priority: Priority,
},
}
impl HFrame {
fn get_type(&self ) -> HFrameType {
match self {
Self ::Data { .. } => HFrameType::DATA,
Self ::Headers { .. } => HFrameType::HEADERS,
Self ::CancelPush { .. } => HFrameType::CANCEL_PUSH,
Self ::Settings { .. } => HFrameType::SETTINGS,
Self ::PushPromise { .. } => HFrameType::PUSH_PROMISE,
Self ::Goaway { .. } => HFrameType::GOAWAY,
Self ::MaxPushId { .. } => HFrameType::MAX_PUSH_ID,
Self ::PriorityUpdateRequest { .. } => HFrameType::PRIORITY_UPDATE_REQUEST,
Self ::PriorityUpdatePush { .. } => HFrameType::PRIORITY_UPDATE_PUSH,
Self ::Grease => {
let r = u64::from_ne_bytes(random::<8 >());
// Zero out the top 7 bits: 2 for being a varint; 5 to account for the *0x1f.
HFrameType((r >> 7 ) * 0 x1f + 0 x21)
}
}
}
pub fn encode<B: Buffer>(&self , enc: &mut Encoder<B>) {
enc.encode_varint(self .get_type());
match self {
Self ::Data { len } => {
// DATA frame only encode the length here.
enc.encode_varint(*len);
}
Self ::Headers { header_block } => {
enc.encode_vvec(header_block);
}
Self ::CancelPush { push_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*push_id);
});
}
Self ::Settings { settings } => {
settings.encode_frame_contents(enc);
}
Self ::PushPromise {
push_id,
header_block,
} => {
enc.encode_varint(
(header_block.len() + (Encoder::varint_len(u64::from(*push_id)))) as u64,
);
enc.encode_varint(*push_id);
enc.encode(header_block);
}
Self ::Goaway { stream_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(stream_id.as_u64());
});
}
Self ::MaxPushId { push_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*push_id);
});
}
Self ::Grease => {
// Encode some number of random bytes.
let r = random::<8 >();
enc.encode_vvec(&r[1 ..usize::from(1 + (r[0 ] & 0 x7))]);
}
Self ::PriorityUpdateRequest {
element_id,
priority,
}
| Self ::PriorityUpdatePush {
element_id,
priority,
} => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*element_id);
write!(enc_inner, "{priority}" ).expect("write OK" );
});
}
}
}
}
impl FrameDecoder<Self > for HFrame {
#[ cfg(feature = "build-fuzzing-corpus" )]
const FUZZING_CORPUS: Option<&'static str> = Some("hframe");
fn frame_type_allowed(frame_type: HFrameType) -> Res<()> {
if HFrameType::RESERVED.contains(&frame_type) {
return Err(Error::HttpFrameUnexpected);
}
Ok(())
}
fn decode(frame_type: HFrameType, frame_len: u64, data: Option<&[u8]>) -> Res<Option<Self >> {
if frame_type == HFrameType::DATA {
Ok(Some(Self ::Data { len: frame_len }))
} else if let Some(payload) = data {
let mut dec = Decoder::from(payload);
Ok(match frame_type {
HFrameType::DATA => unreachable!("DATA frame has been handled already" ),
HFrameType::HEADERS => Some(Self ::Headers {
header_block: dec.decode_remainder().to_vec(),
}),
HFrameType::CANCEL_PUSH => Some(Self ::CancelPush {
push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(),
}),
HFrameType::SETTINGS => {
let mut settings = HSettings::default();
settings.decode_frame_contents(&mut dec).map_err(|e| {
if e == Error::HttpSettings {
e
} else {
Error::HttpFrame
}
})?;
Some(Self ::Settings { settings })
}
HFrameType::PUSH_PROMISE => Some(Self ::PushPromise {
push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(),
header_block: dec.decode_remainder().to_vec(),
}),
HFrameType::GOAWAY => Some(Self ::Goaway {
stream_id: StreamId::new(dec.decode_varint().ok_or(Error::HttpFrame)?),
}),
HFrameType::MAX_PUSH_ID => Some(Self ::MaxPushId {
push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(),
}),
HFrameType::PRIORITY_UPDATE_REQUEST | HFrameType::PRIORITY_UPDATE_PUSH => {
let element_id = dec.decode_varint().ok_or(Error::HttpFrame)?;
let priority = dec.decode_remainder();
let priority = Priority::from_bytes(priority)?;
if frame_type == HFrameType::PRIORITY_UPDATE_REQUEST {
Some(Self ::PriorityUpdateRequest {
element_id,
priority,
})
} else {
Some(Self ::PriorityUpdatePush {
element_id,
priority,
})
}
}
_ => None,
})
} else {
Ok(None)
}
}
fn is_known_type(frame_type: HFrameType) -> bool {
matches!(
frame_type,
HFrameType::DATA
| HFrameType::HEADERS
| HFrameType::CANCEL_PUSH
| HFrameType::SETTINGS
| HFrameType::PUSH_PROMISE
| HFrameType::GOAWAY
| HFrameType::MAX_PUSH_ID
| HFrameType::PRIORITY_UPDATE_REQUEST
| HFrameType::PRIORITY_UPDATE_PUSH
)
}
}
Messung V0.5 in Prozent C=80 H=97 G=88
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland