|
|
@ -1,6 +1,7 @@ |
|
|
|
use crate::{Args, BoxResult}; |
|
|
|
use crate::{Args, BoxResult}; |
|
|
|
|
|
|
|
|
|
|
|
use futures::TryStreamExt; |
|
|
|
use futures::TryStreamExt; |
|
|
|
|
|
|
|
use hyper::header::HeaderValue; |
|
|
|
use hyper::service::{make_service_fn, service_fn}; |
|
|
|
use hyper::service::{make_service_fn, service_fn}; |
|
|
|
use hyper::{Body, Method, StatusCode}; |
|
|
|
use hyper::{Body, Method, StatusCode}; |
|
|
|
use percent_encoding::percent_decode; |
|
|
|
use percent_encoding::percent_decode; |
|
|
@ -62,6 +63,9 @@ impl InnerService { |
|
|
|
let res = if req.method() == Method::GET { |
|
|
|
let res = if req.method() == Method::GET { |
|
|
|
self.handle_static(req).await |
|
|
|
self.handle_static(req).await |
|
|
|
} else if req.method() == Method::PUT { |
|
|
|
} else if req.method() == Method::PUT { |
|
|
|
|
|
|
|
if self.args.readonly { |
|
|
|
|
|
|
|
return Ok(status_code!(StatusCode::FORBIDDEN)); |
|
|
|
|
|
|
|
} |
|
|
|
self.handle_upload(req).await |
|
|
|
self.handle_upload(req).await |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return Ok(status_code!(StatusCode::NOT_FOUND)); |
|
|
|
return Ok(status_code!(StatusCode::NOT_FOUND)); |
|
|
@ -70,6 +74,11 @@ impl InnerService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async fn handle_static(&self, req: Request) -> BoxResult<Response> { |
|
|
|
async fn handle_static(&self, req: Request) -> BoxResult<Response> { |
|
|
|
|
|
|
|
if !self.auth_guard(&req).unwrap_or_default() { |
|
|
|
|
|
|
|
let mut res = status_code!(StatusCode::UNAUTHORIZED); |
|
|
|
|
|
|
|
res.headers_mut().insert("WWW-Authenticate" , HeaderValue::from_static("Basic")); |
|
|
|
|
|
|
|
return Ok(res) |
|
|
|
|
|
|
|
} |
|
|
|
let path = match self.get_file_path(req.uri().path())? { |
|
|
|
let path = match self.get_file_path(req.uri().path())? { |
|
|
|
Some(path) => path, |
|
|
|
Some(path) => path, |
|
|
|
None => return Ok(status_code!(StatusCode::FORBIDDEN)), |
|
|
|
None => return Ok(status_code!(StatusCode::FORBIDDEN)), |
|
|
@ -87,6 +96,11 @@ impl InnerService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async fn handle_upload(&self, mut req: Request) -> BoxResult<Response> { |
|
|
|
async fn handle_upload(&self, mut req: Request) -> BoxResult<Response> { |
|
|
|
|
|
|
|
if !self.auth_guard(&req).unwrap_or_default() { |
|
|
|
|
|
|
|
let mut res = status_code!(StatusCode::UNAUTHORIZED); |
|
|
|
|
|
|
|
res.headers_mut().insert("WWW-Authenticate" , HeaderValue::from_static("Basic")); |
|
|
|
|
|
|
|
return Ok(res) |
|
|
|
|
|
|
|
} |
|
|
|
let path = match self.get_file_path(req.uri().path())? { |
|
|
|
let path = match self.get_file_path(req.uri().path())? { |
|
|
|
Some(path) => path, |
|
|
|
Some(path) => path, |
|
|
|
None => return Ok(status_code!(StatusCode::FORBIDDEN)), |
|
|
|
None => return Ok(status_code!(StatusCode::FORBIDDEN)), |
|
|
@ -165,7 +179,7 @@ impl InnerService { |
|
|
|
|
|
|
|
|
|
|
|
paths.sort_unstable(); |
|
|
|
paths.sort_unstable(); |
|
|
|
let breadcrumb = self.get_breadcrumb(path); |
|
|
|
let breadcrumb = self.get_breadcrumb(path); |
|
|
|
let data = SendDirData { breadcrumb, paths }; |
|
|
|
let data = SendDirData { breadcrumb, paths, readonly: !self.args.readonly }; |
|
|
|
let data = serde_json::to_string(&data).unwrap(); |
|
|
|
let data = serde_json::to_string(&data).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
let mut output = |
|
|
|
let mut output = |
|
|
@ -182,6 +196,25 @@ impl InnerService { |
|
|
|
Ok(Response::new(body)) |
|
|
|
Ok(Response::new(body)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn auth_guard(&self, req: &Request) -> BoxResult<bool> { |
|
|
|
|
|
|
|
if let Some(auth) = &self.args.auth { |
|
|
|
|
|
|
|
if let Some(value) = req.headers().get("Authorization") { |
|
|
|
|
|
|
|
let value = value.to_str()?; |
|
|
|
|
|
|
|
let value = if value.contains("Basic ") { |
|
|
|
|
|
|
|
&value[6..] |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return Ok(false); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let value = base64::decode(value)?; |
|
|
|
|
|
|
|
let value = std::str::from_utf8(&value)?; |
|
|
|
|
|
|
|
return Ok(value == auth); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return Ok(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Ok(true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_breadcrumb(&self, path: &Path) -> String { |
|
|
|
fn get_breadcrumb(&self, path: &Path) -> String { |
|
|
|
let path = match self.args.path.parent() { |
|
|
|
let path = match self.args.path.parent() { |
|
|
|
Some(p) => path.strip_prefix(p).unwrap(), |
|
|
|
Some(p) => path.strip_prefix(p).unwrap(), |
|
|
@ -210,6 +243,7 @@ impl InnerService { |
|
|
|
struct SendDirData { |
|
|
|
struct SendDirData { |
|
|
|
breadcrumb: String, |
|
|
|
breadcrumb: String, |
|
|
|
paths: Vec<PathItem>, |
|
|
|
paths: Vec<PathItem>, |
|
|
|
|
|
|
|
readonly: bool, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Eq, PartialEq, Ord, PartialOrd)] |
|
|
|
#[derive(Debug, Serialize, Eq, PartialEq, Ord, PartialOrd)] |
|
|
|