forked from Emi/faery-ring
115 lines
2.4 KiB
Rust
115 lines
2.4 KiB
Rust
use std::borrow::Cow;
|
|
use std::io::Cursor;
|
|
use std::ops::Deref;
|
|
use std::sync::Arc;
|
|
|
|
use tiny_http::Header;
|
|
use tiny_http::Request;
|
|
use tiny_http::Response;
|
|
use tiny_http::Server;
|
|
use tiny_http::StatusCode;
|
|
|
|
pub fn go(domains: &[&str]) {
|
|
let server = Server::http("0.0.0.0:3243").unwrap();
|
|
let server = Arc::new(server);
|
|
|
|
for req in server.incoming_requests() {
|
|
let route = Route::parse_request(&req);
|
|
let resp = route.render(domains);
|
|
if let Err(e) = req.respond(resp) {
|
|
eprintln!("WARN: {}", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum Route<'a> {
|
|
Next(&'a str),
|
|
Prev(&'a str),
|
|
NotFound,
|
|
}
|
|
|
|
pub enum RuntimeStatic {
|
|
JsonIndex,
|
|
}
|
|
|
|
impl<'a> Route<'a> {
|
|
pub fn parse_request(r: &'a Request) -> Self {
|
|
let segments: Vec<_> = r.url()
|
|
.split('/')
|
|
.filter(|s| !s.is_empty())
|
|
.collect();
|
|
|
|
// TODO automatically detect a fallback url from the request's Referer header
|
|
let referrer_domain = segments.get(1).map(|s| *s).unwrap_or("missing_referrer_domain");
|
|
|
|
match segments.get(0).map(Deref::deref) {
|
|
Some("next") => {
|
|
Route::Next(referrer_domain)
|
|
},
|
|
Some("prev") => {
|
|
Route::Prev(referrer_domain)
|
|
},
|
|
_ => Route::NotFound,
|
|
}
|
|
}
|
|
|
|
pub fn render<'b>(&self, domains: &[&'b str]) -> Response<Cursor<Cow<'b, [u8]>>> {
|
|
match self {
|
|
Self::Next(this_domain) | Self::Prev(this_domain) => {
|
|
|
|
let offset: isize = if let Self::Next(_) = self {
|
|
1
|
|
} else {
|
|
-1
|
|
};
|
|
|
|
let destination = domains.iter()
|
|
.position(|d| this_domain.starts_with(d))
|
|
.map(|i| (i as isize + offset).rem_euclid(domains.len() as isize))
|
|
.map(|i| domains[i as usize]);
|
|
|
|
if let Some(url) = destination {
|
|
let destination = format!(
|
|
"https://{}",
|
|
url
|
|
);
|
|
Response::new(
|
|
StatusCode(303),
|
|
vec![
|
|
Header::from_bytes(
|
|
b"Location".to_owned(),
|
|
destination.as_bytes(),
|
|
).unwrap(),
|
|
],
|
|
Cursor::new(Cow::Borrowed(b"")),
|
|
Some(0),
|
|
None,
|
|
)
|
|
} else {
|
|
let bytes = format!(
|
|
"Misconfigured server. Website {} not found in webring.",
|
|
this_domain,
|
|
);
|
|
let blen = bytes.len();
|
|
Response::new(
|
|
StatusCode(400),
|
|
Vec::new(),
|
|
Cursor::new(Cow::Owned(bytes.into_bytes())),
|
|
Some(blen),
|
|
None,
|
|
)
|
|
}
|
|
},
|
|
Self::NotFound => {
|
|
Response::new(
|
|
StatusCode(404),
|
|
Vec::new(),
|
|
Cursor::new(Cow::Borrowed(b"Page not found")),
|
|
Some(14),
|
|
None,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|