websocket_base/
header.rs

1//! This file contains some framework-agnostic aspects of WebSocket HTTP headers.
2
3extern crate rand;
4
5/// WebSocket header names
6pub mod names {
7	pub const PROTOCOL: &str = "Sec-WebSocket-Protocol";
8	pub const ACCEPT: &str = "Sec-WebSocket-Accept";
9	pub const EXTENSIONS: &str = "Sec-WebSocket-Extensions";
10	pub const KEY: &str = "Sec-WebSocket-Key";
11}
12
13extern crate base64;
14extern crate sha1;
15use sha1::{Digest, Sha1};
16
17use crate::result::{WebSocketError, WebSocketResult};
18use std::fmt::{self, Debug};
19
20use std::str::FromStr;
21
22/// Represents a Sec-WebSocket-Key header.
23#[derive(PartialEq, Clone, Copy, Default)]
24pub struct WebSocketKey(pub [u8; 16]);
25
26impl Debug for WebSocketKey {
27	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28		write!(f, "WebSocketKey({})", self.serialize())
29	}
30}
31
32impl FromStr for WebSocketKey {
33	type Err = WebSocketError;
34
35	fn from_str(key: &str) -> WebSocketResult<WebSocketKey> {
36		match base64::decode(key) {
37			Ok(vec) => {
38				if vec.len() != 16 {
39					return Err(WebSocketError::ProtocolError(
40						"Sec-WebSocket-Key must be 16 bytes",
41					));
42				}
43				let mut array = [0u8; 16];
44				array[..16].clone_from_slice(&vec[..16]);
45				Ok(WebSocketKey(array))
46			}
47			Err(_) => Err(WebSocketError::ProtocolError(
48				"Invalid Sec-WebSocket-Accept",
49			)),
50		}
51	}
52}
53
54impl WebSocketKey {
55	/// Generate a new, random WebSocketKey
56	pub fn new() -> WebSocketKey {
57		let key = rand::random();
58		WebSocketKey(key)
59	}
60	/// Return the Base64 encoding of this WebSocketKey
61	pub fn serialize(&self) -> String {
62		let WebSocketKey(key) = *self;
63		base64::encode(&key)
64	}
65}
66
67static MAGIC_GUID: &str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
68
69/// Represents a Sec-WebSocket-Accept header
70#[derive(PartialEq, Clone, Copy)]
71pub struct WebSocketAccept([u8; 20]);
72
73impl Debug for WebSocketAccept {
74	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75		write!(f, "WebSocketAccept({})", self.serialize())
76	}
77}
78
79impl FromStr for WebSocketAccept {
80	type Err = WebSocketError;
81
82	fn from_str(accept: &str) -> WebSocketResult<WebSocketAccept> {
83		match base64::decode(accept) {
84			Ok(vec) => {
85				if vec.len() != 20 {
86					return Err(WebSocketError::ProtocolError(
87						"Sec-WebSocket-Accept must be 20 bytes",
88					));
89				}
90				let mut array = [0u8; 20];
91				array[..20].clone_from_slice(&vec[..20]);
92				Ok(WebSocketAccept(array))
93			}
94			Err(_) => Err(WebSocketError::ProtocolError(
95				"Invalid Sec-WebSocket-Accept ",
96			)),
97		}
98	}
99}
100
101impl WebSocketAccept {
102	/// Create a new WebSocketAccept from the given WebSocketKey
103	pub fn new(key: &WebSocketKey) -> WebSocketAccept {
104		let serialized = key.serialize();
105		let mut concat_key = String::with_capacity(serialized.len() + 36);
106		concat_key.push_str(&serialized[..]);
107		concat_key.push_str(MAGIC_GUID);
108		let hash = Sha1::digest(concat_key.as_bytes());
109		WebSocketAccept(hash.into())
110	}
111	/// Return the Base64 encoding of this WebSocketAccept
112	pub fn serialize(&self) -> String {
113		let WebSocketAccept(accept) = *self;
114		base64::encode(&accept)
115	}
116}