Crate fastwebsockets
source ·Expand description
fastwebsockets is a minimal, fast WebSocket server implementation.
https://github.com/denoland/fastwebsockets
Passes the Autobahn|TestSuite and fuzzed with LLVM’s libfuzzer.
You can use it as a raw websocket frame parser and deal with spec compliance yourself, or you can use it as a full-fledged websocket server.
§Example
use tokio::net::TcpStream;
use fastwebsockets::{WebSocket, OpCode, Role};
use anyhow::Result;
async fn handle(
socket: TcpStream,
) -> Result<()> {
let mut ws = WebSocket::after_handshake(socket, Role::Server);
ws.set_writev(false);
ws.set_auto_close(true);
ws.set_auto_pong(true);
loop {
let frame = ws.read_frame().await?;
match frame.opcode {
OpCode::Close => break,
OpCode::Text | OpCode::Binary => {
ws.write_frame(frame).await?;
}
_ => {}
}
}
Ok(())
}
§Fragmentation
By default, fastwebsockets will give the application raw frames with FIN set. Other crates like tungstenite which will give you a single message with all the frames concatenated.
For concanated frames, use FragmentCollector
:
use fastwebsockets::{FragmentCollector, WebSocket, Role};
use tokio::net::TcpStream;
use anyhow::Result;
async fn handle(
socket: TcpStream,
) -> Result<()> {
let mut ws = WebSocket::after_handshake(socket, Role::Server);
let mut ws = FragmentCollector::new(ws);
let incoming = ws.read_frame().await?;
// Always returns full messages
assert!(incoming.fin);
Ok(())
}
permessage-deflate is not supported yet.
§HTTP Upgrades
Enable the upgrade
feature to do server-side upgrades and client-side
handshakes.
This feature is powered by hyper.
use fastwebsockets::upgrade::upgrade;
use http_body_util::Empty;
use hyper::{Request, body::{Incoming, Bytes}, Response};
use anyhow::Result;
async fn server_upgrade(
mut req: Request<Incoming>,
) -> Result<Response<Empty<Bytes>>> {
let (response, fut) = upgrade(&mut req)?;
tokio::spawn(async move {
let ws = fut.await;
// Do something with the websocket
});
Ok(response)
}
Use the handshake
module for client-side handshakes.
use fastwebsockets::handshake;
use fastwebsockets::FragmentCollector;
use hyper::{Request, body::Bytes, upgrade::Upgraded, header::{UPGRADE, CONNECTION}};
use http_body_util::Empty;
use hyper_util::rt::TokioIo;
use tokio::net::TcpStream;
use std::future::Future;
use anyhow::Result;
async fn connect() -> Result<FragmentCollector<TokioIo<Upgraded>>> {
let stream = TcpStream::connect("localhost:9001").await?;
let req = Request::builder()
.method("GET")
.uri("http://localhost:9001/")
.header("Host", "localhost:9001")
.header(UPGRADE, "websocket")
.header(CONNECTION, "upgrade")
.header(
"Sec-WebSocket-Key",
fastwebsockets::handshake::generate_key(),
)
.header("Sec-WebSocket-Version", "13")
.body(Empty::<Bytes>::new())?;
let (ws, _) = handshake::client(&SpawnExecutor, req, stream).await?;
Ok(FragmentCollector::new(ws))
}
// Tie hyper's executor to tokio runtime
struct SpawnExecutor;
impl<Fut> hyper::rt::Executor<Fut> for SpawnExecutor
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
fn execute(&self, fut: Fut) {
tokio::task::spawn(fut);
}
}
Modules§
Structs§
- Collects fragmented messages over a WebSocket connection and returns the completed message once all fragments have been received.
- Represents a WebSocket frame.
- WebSocket protocol implementation over an async stream.
Enums§
- Status code used to indicate why an endpoint is closing the WebSocket connection.
Functions§
- Unmask a payload using the given 4-byte mask.