diff --git a/src/apps/chat.html b/src/apps/chat.html index f92c6e6..c39fb7c 100644 --- a/src/apps/chat.html +++ b/src/apps/chat.html @@ -2,10 +2,18 @@ +

Chat

-
+
+

Online Users :

+
+
{ let elem = document.createElement("p"); elem["data-id"] = msg.id; elem.innerHTML = - "" + users[msg.author] + " : " + msg.content; + "" + users[msg.author] + " : " + msg.content; for (c of msgs.children) { if (c["data-id"] > msg.id) { msgs.insertBefore(elem, c); diff --git a/src/socket.rs b/src/socket.rs index 0dbdfa4..7eb61d4 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -53,9 +53,137 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps: socket.remote_endpoint() ); + let (mut rx, mut tx) = socket.split(); let mut ws_path: Option> = None; loop { Timer::after_secs(0).await; + let mut cont = &[]; + rx.read_with(|msg| { + let (headers, content) = match from_utf8(msg) { + Ok(b) => match b.split_once("\r\n\r\n") { + Some(t) => t, + None => (b, ""), + }, + Err(_) => { + warn!("Non utf8 http request"); + return (0, Err(())); + } + }; + let mut hl = headers.lines(); + let (request_type, path) = match hl.next() { + None => { + warn!("Empty request"); + return (0, Err(())); + } + Some(l1) => { + let mut l1 = l1.split(' '); + ( + match l1.next() { + Some("GET") => HttpRequestType::Get, + Some("POST") => HttpRequestType::Post, + Some(t) => { + warn!("Unknown request type : {}", t); + return (0, Err(())); + } + None => { + warn!("No request type"); + return (0, Err(())); + } + }, + match l1.next() { + Some(path) => path, + None => { + warn!("No path"); + return (0, Err(())); + } + }, + ) + } + }; + let mut host = None; + let mut ws_handshake = false; + let mut ws_key = None; + for h in hl { + let Some((name, val)) = h.split_once(':') else { + continue; + }; + let name = name.trim(); + let val = val.trim(); + match (name, val) { + ("Host", _) => host = Some(val), + ("Upgrade", "websocket") => ws_handshake = true, + ("Sec-WebSocket-Key", _) => ws_key = Some(val), + _ => {} + } + } + let Some(host) = host else { + warn!("No host"); + return (0, Err(())); + }; + info!( + "Socket {}: {:?}{} request for {}{}", + app.socket_name(), + request_type, + if ws_handshake { " websocket" } else { "" }, + host, + path, + ); + head_buf.clear(); + let res_content: Result, core::fmt::Error> = try { + if ws_handshake { + if !app.accept_ws(path) { + warn!("No ws there!"); + write!( + &mut head_buf, + "{}\r\n\r\n", + Into::<&str>::into(HttpResCode::NotFound) + )?; + None + } else { + if path.len() > 16 { + warn!("Ws socket cannot have path longer than 16 chars!"); + return (0, Err(())); + } + let Some(key) = ws_key else { + warn!("No ws key!"); + return (0, Err(())); + }; + let Ok(accept) = compute_ws_accept(key) else { + return (0, Err(())); + }; + write!( + &mut head_buf, + "{}\r\n\ + Upgrade: websocket\r\n\ + Connection: Upgrade\r\n\ + Sec-WebSocket-Accept: {}\r\n\r\n", + Into::<&str>::into(HttpResCode::SwitchingProtocols), + accept + )?; + None + } + } else { + let (code, res_type, res_content) = + app.handle_request(path, request_type, content).await; + + write!(&mut head_buf, "{}", Into::<&str>::into(code))?; + if let Some(ref c) = res_content { + write!( + &mut head_buf, + "\r\n\ + Content-Type: text/{}\r\n\ + Content-Length: {}\r\n", + res_type, + c.len() + )?; + } + write!(&mut head_buf, "\r\n\r\n")?; + res_content + } + }; + (msg.len(), Ok(())) + }) + .await; let n = match socket.read(&mut buf).await { Ok(0) => { warn!("read EOF"); @@ -67,137 +195,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps: break; } }; - head_buf.clear(); - let msg = unwrap_opt(buf.get(..n)).await; - let (headers, content) = match from_utf8(msg) { - Ok(b) => match b.split_once("\r\n\r\n") { - Some(t) => t, - None => (b, ""), - }, - Err(_) => { - warn!("Non utf8 http request"); - break; - } - }; - - let mut hl = headers.lines(); - let (request_type, path) = match hl.next() { - None => { - warn!("Empty request"); - break; - } - Some(l1) => { - let mut l1 = l1.split(' '); - ( - match l1.next() { - Some("GET") => HttpRequestType::Get, - Some("POST") => HttpRequestType::Post, - Some(t) => { - warn!("Unknown request type : {}", t); - break; - } - None => { - warn!("No request type"); - break; - } - }, - match l1.next() { - Some(path) => path, - None => { - warn!("No path"); - break; - } - }, - ) - } - }; - let mut host = None; - let mut ws_handshake = false; - let mut ws_key = None; - for h in hl { - let Some((name, val)) = h.split_once(':') else { - continue; - }; - let name = name.trim(); - let val = val.trim(); - match (name, val) { - ("Host", _) => host = Some(val), - ("Upgrade", "websocket") => ws_handshake = true, - ("Sec-WebSocket-Key", _) => ws_key = Some(val), - _ => {} - } - } - let Some(host) = host else { - warn!("No host"); - break; - }; - - info!( - "Socket {}: {:?}{} request for {}{}", - app.socket_name(), - request_type, - if ws_handshake { " websocket" } else { "" }, - host, - path, - ); - - head_buf.clear(); - let res_content: Result, core::fmt::Error> = try { - if ws_handshake { - if !app.accept_ws(path) { - warn!("No ws there!"); - write!( - &mut head_buf, - "{}\r\n\r\n", - Into::<&str>::into(HttpResCode::NotFound) - )?; - None - } else { - if path.len() > 16 { - warn!("Ws socket cannot have path longer than 16 chars!"); - break; - } - let Some(key) = ws_key else { - warn!("No ws key!"); - break; - }; - let accept = match compute_ws_accept(key).await { - Ok(a) => a, - Err(e) => { - warn!("compute ws accept error : {:?}", e); - break; - } - }; - write!( - &mut head_buf, - "{}\r\n\ - Upgrade: websocket\r\n\ - Connection: Upgrade\r\n\ - Sec-WebSocket-Accept: {}\r\n\r\n", - Into::<&str>::into(HttpResCode::SwitchingProtocols), - accept - )?; - None - } - } else { - let (code, res_type, res_content) = - app.handle_request(path, request_type, content).await; - - write!(&mut head_buf, "{}", Into::<&str>::into(code))?; - if let Some(ref c) = res_content { - write!( - &mut head_buf, - "\r\n\ - Content-Type: text/{}\r\n\ - Content-Length: {}\r\n", - res_type, - c.len() - )?; - } - write!(&mut head_buf, "\r\n\r\n")?; - res_content - } - }; let res_content = match res_content { Ok(rc) => rc, @@ -269,13 +266,22 @@ impl Into<&str> for HttpResCode { } } -async fn compute_ws_accept(key: &str) -> Result, EncodeSliceError> { +fn compute_ws_accept(key: &str) -> Result, ()> { let mut res = Vec::::new(); - res.extend_from_slice(&[0; 28]).unwrap(); + res.fill(0); let mut hasher = Sha1::new(); hasher.update(key.as_bytes()); hasher.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); let hash = hasher.finalize(); - BASE64_STANDARD.encode_slice(hash, &mut res)?; - Ok(unwrap(String::from_utf8(res)).await) + if let Err(e) = BASE64_STANDARD.encode_slice(hash, &mut res) { + warn!("Error while base64 encoding : {}", e); + return Err(()); + }; + match String::from_utf8(res) { + Ok(r) => Ok(r), + Err(e) => { + warn!("Ws accept is not utf8! ({})", e); + Err(()) + } + } }