mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
gzip and brotli (#2186)
This commit is contained in:
51
backend/Cargo.lock
generated
51
backend/Cargo.lock
generated
@@ -60,6 +60,21 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc-no-stdlib"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc-stdlib"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -130,6 +145,20 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-compression"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a"
|
||||||
|
dependencies = [
|
||||||
|
"brotli",
|
||||||
|
"flate2",
|
||||||
|
"futures-core",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -417,6 +446,27 @@ dependencies = [
|
|||||||
"serde_with 1.14.0",
|
"serde_with 1.14.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli"
|
||||||
|
version = "3.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
"alloc-stdlib",
|
||||||
|
"brotli-decompressor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli-decompressor"
|
||||||
|
version = "2.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
"alloc-stdlib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -1266,6 +1316,7 @@ name = "embassy-os"
|
|||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
|
"async-compression",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"avahi-sys",
|
"avahi-sys",
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ unstable = ["patch-db/unstable"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aes = { version = "0.7.5", features = ["ctr"] }
|
aes = { version = "0.7.5", features = ["ctr"] }
|
||||||
|
async-compression = { version = "0.3.15", features = [
|
||||||
|
"gzip",
|
||||||
|
"brotli",
|
||||||
|
"tokio",
|
||||||
|
] }
|
||||||
async-stream = "0.3.3"
|
async-stream = "0.3.3"
|
||||||
async-trait = "0.1.56"
|
async-trait = "0.1.56"
|
||||||
avahi-sys = { git = "https://github.com/Start9Labs/avahi-sys", version = "0.10.0", branch = "feature/dynamic-linking", features = [
|
avahi-sys = { git = "https://github.com/Start9Labs/avahi-sys", version = "0.10.0", branch = "feature/dynamic-linking", features = [
|
||||||
|
|||||||
@@ -3,14 +3,18 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::UNIX_EPOCH;
|
use std::time::UNIX_EPOCH;
|
||||||
|
|
||||||
|
use async_compression::tokio::bufread::BrotliEncoder;
|
||||||
|
use async_compression::tokio::bufread::GzipEncoder;
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use http::header::ACCEPT_ENCODING;
|
||||||
use http::response::Builder;
|
use http::response::Builder;
|
||||||
use hyper::{Body, Method, Request, Response, StatusCode};
|
use hyper::{Body, Method, Request, Response, StatusCode};
|
||||||
use rpc_toolkit::rpc_handler;
|
use rpc_toolkit::rpc_handler;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
use tokio::io::BufReader;
|
||||||
|
use tokio_util::io::ReaderStream;
|
||||||
|
|
||||||
use crate::context::{DiagnosticContext, InstallContext, RpcContext, SetupContext};
|
use crate::context::{DiagnosticContext, InstallContext, RpcContext, SetupContext};
|
||||||
use crate::core::rpc_continuations::RequestGuid;
|
use crate::core::rpc_continuations::RequestGuid;
|
||||||
@@ -225,11 +229,20 @@ async fn alt_ui(req: Request<Body>, ui_mode: UiMode) -> Result<Response<Body>, E
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (request_parts, _body) = req.into_parts();
|
let (request_parts, _body) = req.into_parts();
|
||||||
|
let accept_encoding = request_parts
|
||||||
|
.headers
|
||||||
|
.get_all(ACCEPT_ENCODING)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|h| h.to_str().ok())
|
||||||
|
.flat_map(|s| s.split(","))
|
||||||
|
.filter_map(|s| s.split(";").next())
|
||||||
|
.map(|s| s.trim())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
match request_parts.uri.path() {
|
match request_parts.uri.path() {
|
||||||
"/" => {
|
"/" => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
||||||
|
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
match (
|
match (
|
||||||
@@ -249,12 +262,12 @@ async fn alt_ui(req: Request<Body>, ui_mode: UiMode) -> Result<Response<Body>, E
|
|||||||
.unwrap_or(request_parts.uri.path());
|
.unwrap_or(request_parts.uri.path());
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
(Method::GET, Some((dir, file))) => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
_ => Ok(not_found()),
|
||||||
@@ -267,11 +280,20 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
let selected_root_dir = MAIN_UI_WWW_DIR;
|
let selected_root_dir = MAIN_UI_WWW_DIR;
|
||||||
|
|
||||||
let (request_parts, _body) = req.into_parts();
|
let (request_parts, _body) = req.into_parts();
|
||||||
|
let accept_encoding = request_parts
|
||||||
|
.headers
|
||||||
|
.get_all(ACCEPT_ENCODING)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|h| h.to_str().ok())
|
||||||
|
.flat_map(|s| s.split(","))
|
||||||
|
.filter_map(|s| s.split(";").next())
|
||||||
|
.map(|s| s.trim())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
match request_parts.uri.path() {
|
match request_parts.uri.path() {
|
||||||
"/" => {
|
"/" => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
let full_path = PathBuf::from(selected_root_dir).join("index.html");
|
||||||
|
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let valid_session = HasValidSession::from_request_parts(&request_parts, &ctx).await;
|
let valid_session = HasValidSession::from_request_parts(&request_parts, &ctx).await;
|
||||||
@@ -290,11 +312,19 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
(Method::GET, Some(("public", path))) => {
|
(Method::GET, Some(("public", path))) => {
|
||||||
let sub_path = Path::new(path);
|
let sub_path = Path::new(path);
|
||||||
if let Ok(rest) = sub_path.strip_prefix("package-data") {
|
if let Ok(rest) = sub_path.strip_prefix("package-data") {
|
||||||
file_send(ctx.datadir.join(PKG_PUBLIC_DIR).join(rest)).await
|
file_send(
|
||||||
|
ctx.datadir.join(PKG_PUBLIC_DIR).join(rest),
|
||||||
|
&accept_encoding,
|
||||||
|
)
|
||||||
|
.await
|
||||||
} else if let Ok(rest) = sub_path.strip_prefix("eos") {
|
} else if let Ok(rest) = sub_path.strip_prefix("eos") {
|
||||||
match rest.to_str() {
|
match rest.to_str() {
|
||||||
Some("local.crt") => {
|
Some("local.crt") => {
|
||||||
file_send(crate::net::ssl::ROOT_CA_STATIC_PATH).await
|
file_send(
|
||||||
|
crate::net::ssl::ROOT_CA_STATIC_PATH,
|
||||||
|
&accept_encoding,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
None => Ok(bad_request()),
|
None => Ok(bad_request()),
|
||||||
_ => Ok(not_found()),
|
_ => Ok(not_found()),
|
||||||
@@ -304,7 +334,11 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Method::GET, Some(("eos", "local.crt"))) => {
|
(Method::GET, Some(("eos", "local.crt"))) => {
|
||||||
file_send(PathBuf::from(crate::net::ssl::ROOT_CA_STATIC_PATH)).await
|
file_send(
|
||||||
|
PathBuf::from(crate::net::ssl::ROOT_CA_STATIC_PATH),
|
||||||
|
&accept_encoding,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
(Method::GET, None) => {
|
(Method::GET, None) => {
|
||||||
@@ -315,12 +349,12 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
.unwrap_or(request_parts.uri.path());
|
.unwrap_or(request_parts.uri.path());
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
(Method::GET, Some((dir, file))) => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
_ => Ok(not_found()),
|
||||||
@@ -350,12 +384,12 @@ async fn main_embassy_ui(req: Request<Body>, ctx: RpcContext) -> Result<Response
|
|||||||
.unwrap_or(request_parts.uri.path());
|
.unwrap_or(request_parts.uri.path());
|
||||||
|
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
let full_path = PathBuf::from(selected_root_dir).join(uri_path);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
(Method::GET, Some((dir, file))) => {
|
(Method::GET, Some((dir, file))) => {
|
||||||
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
let full_path = PathBuf::from(selected_root_dir).join(dir).join(file);
|
||||||
file_send(full_path).await
|
file_send(full_path, &accept_encoding).await
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Ok(not_found()),
|
_ => Ok(not_found()),
|
||||||
@@ -397,7 +431,10 @@ fn bad_request() -> Response<Body> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn file_send(path: impl AsRef<Path>) -> Result<Response<Body>, Error> {
|
async fn file_send(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
accept_encoding: &[&str],
|
||||||
|
) -> Result<Response<Body>, Error> {
|
||||||
// Serve a file by asynchronously reading it by chunks using tokio-util crate.
|
// Serve a file by asynchronously reading it by chunks using tokio-util crate.
|
||||||
|
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
@@ -414,8 +451,13 @@ async fn file_send(path: impl AsRef<Path>) -> Result<Response<Body>, Error> {
|
|||||||
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 stream = FramedRead::new(file, BytesCodec::new());
|
let body = if accept_encoding.contains(&"br") {
|
||||||
let body = Body::wrap_stream(stream);
|
Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(BufReader::new(file))))
|
||||||
|
} else if accept_encoding.contains(&"gzip") {
|
||||||
|
Body::wrap_stream(ReaderStream::new(GzipEncoder::new(BufReader::new(file))))
|
||||||
|
} else {
|
||||||
|
Body::wrap_stream(ReaderStream::new(file))
|
||||||
|
};
|
||||||
return builder.body(body).with_kind(ErrorKind::Network);
|
return builder.body(body).with_kind(ErrorKind::Network);
|
||||||
}
|
}
|
||||||
tracing::debug!("File not found: {:?}", path);
|
tracing::debug!("File not found: {:?}", path);
|
||||||
|
|||||||
Reference in New Issue
Block a user