🐛 Fix the backlinks from servers up to the relay
parent
345fa64ad0
commit
c5691d9d05
|
@ -4,3 +4,4 @@
|
||||||
/ptth_server.toml
|
/ptth_server.toml
|
||||||
/ptth_relay.toml
|
/ptth_relay.toml
|
||||||
/target
|
/target
|
||||||
|
/test
|
||||||
|
|
|
@ -10,25 +10,30 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-width: 50%;
|
min-width: 50%;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.entry_list div:nth-child(odd) {
|
.entry_list div:nth-child(odd) {
|
||||||
background-color: #ddd;
|
background-color: #ddd;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<title>{{path}}</title>
|
<title>{{path}} {{server_name}}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<p>{{server_name}}</p>
|
||||||
|
|
||||||
|
<p>{{path}}</p>
|
||||||
|
|
||||||
<div class="entry_list">
|
<div class="entry_list">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a class="entry" href="../">../</a>
|
<a class="entry" href="../">📁 ../</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#each entries}}
|
{{#each entries}}
|
||||||
<div>
|
<div>
|
||||||
<a class="entry" href="{{this.encoded_file_name}}{{this.trailing_slash}}">
|
<a class="entry" href="{{this.encoded_file_name}}{{this.trailing_slash}}">
|
||||||
{{this.file_name}}{{this.trailing_slash}}
|
{{this.icon}} {{this.file_name}}{{this.trailing_slash}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
.entry {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px;
|
||||||
|
min-width: 50%;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.entry_list div:nth-child(odd) {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>{{server_name}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="entry_list">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="entry" href="../">📁 ../</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="entry" href="files/">
|
||||||
|
📁 Files
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
.entry {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px;
|
||||||
|
min-width: 50%;
|
||||||
|
}
|
||||||
|
.entry_list div:nth-child(odd) {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>PTTH relay</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>PTTH relay</h1>
|
||||||
|
|
||||||
|
<div class="entry_list">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="entry" href="frontend/servers/">Server list</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -23,7 +23,6 @@ use tracing::{
|
||||||
|
|
||||||
use ptth::{
|
use ptth::{
|
||||||
http_serde::RequestParts,
|
http_serde::RequestParts,
|
||||||
prefix_match,
|
|
||||||
server::file_server,
|
server::file_server,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,54 +45,50 @@ fn status_reply <B: Into <Body>> (status: StatusCode, b: B)
|
||||||
async fn handle_all (req: Request <Body>, state: Arc <ServerState <'static>>)
|
async fn handle_all (req: Request <Body>, state: Arc <ServerState <'static>>)
|
||||||
-> Result <Response <Body>, String>
|
-> Result <Response <Body>, String>
|
||||||
{
|
{
|
||||||
|
debug! ("req.uri () = {:?}", req.uri ());
|
||||||
|
|
||||||
let path = req.uri ().path ();
|
let path = req.uri ().path ();
|
||||||
//println! ("{}", path);
|
|
||||||
|
|
||||||
if let Some (path) = prefix_match (path, "/files") {
|
let path = path.into ();
|
||||||
let path = path.into ();
|
|
||||||
|
|
||||||
let (parts, _) = req.into_parts ();
|
let (parts, _) = req.into_parts ();
|
||||||
|
|
||||||
let ptth_req = match RequestParts::from_hyper (parts.method, path, parts.headers) {
|
let ptth_req = match RequestParts::from_hyper (parts.method, path, parts.headers) {
|
||||||
Ok (x) => x,
|
Ok (x) => x,
|
||||||
_ => return Ok (status_reply (StatusCode::BAD_REQUEST, "Bad request")),
|
_ => return Ok (status_reply (StatusCode::BAD_REQUEST, "Bad request")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let default_root = PathBuf::from ("./");
|
let default_root = PathBuf::from ("./");
|
||||||
let file_server_root: &std::path::Path = state.config.file_server_root
|
let file_server_root: &std::path::Path = state.config.file_server_root
|
||||||
.as_ref ()
|
.as_ref ()
|
||||||
.unwrap_or (&default_root);
|
.unwrap_or (&default_root);
|
||||||
|
|
||||||
let ptth_resp = file_server::serve_all (
|
let ptth_resp = file_server::serve_all (
|
||||||
&state.handlebars,
|
&state.handlebars,
|
||||||
file_server_root,
|
file_server_root,
|
||||||
ptth_req.method,
|
ptth_req.method,
|
||||||
&ptth_req.uri,
|
&ptth_req.uri,
|
||||||
&ptth_req.headers,
|
&ptth_req.headers,
|
||||||
None
|
None
|
||||||
).await;
|
).await;
|
||||||
|
|
||||||
let mut resp = Response::builder ()
|
let mut resp = Response::builder ()
|
||||||
.status (StatusCode::from (ptth_resp.parts.status_code));
|
.status (StatusCode::from (ptth_resp.parts.status_code));
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
for (k, v) in ptth_resp.parts.headers.into_iter () {
|
for (k, v) in ptth_resp.parts.headers.into_iter () {
|
||||||
resp = resp.header (hyper::header::HeaderName::from_str (&k).unwrap (), v);
|
resp = resp.header (hyper::header::HeaderName::from_str (&k).unwrap (), v);
|
||||||
}
|
|
||||||
|
|
||||||
let body = ptth_resp.body
|
|
||||||
.map (Body::wrap_stream)
|
|
||||||
.unwrap_or_else (Body::empty)
|
|
||||||
;
|
|
||||||
|
|
||||||
let resp = resp.body (body).unwrap ();
|
|
||||||
|
|
||||||
Ok (resp)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Ok (status_reply (StatusCode::NOT_FOUND, "404 Not Found\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let body = ptth_resp.body
|
||||||
|
.map (Body::wrap_stream)
|
||||||
|
.unwrap_or_else (Body::empty)
|
||||||
|
;
|
||||||
|
|
||||||
|
let resp = resp.body (body).unwrap ();
|
||||||
|
|
||||||
|
Ok (resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Deserialize)]
|
#[derive (Deserialize)]
|
||||||
|
|
|
@ -158,11 +158,17 @@ impl Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body_bytes (&mut self, b: Vec <u8>) -> &mut Self {
|
pub fn body_bytes (&mut self, b: Vec <u8>) -> &mut Self {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
self.content_length = b.len ().try_into ().ok ();
|
||||||
|
self.header ("content-length".to_string (), b.len ().to_string ().into_bytes ());
|
||||||
|
|
||||||
let (mut tx, rx) = tokio::sync::mpsc::channel (1);
|
let (mut tx, rx) = tokio::sync::mpsc::channel (1);
|
||||||
tokio::spawn (async move {
|
tokio::spawn (async move {
|
||||||
tx.send (Ok (b)).await.unwrap ();
|
tx.send (Ok (b)).await.unwrap ();
|
||||||
});
|
});
|
||||||
self.body = Some (rx);
|
self.body = Some (rx);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,6 +523,10 @@ async fn handle_all (req: Request <Body>, state: Arc <RelayState>)
|
||||||
error_reply (StatusCode::BAD_REQUEST, "Bad URI format")
|
error_reply (StatusCode::BAD_REQUEST, "Bad URI format")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if path == "/" {
|
||||||
|
let s = state.handlebars.render ("relay_root", &()).unwrap ();
|
||||||
|
ok_reply (s)
|
||||||
|
}
|
||||||
else if path == "/frontend/relay_up_check" {
|
else if path == "/frontend/relay_up_check" {
|
||||||
error_reply (StatusCode::OK, "Relay is up")
|
error_reply (StatusCode::OK, "Relay is up")
|
||||||
}
|
}
|
||||||
|
@ -539,6 +543,7 @@ pub fn load_templates ()
|
||||||
|
|
||||||
for (k, v) in vec! [
|
for (k, v) in vec! [
|
||||||
("relay_server_list", "relay_server_list.html"),
|
("relay_server_list", "relay_server_list.html"),
|
||||||
|
("relay_root", "relay_root.html"),
|
||||||
].into_iter () {
|
].into_iter () {
|
||||||
handlebars.register_template_file (k, format! ("ptth_handlebars/{}", v))?;
|
handlebars.register_template_file (k, format! ("ptth_handlebars/{}", v))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
|
use serde::Serialize;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::{
|
fs::{
|
||||||
|
DirEntry,
|
||||||
File,
|
File,
|
||||||
read_dir,
|
read_dir,
|
||||||
ReadDir,
|
ReadDir,
|
||||||
|
@ -28,7 +30,43 @@ use tracing::{
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::http_serde;
|
use crate::{
|
||||||
|
http_serde,
|
||||||
|
prefix_match,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive (Serialize)]
|
||||||
|
struct ServerInfo <'a> {
|
||||||
|
server_name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive (Serialize)]
|
||||||
|
struct TemplateDirEntry {
|
||||||
|
icon: &'static str,
|
||||||
|
trailing_slash: &'static str,
|
||||||
|
|
||||||
|
// Unfortunately file_name will allocate as long as some platforms
|
||||||
|
// (Windows!) aren't UTF-8. Cause I don't want to write separate code
|
||||||
|
// for such a small problem.
|
||||||
|
|
||||||
|
file_name: String,
|
||||||
|
|
||||||
|
// This could be a Cow with file_name if no encoding was done but
|
||||||
|
// it's simpler to allocate.
|
||||||
|
|
||||||
|
encoded_file_name: String,
|
||||||
|
|
||||||
|
error: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive (Serialize)]
|
||||||
|
struct TemplateDirPage <'a> {
|
||||||
|
#[serde (flatten)]
|
||||||
|
server_info: ServerInfo <'a>,
|
||||||
|
|
||||||
|
path: Cow <'a, str>,
|
||||||
|
entries: Vec <TemplateDirEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_range_header (range_str: &str) -> (Option <u64>, Option <u64>) {
|
fn parse_range_header (range_str: &str) -> (Option <u64>, Option <u64>) {
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
|
@ -52,47 +90,60 @@ fn parse_range_header (range_str: &str) -> (Option <u64>, Option <u64>) {
|
||||||
(start, end)
|
(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
use serde::Serialize;
|
|
||||||
use tokio::fs::DirEntry;
|
|
||||||
|
|
||||||
// This could probably be done with borrows, if I owned the
|
|
||||||
// tokio::fs::DirEntry instead of consuming it
|
|
||||||
|
|
||||||
#[derive (Serialize)]
|
|
||||||
struct TemplateDirEntry {
|
|
||||||
trailing_slash: &'static str,
|
|
||||||
file_name: String,
|
|
||||||
encoded_file_name: String,
|
|
||||||
error: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_dir_entry (entry: DirEntry) -> TemplateDirEntry
|
async fn read_dir_entry (entry: DirEntry) -> TemplateDirEntry
|
||||||
{
|
{
|
||||||
let trailing_slash = match entry.file_type ().await {
|
|
||||||
Ok (t) => if t.is_dir () {
|
|
||||||
"/"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
Err (_) => "",
|
|
||||||
};
|
|
||||||
|
|
||||||
let file_name = match entry.file_name ().into_string () {
|
let file_name = match entry.file_name ().into_string () {
|
||||||
Ok (x) => x,
|
Ok (x) => x,
|
||||||
Err (_) => return TemplateDirEntry {
|
Err (_) => return TemplateDirEntry {
|
||||||
|
icon: "⚠️",
|
||||||
trailing_slash: "",
|
trailing_slash: "",
|
||||||
file_name: "".into (),
|
file_name: "File / directory name is not UTF-8".into (),
|
||||||
encoded_file_name: "".into (),
|
encoded_file_name: "".into (),
|
||||||
error: true,
|
error: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (trailing_slash, icon) = match entry.file_type ().await {
|
||||||
|
Ok (t) => if t.is_dir () {
|
||||||
|
("/", "📁")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let icon = if file_name.ends_with (".mp4") {
|
||||||
|
"🎞️"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".avi") {
|
||||||
|
"🎞️"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".mkv") {
|
||||||
|
"🎞️"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".jpg") {
|
||||||
|
"📷"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".jpeg") {
|
||||||
|
"📷"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".png") {
|
||||||
|
"📷"
|
||||||
|
}
|
||||||
|
else if file_name.ends_with (".bmp") {
|
||||||
|
"📷"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"📄"
|
||||||
|
};
|
||||||
|
|
||||||
|
("", icon)
|
||||||
|
},
|
||||||
|
Err (_) => ("", "⚠️"),
|
||||||
|
};
|
||||||
|
|
||||||
use percent_encoding::*;
|
use percent_encoding::*;
|
||||||
|
|
||||||
let encoded_file_name = utf8_percent_encode (&file_name, CONTROLS).to_string ();
|
let encoded_file_name = utf8_percent_encode (&file_name, CONTROLS).to_string ();
|
||||||
|
|
||||||
TemplateDirEntry {
|
TemplateDirEntry {
|
||||||
|
icon,
|
||||||
trailing_slash: &trailing_slash,
|
trailing_slash: &trailing_slash,
|
||||||
file_name,
|
file_name,
|
||||||
encoded_file_name,
|
encoded_file_name,
|
||||||
|
@ -100,6 +151,25 @@ async fn read_dir_entry (entry: DirEntry) -> TemplateDirEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn serve_root (
|
||||||
|
handlebars: &Handlebars <'static>,
|
||||||
|
) -> http_serde::Response
|
||||||
|
{
|
||||||
|
let server_info = ServerInfo {
|
||||||
|
server_name: "PTTH file server",
|
||||||
|
};
|
||||||
|
|
||||||
|
let s = handlebars.render ("file_server_root", &server_info).unwrap ();
|
||||||
|
let body = s.into_bytes ();
|
||||||
|
|
||||||
|
let mut resp = http_serde::Response::default ();
|
||||||
|
resp
|
||||||
|
.header ("content-type".to_string (), "text/html".to_string ().into_bytes ())
|
||||||
|
.body_bytes (body)
|
||||||
|
;
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[instrument (level = "debug", skip (handlebars, dir))]
|
#[instrument (level = "debug", skip (handlebars, dir))]
|
||||||
|
@ -109,6 +179,10 @@ async fn serve_dir (
|
||||||
mut dir: ReadDir
|
mut dir: ReadDir
|
||||||
) -> http_serde::Response
|
) -> http_serde::Response
|
||||||
{
|
{
|
||||||
|
let server_info = ServerInfo {
|
||||||
|
server_name: "PTTH file server",
|
||||||
|
};
|
||||||
|
|
||||||
let mut entries = vec! [];
|
let mut entries = vec! [];
|
||||||
|
|
||||||
while let Ok (Some (entry)) = dir.next_entry ().await {
|
while let Ok (Some (entry)) = dir.next_entry ().await {
|
||||||
|
@ -117,23 +191,16 @@ async fn serve_dir (
|
||||||
|
|
||||||
entries.sort_unstable_by (|a, b| a.file_name.partial_cmp (&b.file_name).unwrap ());
|
entries.sort_unstable_by (|a, b| a.file_name.partial_cmp (&b.file_name).unwrap ());
|
||||||
|
|
||||||
#[derive (Serialize)]
|
|
||||||
struct TemplateDirPage <'a> {
|
|
||||||
path: Cow <'a, str>,
|
|
||||||
entries: Vec <TemplateDirEntry>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let s = handlebars.render ("file_server_dir", &TemplateDirPage {
|
let s = handlebars.render ("file_server_dir", &TemplateDirPage {
|
||||||
path,
|
path,
|
||||||
entries,
|
entries,
|
||||||
|
server_info,
|
||||||
}).unwrap ();
|
}).unwrap ();
|
||||||
let body = s.into_bytes ();
|
let body = s.into_bytes ();
|
||||||
|
|
||||||
let mut resp = http_serde::Response::default ();
|
let mut resp = http_serde::Response::default ();
|
||||||
resp.content_length = Some (body.len ().try_into ().unwrap ());
|
|
||||||
resp
|
resp
|
||||||
.header ("content-type".to_string (), "text/html".to_string ().into_bytes ())
|
.header ("content-type".to_string (), "text/html".to_string ().into_bytes ())
|
||||||
.header ("content-length".to_string (), body.len ().to_string ().into_bytes ())
|
|
||||||
.body_bytes (body)
|
.body_bytes (body)
|
||||||
;
|
;
|
||||||
resp
|
resp
|
||||||
|
@ -237,8 +304,8 @@ async fn serve_error (
|
||||||
-> http_serde::Response
|
-> http_serde::Response
|
||||||
{
|
{
|
||||||
let mut resp = http_serde::Response::default ();
|
let mut resp = http_serde::Response::default ();
|
||||||
resp.status_code (status_code)
|
resp.status_code (status_code);
|
||||||
.body_bytes (msg.into_bytes ());
|
resp.body_bytes (msg.into_bytes ());
|
||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,31 +321,19 @@ pub async fn serve_all (
|
||||||
-> http_serde::Response
|
-> http_serde::Response
|
||||||
{
|
{
|
||||||
info! ("Client requested {}", uri);
|
info! ("Client requested {}", uri);
|
||||||
let mut range_start = None;
|
|
||||||
let mut range_end = None;
|
|
||||||
|
|
||||||
if let Some (v) = headers.get ("range") {
|
|
||||||
let v = std::str::from_utf8 (v).unwrap ();
|
|
||||||
|
|
||||||
let (start, end) = parse_range_header (v);
|
|
||||||
range_start = start;
|
|
||||||
range_end = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
let should_send_body = match &method {
|
|
||||||
http_serde::Method::Get => true,
|
|
||||||
http_serde::Method::Head => false,
|
|
||||||
m => {
|
|
||||||
debug! ("Unsupported method {:?}", m);
|
|
||||||
return serve_error (http_serde::StatusCode::MethodNotAllowed, "Unsupported method".into ()).await;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
use percent_encoding::*;
|
use percent_encoding::*;
|
||||||
|
|
||||||
|
let uri = match prefix_match (uri, "/files/") {
|
||||||
|
Some (x) => x,
|
||||||
|
None => {
|
||||||
|
return serve_root (handlebars).await;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: There is totally a dir traversal attack in here somewhere
|
// TODO: There is totally a dir traversal attack in here somewhere
|
||||||
|
|
||||||
let encoded_path = &uri [1..];
|
let encoded_path = &uri [..];
|
||||||
|
|
||||||
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().unwrap ();
|
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().unwrap ();
|
||||||
let path = Path::new (&*path_s);
|
let path = Path::new (&*path_s);
|
||||||
|
@ -294,7 +349,10 @@ pub async fn serve_all (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok (dir) = read_dir (&full_path).await {
|
if uri == "/" {
|
||||||
|
serve_root (handlebars).await
|
||||||
|
}
|
||||||
|
else if let Ok (dir) = read_dir (&full_path).await {
|
||||||
serve_dir (
|
serve_dir (
|
||||||
handlebars,
|
handlebars,
|
||||||
full_path.to_string_lossy (),
|
full_path.to_string_lossy (),
|
||||||
|
@ -302,6 +360,26 @@ pub async fn serve_all (
|
||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
else if let Ok (file) = File::open (&full_path).await {
|
else if let Ok (file) = File::open (&full_path).await {
|
||||||
|
let mut range_start = None;
|
||||||
|
let mut range_end = None;
|
||||||
|
|
||||||
|
if let Some (v) = headers.get ("range") {
|
||||||
|
let v = std::str::from_utf8 (v).unwrap ();
|
||||||
|
|
||||||
|
let (start, end) = parse_range_header (v);
|
||||||
|
range_start = start;
|
||||||
|
range_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
let should_send_body = match &method {
|
||||||
|
http_serde::Method::Get => true,
|
||||||
|
http_serde::Method::Head => false,
|
||||||
|
m => {
|
||||||
|
debug! ("Unsupported method {:?}", m);
|
||||||
|
return serve_error (http_serde::StatusCode::MethodNotAllowed, "Unsupported method".into ()).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
serve_file (
|
serve_file (
|
||||||
file,
|
file,
|
||||||
should_send_body,
|
should_send_body,
|
||||||
|
@ -322,6 +400,7 @@ pub fn load_templates ()
|
||||||
|
|
||||||
for (k, v) in vec! [
|
for (k, v) in vec! [
|
||||||
("file_server_dir", "file_server_dir.html"),
|
("file_server_dir", "file_server_dir.html"),
|
||||||
|
("file_server_root", "file_server_root.html"),
|
||||||
].into_iter () {
|
].into_iter () {
|
||||||
handlebars.register_template_file (k, format! ("ptth_handlebars/{}", v))?;
|
handlebars.register_template_file (k, format! ("ptth_handlebars/{}", v))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,25 +66,19 @@ async fn handle_req_resp <'a> (
|
||||||
|
|
||||||
debug! ("Handling request {}", req_id);
|
debug! ("Handling request {}", req_id);
|
||||||
|
|
||||||
let response = if let Some (uri) = prefix_match (&parts.uri, "/files") {
|
let default_root = PathBuf::from ("./");
|
||||||
let default_root = PathBuf::from ("./");
|
let file_server_root: &std::path::Path = state.config.file_server_root
|
||||||
let file_server_root: &std::path::Path = state.config.file_server_root
|
.as_ref ()
|
||||||
.as_ref ()
|
.unwrap_or (&default_root);
|
||||||
.unwrap_or (&default_root);
|
|
||||||
|
|
||||||
file_server::serve_all (
|
let response = file_server::serve_all (
|
||||||
&state.handlebars,
|
&state.handlebars,
|
||||||
file_server_root,
|
file_server_root,
|
||||||
parts.method,
|
parts.method,
|
||||||
uri,
|
&parts.uri,
|
||||||
&parts.headers,
|
&parts.headers,
|
||||||
state.hidden_path.as_ref ().map (|p| p.as_path ())
|
state.hidden_path.as_ref ().map (|p| p.as_path ())
|
||||||
).await
|
).await;
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug! ("404 not found");
|
|
||||||
status_reply (http_serde::StatusCode::NotFound, "404 Not Found")
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut resp_req = state.client
|
let mut resp_req = state.client
|
||||||
.post (&format! ("{}/http_response/{}", state.config.relay_url, req_id))
|
.post (&format! ("{}/http_response/{}", state.config.relay_url, req_id))
|
||||||
|
|
3
todo.md
3
todo.md
|
@ -1,8 +1,7 @@
|
||||||
- Not working behind Nginx (Works okay behind Caddy)
|
- Not working behind Nginx (Works okay behind Caddy)
|
||||||
- Reduce idle memory use?
|
- Reduce idle memory use?
|
||||||
|
|
||||||
- Folder icons in dir list
|
- Package templates into exe for release
|
||||||
- ".." from server to server list is broken
|
|
||||||
- Redirect to add trailing slashes
|
- Redirect to add trailing slashes
|
||||||
- Add file size in directory listing
|
- Add file size in directory listing
|
||||||
- Allow spaces in server names
|
- Allow spaces in server names
|
||||||
|
|
Loading…
Reference in New Issue