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
doctorpavel
Dawid J. Kubis 1 year ago
parent 06d2d7a957
commit 7cf755b47b

38
Cargo.lock generated

@ -186,7 +186,6 @@ dependencies = [
"structopt", "structopt",
"thiserror", "thiserror",
"threadpool", "threadpool",
"urlencoding",
] ]
[[package]] [[package]]
@ -197,15 +196,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.144" version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"scopeguard", "scopeguard",
@ -213,12 +212,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
@ -299,9 +295,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.59" version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -332,18 +328,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.163" version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.163" version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -484,9 +480,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.21" version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
dependencies = [ dependencies = [
"itoa", "itoa",
"libc", "libc",
@ -529,12 +525,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "urlencoding"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
[[package]] [[package]]
name = "utf8-width" name = "utf8-width"
version = "0.1.6" version = "0.1.6"

@ -17,7 +17,6 @@ serde = { version = "1.0.136", features = ["derive"] }
log = "0.4.17" log = "0.4.17"
simplelog = "0.12.1" simplelog = "0.12.1"
html-escape = "0.2.13" html-escape = "0.2.13"
urlencoding = "2.1.2" #urlencoding = "2.1.2"
#ctrlc = "3.3.1"
#image = "0.24.6" #image = "0.24.6"

@ -13,8 +13,6 @@ pub enum RequestError {
NotFound, NotFound,
#[error("unused method")] #[error("unused method")]
UnusedMethod, UnusedMethod,
#[error("request not authorized, incorred hash: {0}")]
NotAuthorized(String),
#[error("urldecoding error")] #[error("urldecoding error")]
UrlDecodeErr(#[from] FromUtf8Error), UrlDecodeErr(#[from] FromUtf8Error),
#[error("bad request")] #[error("bad request")]
@ -59,7 +57,6 @@ impl From<RequestError> for Status {
RequestError::NotAForm => Status::BadRequest, RequestError::NotAForm => Status::BadRequest,
RequestError::NotFound => Status::NotFound, RequestError::NotFound => Status::NotFound,
RequestError::UnusedMethod => Status::BadRequest, RequestError::UnusedMethod => Status::BadRequest,
RequestError::NotAuthorized(_) => Status::Unauthorized,
RequestError::UrlDecodeErr(_) => Status::BadRequest, RequestError::UrlDecodeErr(_) => Status::BadRequest,
RequestError::BadRequest => Status::BadRequest, RequestError::BadRequest => Status::BadRequest,
RequestError::MissingBody => Status::BadRequest, RequestError::MissingBody => Status::BadRequest,
@ -72,7 +69,7 @@ impl From<HandlingError> for Response {
let status = match err { let status = match err {
HandlingError::ClientError(e) => Status::from(e), HandlingError::ClientError(e) => Status::from(e),
HandlingError::ServerError(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()) Response::new(status, vec![], status.message().into())
} }

@ -1,9 +1,6 @@
use std::fmt;
use std::str::{FromStr, Lines}; use std::str::{FromStr, Lines};
use crate::errors::{HandlingError, RequestError}; use crate::errors::RequestError;
use html_escape::encode_text;
const HTTP_VERSION: &'static str = "HTTP/1.1"; const HTTP_VERSION: &'static str = "HTTP/1.1";
@ -28,7 +25,6 @@ pub enum Status {
SeeOther = 303, SeeOther = 303,
NotFound = 404, NotFound = 404,
BadRequest = 400, BadRequest = 400,
Unauthorized = 401,
InternalServerError = 500, InternalServerError = 500,
} }
@ -57,7 +53,6 @@ impl Status {
Self::Ok => "OK", Self::Ok => "OK",
Self::NotFound => "NOT FOUND", Self::NotFound => "NOT FOUND",
Self::BadRequest => "BAD REQUEST", Self::BadRequest => "BAD REQUEST",
Self::Unauthorized => "UNAUTHORIZED",
Self::InternalServerError => "INTERNAL SERVER ERROR", Self::InternalServerError => "INTERNAL SERVER ERROR",
Self::SeeOther => "SEE OTHER", 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 = String::from_utf8_lossy(&body[pos..temp]).to_string();
//let content = encode_text(&content.trim().to_string()).to_string(); //let content = encode_text(&content.trim().to_string()).to_string();
// do that later // do that later
dbg!(&content); //dbg!(&content);
// good so far // good so far
@ -140,7 +135,7 @@ impl TryFrom<&Request> for Form {
+ pos; + pos;
let image = if &body[pos..temp] == b"\r\n" { let image = if &body[pos..temp] == b"\r\n" {
dbg!("no image"); //dbg!("no image");
None None
} else { } else {
Some(body[pos..temp].to_owned()) Some(body[pos..temp].to_owned())
@ -154,17 +149,6 @@ impl Request {
pub fn add_body(&mut self, body: Vec<u8>) { pub fn add_body(&mut self, body: Vec<u8>) {
self.body = Some(body); self.body = Some(body);
} }
// pub fn form(&self) -> Result<HashMap<&str, String>, 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<Vec<String>> for Request { impl TryFrom<Vec<String>> for Request {

@ -6,15 +6,11 @@ use crate::errors::{HandlingError, RequestError};
use crate::http::{Form, Request, Response, Status}; use crate::http::{Form, Request, Response, Status};
use crate::post::{Post, Thread}; use crate::post::{Post, Thread};
use std::error::Error;
use std::io; use std::io;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::net::{SocketAddr, TcpListener, TcpStream}; use std::net::{SocketAddr, TcpListener, TcpStream};
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::str; use std::str;
use std::str::from_utf8;
use std::sync::{Arc, RwLock};
use std::thread::JoinHandle;
use bincode::{deserialize, serialize}; use bincode::{deserialize, serialize};
use errors::DatabaseError; use errors::DatabaseError;
@ -25,14 +21,13 @@ use log::*;
use simplelog::*; use simplelog::*;
use structopt::StructOpt; use structopt::StructOpt;
use threadpool::ThreadPool; use threadpool::ThreadPool;
use urlencoding::decode;
// use this instead of hard-coding // use this instead of hard-coding
type ID_TYPE = u32; //type ID_TYPE = u32;
pub const INDEX: &'static str = include_str!("www/index.html"); pub const INDEX: &str = include_str!("www/index.html");
pub const FAVICON: &'static [u8] = include_bytes!("www/favicon.ico"); pub const FAVICON: &[u8] = include_bytes!("www/favicon.ico");
pub const STYLE: &'static str = include_str!("www/style.css"); pub const STYLE: &str = include_str!("www/style.css");
pub const FAQ: &'static str = include_str!("www/faq.html"); pub const FAQ: &str = include_str!("www/faq.html");
// represents command line arguments // represents command line arguments
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
@ -40,9 +35,6 @@ struct Opt {
#[structopt(short, long, default_value = "8000")] #[structopt(short, long, default_value = "8000")]
port: u16, port: u16,
#[structopt(short, long)]
admin_hash: Option<String>,
#[structopt(short, long, default_value = "data")] #[structopt(short, long, default_value = "data")]
database: PathBuf, database: PathBuf,
} }
@ -87,6 +79,7 @@ fn get_thread(id: u32) -> Result<Vec<Post>, DatabaseError> {
.and_then(|x| deserialize::<Thread>(&x).map_err(|_| DatabaseError::SerError))? .and_then(|x| deserialize::<Thread>(&x).map_err(|_| DatabaseError::SerError))?
.into_iter() .into_iter()
.map(|x| get_post(x)) .map(|x| get_post(x))
.filter(|x| x.is_ok())
.collect() .collect()
// let thread = THREADS.get(id.to_be_bytes()).and_then() // let thread = THREADS.get(id.to_be_bytes()).and_then()
} }
@ -104,14 +97,6 @@ fn next_id() -> Result<u32, DatabaseError> {
.map_err(|e| DatabaseError::from(e)) .map_err(|e| DatabaseError::from(e))
} }
/// returns current id
/// not used
fn get_id() -> Result<u32, DatabaseError> {
let s = DB.get(b"id")?.unwrap();
let buf: [u8; 4] = (*s).try_into().unwrap();
Ok(u32::from_be_bytes(buf))
}
/// lists all threads /// lists all threads
fn list_threads() -> Result<Vec<Post>, DatabaseError> { fn list_threads() -> Result<Vec<Post>, DatabaseError> {
THREADS THREADS
@ -155,6 +140,15 @@ fn add_post(mut post: Post, thread_id: u32) -> Result<(), DatabaseError> {
Ok(()) 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> { fn add_thread(mut post: Post) -> Result<(), DatabaseError> {
let id = next_id()?; let id = next_id()?;
let thread = Thread::new(id); let thread = Thread::new(id);
@ -205,9 +199,7 @@ fn handle(mut reader: BufReader<&mut TcpStream>) -> Result<Response, HandlingErr
Method::Get => get(&request.uri), Method::Get => get(&request.uri),
Method::Post => post(request), Method::Post => post(request),
// TODO check admin hash // TODO check admin hash
_ => Ok(Response::from(HandlingError::from( Method::Delete => delete(&request.uri),
RequestError::BadRequest,
))),
} }
} }
@ -269,12 +261,7 @@ fn post(request: Request) -> Result<Response, HandlingError> {
let form = Form::try_from(&request)?; let form = Form::try_from(&request)?;
let mut post = Post::new( let mut post = Post::new(0, encode_text(form.content.trim()).replace("\r\n", "<br>"));
0,
dbg!(encode_text(form.content.trim()))
.replace("\r\n", "<br>")
.to_string(),
);
post.img = form.image; post.img = form.image;
match request.uri.as_str() { match request.uri.as_str() {
@ -294,8 +281,8 @@ fn post(request: Request) -> Result<Response, HandlingError> {
// means we wish to post in specific thread // means we wish to post in specific thread
s => { s => {
let id = s let id = s
.trim_start_matches("/") .trim_start_matches('/')
.split("/") .split('/')
.next() .next()
.unwrap() .unwrap()
.parse::<u32>() .parse::<u32>()
@ -314,8 +301,17 @@ fn post(request: Request) -> Result<Response, HandlingError> {
} }
} }
fn delete(path: &str) -> Response { fn delete(path: &str) -> Result<Response, HandlingError> {
todo!(); let id = path
.trim_start_matches("/")
.parse::<u32>()
.map_err(|_| RequestError::NotFound)?;
delete_post(id)?;
Ok(Response::new(
Status::SeeOther,
vec![("location", "/")],
vec![],
))
} }
fn content(name: &str, main: &str) -> String { fn content(name: &str, main: &str) -> String {
@ -323,11 +319,6 @@ fn content(name: &str, main: &str) -> String {
} }
fn main() { 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 // setup logger
TermLogger::init( TermLogger::init(
LevelFilter::Info, LevelFilter::Info,
@ -337,6 +328,15 @@ fn main() {
) )
.expect("failed to setup logger"); .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 // wait for requests
for stream in listener.incoming() { for stream in listener.incoming() {
let mut stream = match stream { let mut stream = match stream {
@ -352,11 +352,14 @@ fn main() {
let response = match handle(reader) { let response = match handle(reader) {
Ok(s) => s, Ok(s) => s,
Err(e) => Response::from(dbg!(e)), Err(e) => {
warn!("{e}");
Response::from(e)
}
}; };
// handle request // handle request
stream.write(&response.respond()).unwrap(); stream.write_all(&response.respond()).unwrap();
}); });
} }
} }

Loading…
Cancel
Save