1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! Websocket endpoint.
//!
//! [`Endpoint`] is used to perform a handshake. It is compatible with
//! both sync and async IO.
//!
//! To open or accept a connection directly, use [`Endpoint::connect`],
//! [`Endpoint::accept`], or their async version.
//!
//! To have detailed control over a handshake, use [`Endpoint::send_request`],
//! [`Endpoint::recv_response`], [`Endpoint::recv_request`], [`Endpoint::send_response`],
//! or their async version.

mod detail;
mod client;
mod server;

cfg_if::cfg_if! {
    if #[cfg(feature = "tokio")] {
        mod async_client;
        mod async_server;
    }
}

use std::marker::PhantomData;

/// Handshake endpoint.
pub struct Endpoint<IO, Role> {
    _marker: PhantomData<IO>,
    __marker: PhantomData<Role>,
}

#[cfg(test)]
mod test {
    use std::io::{Read, Write, Result};

    pub const REQUEST: &[u8] = b"\
    GET /ws HTTP/1.1\r\n\
    host: www.example.com\r\n\
    upgrade: websocket\r\n\
    connection: upgrade\r\n\
    sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\r\n\
    sec-websocket-version: 13\r\n\r\n";

    pub const RESPONSE: &[u8] = b"\
        HTTP/1.1 101 Switching Protocols\r\n\
        upgrade: websocket\r\n\
        connection: upgrade\r\n\
        sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";

    pub struct LimitReadWriter {
        pub rbuf: Vec<u8>,
        pub wbuf: Vec<u8>,
        pub rlimit: usize,
        pub wlimit: usize,
        pub cursor: usize,
    }

    impl Read for LimitReadWriter {
        fn read(&mut self, mut buf: &mut [u8]) -> Result<usize> {
            let to_read = std::cmp::min(buf.len(), self.rlimit);
            let left_data = self.rbuf.len() - self.cursor;
            if left_data == 0 {
                return Ok(0);
            }
            if left_data <= to_read {
                buf.write(&self.rbuf[self.cursor..]).unwrap();
                self.cursor = self.rbuf.len();
                return Ok(left_data);
            }

            buf.write(&self.rbuf[self.cursor..self.cursor + to_read])
                .unwrap();
            self.cursor += to_read;
            Ok(to_read)
        }
    }

    impl Write for LimitReadWriter {
        fn write(&mut self, buf: &[u8]) -> Result<usize> {
            let len = std::cmp::min(buf.len(), self.wlimit);
            self.wbuf.write(&buf[..len])
        }

        fn flush(&mut self) -> Result<()> { Ok(()) }
    }
}