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:
parent
ef977055fc
commit
ecb4616d2a
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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";
|
||||
|
Loading…
x
Reference in New Issue
Block a user