1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-02-22 04:03:17 +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::{ use super::{
frame::Parser, frame::Parser,
proto::{CloseReason, OpCode}, proto::{CloseReason, OpCode, RsvBits},
ProtocolError, ProtocolError,
}; };
@ -71,6 +71,9 @@ pub enum Item {
pub struct Codec { pub struct Codec {
flags: Flags, flags: Flags,
max_size: usize, max_size: usize,
inbound_rsv_bits: Option<RsvBits>,
outbound_rsv_bits: RsvBits,
} }
bitflags! { bitflags! {
@ -88,6 +91,9 @@ impl Codec {
Codec { Codec {
max_size: 65_536, max_size: 65_536,
flags: Flags::SERVER, flags: Flags::SERVER,
inbound_rsv_bits: None,
outbound_rsv_bits: RsvBits::empty(),
} }
} }
@ -108,6 +114,18 @@ impl Codec {
self.flags.remove(Flags::SERVER); self.flags.remove(Flags::SERVER);
self 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 { impl Default for Codec {
@ -125,6 +143,7 @@ impl Encoder<Message> for Codec {
dst, dst,
txt, txt,
OpCode::Text, OpCode::Text,
self.outbound_rsv_bits,
true, true,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
), ),
@ -132,6 +151,7 @@ impl Encoder<Message> for Codec {
dst, dst,
bin, bin,
OpCode::Binary, OpCode::Binary,
self.outbound_rsv_bits,
true, true,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
), ),
@ -139,6 +159,7 @@ impl Encoder<Message> for Codec {
dst, dst,
txt, txt,
OpCode::Ping, OpCode::Ping,
self.outbound_rsv_bits,
true, true,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
), ),
@ -146,12 +167,16 @@ impl Encoder<Message> for Codec {
dst, dst,
txt, txt,
OpCode::Pong, OpCode::Pong,
self.outbound_rsv_bits,
true, true,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
), ),
Message::Close(reason) => { Message::Close(reason) => Parser::write_close(
Parser::write_close(dst, reason, !self.flags.contains(Flags::SERVER)) dst,
} reason,
self.outbound_rsv_bits,
!self.flags.contains(Flags::SERVER),
),
Message::Continuation(cont) => match cont { Message::Continuation(cont) => match cont {
Item::FirstText(data) => { Item::FirstText(data) => {
if self.flags.contains(Flags::W_CONTINUATION) { if self.flags.contains(Flags::W_CONTINUATION) {
@ -162,6 +187,7 @@ impl Encoder<Message> for Codec {
dst, dst,
&data[..], &data[..],
OpCode::Text, OpCode::Text,
self.outbound_rsv_bits,
false, false,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
) )
@ -176,6 +202,7 @@ impl Encoder<Message> for Codec {
dst, dst,
&data[..], &data[..],
OpCode::Binary, OpCode::Binary,
self.outbound_rsv_bits,
false, false,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
) )
@ -187,6 +214,7 @@ impl Encoder<Message> for Codec {
dst, dst,
&data[..], &data[..],
OpCode::Continue, OpCode::Continue,
self.outbound_rsv_bits,
false, false,
!self.flags.contains(Flags::SERVER), !self.flags.contains(Flags::SERVER),
) )
@ -201,6 +229,7 @@ impl Encoder<Message> for Codec {
dst, dst,
&data[..], &data[..],
OpCode::Continue, OpCode::Continue,
self.outbound_rsv_bits,
true, true,
!self.flags.contains(Flags::SERVER), !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> { 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) { 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 // continuation is not supported
if !finished { if !finished {
return match opcode { return match opcode {

View File

@ -5,7 +5,7 @@ use tracing::debug;
use super::{ use super::{
mask::apply_mask, mask::apply_mask,
proto::{CloseCode, CloseReason, OpCode}, proto::{CloseCode, CloseReason, OpCode, RsvBits},
ProtocolError, ProtocolError,
}; };
@ -17,7 +17,7 @@ impl Parser {
fn parse_metadata( fn parse_metadata(
src: &[u8], src: &[u8],
server: bool, 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 chunk_len = src.len();
let mut idx = 2; let mut idx = 2;
@ -37,6 +37,9 @@ impl Parser {
return Err(ProtocolError::MaskedFrame); return Err(ProtocolError::MaskedFrame);
} }
// RSV bits
let rsv_bits = RsvBits::from_bits((first & 0x70) >> 4).unwrap_or(RsvBits::empty());
// Op code // Op code
let opcode = OpCode::from(first & 0x0F); let opcode = OpCode::from(first & 0x0F);
@ -79,7 +82,7 @@ impl Parser {
None None
}; };
Ok(Some((idx, finished, opcode, length, mask))) Ok(Some((idx, finished, opcode, rsv_bits, length, mask)))
} }
/// Parse the input stream into a frame. /// Parse the input stream into a frame.
@ -87,12 +90,13 @@ impl Parser {
src: &mut BytesMut, src: &mut BytesMut,
server: bool, server: bool,
max_size: usize, max_size: usize,
) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> { ) -> Result<Option<(bool, OpCode, RsvBits, Option<BytesMut>)>, ProtocolError> {
// try to parse ws frame metadata // try to parse ws frame metadata
let (idx, finished, opcode, length, mask) = match Parser::parse_metadata(src, server)? { let (idx, finished, opcode, rsv_bits, length, mask) =
None => return Ok(None), match Parser::parse_metadata(src, server)? {
Some(res) => res, None => return Ok(None),
}; Some(res) => res,
};
// not enough data // not enough data
if src.len() < idx + length { if src.len() < idx + length {
@ -115,7 +119,7 @@ impl Parser {
// no need for body // no need for body
if length == 0 { if length == 0 {
return Ok(Some((finished, opcode, None))); return Ok(Some((finished, opcode, rsv_bits, None)));
} }
let mut data = src.split_to(length); let mut data = src.split_to(length);
@ -127,7 +131,7 @@ impl Parser {
} }
OpCode::Close if length > 125 => { OpCode::Close if length > 125 => {
debug!("Received close frame with payload length exceeding 125. Morphing to protocol close frame."); 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); 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. /// Parse the payload of a close frame.
@ -161,15 +165,15 @@ impl Parser {
dst: &mut BytesMut, dst: &mut BytesMut,
pl: B, pl: B,
op: OpCode, op: OpCode,
rsv_bits: RsvBits,
fin: bool, fin: bool,
mask: bool, mask: bool,
) { ) {
let payload = pl.as_ref(); let payload = pl.as_ref();
let one: u8 = if fin { let fin_bits = if fin { 0x80 } else { 0x00 };
0x80 | Into::<u8>::into(op) let rsv_bits = rsv_bits.bits() << 4;
} else {
op.into() let one: u8 = fin_bits | rsv_bits | Into::<u8>::into(op);
};
let payload_len = payload.len(); let payload_len = payload.len();
let (two, p_len) = if mask { let (two, p_len) = if mask {
(0x80, payload_len + 4) (0x80, payload_len + 4)
@ -203,7 +207,12 @@ impl Parser {
/// Create a new Close control frame. /// Create a new Close control frame.
#[inline] #[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 { let payload = match reason {
None => Vec::new(), None => Vec::new(),
Some(reason) => { 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}, codec::{Codec, Frame, Item, Message},
dispatcher::Dispatcher, dispatcher::Dispatcher,
frame::Parser, frame::Parser,
proto::{hash_key, CloseCode, CloseReason, OpCode}, proto::{hash_key, CloseCode, CloseReason, OpCode, RsvBits},
}; };
/// WebSocket protocol errors. /// 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. /// The WebSocket GUID as stated in the spec.
/// See <https://datatracker.ietf.org/doc/html/rfc6455#section-1.3>. /// See <https://datatracker.ietf.org/doc/html/rfc6455#section-1.3>.
static WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";