A WebSocket (RFC6455) library written in Rust

Overview

Rust-WebSocket Build Status docs.rs

Note: Maintainership of this project is slugglish. You may want to use tungstenite or tokio-tungstenite instead.

Rust-WebSocket is a WebSocket (RFC6455) library written in Rust.

Rust-WebSocket provides a framework for dealing with WebSocket connections (both clients and servers). The library is currently in an experimental state, but provides functionality for both normal and secure WebSockets, a message level API supporting fragmentation, a data frame level API, and the ability to extend and customize behaviour.

Installation

To add a library release version from crates.io to a Cargo project, add this to the 'dependencies' section of your Cargo.toml:

websocket = "0.24.0"

To add the library's Git repository to a Cargo project, add this to your Cargo.toml:

[dependencies.websocket]

git = "https://github.com/websockets-rs/rust-websocket.git"

Optionally add extern crate websocket; to your project.

Note that 0.24.0 is the last version of rust-websocket that supports some very old Rust versions (I'm not sure which exactly, maybe 1.28).

Usage

The library can be compiled with tests and benches and some extra capabilities on Rust nightly. To enable the nightly features, use cargo --features nightly ....

See the documentation for the latest release of the library here, and also the examples, which are located in /examples and can be run with:

cargo run --example server

And in a separate terminal:

cargo run --example client

Testing

The library can be tested using cargo test to run tests and cargo bench to run bench tests.

A number of tests are included, which ensure core WebSocket functionality works as expected. These tests are not yet comprehensive, and are still being worked on.

Autobahn TestSuite

Rust-WebSocket uses the Autobahn TestSuite to test conformance to RFC6455. If you have Autobahn TestSuite installed you can run these tests yourself using the commands:

wstest -m fuzzingserver
cargo run --example autobahn-client

To test the client implementation, and

wstest -m fuzzingclient
cargo run --example autobahn-server

To test the server implementation. The spec files are available here.

The results of these tests are available here.

Contributing

Before you make a PR be sure to run all the tests!

# install
rustup component add rustfmt-preview
rustup component add clippy-preview

# test
cargo +nightly fmt -- --check
cargo +nightly clippy --all-features -- -D clippy::all
cargo test --features nightly
cargo bench --features nightly
./scripts/build-all.sh

License

The MIT License (MIT)

Copyright (c) 2014-2015 Cyderize

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • one client, one thread?

    one client, one thread?

    In rust and rust-websocket, how to keep the connection for each client persion? if one client, one thread, can reach 10k connections in single server machine?

    opened by miketang84 21
  • wss client without split

    wss client without split

    I'm upgrading from 0.17 to 0.19 and it looks like splitting a generic client (one that supports both WS and WSS) into its Sender and Receiver components is no longer possible because SslStream doesn't implement Splittable. Up to now splitting the client has been the idiomatic way to do things (at least in the examples) - is there a way around this limitation?

    opened by alex-shapiro 20
  • Update Openssl?

    Update Openssl?

    Because of the outdated Openssl I get

    error: native library `openssl` is being linked to by more than one version of the same package, but it can only be linked once; try updating or pinning your dependencies to ensure that this package only shows up once
    
      openssl-sys v0.9.6
      openssl-sys v0.7.17
    

    with other crates I want to use. Is that planned or possible?

    opened by MTRNord 16
  • Client::connect does not conform to rfc6455 section-4.1

    Client::connect does not conform to rfc6455 section-4.1

    According to http://tools.ietf.org/html/rfc6455#section-4.1 connect should take a host, port, resource name, and a secure flag, along with a list of protocols and extensions to be used. Currently, it accepts a Url object.

    "A client will need to supply a /host/, /port/, /resource name/, and a /secure/ flag, which are the components of a WebSocket URI as discussed in Section 3, along with a list of /protocols/ and /extensions/ to be used."

    opened by Nashenas88 15
  • Implement Splittable for SslStream

    Implement Splittable for SslStream

    I currently can't run the client example with a secure web socket

    error: no method named `split` found for type `websocket::Client<openssl::ssl::SslStream<std::net::TcpStream>>` in the current scope
      --> src\main.rs:30:43
       |
    30 |   let (mut receiver, mut sender) = client.split().unwrap();
       |                                           ^^^^^
       |
       = note: the method `split` exists but the following trait bounds were not satisfied: `openssl::ssl::SslStream<std::net::TcpStream> : websocket::stream::Splittable`
    

    not sure if I'm doing this wrong, but I just use .connect_secure(None) instead of .connect_insecure()

    opened by ForsakenHarmony 14
  • Turn rust-websocket into an organization?

    Turn rust-websocket into an organization?

    rust-websocket development is prone to hiatuses, and users are complaining.

    Maybe the repository should be just turned into an organization, with multiple contributes having granted access to publish to crates.io?

    opened by vi 13
  • openssl dependency conflics breaks build

    openssl dependency conflics breaks build

    My local build fails with:

    native library openssl is being linked to by more than one package, and can only be linked to by one package openssl-sys v0.7.0 openssl-sys v0.6.7

    Hacking the library to depend on 0.6.7 fixes the build, for now at least.

    opened by letharion 13
  • Tokio reform

    Tokio reform

    With the recent tokio reform, tokio-core has been deprecated in favour of the tokio crate. It would be nice to migrate over; There have been some breaking changes, but at first glance it doesn't seem like it'll be too hard.

    opened by FreeFull 11
  • Timeout on `recv_message`

    Timeout on `recv_message`

    Currently as I'm seeing it, an attacker could hold a thread responding to requests hostage as long as they want. I can of course terminate threads after a certain time but this probably has some dangerous side-effects that I don't ever want to happen.

    opened by LaylBongers 11
  • New PRs

    New PRs

    Hi everyone!

    When I opened this crate the readme states

    Note: Maintainership of this project is slugglish. You may want to use tungstenite or tokio-tungstenite instead.

    Is it worth making pull requests for this project or do you suggest to move on to another project?

    opened by jeroenvervaeke 10
  • API Discussion: becoming lightweight and feature-full (through hyper, mio, net2 and more)

    API Discussion: becoming lightweight and feature-full (through hyper, mio, net2 and more)

    This seemed like a good place for this. I wanted to flesh out a few things I was thinking about. There are many websocket libraries out there today but this one is the coolest, and it can be cooler! There are many missing features and pain points of the library that I wanted to discuss and I thought I would list them here. We should also include some features from other libraries and become the best ws library out there!

    Features:

    • HTTP Server integration
      • Take hyper requests and turn them into websockets
      • integration with hyper and others can be kept under a feature.
      • easier routing
    • custom headers
      • Cookies is probably useful, etc.
    • non-blocking
      • simple, use the net2 crate
    • mio support
      • easy, but API should be decided first
    • protocols
      • easy, needs API change
    • bare bones
      • easier user control of the dataframe sent over the wire
      • a lot of this is just more documentation
    • thread pool
      • probably behind a feature toggle, not a priority, seems useful
    • autobahn tests
      • add permessage-deflate

    Pain Points:

    • maybe using hyper is overkill. still not 100% sure.
      • http-muncher or httparse + some header library might be OK
      • we really don't need anything more than stdlib, see websocket-stream
      • we might be able to get away with maybe 1 dependency
    • not so precise error handling scheme, although this is a low priority
    • more documentation
    • more fluent API
      • this is mostly true but I think there are some places that could be more readable
    • less unecessary copying (there is still some going on!)

    Future:

    • I'm a worried about supporting future revisions to the standard, the code now isn't so flexible.

    This mostly spawned out of me trying to fix #53, and I thought we should discuss some API before I sink more time into it. If we're all clear on what we want it to look like we can easily split up work and people can more easily contribute.

    So @cyderize to start off do you think this list is complete? I have some API ideas I'll post soon.

    opened by illegalprime 10
  • Half-blocking method. Is it supported/possible?

    Half-blocking method. Is it supported/possible?

    Hi

    I am trying to implement "half-blocking" mode. That is blocking write & non-blocking read. Currently I use following code together with tungstenite. Blocking write is done using "write_inner". TcpStream is from "mio" crate.

    Unfortunately, it does not work reliably. I am getting various errors at handshake & later time.

    I'd like to ask. If rust-websocket could be used to implement working scheme like that?

    struct TcpCustomStream {
        s: TcpStream,
    
        block: bool,
        poll: Poll,
        events: Events,
    }
    
    impl TcpCustomStream {
        pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
            let a = if let Some(x) = addr.to_socket_addrs()?.next() {
                x
            } else {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    "Tcp connect call failed",
                ));
            };
            match TcpStream::connect(a) {
                Ok(mut x) => {
                    let poll = Poll::new()?;
                    let events = Events::with_capacity(128);
    
                    // Register the socket with `Poll`
                    poll.registry()
                        .register(&mut x, Token(0), Interest::WRITABLE)?;
    
                    Ok(Self {
                        s: x,
                        poll,
                        events,
                        block: true,
                    })
                }
                Err(x) => Err(x),
            }
        }
    
        pub fn set_nonblocking(&mut self) -> io::Result<()> {
            self.block = false;
            Ok(())
        }
    
        pub fn wait_write(&mut self) -> io::Result<()> {
            loop {
                //println!("tcp wait_write poll");
                self.poll.poll(&mut self.events, None)?;
    
                for event in &self.events {
                    if event.token() == Token(0) && event.is_writable() {
                        // The socket connected (probably, it could still be a spurious
                        // wakeup)
                        //println!("tcp wait_write ready");
                        return Ok(());
                    }
                }
            }
        }
    
    }
    
    impl std::io::Read for TcpCustomStream {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            loop {
                match self.s.read(buf) {
                    Err(x) if self.block && would_block(&x) => {
                        //println!("tcp read would_block {:?}", x);
                        thread::yield_now();
                    }
                    // x @ Err(_) => {
                    //     //println!("tcp read err {:?}", x);
                    //     break x;
                    // }
                    x => break x,
                }
            }
        }
    }
    
    impl std::io::Write for TcpCustomStream {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            match self.s.write(buf) {
                // x @ Err(_) => {
                //     println!("tcp write err {:?}", x);
                //     x
                // }
                x => x,
            }
        }
        fn flush(&mut self) -> std::io::Result<()> {
            self.s.flush()
        }
    }
    
    ... skipped
    pub struct Client {
        socket: Option<WebSocket<TcpCustomStream>>,
    }
    
    fn would_block(err: &std::io::Error) -> bool {
        match err {
            x if (x.kind() == io::ErrorKind::WouldBlock)
                || (x.kind() == std::io::ErrorKind::Interrupted) =>
            {
                true
            }
            _ => false,
        }
    }
    
    impl Client {
        pub fn new() -> Self {
            Self {
                socket: None,
            }
        }
    
        pub fn connect<'a>(&mut self, uri_str: &'a str) -> Result<(), std::io::Error> {
            println!("Client started");
    
            let (mut client, _) = {
                let mut c = 10;
                loop {
                    let req = Uri::from_maybe_shared(uri_str.to_string()).map_err(|_| {
                        std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid connect URI")
                    })?;
    
                    let host_port = req
                        .authority()
                        .ok_or(std::io::Error::new(
                            std::io::ErrorKind::InvalidInput,
                            "Invalid connect URI",
                        ))?
                        .as_str();
    
                    let stream = TcpCustomStream::connect(host_port)?;
                    println!("Client connected");
    
                    match client(req, stream) {
                        Err(x) => {
                            println!("Connect {:?}", x);
                            if c == 1 {
                                return Err(std::io::Error::new(
                                    std::io::ErrorKind::Other,
                                    format!("Cannot connect to {}", uri_str),
                                ));
                            }
                            c -= 1;
                            thread::sleep(std::time::Duration::from_millis(1000));
                        }
                        Ok(x) => break x,
                    }
                }
            };
            println!("WSClient connected");
    
            client.get_mut().set_nonblocking()?;
            println!("Set nonblocking mode");
    
            self.socket = Some(client);
    
            Ok(())
        }
    
        fn write_inner(socket: &mut WebSocket<TcpCustomStream>, m: Message) -> Result<(), Error> {
            match socket.write_message(m) {
                Err(tungstenite::Error::Io(e)) if would_block(&e) => {
                    //println!("cl write would_block");
                    return loop {
                        socket.get_mut().wait_write()?;
                        match socket.write_pending() {
                            Err(tungstenite::Error::Io(e)) if would_block(&e) => continue,
                            x => break x,
                        }
                    };
                }
                x => {
                    //println!("cl write {:?}", x);
                    x
                }
            }
        }
    
    
    opened by MageSlayer 11
  • Close message different behaviour on Mac and Linux.

    Close message different behaviour on Mac and Linux.

    i am implementing multi-threaded websocket client server chat application. On client side i am using rust-websocket library, while on the server side i am not using this library rather manually reading from the socket(TcpStream) connection.

    On server side i am trying to read the data as let buf = socket.read_u16::<BigEndian>()?; where read_u16 is from byteorder::io::ReadBytesExt. it work fine for the text message sent by the client, The issue starts when we try to close any client by sending close message to the server as below,

    let close_msg = Message::close();
    let res = sender.send_message(&close_msg);
    

    while reading this message on server side, with let buf = socket.read_u16::<BigEndian>()?; , it is successful on mac, but while in Linux it fails with wouldblock error i.e:

    thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }
    

    On other hand if we send as close message using ping,

    let close_msg = Message::ping(vec![1u8]);;
    let res = sender.send_message(&close_msg);
    

    then it don't give the above error and is successful on linux . I didn't understand why it behave different on mac and linux , can anyone please help?

    opened by Rohit171994 2
  •  Cross luaguage

    Cross luaguage

    websocket-client in rust,but websocket-server use C++,but client can't connect to server

    error:thread 'main' panicked at 'called Result::unwrap() on an Err value: Other(HttpError(Io(Custom { kind: UnexpectedEof, error: "end of stream before headers finished" })))'

    opened by tuoeg 3
  • weird

    weird "websocket protocol error"

    I got "websocket protocol error" from "recev_messages" method when the server program deployed on the Cloud, but this problem won't be seen on Native

    Is there any possible ideas?

    opened by ashuralyk 1
  • Security issues with hyper versions `< 0.14.10`

    Security issues with hyper versions `< 0.14.10`

    Hi there! I am using the websocket crate in one of my projects and I got a hint that I am depending on hyper version 0.10.6, which is vulnerable to RUSTSEC-2021-0079 and RUSTSEC-2021-0078. As it turns out the dependency was introduced through this library. I've looked into this and a potential fix would be to bump the hyper version to >=0.14.10, but this would introduce quite a few changes to this library as hyper changed it's whole header API (and more).

    opened by 1c3t3a 3
Releases(v0.20.2)
  • v0.20.2(Jun 19, 2017)

  • v0.20.1(May 29, 2017)

  • v0.20.0(May 29, 2017)

    Asynchronous WebSockets!

    1. First class tokio support!
    2. Fully async websocket clients! (and SSL!)
    3. Fully async websocket servers! (and SSL!)
    4. Messages now get parsed into their semantic meaning! (Text types are given as String)
    5. Native SSL on Windows & MacOS!
    6. Simplified APIs
    7. Docs and examples on how to use everything async!
    8. Split entire crate into async and sync components and with feature flags.
    Source code(tar.gz)
    Source code(zip)
  • v0.19.2(May 19, 2017)

  • v0.19.1(Apr 10, 2017)

  • v0.19.0(Apr 3, 2017)

    1. Upgrade from a hyper request to a websocket connection
    2. Upgrade all crate dependencies (openssl, hyper, etc.)
    3. Make openssl an optional dependency
    4. Use any Read/Write stream to make a websocket connection
    5. Make clients with builder style API
    6. Add / check protocols, extensions, headers, when upgrading connectin
    7. Add / check protocols, extensions, headers, when building client
    8. Docs for everything new
    9. Much cleaner API overall
    Source code(tar.gz)
    Source code(zip)
A simple toy websocket client to connect to Bitstamp.net and print the live order book written in Rust.

A simple toy websocket client to connect to Bitstamp.net and print the live order book written in Rust.

Nate Houk 1 Feb 14, 2022
Websocket generic library for Bitwyre WS-API

Websocket Core (Rust) Websocket generic server library for: Periodic message broadcast Eventual (Pubsub) message broadcast Async request reply Authors

Bitwyre 13 Oct 28, 2022
Lightweight stream-based WebSocket implementation for Rust.

Tungstenite Lightweight stream-based WebSocket implementation for Rust. use std::net::TcpListener; use std::thread::spawn; use tungstenite::server::ac

Snapview GmbH 1.3k Jan 2, 2023
An aria2 websocket jsonrpc in Rust.

aria2-ws An aria2 websocket jsonrpc in Rust. Built with tokio. Docs.rs aria2 RPC docs Features Almost all methods and structed responses Auto reconnec

null 8 Sep 7, 2022
Jamsocket is a lightweight framework for building WebSocket-based application backends.

Jamsocket is a lightweight framework for building services that are accessed through WebSocket connections.

null 94 Dec 30, 2022
A CLI development tool for WebSocket APIs

A CLI development tool for WebSocket APIs

Espen Henriksen 622 Dec 26, 2022
Spawn process IO to websocket with full PTY support.

Cliws Spawn process IO to websocket with full PTY support. Features Any process IO through Websocket Full pty support: VIM, SSH, readline, Ctrl+X Auto

B23r0 91 Jan 5, 2023
A lightweight framework for building WebSocket-based application backends.

Jamsocket Jamsocket is a lightweight framework for building services that are accessed through WebSocket connections. Services can either be native Ru

drifting in space 94 Dec 30, 2022
The ever fast websocket tunnel built on top of lightws

Kaminari The ever fast websocket tunnel built on top of lightws. Intro Client side receives tcp then sends [tcp/ws/tls/wss]. Server side receives [tcp

zephyr 261 Dec 27, 2022
Lightweight websocket implement for stream transmission.

Lightws Lightweight websocket implement for stream transmission. Features Avoid heap allocation. Avoid buffering frame payload. Use vectored-io if ava

zephyr 25 Dec 27, 2022
websocket client

#websocket client async fn test_websocket()->anyhow::Result<()> { wasm_logger::init(wasm_logger::Config::default()); let (tx, rx) = futures_c

null 1 Feb 11, 2022
A webserver and websocket pair to stop your viewers from spamming !np and "what's the song?" all the time.

spotify-np ?? spotify-np is a Rust-based local webserver inspired by l3lackShark's gosumemory application, but the catch is that it's for Spotify! ??

Noire 2 Aug 27, 2022
WebSocket-to-HTTP reverse proxy

websocket-bridge This is a simple reverse proxy server which accepts WebSocket connections and forwards any incoming frames to backend HTTP server(s)

Fermyon 5 Dec 21, 2022
A secure, real-time, low-latency binary WebSocket RPC subprotocol.

HardLight A secure, real-time, low-latency binary WebSocket RPC subprotocol. HardLight has two data models: RPC: a client connects to a server, and ca

valera 5 Apr 2, 2023
A MITM Proxy Written in Rust 🦀! Toolkit for HTTP/1, HTTP/2, and WebSockets with SSL/TLS Capabilities. Learning Project.

Man In The Middle Proxy Description Rust-based Man in the Middle proxy, an early-stage project aimed at providing visibility into network traffic. Cur

null 158 Mar 9, 2023
ChatApp made using the standard library net module and tui-rs.

chatui Simple chat application. You'll need both chatui_server and chatui_client to run this application. Installation With cargo cargo install chatui

Gauravsingh Sisodia 6 Dec 15, 2021
SockJS server for rust language

SockJS server SockJS server for Actix framework. API Documentation Cargo package: sockjs SockJS is built with Actix web Minimum supported Rust version

Actix 63 Oct 7, 2022
Lightweight, event-driven WebSockets for Rust.

WS-RS Lightweight, event-driven WebSockets for Rust. /// A WebSocket echo server listen("127.0.0.1:3012", |out| { move |msg| { out.send(ms

Jason Housley 1.3k Jan 8, 2023
A very-very simple url shortener for Rust

urlshortener-rs A very simple urlshortener for Rust. This library aims to implement as much URL shortener services as possible and to provide an inter

Victor Polevoy 39 Nov 20, 2022