From 7cf755b47b41fe7768c9300438b1ae02f6dbf918 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Fri, 9 Jun 2023 19:27:38 +0200 Subject: [PATCH] added support for the DELTE method to moderate the board, removed authorization code as it can be handled from nginx updated dependencies, resolved some warnings --- Cargo.lock | 38 +++++++++------------- Cargo.toml | 3 +- src/errors.rs | 5 +-- src/http.rs | 22 ++----------- src/main.rs | 87 ++++++++++++++++++++++++++------------------------- 5 files changed, 64 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bfe406..cde4799 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,6 @@ dependencies = [ "structopt", "thiserror", "threadpool", - "urlencoding", ] [[package]] @@ -197,15 +196,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -213,12 +212,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "memoffset" @@ -299,9 +295,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -332,18 +328,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", @@ -484,9 +480,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "libc", @@ -529,12 +525,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "urlencoding" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" - [[package]] name = "utf8-width" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 58a6501..e1b9c76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ serde = { version = "1.0.136", features = ["derive"] } log = "0.4.17" simplelog = "0.12.1" html-escape = "0.2.13" -urlencoding = "2.1.2" -#ctrlc = "3.3.1" +#urlencoding = "2.1.2" #image = "0.24.6" diff --git a/src/errors.rs b/src/errors.rs index 232adc6..83d19fc 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -13,8 +13,6 @@ pub enum RequestError { NotFound, #[error("unused method")] UnusedMethod, - #[error("request not authorized, incorred hash: {0}")] - NotAuthorized(String), #[error("urldecoding error")] UrlDecodeErr(#[from] FromUtf8Error), #[error("bad request")] @@ -59,7 +57,6 @@ impl From for Status { RequestError::NotAForm => Status::BadRequest, RequestError::NotFound => Status::NotFound, RequestError::UnusedMethod => Status::BadRequest, - RequestError::NotAuthorized(_) => Status::Unauthorized, RequestError::UrlDecodeErr(_) => Status::BadRequest, RequestError::BadRequest => Status::BadRequest, RequestError::MissingBody => Status::BadRequest, @@ -72,7 +69,7 @@ impl From for Response { let status = match err { HandlingError::ClientError(e) => Status::from(e), HandlingError::ServerError(e) => Status::from(e), - HandlingError::Io(e) => Status::InternalServerError, + HandlingError::Io(_) => Status::InternalServerError, }; Response::new(status, vec![], status.message().into()) } diff --git a/src/http.rs b/src/http.rs index 191f94c..e50781d 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,9 +1,6 @@ -use std::fmt; use std::str::{FromStr, Lines}; -use crate::errors::{HandlingError, RequestError}; - -use html_escape::encode_text; +use crate::errors::RequestError; const HTTP_VERSION: &'static str = "HTTP/1.1"; @@ -28,7 +25,6 @@ pub enum Status { SeeOther = 303, NotFound = 404, BadRequest = 400, - Unauthorized = 401, InternalServerError = 500, } @@ -57,7 +53,6 @@ impl Status { Self::Ok => "OK", Self::NotFound => "NOT FOUND", Self::BadRequest => "BAD REQUEST", - Self::Unauthorized => "UNAUTHORIZED", Self::InternalServerError => "INTERNAL SERVER ERROR", Self::SeeOther => "SEE OTHER", } @@ -121,7 +116,7 @@ impl TryFrom<&Request> for Form { let content = String::from_utf8_lossy(&body[pos..temp]).to_string(); //let content = encode_text(&content.trim().to_string()).to_string(); // do that later - dbg!(&content); + //dbg!(&content); // good so far @@ -140,7 +135,7 @@ impl TryFrom<&Request> for Form { + pos; let image = if &body[pos..temp] == b"\r\n" { - dbg!("no image"); + //dbg!("no image"); None } else { Some(body[pos..temp].to_owned()) @@ -154,17 +149,6 @@ impl Request { pub fn add_body(&mut self, body: Vec) { self.body = Some(body); } - // pub fn form(&self) -> Result, RequestError> { - // let mut hashmap = HashMap::new(); - // dbg!(&self.body); - // for mut x in self.body.split("&").map(|x| x.split("=")) { - // hashmap.insert( - // x.next().ok_or(RequestError::NotAForm)?, - // decode(x.next().ok_or(RequestError::NotAForm)?)?.into_owned().replace("+", " "), - // ); - // } - // Ok(hashmap) - // } } impl TryFrom> for Request { diff --git a/src/main.rs b/src/main.rs index 52ab05d..e0b514c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,15 +6,11 @@ use crate::errors::{HandlingError, RequestError}; use crate::http::{Form, Request, Response, Status}; use crate::post::{Post, Thread}; -use std::error::Error; use std::io; use std::io::{BufRead, BufReader, Read, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::str; -use std::str::from_utf8; -use std::sync::{Arc, RwLock}; -use std::thread::JoinHandle; use bincode::{deserialize, serialize}; use errors::DatabaseError; @@ -25,14 +21,13 @@ use log::*; use simplelog::*; use structopt::StructOpt; use threadpool::ThreadPool; -use urlencoding::decode; // use this instead of hard-coding -type ID_TYPE = u32; -pub const INDEX: &'static str = include_str!("www/index.html"); -pub const FAVICON: &'static [u8] = include_bytes!("www/favicon.ico"); -pub const STYLE: &'static str = include_str!("www/style.css"); -pub const FAQ: &'static str = include_str!("www/faq.html"); +//type ID_TYPE = u32; +pub const INDEX: &str = include_str!("www/index.html"); +pub const FAVICON: &[u8] = include_bytes!("www/favicon.ico"); +pub const STYLE: &str = include_str!("www/style.css"); +pub const FAQ: &str = include_str!("www/faq.html"); // represents command line arguments #[derive(StructOpt, Debug)] @@ -40,9 +35,6 @@ struct Opt { #[structopt(short, long, default_value = "8000")] port: u16, - #[structopt(short, long)] - admin_hash: Option, - #[structopt(short, long, default_value = "data")] database: PathBuf, } @@ -87,6 +79,7 @@ fn get_thread(id: u32) -> Result, DatabaseError> { .and_then(|x| deserialize::(&x).map_err(|_| DatabaseError::SerError))? .into_iter() .map(|x| get_post(x)) + .filter(|x| x.is_ok()) .collect() // let thread = THREADS.get(id.to_be_bytes()).and_then() } @@ -104,14 +97,6 @@ fn next_id() -> Result { .map_err(|e| DatabaseError::from(e)) } -/// returns current id -/// not used -fn get_id() -> Result { - let s = DB.get(b"id")?.unwrap(); - let buf: [u8; 4] = (*s).try_into().unwrap(); - Ok(u32::from_be_bytes(buf)) -} - /// lists all threads fn list_threads() -> Result, DatabaseError> { THREADS @@ -155,6 +140,15 @@ fn add_post(mut post: Post, thread_id: u32) -> Result<(), DatabaseError> { Ok(()) } +fn delete_post(id: u32) -> Result<(), DatabaseError> { + POSTS.remove(id.to_be_bytes())?; + if THREADS.contains_key(id.to_be_bytes())? { + THREADS.remove(id.to_be_bytes())?; + } else { + } + Ok(()) +} + fn add_thread(mut post: Post) -> Result<(), DatabaseError> { let id = next_id()?; let thread = Thread::new(id); @@ -205,9 +199,7 @@ fn handle(mut reader: BufReader<&mut TcpStream>) -> Result get(&request.uri), Method::Post => post(request), // TODO check admin hash - _ => Ok(Response::from(HandlingError::from( - RequestError::BadRequest, - ))), + Method::Delete => delete(&request.uri), } } @@ -269,12 +261,7 @@ fn post(request: Request) -> Result { let form = Form::try_from(&request)?; - let mut post = Post::new( - 0, - dbg!(encode_text(form.content.trim())) - .replace("\r\n", "
") - .to_string(), - ); + let mut post = Post::new(0, encode_text(form.content.trim()).replace("\r\n", "
")); post.img = form.image; match request.uri.as_str() { @@ -294,8 +281,8 @@ fn post(request: Request) -> Result { // means we wish to post in specific thread s => { let id = s - .trim_start_matches("/") - .split("/") + .trim_start_matches('/') + .split('/') .next() .unwrap() .parse::() @@ -314,8 +301,17 @@ fn post(request: Request) -> Result { } } -fn delete(path: &str) -> Response { - todo!(); +fn delete(path: &str) -> Result { + let id = path + .trim_start_matches("/") + .parse::() + .map_err(|_| RequestError::NotFound)?; + delete_post(id)?; + Ok(Response::new( + Status::SeeOther, + vec![("location", "/")], + vec![], + )) } fn content(name: &str, main: &str) -> String { @@ -323,11 +319,6 @@ fn content(name: &str, main: &str) -> String { } fn main() { - // bind listener to local adress and port - let listener = - TcpListener::bind(("127.0.0.1", OPT.port)).expect("Cannot bind to specified port."); - // create threadpool for incoming requests - let pool = ThreadPool::new(num_cpus::get()); // setup logger TermLogger::init( LevelFilter::Info, @@ -337,6 +328,15 @@ fn main() { ) .expect("failed to setup logger"); + // bind listener to local adress and port + let listener = + TcpListener::bind(("127.0.0.1", OPT.port)).expect("Cannot bind to specified port."); + + info!("listening on port {}", OPT.port); + + // create threadpool for incoming requests + let pool = ThreadPool::new(num_cpus::get()); + // wait for requests for stream in listener.incoming() { let mut stream = match stream { @@ -352,11 +352,14 @@ fn main() { let response = match handle(reader) { Ok(s) => s, - Err(e) => Response::from(dbg!(e)), + Err(e) => { + warn!("{e}"); + Response::from(e) + } }; // handle request - stream.write(&response.respond()).unwrap(); + stream.write_all(&response.respond()).unwrap(); }); } }