Skip to content

fix: Role::Server doesn't work without auto_apply_mask #103

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

flisky
Copy link

@flisky flisky commented Apr 18, 2025

I'm trying to replace tokio-tungstenite client with fastwebsockets in one of my project, and have to use buffer level AsyncRead & AsyncWrite instead of message level Stream & Sink. I'm using tokio::io::SimplexStream to accumulate an echo service in the testcases, and I known it's a really bad server implementation, but mask still surprises me: the mannual frame.unmask call doesn't work with text/binary message due to Fragments::accumulate!

  • the mask is dropped
  • even we keep mask, text message goes InvalidUTF8 error because of the eager check.

It means the server only work under auto_apply_mask in current implementation!

This is the easiest way to be sound. Free free to close this PR, because we may choose to support it, even it's acceptable that we ignore it because it's totally the server implementation fault

@littledivy
Copy link
Member

@flisky Thanks for the PR. fastwebsockets intends to provide very low-level access to websockets, so for example, a client and server can mutually agree to always use unmasked payloads if they want to. This PR always enables unmasking which will break that usage.

Can you elaborate more or provide a code sample that explains why this is needed instead of using the set_auto_apply_mask option?

@flisky
Copy link
Author

flisky commented May 13, 2025

server side:

diff --git a/examples/echo_server.rs b/examples/echo_server.rs
index aefe739..08b60a2 100644
--- a/examples/echo_server.rs
+++ b/examples/echo_server.rs
@@ -25,13 +25,16 @@ use hyper::Response;
 use tokio::net::TcpListener;

 async fn handle_client(fut: upgrade::UpgradeFut) -> Result<(), WebSocketError> {
-  let mut ws = fastwebsockets::FragmentCollector::new(fut.await?);
+  let mut ws  = fut.await?;
+  ws.set_auto_apply_mask(false);
+  let mut ws = fastwebsockets::FragmentCollector::new(ws);

   loop {
-    let frame = ws.read_frame().await?;
+    let mut frame = ws.read_frame().await?;
     match frame.opcode {
       OpCode::Close => break,
       OpCode::Text | OpCode::Binary => {
+        frame.unmask();
         ws.write_frame(frame).await?;
       }
       _ => {}

client side:

const ws = new WebSocket("ws://localhost:8080");
ws.onmessage = (msg) => console.log(msg.data);
ws.onerror = (err) => console.log(err);
const msg = "a".repeat(2048);
ws.send(msg);

server error:

Error in websocket connection: Invalid UTF-8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants