Compare commits
4 Commits
927d6d32b9
...
b3f73fde50
Author | SHA1 | Date |
---|---|---|
meeg_leeto | b3f73fde50 | |
meeg_leeto | adb6853de5 | |
meeg_leeto | 23c77c79f3 | |
meeg_leeto | f7297cdadd |
|
@ -1,13 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<title>Lonk</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
|
||||
<script src="main.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1 id="shortened"></h1>
|
||||
|
||||
<!-- Yes, this form requires Javascript, sorry.
|
||||
I promise there are no trackers on this page,
|
||||
but if you're tech savvy (and paranoid) enough to
|
||||
be browsing the web with Javascript blocked, then
|
||||
just do a POST request to /shorten with the URL you
|
||||
wish to shorten Base64-encoded as the body. -->
|
||||
<form id="form">
|
||||
<input type="url" name="url" id="url" required>
|
||||
<input type="submit" hidden />
|
||||
</form>
|
||||
|
||||
<p id="info"></p>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
(() => {
|
||||
document.addEventListener('DOMContentLoaded', (_) => {
|
||||
const waiting = false;
|
||||
let xhr;
|
||||
|
||||
const field = document.getElementById('url');
|
||||
|
||||
field.addEventListener('change', () => {
|
||||
if (waiting && xhr != null) {
|
||||
xhr.abort();
|
||||
}
|
||||
});
|
||||
|
||||
const form = document.getElementById('form');
|
||||
|
||||
form.addEventListener('submit', (event) => {
|
||||
// We need to create a different body, so prevent the default submission.
|
||||
event.preventDefault();
|
||||
|
||||
if (waiting) {
|
||||
// Prevent multiple requests.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the URL the user is trying to shorten.
|
||||
const url = document.getElementById('url').value;
|
||||
|
||||
// Encode the URL as Base64.
|
||||
const encoded = btoa(encodeURIComponent(url).replace(/%([0-9A-F]{2})/g, (match, p1) =>
|
||||
String.fromCharCode('0x' + p1)
|
||||
));
|
||||
|
||||
// POST the body to /shorten.
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/shorten', true);
|
||||
xhr.overrideMimeType('text/plain');
|
||||
xhr.send(encoded);
|
||||
xhr.onload = () => {
|
||||
switch (xhr.status) {
|
||||
case 200:
|
||||
let slug = xhr.response;
|
||||
console.log(slug);
|
||||
break;
|
||||
default:
|
||||
console.log(xhr.response);
|
||||
break;
|
||||
}
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
// TODO
|
||||
};
|
||||
});
|
||||
});
|
||||
})();
|
47
src/main.rs
47
src/main.rs
|
@ -6,19 +6,6 @@ use warp::{http::Response, hyper::StatusCode, Filter};
|
|||
#[macro_use]
|
||||
/// Module containing custom defined macros.
|
||||
mod macros {
|
||||
macro_rules! clone {
|
||||
(mut $y:ident) => {
|
||||
let mut $y = $y.clone();
|
||||
};
|
||||
($y:ident) => {
|
||||
let $y = $y.clone();
|
||||
};
|
||||
($y:ident, $($x:ident),+) => {
|
||||
clone!($y);
|
||||
clone!($($x),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Macros useful for debug contexts.
|
||||
///
|
||||
/// For example, `ifdbg!(expr)` replaces the $expr with () when the compile
|
||||
|
@ -90,8 +77,6 @@ mod macros {
|
|||
}
|
||||
}
|
||||
|
||||
use macros::debug;
|
||||
|
||||
/// Affine to static configuration.
|
||||
mod conf {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -675,23 +660,21 @@ async fn shorten(
|
|||
db: &db::SlugDatabase,
|
||||
b64str: &str,
|
||||
) -> Result<slug::Slug, (StatusCode, String)> {
|
||||
// Parse the URL given by the user. It should arrive as a URL Base64
|
||||
// no-padding string, and anything other than this should cleanly result in
|
||||
// an HTTP rejection.
|
||||
// Parse the URL given by the user. It should arrive as a Base64 string,
|
||||
// and anything other than this should cleanly result in an HTTP rejection.
|
||||
let url = {
|
||||
let unencoded_bytes =
|
||||
base64::decode_config(b64str, base64::URL_SAFE_NO_PAD).map_err(|_| {
|
||||
(
|
||||
warp::http::StatusCode::BAD_REQUEST,
|
||||
debuginfo!("Could not decode base64 str.", "Invalid URL Base64.").into(),
|
||||
)
|
||||
})?;
|
||||
let unencoded_bytes = base64::decode_config(b64str, base64::STANDARD).map_err(|_| {
|
||||
(
|
||||
warp::http::StatusCode::BAD_REQUEST,
|
||||
debuginfo!("Could not decode base64 str.", "Invalid Base64.").into(),
|
||||
)
|
||||
})?;
|
||||
let url_str = std::str::from_utf8(&unencoded_bytes[..]).map_err(|_| {
|
||||
(
|
||||
warp::http::StatusCode::BAD_REQUEST,
|
||||
debuginfo!(
|
||||
"Parsed bytes of base64 str, but could not decode as UTF8.",
|
||||
"Invalid URL Base64."
|
||||
"Invalid Base64."
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
|
@ -822,10 +805,7 @@ async fn serve() {
|
|||
let slug_factory: &'static slug::SlugFactory = Box::leak(Box::new(slug_factory));
|
||||
let db: &'static db::SlugDatabase = Box::leak(Box::new(db));
|
||||
|
||||
// GET /
|
||||
let homepage = warp::path::end().and(config.serve_rules.dir.to_filter());
|
||||
|
||||
// POST /shorten/ with argument link:Base64WithoutPaddingUrl
|
||||
// POST /shorten/ with link in argument
|
||||
let shorten = warp::post()
|
||||
.and(warp::path("shorten"))
|
||||
.and(warp::body::content_length_limit(1024))
|
||||
|
@ -860,7 +840,12 @@ async fn serve() {
|
|||
}
|
||||
});
|
||||
|
||||
let get_routes = warp::get().and(homepage.or(link));
|
||||
// GET /
|
||||
// This should be the last thing matched, so that anything that doesn't
|
||||
// match another filter will try to match a file.
|
||||
let homepage = warp::get().and(config.serve_rules.dir.to_filter());
|
||||
|
||||
let get_routes = warp::get().and(link.or(homepage));
|
||||
let post_routes = warp::post().and(shorten);
|
||||
let routes = get_routes.or(post_routes);
|
||||
|
||||
|
|
Loading…
Reference in New Issue