Initial Commit
This commit is contained in:
commit
7d73f63cd4
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
270
Cargo.lock
generated
Normal file
270
Cargo.lock
generated
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f023c76cd7975f9969f8e29f0e461decbdc7f51048ce43427107a3d192f1c9bf"
|
||||||
|
dependencies = [
|
||||||
|
"argh_derive",
|
||||||
|
"argh_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_derive"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48ad219abc0c06ca788aface2e3a1970587e3413ab70acd20e54b6ec524c1f8f"
|
||||||
|
dependencies = [
|
||||||
|
"argh_shared",
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_shared"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ascii"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chunked_transfer"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "faery-ring"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"argh",
|
||||||
|
"tiny_http",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||||
|
dependencies = [
|
||||||
|
"matches",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||||
|
dependencies = [
|
||||||
|
"matches",
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.107"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matches"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiny_http"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96155b5f7149ba7a99ea5d516c538250b26eab60b4485c0f5344432573e7a450"
|
||||||
|
dependencies = [
|
||||||
|
"ascii",
|
||||||
|
"chrono",
|
||||||
|
"chunked_transfer",
|
||||||
|
"log",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"matches",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "faery-ring"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tiny_http = "0.9.0"
|
||||||
|
argh = "0.1.6"
|
84
src/main.rs
Normal file
84
src/main.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
pub mod server;
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use argh;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: CommandlineArgs = argh::from_env();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 1: Read the file
|
||||||
|
//
|
||||||
|
let mut config = match File::open(&args.domains) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(e) => {
|
||||||
|
match e.kind() {
|
||||||
|
ErrorKind::NotFound => {
|
||||||
|
eprintln!("Domains file not found: {}", args.domains.display());
|
||||||
|
exit(1001);
|
||||||
|
},
|
||||||
|
ErrorKind::PermissionDenied => {
|
||||||
|
eprintln!(
|
||||||
|
"Permission denied to read domain file: {}",
|
||||||
|
args.domains.display()
|
||||||
|
);
|
||||||
|
exit(1002);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
eprintln!(
|
||||||
|
"Unexepected error opening domain file: {}",
|
||||||
|
args.domains.display()
|
||||||
|
);
|
||||||
|
exit(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut read_into = String::with_capacity(1_000);
|
||||||
|
match config.read_to_string(&mut read_into) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
match e.kind() {
|
||||||
|
ErrorKind::BrokenPipe => {
|
||||||
|
eprintln!("Broken pipe (filesystem error) while reading {}", args.domains.display());
|
||||||
|
exit(1000);
|
||||||
|
},
|
||||||
|
ErrorKind::InvalidData => {
|
||||||
|
eprintln!(
|
||||||
|
"Domain file {} contains non-UTF-8 data. Are you sure this is a domains file?",
|
||||||
|
args.domains.display()
|
||||||
|
);
|
||||||
|
exit(1003);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!(
|
||||||
|
"Unexepected error opening domain file: {}",
|
||||||
|
args.domains.display()
|
||||||
|
);
|
||||||
|
exit(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let domains: Vec<_> = read_into.split('\n')
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 2: Run the server
|
||||||
|
//
|
||||||
|
server::go(&domains);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(argh::FromArgs)]
|
||||||
|
/// Run a basic webring hub
|
||||||
|
struct CommandlineArgs {
|
||||||
|
/// a text file listing all domains in the ring, one per line
|
||||||
|
#[argh(positional)]
|
||||||
|
domains: PathBuf,
|
||||||
|
}
|
114
src/server.rs
Normal file
114
src/server.rs
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue