use super::Method; use crate::usimp; use crate::websocket; use crate::error::*; use serde_json; pub struct HttpStream { pub stream: super::Stream, pub request_num: u32, pub client_keep_alive: bool, pub server_keep_alive: bool, } pub fn connection_handler(client: super::Stream) { let mut client = super::HttpStream { stream: client, request_num: 0, client_keep_alive: true, server_keep_alive: true, }; while client.request_num < super::REQUESTS_PER_CONNECTION && client.client_keep_alive && client.server_keep_alive { request_handler(&mut client); client.request_num += 1; } } fn request_handler(client: &mut super::HttpStream) { let mut res = super::Response::new(); match super::parser::parse_request(&mut client.stream) { Ok(Some(req)) => { println!("{} {}", req.method, req.uri); if !req.uri.starts_with("/") || req.uri.contains("/./") || req.uri.contains("/../") || req.uri.ends_with("/..") { res.status(400); } else if req.uri.contains("/.") { res.status(404); } else if req.uri.eq("/") { res.status(200); } else if req.uri.eq("/_usimp/websocket") { return websocket::connection_handler(client, &req); } else if req.uri.starts_with("/_usimp/") { let parts: Vec<&str> = req.uri.split('/').collect(); match parts[2..] { ["entity", entity] => res.status(501), [endpoint] => match req.method { Method::POST => return endpoint_handler(client, &req, &mut res, endpoint), _ => { res.status(405); res.add_header("Allow", "POST"); } }, _ => res.status(400), } } else { res.status(404); } } Ok(None) => { client.client_keep_alive = false; return; } Err(e) => { res.status(400); res.error_info(format!("{}", &e)); println!("{}", &e); client.server_keep_alive = false; } } if let Err(e) = res.send(&mut client.stream) { println!("Unable to send: {}", e); client.server_keep_alive = false; } client.server_keep_alive = false; } fn endpoint_handler( client: &mut super::HttpStream, req: &super::Request, res: &mut super::Response, endpoint: &str, ) { res.add_header("Cache-Control", "no-store"); let mut error = |error: Error, client: &mut super::HttpStream| { println!("{}", error.to_string()); res.status(match &error.class() { Class::ClientError => 400, Class::ServerError => 500, }); res.error_info(error.to_string()); let mut obj = serde_json::Value::Object(serde_json::Map::new()); obj["status"] = serde_json::Value::String("error".to_string()); obj["message"] = serde_json::Value::String(error.to_string()); 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"); if let Err(e) = res.send(&mut client.stream) { println!("Unable to send: {}", e); client.server_keep_alive = false; } client.stream.write_all(buf.as_bytes()); }; let length = req.find_header("Content-Length"); let length: usize = match match length { Some(length) => length, None => { return error( Error::new(Kind::HttpRequestParseError, Class::ClientError) .set_desc("field 'Content-Length' missing".to_string()), client, ) } } .parse() { Ok(length) => length, Err(e) => { return error( Error::new(Kind::HttpRequestParseError, Class::ClientError) .set_desc(format!("unable to parse field 'Content-Length': {}", &e).to_string()), client, ) } }; let mut buf = [0; 8192]; client.stream.read_exact(&mut buf[..length]); // TODO decompress let input = match serde_json::from_slice(&buf[..length]) { Ok(val) => val, Err(e) => { return error(e.into(), client) } }; let buf = match usimp::endpoint(endpoint, input) { Ok(output) => output.to_string() + "\r\n", Err(e) => return error(e, client), }; // 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.status(200); res.send(&mut client.stream); client.stream.write_all(buf.as_bytes()); }