From 3867435a2dfee3b4ebbe957033e0226a62aa4abe Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sat, 22 May 2021 14:24:42 +0200 Subject: [PATCH] WebSocket Firefox --- src/http/handler.rs | 27 +++++++++++++----------- src/http/mod.rs | 45 ++++++++++++++++++---------------------- src/websocket/handler.rs | 18 ++++++++-------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/http/handler.rs b/src/http/handler.rs index c6b7526..f75277c 100644 --- a/src/http/handler.rs +++ b/src/http/handler.rs @@ -24,14 +24,13 @@ pub fn connection_handler(client: super::Stream) { fn request_handler(client: &mut super::HttpStream) { let mut res = super::Response::new(); - if let Some(conn) = res.find_header("Connection") { - client.client_keep_alive = client.client_keep_alive && conn.eq_ignore_ascii_case("keep-alive"); - } - match super::parser::parse_request(&mut client.stream) { Ok(Some(req)) => { println!("{} {}", req.method, req.uri); + client.client_keep_alive = + client.client_keep_alive && req.header.field_has_value("Connection", "keep-alive"); + if !req.uri.starts_with("/") || req.uri.contains("/./") || req.uri.contains("/../") @@ -43,8 +42,8 @@ fn request_handler(client: &mut super::HttpStream) { } else if req.uri.eq("/") { res.status(200); } else if req.uri.starts_with("/_usimp/") { - res.add_header("Cache-Control", "no-store"); - res.add_header("Access-Control-Allow-Origin", "*"); + res.header.add_field("Cache-Control", "no-store"); + res.header.add_field("Access-Control-Allow-Origin", "*"); if req.uri.eq("/_usimp/websocket") { return websocket::connection_handler(client, &req, res); @@ -62,7 +61,7 @@ fn request_handler(client: &mut super::HttpStream) { Method::POST => return endpoint_handler(client, &req, res, endpoint), _ => { res.status(405); - res.add_header("Allow", "POST"); + res.header.add_field("Allow", "POST"); error = Some(Error::new(Kind::UsimpProtocolError, Class::ClientError)) } }, @@ -119,8 +118,10 @@ pub fn error_handler(client: &mut super::HttpStream, mut res: super::Response, e let buf = obj.to_string() + "\r\n"; let length = buf.as_bytes().len(); - res.add_header("Content-Length", length.to_string().as_str()); - res.add_header("Content-Type", "application/json; charset=utf-8"); + res.header + .add_field("Content-Length", length.to_string().as_str()); + res.header + .add_field("Content-Type", "application/json; charset=utf-8"); if let Err(e) = client.respond(&mut res) { println!("Unable to send: {}", e); @@ -136,7 +137,7 @@ fn endpoint_handler( mut res: super::Response, endpoint: &str, ) { - let length = req.find_header("Content-Length"); + let length = req.header.find_field("Content-Length"); let length: usize = match match length { Some(length) => length, None => { @@ -178,8 +179,10 @@ fn endpoint_handler( // TODO compress let length = buf.as_bytes().len(); - res.add_header("Content-Length", length.to_string().as_str()); - res.add_header("Content-Type", "application/json; charset=utf-8"); + res.header + .add_field("Content-Length", length.to_string().as_str()); + res.header + .add_field("Content-Type", "application/json; charset=utf-8"); res.status(200); client.respond(&mut res).unwrap(); diff --git a/src/http/mod.rs b/src/http/mod.rs index b081cab..8057d07 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -66,13 +66,13 @@ pub struct Request { version: String, pub method: Method, pub uri: String, - header: Header, + pub header: Header, } pub struct Response { version: String, status: Status, - header: Header, + pub header: Header, } impl Method { @@ -200,15 +200,17 @@ impl Header { value: String::from(value), }) } -} -impl Request { - pub fn find_header(&self, name: &str) -> Option<&str> { - self.header.find_field(name) - } - - pub fn add_header(&mut self, name: &str, value: &str) { - self.header.add_field(name, value) + pub fn field_has_value(&self, field_name: &str, value: &str) -> bool { + if let Some(field) = self.find_field(field_name) { + let value = value.to_lowercase(); + field + .to_lowercase() + .split(",") + .any(|mut s| s.trim().eq(value.as_str())) + } else { + false + } } } @@ -219,8 +221,8 @@ impl Response { status: Status::from_code(200).unwrap(), header: Header::new(), }; - res.add_header("Server", "Locutus"); - res.add_header( + res.header.add_field("Server", "Locutus"); + res.header.add_field( "Date", chrono::Utc::now() .format("%a, %d %b %Y %H:%M:%S GMT") @@ -230,14 +232,6 @@ impl Response { res } - pub fn find_header(&self, name: &str) -> Option<&str> { - self.header.find_field(name) - } - - pub fn add_header(&mut self, name: &str, value: &str) { - self.header.add_field(name, value) - } - pub fn status(&mut self, status_code: u16) { self.status = Status::from_code(status_code).unwrap() } @@ -261,13 +255,14 @@ impl Response { pub fn send_default(&mut self, stream: &mut Stream) -> Result<(), std::io::Error> { let mut buf = None; - if let None = self.find_header("Content-Length") { + if let None = self.header.find_field("Content-Length") { let new_buf = self.format_default_response(); - self.add_header( + self.header.add_field( "Content-Length", new_buf.as_bytes().len().to_string().as_str(), ); - self.add_header("Content-Type", "text/html; charset=utf-8"); + self.header + .add_field("Content-Type", "text/html; charset=utf-8"); buf = Some(new_buf); } @@ -324,8 +319,8 @@ impl HttpStream { fn keep_alive(&mut self, res: &mut Response) { if self.client_keep_alive && self.server_keep_alive { - res.add_header("Connection", "keep-alive"); - res.add_header("Keep-Alive", "timeout=3600, max=200"); + res.header.add_field("Connection", "keep-alive"); + res.header.add_field("Keep-Alive", "timeout=3600, max=200"); } } } diff --git a/src/websocket/handler.rs b/src/websocket/handler.rs index 5ced870..57b1fd5 100644 --- a/src/websocket/handler.rs +++ b/src/websocket/handler.rs @@ -14,7 +14,7 @@ pub fn connection_handler( if let http::Method::GET = req.method { } else { res.status(405); - res.add_header("Allow", "GET"); + res.header.add_field("Allow", "GET"); return http::error_handler( client, res, @@ -23,8 +23,8 @@ pub fn connection_handler( ); } - if let Some(connection) = req.find_header("Connection") { - if !connection.eq_ignore_ascii_case("upgrade") { + if let Some(_) = req.header.find_field("Connection") { + if !req.header.field_has_value("Connection", "upgrade") { return http::error_handler( client, res, @@ -41,7 +41,7 @@ pub fn connection_handler( ); } - if let Some(upgrade) = req.find_header("Upgrade") { + if let Some(upgrade) = req.header.find_field("Upgrade") { if !upgrade.eq_ignore_ascii_case("websocket") { return http::error_handler( client, @@ -59,7 +59,7 @@ pub fn connection_handler( ); } - if let Some(version) = req.find_header("Sec-WebSocket-Version") { + if let Some(version) = req.header.find_field("Sec-WebSocket-Version") { if !version.eq("13") { return http::error_handler( client, @@ -77,7 +77,7 @@ pub fn connection_handler( ); } - if let Some(key) = req.find_header("Sec-WebSocket-Key") { + if let Some(key) = req.header.find_field("Sec-WebSocket-Key") { let mut hasher = crypto::sha1::Sha1::new(); hasher.input_str(key); hasher.input_str("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); @@ -85,7 +85,7 @@ pub fn connection_handler( let mut result = [0u8; 160 / 8]; hasher.result(&mut result); let key = base64::encode(result); - res.add_header("Sec-WebSocket-Accept", key.as_str()); + res.header.add_field("Sec-WebSocket-Accept", key.as_str()); } else { return http::error_handler( client, @@ -96,8 +96,8 @@ pub fn connection_handler( } client.server_keep_alive = false; - res.add_header("Connection", "Upgrade"); - res.add_header("Upgrade", "websocket"); + res.header.add_field("Connection", "Upgrade"); + res.header.add_field("Upgrade", "websocket"); res.status(101); res.send(&mut client.stream).unwrap();