#tokio #websocket #codec #serverproto

twist

An implementation of the RFC6455 websocket protocol as a tokio Codec and a tokio-proto pipeline ServerProto

15 releases (6 breaking)

Uses old Rust 2015

0.7.1 Mar 21, 2017
0.7.0 Mar 19, 2017
0.6.0 Mar 16, 2017
0.5.3 Mar 13, 2017
0.1.4 Feb 23, 2017

#94 in WebSocket

Download history 36/week @ 2022-03-11 69/week @ 2022-03-18 4/week @ 2022-03-25 6/week @ 2022-04-01 7/week @ 2022-04-08 8/week @ 2022-04-15 20/week @ 2022-04-22 122/week @ 2022-04-29 96/week @ 2022-05-06 261/week @ 2022-05-13 51/week @ 2022-05-20 95/week @ 2022-05-27 125/week @ 2022-06-03 5/week @ 2022-06-10 8/week @ 2022-06-17 6/week @ 2022-06-24

159 downloads per month
Used in 5 crates

MIT/Apache

140KB
3K SLoC

twist

An implementation of the RFC6455 websocket protocol as a tokio-core Codec and a tokio-proto pipeline ServerProto

This can be used to serve up a tokio-service Service in a tokio-proto TcpServer (See twists for an example).

Note: Even though this is implemented as a pipeline protocol, fragmented websocket messages are supported, so streaming from a websocket client is supported.

Usage

Include the following in your Cargo.toml dependencies section

twist = "0.1.3"

Extensions

Per Message extensions are now supported by twist. A per-message extension is applied when a text or binary frame is complete, or a set of fragmented text or binary frames have been fully assembled.

Implementation

twist exposes three traits relevant for implementing an extension:

  1. FromHeader - Extensions are configured based on the contents of the Sec-WebSocket-Extensions request header. Implement the init function to configure your extension based off of this header. You should return an io::Error if you are unable to support the given header parameters. If the parameters aren't relevant to your extension, you should ensure that your enabled function returns false.

     fn init(&mut self, request: &str) -> Result<(), io::Error> {
         if request.contains("permessage-deflate") {
             self.enabled = true;
             let pmds: Vec<&str> =
                 request.split(',').take_while(|s| s.starts_with("permessage-deflate")).collect();
             for pmd in pmds {
                 // Check the config here.
                 // return io::Error if it is invalid.
             }
         }
         Ok(())
     }
    
  2. IntoResponse - Implement the response function to return the Sec-WebSocket-Extensions response header. If you are disabled, return None.

  3. PerMessage - This is the meat of the extension. There are three methods to implement.

    a. reserve_rsv - If your extension requires the use of one of the frame's rsv bits, you can attempt to reserve it. The value you receive represents the bits that have already been reserved previously in the extension chain. Check if your bit (or bits) are free, and bitwise or your bits with the given, and return that value. Below is an example from twist-deflate. The deflate extension requires the rsv1 bit, so RSV1 is 4 (0b100).

     if current_rsv & RSV1 == 0 {
       Ok(current_rsv | RSV1)
     } else {
       Err(other("rsv1 bit already reserved"))
     }
    

    b. decode - Implement this to apply decoding to a message frame (for example decompressing the application data).

    c. encode - Implement this to apply encoding to a message frame before final encoding by twist (for example compressing the application data).

See twist-deflate for a more complete example.

Documentation

Documentation

Example Usage

See the twists project for an example implementation of an echo server using twist.

Dependencies

~11MB
~200K SLoC