1use std::{
4 io::{self, Read, Write},
5 marker::PhantomData,
6 result::Result as StdResult,
7};
8
9use headers::{Header, HeaderMapExt};
10use http::{
11 response::Builder, HeaderMap, Request as HttpRequest, Response as HttpResponse, StatusCode,
12};
13use httparse::Status;
14use log::*;
15
16use super::{
17 derive_accept_key,
18 headers::{FromHttparse, MAX_HEADERS},
19 machine::{HandshakeMachine, StageResult, TryParse},
20 HandshakeRole, MidHandshake, ProcessingResult,
21};
22use crate::{
23 error::{Error, ProtocolError, Result},
24 extensions::{headers::SecWebsocketExtensions, Extensions},
25 handshake::version_as_str,
26 protocol::{Role, WebSocket, WebSocketConfig},
27};
28
29pub type Request = HttpRequest<()>;
31
32pub type Response = HttpResponse<()>;
34
35pub type ErrorResponse = HttpResponse<Option<String>>;
37
38fn create_parts<T>(request: &HttpRequest<T>) -> Result<Builder> {
39 if request.method() != http::Method::GET {
40 return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
41 }
42
43 if request.version() < http::Version::HTTP_11 {
44 return Err(Error::Protocol(ProtocolError::WrongHttpVersion));
45 }
46
47 if !request
48 .headers()
49 .get("Connection")
50 .and_then(|h| h.to_str().ok())
51 .map(|h| h.split([' ', ',']).any(|p| p.eq_ignore_ascii_case("Upgrade")))
52 .unwrap_or(false)
53 {
54 return Err(Error::Protocol(ProtocolError::MissingConnectionUpgradeHeader));
55 }
56
57 if !request
58 .headers()
59 .get("Upgrade")
60 .and_then(|h| h.to_str().ok())
61 .map(|h| h.eq_ignore_ascii_case("websocket"))
62 .unwrap_or(false)
63 {
64 return Err(Error::Protocol(ProtocolError::MissingUpgradeWebSocketHeader));
65 }
66
67 if !request.headers().get("Sec-WebSocket-Version").map(|h| h == "13").unwrap_or(false) {
68 return Err(Error::Protocol(ProtocolError::MissingSecWebSocketVersionHeader));
69 }
70
71 let key = request
72 .headers()
73 .get("Sec-WebSocket-Key")
74 .ok_or(Error::Protocol(ProtocolError::MissingSecWebSocketKey))?;
75
76 let builder = Response::builder()
77 .status(StatusCode::SWITCHING_PROTOCOLS)
78 .version(request.version())
79 .header("Connection", "Upgrade")
80 .header("Upgrade", "websocket")
81 .header("Sec-WebSocket-Accept", derive_accept_key(key.as_bytes()));
82
83 Ok(builder)
84}
85
86pub fn create_response(request: &Request) -> Result<Response> {
88 Ok(create_parts(request)?.body(())?)
89}
90
91pub fn create_response_with_body<T1, T2>(
93 request: &HttpRequest<T1>,
94 generate_body: impl FnOnce() -> T2,
95) -> Result<HttpResponse<T2>> {
96 Ok(create_parts(request)?.body(generate_body())?)
97}
98
99pub fn write_response<T>(mut w: impl io::Write, response: &HttpResponse<T>) -> Result<()> {
101 writeln!(
102 w,
103 "{version} {status}\r",
104 version = version_as_str(response.version())?,
105 status = response.status()
106 )?;
107
108 for (k, v) in response.headers() {
109 writeln!(w, "{}: {}\r", k, v.to_str()?)?;
110 }
111
112 writeln!(w, "\r")?;
113
114 Ok(())
115}
116
117impl TryParse for Request {
118 fn try_parse(buf: &[u8]) -> Result<Option<(usize, Self)>> {
119 let mut hbuffer = [httparse::EMPTY_HEADER; MAX_HEADERS];
120 let mut req = httparse::Request::new(&mut hbuffer);
121 Ok(match req.parse(buf)? {
122 Status::Partial => None,
123 Status::Complete(size) => Some((size, Request::from_httparse(req)?)),
124 })
125 }
126}
127
128impl<'h, 'b: 'h> FromHttparse<httparse::Request<'h, 'b>> for Request {
129 fn from_httparse(raw: httparse::Request<'h, 'b>) -> Result<Self> {
130 if raw.method.expect("Bug: no method in header") != "GET" {
131 return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
132 }
133
134 if raw.version.expect("Bug: no HTTP version") < 1 {
135 return Err(Error::Protocol(ProtocolError::WrongHttpVersion));
136 }
137
138 let headers = HeaderMap::from_httparse(raw.headers)?;
139
140 let mut request = Request::new(());
141 *request.method_mut() = http::Method::GET;
142 *request.headers_mut() = headers;
143 *request.uri_mut() = raw.path.expect("Bug: no path in header").parse()?;
144 *request.version_mut() = http::Version::HTTP_11;
147
148 Ok(request)
149 }
150}
151
152pub trait Callback: Sized {
159 fn on_request(
163 self,
164 request: &Request,
165 response: Response,
166 ) -> StdResult<Response, ErrorResponse>;
167}
168
169impl<F> Callback for F
170where
171 F: FnOnce(&Request, Response) -> StdResult<Response, ErrorResponse>,
172{
173 fn on_request(
174 self,
175 request: &Request,
176 response: Response,
177 ) -> StdResult<Response, ErrorResponse> {
178 self(request, response)
179 }
180}
181
182#[derive(Clone, Copy, Debug)]
184pub struct NoCallback;
185
186impl Callback for NoCallback {
187 fn on_request(
188 self,
189 _request: &Request,
190 response: Response,
191 ) -> StdResult<Response, ErrorResponse> {
192 Ok(response)
193 }
194}
195
196#[allow(missing_copy_implementations)]
198#[derive(Debug)]
199pub struct ServerHandshake<S, C> {
200 callback: Option<C>,
204 config: Option<WebSocketConfig>,
206 error_response: Option<ErrorResponse>,
208 extensions: Extensions,
210 _marker: PhantomData<S>,
212}
213
214impl<S: Read + Write, C: Callback> ServerHandshake<S, C> {
215 pub fn start(stream: S, callback: C, config: Option<WebSocketConfig>) -> MidHandshake<Self> {
220 trace!("Server handshake initiated.");
221 MidHandshake {
222 machine: HandshakeMachine::start_read(stream),
223 role: ServerHandshake {
224 callback: Some(callback),
225 config,
226 error_response: None,
227 extensions: Extensions::default(),
228 _marker: PhantomData,
229 },
230 }
231 }
232}
233
234impl<S: Read + Write, C: Callback> HandshakeRole for ServerHandshake<S, C> {
235 type IncomingData = Request;
236 type InternalStream = S;
237 type FinalResult = WebSocket<S>;
238
239 fn stage_finished(
240 &mut self,
241 finish: StageResult<Self::IncomingData, Self::InternalStream>,
242 ) -> Result<ProcessingResult<Self::InternalStream, Self::FinalResult>> {
243 Ok(match finish {
244 StageResult::DoneReading { stream, result, tail } => {
245 if !tail.is_empty() {
246 return Err(Error::Protocol(ProtocolError::JunkAfterRequest));
247 }
248
249 let mut response = create_response(&result)?;
250 if let Some(extensions) =
251 result.headers().typed_try_get::<SecWebsocketExtensions>().map_err(|_| {
252 ProtocolError::InvalidHeader(SecWebsocketExtensions::name().clone().into())
253 })?
254 {
255 let extensions_config = self
256 .config
257 .ok_or_else(|| {
258 ProtocolError::InvalidHeader(
259 SecWebsocketExtensions::name().clone().into(),
260 )
261 })?
262 .extensions;
263 let (extensions, agreed) = extensions_config
264 .accept_offers(&extensions)
265 .map_err(ProtocolError::from)?;
266
267 if let Some(agreed) = agreed {
268 response.headers_mut().typed_insert(agreed)
269 };
270 self.extensions = extensions;
271 }
272
273 let callback_result = if let Some(callback) = self.callback.take() {
274 callback.on_request(&result, response)
275 } else {
276 Ok(response)
277 };
278
279 match callback_result {
280 Ok(response) => {
281 let mut output = vec![];
282 write_response(&mut output, &response)?;
283 ProcessingResult::Continue(HandshakeMachine::start_write(stream, output))
284 }
285
286 Err(resp) => {
287 if resp.status().is_success() {
288 return Err(Error::Protocol(ProtocolError::CustomResponseSuccessful));
289 }
290
291 self.error_response = Some(resp);
292 let resp = self.error_response.as_ref().unwrap();
293
294 let mut output = vec![];
295 write_response(&mut output, resp)?;
296
297 if let Some(body) = resp.body() {
298 output.extend_from_slice(body.as_bytes());
299 }
300
301 ProcessingResult::Continue(HandshakeMachine::start_write(stream, output))
302 }
303 }
304 }
305
306 StageResult::DoneWriting(stream) => {
307 if let Some(err) = self.error_response.take() {
308 debug!("Server handshake failed.");
309
310 let (parts, body) = err.into_parts();
311 let body = body.map(|b| b.as_bytes().to_vec());
312 return Err(Error::Http(http::Response::from_parts(parts, body).into()));
313 } else {
314 debug!("Server handshake done.");
315 let websocket = WebSocket::from_raw_socket_with_extensions(
316 stream,
317 Role::Server,
318 self.config,
319 std::mem::take(&mut self.extensions),
320 );
321 ProcessingResult::Done(websocket)
322 }
323 }
324 })
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::{super::machine::TryParse, create_response, Request};
331
332 #[test]
333 fn request_parsing() {
334 const DATA: &[u8] = b"GET /script.ws HTTP/1.1\r\nHost: foo.com\r\n\r\n";
335 let (_, req) = Request::try_parse(DATA).unwrap().unwrap();
336 assert_eq!(req.uri().path(), "/script.ws");
337 assert_eq!(req.headers().get("Host").unwrap(), &b"foo.com"[..]);
338 }
339
340 #[test]
341 fn request_replying() {
342 const DATA: &[u8] = b"\
343 GET /script.ws HTTP/1.1\r\n\
344 Host: foo.com\r\n\
345 Connection: upgrade\r\n\
346 Upgrade: websocket\r\n\
347 Sec-WebSocket-Version: 13\r\n\
348 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\
349 \r\n";
350 let (_, req) = Request::try_parse(DATA).unwrap().unwrap();
351 let response = create_response(&req).unwrap();
352
353 assert_eq!(
354 response.headers().get("Sec-WebSocket-Accept").unwrap(),
355 b"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=".as_ref()
356 );
357 }
358}