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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use hyper::header::{Header, HeaderFormat};
use hyper::header::parsing::from_one_raw_str;
use hyper;
use std::fmt::{self, Debug};
use std::str::FromStr;
use serialize::base64::{ToBase64, FromBase64, STANDARD};
use header::WebSocketKey;
use openssl::crypto::hash::{self, hash};
use result::{WebSocketResult, WebSocketError};
static MAGIC_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
#[derive(PartialEq, Clone, Copy)]
pub struct WebSocketAccept([u8; 20]);
impl Debug for WebSocketAccept {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WebSocketAccept({})", self.serialize())
}
}
impl FromStr for WebSocketAccept {
type Err = WebSocketError;
fn from_str(accept: &str) -> WebSocketResult<WebSocketAccept> {
match accept.from_base64() {
Ok(vec) => {
if vec.len() != 20 {
return Err(WebSocketError::ProtocolError(
"Sec-WebSocket-Accept must be 20 bytes"
));
}
let mut array = [0u8; 20];
let mut iter = vec.into_iter();
for i in array.iter_mut() {
*i = iter.next().unwrap();
}
Ok(WebSocketAccept(array))
}
Err(_) => {
return Err(WebSocketError::ProtocolError(
"Invalid Sec-WebSocket-Accept "
));
}
}
}
}
impl WebSocketAccept {
pub fn new(key: &WebSocketKey) -> WebSocketAccept {
let serialized = key.serialize();
let mut concat_key = String::with_capacity(serialized.len() + 36);
concat_key.push_str(&serialized[..]);
concat_key.push_str(MAGIC_GUID);
let output = hash(hash::Type::SHA1, concat_key.as_bytes());
let mut iter = output.into_iter();
let mut bytes = [0u8; 20];
for i in bytes.iter_mut() {
*i = iter.next().unwrap();
}
WebSocketAccept(bytes)
}
pub fn serialize(&self) -> String {
let WebSocketAccept(accept) = *self;
accept.to_base64(STANDARD)
}
}
impl Header for WebSocketAccept {
fn header_name() -> &'static str {
"Sec-WebSocket-Accept"
}
fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<WebSocketAccept> {
from_one_raw_str(raw)
}
}
impl HeaderFormat for WebSocketAccept {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.serialize())
}
}
#[cfg(all(feature = "nightly", test))]
mod tests {
use super::*;
use test;
use std::str::FromStr;
use header::{Headers, WebSocketKey};
use hyper::header::{Header, HeaderFormatter};
#[test]
fn test_header_accept() {
let key = FromStr::from_str("dGhlIHNhbXBsZSBub25jZQ==").unwrap();
let accept = WebSocketAccept::new(&key);
let mut headers = Headers::new();
headers.set(accept);
assert_eq!(&headers.to_string()[..], "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n");
}
#[bench]
fn bench_header_accept_new(b: &mut test::Bencher) {
let key = WebSocketKey::new();
b.iter(|| {
let mut accept = WebSocketAccept::new(&key);
test::black_box(&mut accept);
});
}
#[bench]
fn bench_header_accept_parse(b: &mut test::Bencher) {
let value = vec![b"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=".to_vec()];
b.iter(|| {
let mut accept: WebSocketAccept = Header::parse_header(&value[..]).unwrap();
test::black_box(&mut accept);
});
}
#[bench]
fn bench_header_accept_format(b: &mut test::Bencher) {
let value = vec![b"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=".to_vec()];
let val: WebSocketAccept = Header::parse_header(&value[..]).unwrap();
let fmt = HeaderFormatter(&val);
b.iter(|| {
format!("{}", fmt);
});
}
}