#details #protocols #low-level #websocket-client #url #header

yanked bare-websocket

Simple client only WebSocket (RFC6455) implementation with low level protocol details exposed (if needed)

Uses old Rust 2015

0.0.6 Feb 23, 2015
0.0.5 Feb 5, 2015
0.0.1 Jan 11, 2015

#67 in #websocket-client

MIT license

29KB
626 lines

bare-websocket

WebSocket implementation in Rust (@rust-lang) according to RFC6455

Unlike other websocket library, this library is focused on more low level details of WebSocket protocol: you can inspect each frame individually, as well as frame header. You can prepare each frame, along with all header details, bit-by-bit. It also supports masking, custom (service-specific) opcodes and reserved bits.

On the other hand it implements WebSocket client side only (but message structs are universal and can be used to implement both client and server parts).

If you don't need to mess with all the protocol scary details, want more high level interface and ready WebSocket server implementation, use websocket.

To use, add dependency to you Cargo.toml (you will also need url crate):

[dependencies]
url = "*"
bare-websocket = "*"

And then in your code:

extern crate url;
extern crate "bare-websocket" as websocket;

use websocket::{WebSocket, WSMessage};
use url::Url;

Example code:

// Initialization
let url = Url::parse("ws://echo.websocket.org").unwrap(); // <-- also supports SSL, just use "wss://" schema
let mut ws = WebSocket::new(url);
ws.connect().unwrap(); // <-- you can pass configured WebSocket somewhere before connecting

let msg = WSMessage::text("Hello, World!"); //.mask(); // <-- optionally turn on automasking
// All masking/unmasking is done transparently, you will never even know about it!

// You can compose fragmented messages as well:
let msg1 = WSMessage::text("Hello").first(); // <-- first fragment
let msg2 = WSMessage::text(", ").more(); // <-- continue fragment
let msg3 = WSMessage::text("world!").last(); // <-- last fragment

// Or easier: split message by size:
for m in WSMessage::text("Hello, world!").split(5) { // <-- WSMessage iterator
    ws.send_message(&m).unwrap();
}

// Usage of .defrag()menting iterator below (you can get each message fragment by not using it)
let reply = ws.iter().defrag().next().unwrap();
println!("received: {} {}", reply, reply.to_string());

// You can get single message as well:
//let msg = ws.read_message().unwrap();

// Simple messages iterator, to handle defragmentation, append .defrag() after .iter()
for msg in ws.iter() {
    println!("{}", msg.to_string());
}

// To take full bitwise control of opcode field, use `.ext()` method
let msg = WSMessage::ext(0b1011, b"bare metal message"); // <-- this is an extension control opcode

// There are also a lot of `.is_???()` methods to inspect:
println!("{}", msg.is_ext(0b1011)); // is it given extended opcode?
println!("{}", msg.is_control()); // is it control or data opcode?
println!("{}", msg.is_text()); // is it a text message?
println!("{}", msg.is_binary()); // is it a binary message?
// Also exist: .is_ping(), .is_pong(), .is_close(), .is_cont()

That's pretty much all of it, actually.

Dependencies

~3.5–5MB
~129K SLoC