Fix RSV bit to be autobahn compliant

This commit is contained in:
Heinz Gies 2019-09-10 13:15:42 +02:00 committed by Heinz N. Gies
parent 73580fb527
commit 74d4a89ae8
3 changed files with 41 additions and 11 deletions

View File

@ -101,12 +101,21 @@ impl Decoder for Codec {
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match Parser::parse(src, self.server, self.max_size) {
Ok(Some((finished, opcode, payload))) => {
Ok(Some((finished, rsv, opcode, payload))) => {
// continuation is not supported
if !finished {
return Err(ProtocolError::NoContinuation);
}
// Since this is the default codec we have no extension
// and should fail if rsv is set.
// In an async context this will cause a NON-STRICT
// autoban complience since we might terminate
// before receiving the prior message.
if rsv != 0 {
return Err(ProtocolError::RSVSet);
}
match opcode {
OpCode::Continue => Err(ProtocolError::NoContinuation),
OpCode::Bad => Err(ProtocolError::BadOpCode),

View File

@ -17,7 +17,8 @@ impl Parser {
src: &[u8],
server: bool,
max_size: usize,
) -> Result<Option<(usize, bool, OpCode, usize, Option<u32>)>, ProtocolError> {
) -> Result<Option<(usize, bool, u8, OpCode, usize, Option<u32>)>, ProtocolError>
{
let chunk_len = src.len();
let mut idx = 2;
@ -28,6 +29,7 @@ impl Parser {
let first = src[0];
let second = src[1];
let finished = first & 0x80 != 0;
let rsv: u8 = first & 0x70 >> 4;
// check masking
let masked = second & 0x80 != 0;
@ -86,7 +88,7 @@ impl Parser {
None
};
Ok(Some((idx, finished, opcode, length, mask)))
Ok(Some((idx, finished, rsv, opcode, length, mask)))
}
/// Parse the input stream into a frame.
@ -94,9 +96,9 @@ impl Parser {
src: &mut BytesMut,
server: bool,
max_size: usize,
) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> {
) -> Result<Option<(bool, u8, OpCode, Option<BytesMut>)>, ProtocolError> {
// try to parse ws frame metadata
let (idx, finished, opcode, length, mask) =
let (idx, finished, rsv, opcode, length, mask) =
match Parser::parse_metadata(src, server, max_size)? {
None => return Ok(None),
Some(res) => res,
@ -112,7 +114,7 @@ impl Parser {
// no need for body
if length == 0 {
return Ok(Some((finished, opcode, None)));
return Ok(Some((finished, rsv, opcode, None)));
}
let mut data = src.split_to(length);
@ -124,7 +126,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, rsv, OpCode::Close, None)));
}
_ => (),
}
@ -134,7 +136,7 @@ impl Parser {
apply_mask(&mut data, mask);
}
Ok(Some((finished, opcode, Some(data))))
Ok(Some((finished, rsv, opcode, Some(data))))
}
/// Parse the payload of a close frame.
@ -223,12 +225,13 @@ mod tests {
struct F {
finished: bool,
rsv: u8,
opcode: OpCode,
payload: Bytes,
}
fn is_none(
frm: &Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>,
frm: &Result<Option<(bool, u8, OpCode, Option<BytesMut>)>, ProtocolError>,
) -> bool {
match *frm {
Ok(None) => true,
@ -237,11 +240,12 @@ mod tests {
}
fn extract(
frm: Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>,
frm: Result<Option<(bool, u8, OpCode, Option<BytesMut>)>, ProtocolError>,
) -> F {
match frm {
Ok(Some((finished, opcode, payload))) => F {
Ok(Some((finished, rsv, opcode, payload))) => F {
finished,
rsv,
opcode,
payload: payload
.map(|b| b.freeze())
@ -344,6 +348,20 @@ mod tests {
}
}
#[test]
fn test_parse_rsv() {
let mut buf = BytesMut::from(&[0b0111_0001u8, 0b0000_0001u8][..]);
buf.extend(&[1u8]);
assert!(Parser::parse(&mut buf, true, 1024).is_err());
let frame = extract(Parser::parse(&mut buf, false, 1024));
assert!(!frame.finished);
assert_eq!(frame.rsv, 7);
assert_eq!(frame.opcode, OpCode::Text);
assert_eq!(frame.payload, Bytes::from(vec![1u8]));
}
#[test]
fn test_ping_frame() {
let mut buf = BytesMut::new();

View File

@ -50,6 +50,9 @@ pub enum ProtocolError {
/// Bad utf-8 encoding
#[display(fmt = "Bad utf-8 encoding.")]
BadEncoding,
/// Continuation is not supported
#[display(fmt = "RSV set without extensions.")]
RSVSet,
/// Io error
#[display(fmt = "io error: {}", _0)]
Io(io::Error),