diff options
author | Dennis Eriksen <d@ennis.no> | 2023-07-01 12:19:44 +0200 |
---|---|---|
committer | Dennis Eriksen <d@ennis.no> | 2023-07-01 12:19:44 +0200 |
commit | 1caa728cb46db4d334204b652a46c27f2fc68ac4 (patch) | |
tree | da2131f06cab3f4d2973c938fcb48079b89fdca3 /src | |
parent | this now actually works, and can be used. TODO: cleanup and make it pretty (diff) | |
download | purl-rs-1caa728cb46db4d334204b652a46c27f2fc68ac4.tar.gz |
Cleaning up. Starting with response-function.
Diffstat (limited to 'src')
-rw-r--r-- | src/cgidebug.rs | 81 | ||||
-rw-r--r-- | src/main.rs | 93 |
2 files changed, 62 insertions, 112 deletions
diff --git a/src/cgidebug.rs b/src/cgidebug.rs deleted file mode 100644 index afdc7ca..0000000 --- a/src/cgidebug.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::io::Write; -use std::env; -use std::collections::btree_map::BTreeMap; - -fn write_stderr( msg : String ) { - let mut stderr = std::io::stderr(); - write!(&mut stderr, "{}", msg).unwrap(); -} - -fn write_stderr_s( msg : &str ) { - write_stderr( msg.to_string() ); -} - -fn write_stdout( msg : String ) { - let mut stdout = std::io::stdout(); - write!(&mut stdout, "{}", msg).unwrap(); -} - -fn write_stdout_s( msg : &str ) { - write_stdout( msg.to_string() ); -} - -fn html_escape( msg : String ) -> String { - let mut copy : String = String::with_capacity( msg.len() ); - - for thechar in msg.chars() { - if thechar == '&' { - copy.push_str( "&" ); - } else if thechar == '<' { - copy.push_str( "<" ); - } else if thechar == '>' { - copy.push_str( ">" ); - } else if thechar == '\"' { - copy.push_str( """ ); - } else { - copy.push( thechar ); - } - } - - return copy; -} - -fn main() { - write_stdout_s( "Status: 301 Moved Permanently\n" ); - write_stdout_s( "Location: https://www.vg.no\n" ); - write_stdout_s( "Content-type: text/html\n" ); - write_stdout_s( "\n" ); - write_stdout_s( "<html>\n" ); - write_stdout_s( " <head>\n" ); - write_stdout_s( " <title>Rust CGI Test</title>\n" ); - write_stdout_s( " <style type=\"text/css\">\n" ); - write_stdout_s( " td { border:1px solid black; }\n" ); - write_stdout_s( " td { font-family:monospace; }\n" ); - write_stdout_s( " table { border-collapse:collapse; }\n" ); - write_stdout_s( " </style>\n" ); - write_stdout_s( " </head>\n" ); - write_stdout_s( " <body>\n" ); - write_stdout_s( " <h1>Environment</h1>\n" ); - write_stdout_s( " <table>\n" ); - write_stdout_s( " <tr><th>Key</th><th>Value</th></tr>\n" ); - - // copy environment into a BTreeMap which is sorted - let mut sortedmap : BTreeMap<String,String> = BTreeMap::new(); - for (key, value) in env::vars() { - sortedmap.insert( key, value ); - } - - // output environment into HTML table - for (key, value) in sortedmap { - write_stdout( - format!( - " <tr><td>{}</td><td>{}</td></tr>\n", - html_escape( key ), - html_escape( value ) - ) - ); - } - write_stdout_s( " </table>\n" ); - write_stdout_s( " </body>\n" ); - write_stdout_s( "</html>\n" ); -} diff --git a/src/main.rs b/src/main.rs index 439f8fd..28e5cd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -//use std::io::Write; +use std::io::Write; use dumb_cgi::{Request, EmptyResponse, Query}; use postgres::{Client, NoTls}; use std::process::exit; @@ -9,6 +9,7 @@ use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; + // Get URL from database fn get_url(dburl:&str, short:&str, update:bool) -> Result<String, postgres::Error> { // Connect to db @@ -33,28 +34,56 @@ fn insert_short(dburl:String, url: &str, short: &str, user: &str) -> Result<u64, client.close()?; Ok(n) } -// Do the redirect -// return std::io::Result<()> so we can use ? - -// https://doc.rust-lang.org/std/result/#the-question-mark-operator- -fn redirect(code:u16, url:&str) { - EmptyResponse::new(code) - .with_header("Location", url) - .with_content_type("text/plain") - .with_body( - format!("Redirecting to {}\n", url)) - .respond().unwrap(); - exit(0); + +fn status<'a>(code:u16) -> &'a str { + // I've only implemented statuscodes I *might* use + return match code { + 200 => "OK", + 201 => "Created", + 202 => "Accepted", + 204 => "No Content", + 301 => "Moved Permanently", + 302 => "Found", + 304 => "Not Modified", + 307 => "Temporary Redirect", + 308 => "Permanent Redirect", + 400 => "Bad Request", + 401 => "Unauthorized", + 402 => "Payment Required", + 403 => "Forbidden", + 404 => "Not Found", + 405 => "Method Not Allowed", + 406 => "Not Acceptableo", + 410 => "Gone", + 414 => "URI Too Long", + 500 => "Internal Server Error", + 501 => "Not Implemented", + 503 => "Service Unavailable", + 508 => "Loop Detected", + _ => "Not Found", + }; } -fn error(code:u16, msg:&str) { - EmptyResponse::new(code) - .with_content_type("text/plain") - .with_body( - format!("{} {}\n", code, msg)) - .respond().unwrap(); +// Do the redirect +fn respond(code:u16, body:&str) { + let mut r = EmptyResponse::new(code) + .with_content_type("text/plain"); + + if code >= 300 { + write!(&mut r, "{} {}\n\n", code, status(code)).unwrap(); + } + + if (300..399).contains(&code) && Url::parse(body).is_ok() { + r.add_header("Location", body); + } + + write!(&mut r, "{}\n", body).unwrap(); + + r.respond().unwrap(); exit(0); } + // Print form fn print_form() { let html = r#"<html> @@ -96,6 +125,8 @@ fn gen_short() -> String { // Do the dirty +// return std::io::Result<()> so we can use ? - +// https://doc.rust-lang.org/std/result/#the-question-mark-operator- fn main() -> std::io::Result<()> { // short = ID for shortened url @@ -128,26 +159,26 @@ fn main() -> std::io::Result<()> { // Make SURE docuri is a valid short let shortregex = Regex::new(r"^[a-zA-Z0-9_-]+$").unwrap(); if !shortregex.is_match(docuri) { - error(400, "Bad Request"); + respond(400, "Bad Request"); } // Fetch URL from postgres, and redirect or return 404 match get_url(&dburl, docuri, true) { - Ok(url) => redirect(301, &url), - Err(_e) => error(404, "Not Found"), + Ok(url) => respond(301, &url), + Err(_e) => respond(404, "Not Found"), }; }, "create" => { match req.query() { - Query::None => redirect(303, "/purl.cgi"), + Query::None => respond(303, "/purl.cgi"), Query::Some(map) => { if map.iter().count() != 1 { - error(400, "Bad Request\n\nIncorrect number of query items"); + respond(400, "Bad Request\n\nIncorrect number of query items"); } let url:&str = &map["url"]; if !Url::parse(url).is_ok() { - error(400, "Bad Request\n\nInvalid url"); + respond(400, "Bad Request\n\nInvalid url"); } let user:&str = req.var("REMOTE_USER").unwrap_or("none"); @@ -162,26 +193,26 @@ fn main() -> std::io::Result<()> { } // Throw error if we couldn't create a unique short in fire tries - if i == 5 { error(500, "Could not find unique short"); } + if i == 5 { respond(500, "Could not find unique short"); } } match insert_short(dburl, url, &short, user) { - Ok(_v) => error(200, &format!("{}{}", shortprefix, short)), - Err(_e) => error(400, "looool"), + Ok(_v) => respond(200, &format!("{}{}", shortprefix, short)), + Err(_e) => respond(400, "looool"), }; //if n == 1 { - // error(200, &res); + // respond(200, &res); //} else { - // error(400, "Bad Request\n\nDunno wtf happened"); + // respond(400, "Bad Request\n\nDunno wtf happened"); //} exit(0); }, - Query::Err(_e) => error(400,"Bad Request\n\nError reading query string"), + Query::Err(_e) => respond(400,"Bad Request\n\nError reading query string"), } }, - _ => error(400, "Bad Request"), + _ => respond(400, "Bad Request"), } |