Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config value for reading frames as passthrough #371

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/protocol/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ pub enum Message {
Pong(Vec<u8>),
/// A close message with the optional close frame.
Close(Option<CloseFrame<'static>>),
/// Raw frame. Note, that you're not going to get this value while reading the message.
/// Raw frame. These will be returned from the socket only if the `read_as_frames` option
/// in [WebSocketConfig] is set to `true`.
Frame(Frame),
}

Expand Down
40 changes: 39 additions & 1 deletion src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use std::{
io::{ErrorKind as IoErrorKind, Read, Write},
mem::replace,
};
use crate::protocol::frame::coding::Control;

/// Indicates a Client or Server role of the websocket
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -73,6 +74,12 @@ pub struct WebSocketConfig {
/// some popular libraries that are sending unmasked frames, ignoring the RFC.
/// By default this option is set to `false`, i.e. according to RFC 6455.
pub accept_unmasked_frames: bool,
/// When set to `true`, all well-formed frames read by the socket will be returned as-is
/// with minimal processing. Close frames and masked frames will still be handled,
/// as they affect control flow, but fragmented or incomplete frames will be returned without
/// reassembly.
/// Set to `false` by default
pub read_as_frames: bool
}

impl Default for WebSocketConfig {
Expand All @@ -85,6 +92,7 @@ impl Default for WebSocketConfig {
max_message_size: Some(64 << 20),
max_frame_size: Some(16 << 20),
accept_unmasked_frames: false,
read_as_frames: false,
}
}
}
Expand Down Expand Up @@ -430,7 +438,6 @@ impl WebSocketContext {
if !self.state.is_active() {
return Err(Error::Protocol(ProtocolError::SendAfterClosing));
}

let frame = match message {
Message::Text(data) => Frame::message(data.into(), OpCode::Data(OpData::Text), true),
Message::Binary(data) => Frame::message(data, OpCode::Data(OpData::Binary), true),
Expand Down Expand Up @@ -544,6 +551,18 @@ impl WebSocketContext {
if !self.state.can_read() {
return Err(Error::Protocol(ProtocolError::ReceivedAfterClosing));
}
if self.config.read_as_frames {
if frame.header().opcode == OpCode::Control(Control::Close) &&
self.state.is_active() {
// Do close, but ignore the output
self.do_close(frame.clone().into_close()?);
}
if frame.is_masked() {
frame.apply_mask();
}
// Always return the original frame
return Ok(Some(Message::Frame(frame)));
}
// MUST be 0 unless an extension is negotiated that defines meanings
// for non-zero values. If a nonzero value is received and none of
// the negotiated extensions defines the meaning of such a nonzero
Expand Down Expand Up @@ -791,6 +810,8 @@ mod tests {
use crate::error::{CapacityError, Error};

use std::{io, io::Cursor};
use crate::protocol::frame::{Frame, FrameHeader};
use crate::protocol::frame::coding::{Data, OpCode};

struct WriteMoc<Stream>(Stream);

Expand Down Expand Up @@ -823,6 +844,23 @@ mod tests {
assert_eq!(socket.read().unwrap(), Message::Binary(vec![0x01, 0x02, 0x03]));
}

#[test]
fn read_extended_frame() {
let raw = vec![
0xc1, 0x0b, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64
];
let mut config = WebSocketConfig::default();
config.read_as_frames = true;
let cursor = Cursor::new(raw.clone());
let mut frame_header = FrameHeader::default();
frame_header.is_final = true;
frame_header.rsv1 = true;
frame_header.opcode = OpCode::Data(Data::Text);
let expected_frame = Frame::from_payload(frame_header, raw[2..].to_vec());
let mut socket = WebSocket::from_raw_socket(WriteMoc(cursor), Role::Client, Some(config));
assert_eq!(socket.read().unwrap(), Message::Frame(expected_frame));
}

#[test]
fn size_limiting_text_fragmented() {
let incoming = Cursor::new(vec![
Expand Down