mirror of
https://github.com/fafhrd91/actix-web
synced 2025-02-22 12:13:16 +01:00
Implement RSV bits
This commit is contained in:
parent
ef977055fc
commit
ecb4616d2a
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user