aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDennis Eriksen <d@ennis.no>2023-07-01 12:19:44 +0200
committerDennis Eriksen <d@ennis.no>2023-07-01 12:19:44 +0200
commit1caa728cb46db4d334204b652a46c27f2fc68ac4 (patch)
treeda2131f06cab3f4d2973c938fcb48079b89fdca3 /src
parentthis now actually works, and can be used. TODO: cleanup and make it pretty (diff)
downloadpurl-rs-1caa728cb46db4d334204b652a46c27f2fc68ac4.tar.gz
Cleaning up. Starting with response-function.
Diffstat (limited to 'src')
-rw-r--r--src/cgidebug.rs81
-rw-r--r--src/main.rs93
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( "&amp;" );
- } else if thechar == '<' {
- copy.push_str( "&lt;" );
- } else if thechar == '>' {
- copy.push_str( "&gt;" );
- } else if thechar == '\"' {
- copy.push_str( "&quot;" );
- } 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"),
}