headers_ext/common/
sec_websocket_accept.rs

1use base64;
2use bytes::Bytes;
3use sha1::{Digest, Sha1};
4
5use super::SecWebsocketKey;
6
7/// The `Sec-Websocket-Accept` header.
8///
9/// This header is used in the Websocket handshake, sent back by the
10/// server indicating a successful handshake. It is a signature
11/// of the `Sec-Websocket-Key` header.
12///
13/// # Example
14///
15/// ```no_run
16/// # extern crate headers_ext as headers;
17/// use headers::{SecWebsocketAccept, SecWebsocketKey};
18///
19/// let sec_key: SecWebsocketKey = /* from request headers */
20/// #    unimplemented!();
21///
22/// let sec_accept = SecWebsocketAccept::from(sec_key);
23/// ```
24#[derive(Clone, Debug, PartialEq, Eq, Hash, Header)]
25pub struct SecWebsocketAccept(::HeaderValue);
26
27impl From<SecWebsocketKey> for SecWebsocketAccept {
28    fn from(key: SecWebsocketKey) -> SecWebsocketAccept {
29        sign(key.0.as_bytes())
30    }
31}
32
33fn sign(key: &[u8]) -> SecWebsocketAccept {
34    let mut sha1 = Sha1::default();
35    sha1.input(key);
36    sha1.input(&b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"[..]);
37    let b64 = Bytes::from(base64::encode(&sha1.result()));
38
39    let val = ::HeaderValue::from_shared(b64)
40        .expect("base64 is a valid value");
41
42    SecWebsocketAccept(val)
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use super::super::{test_encode, test_decode};
49
50    #[test]
51    fn key_to_accept() {
52        // From https://tools.ietf.org/html/rfc6455#section-1.2
53        let key = test_decode::<SecWebsocketKey>(&["dGhlIHNhbXBsZSBub25jZQ=="]).expect("key");
54        let accept = SecWebsocketAccept::from(key);
55        let headers = test_encode(accept);
56
57        assert_eq!(headers["sec-websocket-accept"], "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
58    }
59}