mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
support path routing (#2188)
This commit is contained in:
@@ -28,6 +28,7 @@ use crate::net::HttpHandler;
|
|||||||
use crate::{diagnostic_api, install_api, main_api, setup_api, Error, ErrorKind, ResultExt};
|
use crate::{diagnostic_api, install_api, main_api, setup_api, Error, ErrorKind, ResultExt};
|
||||||
|
|
||||||
static NOT_FOUND: &[u8] = b"Not Found";
|
static NOT_FOUND: &[u8] = b"Not Found";
|
||||||
|
static METHOD_NOT_ALLOWED: &[u8] = b"Method Not Allowed";
|
||||||
static NOT_AUTHORIZED: &[u8] = b"Not Authorized";
|
static NOT_AUTHORIZED: &[u8] = b"Not Authorized";
|
||||||
|
|
||||||
pub const MAIN_UI_WWW_DIR: &str = "/var/www/html/main";
|
pub const MAIN_UI_WWW_DIR: &str = "/var/www/html/main";
|
||||||
@@ -238,41 +239,26 @@ async fn alt_ui(req: Request<Body>, ui_mode: UiMode) -> Result<Response<Body>, E
|
|||||||
.filter_map(|s| s.split(";").next())
|
.filter_map(|s| s.split(";").next())
|
||||||
.map(|s| s.trim())
|
.map(|s| s.trim())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
match request_parts.uri.path() {
|
match &request_parts.method {
|
||||||
"/" => {
|
&Method::GET => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
let uri_path = request_parts
|
||||||
|
.uri
|
||||||
|
.path()
|
||||||
|
.strip_prefix('/')
|
||||||
|
.unwrap_or(request_parts.uri.path());
|
||||||
|
|
||||||
file_send(full_path, &accept_encoding).await
|
let full_path = Path::new(selected_root_dir).join(uri_path);
|
||||||
}
|
file_send(
|
||||||
_ => {
|
if tokio::fs::metadata(&full_path).await.is_ok() {
|
||||||
match (
|
full_path
|
||||||
request_parts.method,
|
} else {
|
||||||
request_parts
|
Path::new(selected_root_dir).join("index.html")
|
||||||
.uri
|
},
|
||||||
.path()
|
&accept_encoding,
|
||||||
.strip_prefix('/')
|
)
|
||||||
.unwrap_or(request_parts.uri.path())
|
.await
|
||||||
.split_once('/'),
|
|
||||||
) {
|
|
||||||
(Method::GET, None) => {
|
|
||||||
let uri_path = request_parts
|
|
||||||
.uri
|
|
||||||
.path()
|
|
||||||
.strip_prefix('/')
|
|
||||||
.unwrap_or(request_parts.uri.path());
|
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_ => Ok(method_not_allowed()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,114 +275,72 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
.filter_map(|s| s.split(";").next())
|
.filter_map(|s| s.split(";").next())
|
||||||
.map(|s| s.trim())
|
.map(|s| s.trim())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
match request_parts.uri.path() {
|
match (
|
||||||
"/" => {
|
&request_parts.method,
|
||||||
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
request_parts
|
||||||
|
.uri
|
||||||
file_send(full_path, &accept_encoding).await
|
.path()
|
||||||
}
|
.strip_prefix('/')
|
||||||
_ => {
|
.unwrap_or(request_parts.uri.path())
|
||||||
let valid_session = HasValidSession::from_request_parts(&request_parts, &ctx).await;
|
.split_once('/'),
|
||||||
|
) {
|
||||||
match valid_session {
|
(&Method::GET, Some(("public", path))) => {
|
||||||
Ok(_valid) => {
|
match HasValidSession::from_request_parts(&request_parts, &ctx).await {
|
||||||
match (
|
Ok(_) => {
|
||||||
request_parts.method,
|
let sub_path = Path::new(path);
|
||||||
request_parts
|
if let Ok(rest) = sub_path.strip_prefix("package-data") {
|
||||||
.uri
|
file_send(
|
||||||
.path()
|
ctx.datadir.join(PKG_PUBLIC_DIR).join(rest),
|
||||||
.strip_prefix('/')
|
&accept_encoding,
|
||||||
.unwrap_or(request_parts.uri.path())
|
)
|
||||||
.split_once('/'),
|
.await
|
||||||
) {
|
} else if let Ok(rest) = sub_path.strip_prefix("eos") {
|
||||||
(Method::GET, Some(("public", path))) => {
|
match rest.to_str() {
|
||||||
let sub_path = Path::new(path);
|
Some("local.crt") => {
|
||||||
if let Ok(rest) = sub_path.strip_prefix("package-data") {
|
file_send(crate::net::ssl::ROOT_CA_STATIC_PATH, &accept_encoding)
|
||||||
file_send(
|
.await
|
||||||
ctx.datadir.join(PKG_PUBLIC_DIR).join(rest),
|
|
||||||
&accept_encoding,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
} else if let Ok(rest) = sub_path.strip_prefix("eos") {
|
|
||||||
match rest.to_str() {
|
|
||||||
Some("local.crt") => {
|
|
||||||
file_send(
|
|
||||||
crate::net::ssl::ROOT_CA_STATIC_PATH,
|
|
||||||
&accept_encoding,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
None => Ok(bad_request()),
|
|
||||||
_ => Ok(not_found()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(not_found())
|
|
||||||
}
|
}
|
||||||
|
None => Ok(bad_request()),
|
||||||
|
_ => Ok(not_found()),
|
||||||
}
|
}
|
||||||
(Method::GET, Some(("eos", "local.crt"))) => {
|
} else {
|
||||||
file_send(
|
Ok(not_found())
|
||||||
PathBuf::from(crate::net::ssl::ROOT_CA_STATIC_PATH),
|
|
||||||
&accept_encoding,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
(Method::GET, None) => {
|
|
||||||
let uri_path = request_parts
|
|
||||||
.uri
|
|
||||||
.path()
|
|
||||||
.strip_prefix('/')
|
|
||||||
.unwrap_or(request_parts.uri.path());
|
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
match (
|
|
||||||
request_parts.method,
|
|
||||||
request_parts
|
|
||||||
.uri
|
|
||||||
.path()
|
|
||||||
.strip_prefix('/')
|
|
||||||
.unwrap_or(request_parts.uri.path())
|
|
||||||
.split_once('/'),
|
|
||||||
) {
|
|
||||||
(Method::GET, Some(("public", _path))) => {
|
|
||||||
un_authorized(err, request_parts.uri.path())
|
|
||||||
}
|
|
||||||
(Method::GET, Some(("eos", "local.crt"))) => {
|
|
||||||
un_authorized(err, request_parts.uri.path())
|
|
||||||
}
|
|
||||||
(Method::GET, None) => {
|
|
||||||
let uri_path = request_parts
|
|
||||||
.uri
|
|
||||||
.path()
|
|
||||||
.strip_prefix('/')
|
|
||||||
.unwrap_or(request_parts.uri.path());
|
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
|
||||||
file_send(full_path, &accept_encoding).await
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(e) => un_authorized(e, &format!("public/{path}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(&Method::GET, Some(("eos", "local.crt"))) => {
|
||||||
|
match HasValidSession::from_request_parts(&request_parts, &ctx).await {
|
||||||
|
Ok(_) => {
|
||||||
|
file_send(
|
||||||
|
PathBuf::from(crate::net::ssl::ROOT_CA_STATIC_PATH),
|
||||||
|
&accept_encoding,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Err(e) => un_authorized(e, "eos/local.crt"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&Method::GET, _) => {
|
||||||
|
let uri_path = request_parts
|
||||||
|
.uri
|
||||||
|
.path()
|
||||||
|
.strip_prefix('/')
|
||||||
|
.unwrap_or(request_parts.uri.path());
|
||||||
|
|
||||||
|
let full_path = Path::new(selected_root_dir).join(uri_path);
|
||||||
|
file_send(
|
||||||
|
if tokio::fs::metadata(&full_path).await.is_ok() {
|
||||||
|
full_path
|
||||||
|
} else {
|
||||||
|
Path::new(selected_root_dir).join("index.html")
|
||||||
|
},
|
||||||
|
&accept_encoding,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
_ => Ok(method_not_allowed()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +361,14 @@ fn not_found() -> Response<Body> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HTTP status code 405
|
||||||
|
fn method_not_allowed() -> Response<Body> {
|
||||||
|
Response::builder()
|
||||||
|
.status(StatusCode::METHOD_NOT_ALLOWED)
|
||||||
|
.body(METHOD_NOT_ALLOWED.into())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn server_error(err: Error) -> Response<Body> {
|
fn server_error(err: Error) -> Response<Body> {
|
||||||
Response::builder()
|
Response::builder()
|
||||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
@@ -439,30 +391,31 @@ async fn file_send(
|
|||||||
|
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
if let Ok(file) = File::open(path).await {
|
let file = File::open(path)
|
||||||
let metadata = file.metadata().await.with_kind(ErrorKind::Filesystem)?;
|
.await
|
||||||
|
.with_ctx(|_| (ErrorKind::Filesystem, path.display().to_string()))?;
|
||||||
|
let metadata = file
|
||||||
|
.metadata()
|
||||||
|
.await
|
||||||
|
.with_ctx(|_| (ErrorKind::Filesystem, path.display().to_string()))?;
|
||||||
|
|
||||||
match IsNonEmptyFile::new(&metadata, path) {
|
match IsNonEmptyFile::new(&metadata, path) {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => return Ok(not_found()),
|
None => return Ok(not_found()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut builder = Response::builder().status(StatusCode::OK);
|
let mut builder = Response::builder().status(StatusCode::OK);
|
||||||
builder = with_e_tag(path, &metadata, builder)?;
|
builder = with_e_tag(path, &metadata, builder)?;
|
||||||
builder = with_content_type(path, builder);
|
builder = with_content_type(path, builder);
|
||||||
builder = with_content_length(&metadata, builder);
|
builder = with_content_length(&metadata, builder);
|
||||||
let body = if accept_encoding.contains(&"br") {
|
let body = if accept_encoding.contains(&"br") {
|
||||||
Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(BufReader::new(file))))
|
Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(BufReader::new(file))))
|
||||||
} else if accept_encoding.contains(&"gzip") {
|
} else if accept_encoding.contains(&"gzip") {
|
||||||
Body::wrap_stream(ReaderStream::new(GzipEncoder::new(BufReader::new(file))))
|
Body::wrap_stream(ReaderStream::new(GzipEncoder::new(BufReader::new(file))))
|
||||||
} else {
|
} else {
|
||||||
Body::wrap_stream(ReaderStream::new(file))
|
Body::wrap_stream(ReaderStream::new(file))
|
||||||
};
|
};
|
||||||
return builder.body(body).with_kind(ErrorKind::Network);
|
builder.body(body).with_kind(ErrorKind::Network)
|
||||||
}
|
|
||||||
tracing::debug!("File not found: {:?}", path);
|
|
||||||
|
|
||||||
Ok(not_found())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IsNonEmptyFile(());
|
struct IsNonEmptyFile(());
|
||||||
|
|||||||
Reference in New Issue
Block a user