From 57fd6c1f4ed579a751006e63664d9ae04715cbf1 Mon Sep 17 00:00:00 2001 From: koehr Date: Fri, 15 Jan 2021 01:26:39 +0100 Subject: [PATCH] use pretty_env_log and clean up code a bit --- Cargo.lock | 45 ++++++++++++++++++++++++++++++++ Cargo.toml | 7 +++-- src/db.rs | 2 ++ src/main.rs | 10 ++++++-- src/server.rs | 65 +++++++++++++++++------------------------------ src/short_code.rs | 1 - 6 files changed, 82 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c250ed8..14bbf78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,6 +308,17 @@ dependencies = [ "syn", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -553,6 +564,19 @@ dependencies = [ "syn", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "exitcode" version = "1.1.2" @@ -878,6 +902,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "idna" version = "0.2.0" @@ -953,7 +986,9 @@ dependencies = [ "failure", "futures", "human-panic", + "log", "mime", + "pretty_env_logger", "r2d2", "r2d2_sqlite", "radix_fmt", @@ -1290,6 +1325,16 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" diff --git a/Cargo.toml b/Cargo.toml index 1241985..4550d82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" description= "Very performant URL shortener service for individuals." readme = "README.md" categories = ["command-line-utilities"] -keywords = ["static", "website", "weblog", "blog", "markdown", "ssr", "web"] +keywords = ["web-service", "web-application", "url-shortener", "self-hosted"] repository = "https://git.sr.ht/~koehr/k0r" homepage = "https://sr.ht/~koehr/k0r/" @@ -24,12 +24,11 @@ r2d2 = "0.8" r2d2_sqlite = "0.17" rusqlite = "0.24" futures = "0.3" +log = { version = "0.4", features = ["max_level_debug", "release_max_level_info"] } +pretty_env_logger = "0.4" failure = "0.1.8" exitcode = "1.1.2" human-panic = "1.0.3" -[features] -debug-output = [] - [build-dependencies] ructe = { version = "0.13", features = ["mime03"] } diff --git a/src/db.rs b/src/db.rs index 5cbf8c1..c4fe3ef 100644 --- a/src/db.rs +++ b/src/db.rs @@ -25,6 +25,8 @@ fn get_url(conn: Connection, short_code: &str) -> Result { fn store_url(conn: Connection, url: &str) -> Result { let _ = conn.execute("INSERT INTO URLs VALUES(NULL, ?, 0, 0)", &[url])?; + // TODO: In case a plain [0-9a-z] string will be included into + // IGNORED_SHORT_CODES, this function should work around such IDs as well. let short_code = ShortCode::new(conn.last_insert_rowid() as usize).code; Ok(short_code) } diff --git a/src/main.rs b/src/main.rs index 535b121..6245dc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate log; +extern crate pretty_env_logger; use human_panic::setup_panic; use std::path::PathBuf; @@ -10,6 +13,7 @@ mod short_code; include!(concat!(env!("OUT_DIR"), "/templates.rs")); fn main() { + pretty_env_logger::init(); setup_panic!(); let arg = std::env::args() @@ -21,18 +25,20 @@ fn main() { println!("k0r [/path/to/k0r.db]\tDatabase name defaults to ./k0r.db"); std::process::exit(exitcode::USAGE); } else { - let mut path = PathBuf::from(arg); + let mut path = PathBuf::from(&arg); // append k0r.db as filename if path is a directory if path.is_dir() { path.push("k0r.db"); + debug!("Expanded given argument \"{}\" to {:?}", &arg, path); } if !path.is_file() { - println!("DB path not found and cannot be created: {:?}", path); + error!("DB path not found and cannot be created: {:?}", path); std::process::exit(exitcode::CANTCREAT); } + debug!("Starting server..."); let _ = server::start(path); } } diff --git a/src/server.rs b/src/server.rs index 3085c66..76391a1 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,11 +4,9 @@ use url::Url; use actix_web::{ self, web, - App, HttpRequest, HttpResponse, - HttpServer, - Error as AWError, + Error, http::header::{ContentType, Expires}, }; use std::time::{Duration, SystemTime}; @@ -20,11 +18,18 @@ const CONTENT_TYPE_HTML: &str = "content-type: text/html; charset=utf-8"; const CONTENT_TYPE_JSON: &str = "content-type: application/json; charset=utf-8"; /// A duration to add to current time for a far expires header. -static FAR: Duration = Duration::from_secs(180 * 24 * 60 * 60); +const FAR: Duration = Duration::from_secs(180 * 24 * 60 * 60); + +/// Common, unsoliticed queries by browsers that should be ignored +const IGNORED_SHORT_CODES: &[&str] = &["favicon.ico"]; // TODO: make db::store_url aware of this type DB = web::Data; type JSON = web::Json; +fn get_request_origin(req: &HttpRequest) -> String { + req.connection_info().remote_addr().unwrap_or("unkown origin").to_string() +} + /// Index page handler #[actix_web::get("/")] async fn index() -> HttpResponse { @@ -56,31 +61,24 @@ fn static_file(path: web::Path) -> HttpResponse { /// Asks the database for the URL matching short_code and responds /// with a redirect or, if not found, a JSON error #[actix_web::get("/{short_code}")] -async fn redirect(req: HttpRequest, db: DB) -> Result { +async fn redirect(req: HttpRequest, db: DB) -> Result { let respond_with_not_found = HttpResponse::NotFound() .content_type(CONTENT_TYPE_JSON) .body("{{\"status\": \"error\", \"message\": \"URL not found\"}}"); let short_code = req.match_info().get("short_code").unwrap_or("0"); - #[cfg(feature = "debug-output")] - let debug_info = format!( - "{} queried \"{}\", got ", - req.connection_info().remote_addr().unwrap_or("unkown origin"), - short_code - ); + if IGNORED_SHORT_CODES.contains(&short_code) { + debug!("{} queried {}: IGNORED", get_request_origin(&req), short_code); + Ok(respond_with_not_found) - if let Ok(url) = db::query(&db, db::Queries::GetURL(short_code.to_owned())).await { + } else if let Ok(url) = db::query(&db, db::Queries::GetURL(short_code.to_owned())).await { let body = format!("Would redirect to {}.", url, url); - - #[cfg(feature = "debug-output")] - println!("{}{}", debug_info, url); - + debug!("{} queried {}, got {}", get_request_origin(&req), short_code, url); Ok(HttpResponse::Ok().content_type(CONTENT_TYPE_HTML).body(body)) - } else { - #[cfg(feature = "debug-output")] - println!("{}Not Found", debug_info); + } else { + debug!("{} queried {}, got Not Found", get_request_origin(&req), short_code); Ok(respond_with_not_found) } } @@ -91,39 +89,25 @@ struct UrlPostData { } #[actix_web::post("/")] -async fn add_url(_req: HttpRequest, data: JSON, db: DB) -> Result { +async fn add_url(_req: HttpRequest, data: JSON, db: DB) -> Result { let respond_with_bad_request = HttpResponse::BadRequest() .content_type("content-type: application/json; charset=utf-8") .body("{{\"status\": \"error\", \"message\": \"invalid URL\"}}"); - #[cfg(feature = "debug-output")] - let debug_info = format!( - "{} posted \"{}\", got ", - _req.connection_info().remote_addr().unwrap_or("unkown origin"), - &data.url - ); - match Url::parse(&data.url) { Ok(parsed_url) => { if !parsed_url.has_authority() { - #[cfg(feature = "debug-output")] - println!("{}Invalid, no authority.", debug_info); - + debug!("{} posted \"{}\", got Invalid, no authority.", get_request_origin(&_req), &data.url); return Ok(respond_with_bad_request); } let code = db::query(&db, db::Queries::StoreNewURL(data.url.clone())).await?; - - #[cfg(feature = "debug-output")] - println!("{}{}.", debug_info, code); - + debug!("{} posted \"{}\", got {}", get_request_origin(&_req), &data.url, code); Ok(HttpResponse::Created() .content_type("content-type: application/json; charset=utf-8") .body(format!("{{\"status\": \"ok\", \"message\": \"{}\"}}", code))) }, Err(_) => { - #[cfg(feature = "debug-output")] - println!("{}Invalid, Parser Error.", debug_info); - + debug!("{} posted \"{}\", got Invalid, Parser Error.", get_request_origin(&_req), &data.url); Ok(respond_with_bad_request) }, } @@ -131,16 +115,15 @@ async fn add_url(_req: HttpRequest, data: JSON, db: DB) -> Result std::io::Result<()> { - #[cfg(feature = "debug-output")] - println!("Using database {:?}", db_path.canonicalize().unwrap()); + debug!("Canonical database path is {:?}", db_path.canonicalize()); let db_manager = SqliteConnectionManager::file(db_path); let db_pool = db::Pool::new(db_manager).unwrap(); println!("Server is listening on 127.0.0.1:8080"); - HttpServer::new(move || { - App::new() + actix_web::HttpServer::new(move || { + actix_web::App::new() .data(db_pool.clone()) .service(static_file) // GET /static/file.xyz .service(index) // GET / diff --git a/src/short_code.rs b/src/short_code.rs index 462ce6e..abc6f75 100644 --- a/src/short_code.rs +++ b/src/short_code.rs @@ -13,7 +13,6 @@ impl ShortCode { } pub fn from_code(code: &str) -> Result { - println!("translating code {:?} to id", code); let n = usize::from_str_radix(code, 36)?; let code = code.to_owned(); Ok(ShortCode { code, n }) -- 2.45.2