1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-02-21 11:54:47 +01:00

Implement RSV bits

This commit is contained in:
Park Joon-Kyu 2024-11-06 21:57:48 +09:00
parent ef977055fc
commit ecb4616d2a
4 changed files with 82 additions and 24 deletions

View File

@ -6,7 +6,7 @@ use tracing::error;
use super::{
frame::Parser,
proto::{CloseReason, OpCode},
proto::{CloseReason, OpCode, RsvBits},
ProtocolError,
};
@ -71,6 +71,9 @@ pub enum Item {
pub struct Codec {
flags: Flags,
max_size: usize,
inbound_rsv_bits: Option<RsvBits>,
outbound_rsv_bits: RsvBits,
}
bitflags! {
@ -88,6 +91,9 @@ impl Codec {
Codec {
max_size: 65_536,
flags: Flags::SERVER,
inbound_rsv_bits: None,
outbound_rsv_bits: RsvBits::empty(),
}
}
@ -108,6 +114,18 @@ impl Codec {
self.flags.remove(Flags::SERVER);
self
}
/// Get inbound RSV bits.
///
/// Returns None if there's no received frame yet.
pub fn get_inbound_rsv_bits(&self) -> Option<RsvBits> {
self.inbound_rsv_bits
}
/// Set outbound RSV bits.
pub fn set_outbound_rsv_bits(&mut self, rsv_bits: RsvBits) {
self.outbound_rsv_bits = rsv_bits;
}
}
impl Default for Codec {
@ -125,6 +143,7 @@ impl Encoder<Message> for Codec {
dst,
txt,
OpCode::Text,
self.outbound_rsv_bits,
true,
!self.flags.contains(Flags::SERVER),
),
@ -132,6 +151,7 @@ impl Encoder<Message> for Codec {
dst,
bin,
OpCode::Binary,
self.outbound_rsv_bits,
true,
!self.flags.contains(Flags::SERVER),
),
@ -139,6 +159,7 @@ impl Encoder<Message> for Codec {
dst,
txt,
OpCode::Ping,
self.outbound_rsv_bits,
true,
!self.flags.contains(Flags::SERVER),
),
@ -146,12 +167,16 @@ impl Encoder<Message> for Codec {
dst,
txt,
OpCode::Pong,
self.outbound_rsv_bits,
true,
!self.flags.contains(Flags::SERVER),
),
Message::Close(reason) => {
Parser::write_close(dst, reason, !self.flags.contains(Flags::SERVER))
}
Message::Close(reason) => Parser::write_close(
dst,
reason,
self.outbound_rsv_bits,
!self.flags.contains(Flags::SERVER),
),
Message::Continuation(cont) => match cont {
Item::FirstText(data) => {
if self.flags.contains(Flags::W_CONTINUATION) {
@ -162,6 +187,7 @@ impl Encoder<Message> for Codec {
dst,
&data[..],
OpCode::Text,
self.outbound_rsv_bits,
false,
!self.flags.contains(Flags::SERVER),
)
@ -176,6 +202,7 @@ impl Encoder<Message> for Codec {
dst,
&data[..],
OpCode::Binary,
self.outbound_rsv_bits,
false,
!self.flags.contains(Flags::SERVER),
)
@ -187,6 +214,7 @@ impl Encoder<Message> for Codec {
dst,
&data[..],
OpCode::Continue,
self.outbound_rsv_bits,
false,
!self.flags.contains(Flags::SERVER),
)
@ -201,6 +229,7 @@ impl Encoder<Message> for Codec {
dst,
&data[..],
OpCode::Continue,
self.outbound_rsv_bits,
true,
!self.flags.contains(Flags::SERVER),
)
@ -221,7 +250,8 @@ impl Decoder for Codec {
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match Parser::parse(src, self.flags.contains(Flags::SERVER), self.max_size) {
Ok(Some((finished, opcode, payload))) => {
Ok(Some((finished, opcode, rsv_bits, payload))) => {
self.inbound_rsv_bits = Some(rsv_bits);
// continuation is not supported
if !finished {
return match opcode {

View File

@ -5,7 +5,7 @@ use tracing::debug;
use super::{
mask::apply_mask,
proto::{CloseCode, CloseReason, OpCode},
proto::{CloseCode, CloseReason, OpCode, RsvBits},
ProtocolError,
};
@ -17,7 +17,7 @@ impl Parser {
fn parse_metadata(
src: &[u8],
server: bool,
) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError> {
) -> Result<Option<(usize, bool, OpCode, RsvBits, usize, Option<[u8; 4]>)>, ProtocolError> {
let chunk_len = src.len();
let mut idx = 2;
@ -37,6 +37,9 @@ impl Parser {
return Err(ProtocolError::MaskedFrame);
}
// RSV bits
let rsv_bits = RsvBits::from_bits((first & 0x70) >> 4).unwrap_or(RsvBits::empty());
// Op code
let opcode = OpCode::from(first & 0x0F);
@ -79,7 +82,7 @@ impl Parser {
None
};
Ok(Some((idx, finished, opcode, length, mask)))
Ok(Some((idx, finished, opcode, rsv_bits, length, mask)))
}
/// Parse the input stream into a frame.
@ -87,12 +90,13 @@ impl Parser {
src: &mut BytesMut,
server: bool,
max_size: usize,
) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> {
) -> Result<Option<(bool, OpCode, RsvBits, Option<BytesMut>)>, ProtocolError> {
// try to parse ws frame metadata
let (idx, finished, opcode, length, mask) = match Parser::parse_metadata(src, server)? {
None => return Ok(None),
Some(res) => res,
};
let (idx, finished, opcode, rsv_bits, length, mask) =
match Parser::parse_metadata(src, server)? {
None => return Ok(None),
Some(res) => res,
};
// not enough data
if src.len() < idx + length {
@ -115,7 +119,7 @@ impl Parser {
// no need for body
if length == 0 {
return Ok(Some((finished, opcode, None)));
return Ok(Some((finished, opcode, rsv_bits, None)));
}
let mut data = src.split_to(length);
@ -127,7 +131,7 @@ impl Parser {
}
OpCode::Close if length > 125 => {
debug!("Received close frame with payload length exceeding 125. Morphing to protocol close frame.");
return Ok(Some((true, OpCode::Close, None)));
return Ok(Some((true, OpCode::Close, rsv_bits, None)));
}
_ => {}
}
@ -137,7 +141,7 @@ impl Parser {
apply_mask(&mut data, mask);
}
Ok(Some((finished, opcode, Some(data))))
Ok(Some((finished, opcode, rsv_bits, Some(data))))
}
/// Parse the payload of a close frame.
@ -161,15 +165,15 @@ impl Parser {
dst: &mut BytesMut,
pl: B,
op: OpCode,
rsv_bits: RsvBits,
fin: bool,
mask: bool,
) {
let payload = pl.as_ref();
let one: u8 = if fin {
0x80 | Into::<u8>::into(op)
} else {
op.into()
};
let fin_bits = if fin { 0x80 } else { 0x00 };
let rsv_bits = rsv_bits.bits() << 4;
let one: u8 = fin_bits | rsv_bits | Into::<u8>::into(op);
let payload_len = payload.len();
let (two, p_len) = if mask {
(0x80, payload_len + 4)
@ -203,7 +207,12 @@ impl Parser {
/// Create a new Close control frame.
#[inline]
pub fn write_close(dst: &mut BytesMut, reason: Option<CloseReason>, mask: bool) {
pub fn write_close(
dst: &mut BytesMut,
reason: Option<CloseReason>,
rsv_bits: RsvBits,
mask: bool,
) {
let payload = match reason {
None => Vec::new(),
Some(reason) => {
@ -215,7 +224,7 @@ impl Parser {
}
};
Parser::write_message(dst, payload, OpCode::Close, true, mask)
Parser::write_message(dst, payload, OpCode::Close, rsv_bits, true, mask)
}
}

View File

@ -20,7 +20,7 @@ pub use self::{
codec::{Codec, Frame, Item, Message},
dispatcher::Dispatcher,
frame::Parser,
proto::{hash_key, CloseCode, CloseReason, OpCode},
proto::{hash_key, CloseCode, CloseReason, OpCode, RsvBits},
};
/// WebSocket protocol errors.

View File

@ -222,6 +222,25 @@ impl<T: Into<String>> From<(CloseCode, T)> for CloseReason {
}
}
bitflags::bitflags! {
/// RSV bits defined in [RFC 6455 §5.2].
/// Reserved for extensions and should be set to zero if no extensions are applicable.
///
/// [RFC 6455]: https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct RsvBits: u8 {
const RSV1 = 0b0000_0100;
const RSV2 = 0b0000_0010;
const RSV3 = 0b0000_0001;
}
}
impl Default for RsvBits {
fn default() -> Self {
Self::empty()
}
}
/// The WebSocket GUID as stated in the spec.
/// See <https://datatracker.ietf.org/doc/html/rfc6455#section-1.3>.
static WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";