You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
Start migrating to Axum
Now with the homepage and the static files
This commit is contained in:
75
Cargo.lock
generated
75
Cargo.lock
generated
@@ -460,6 +460,50 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9f346c92c1e9a71d14fe4aaf7c2a5d9932cc4e5e48d8fb6641524416eb79ddd"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"bitflags",
|
||||||
|
"bytes 1.1.0",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-http",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbcda393bef9c87572779cb8ef916f12d77750b27535dd6819fa86591627a51"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes 1.1.0",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"mime",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.64"
|
version = "0.3.64"
|
||||||
@@ -1820,6 +1864,18 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mas-axum-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum",
|
||||||
|
"futures-util",
|
||||||
|
"headers",
|
||||||
|
"mas-templates",
|
||||||
|
"sqlx",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mas-cli"
|
name = "mas-cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1928,6 +1984,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
@@ -1936,6 +1993,7 @@ dependencies = [
|
|||||||
"hyper",
|
"hyper",
|
||||||
"indoc",
|
"indoc",
|
||||||
"lettre",
|
"lettre",
|
||||||
|
"mas-axum-utils",
|
||||||
"mas-config",
|
"mas-config",
|
||||||
"mas-data-model",
|
"mas-data-model",
|
||||||
"mas-email",
|
"mas-email",
|
||||||
@@ -2052,10 +2110,13 @@ dependencies = [
|
|||||||
name = "mas-static-files"
|
name = "mas-static-files"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"axum",
|
||||||
"headers",
|
"headers",
|
||||||
|
"http",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"warp",
|
"tokio",
|
||||||
|
"tower",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2173,6 +2234,12 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9376a4f0340565ad675d11fc1419227faf5f60cd7ac9cb2e7185a471f30af833"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@@ -3788,6 +3855,12 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.12.6"
|
version = "0.12.6"
|
||||||
|
@@ -203,20 +203,16 @@ impl Options {
|
|||||||
.context("could not watch for templates changes")?;
|
.context("could not watch for templates changes")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the server
|
let router =
|
||||||
let root = mas_handlers::root(&pool, &templates, &key_store, &encrypter, &mailer, &config);
|
mas_handlers::router(&pool, &templates, &key_store, &encrypter, &mailer, &config);
|
||||||
|
|
||||||
// Explicitely the config to properly zeroize secret keys
|
// Explicitely the config to properly zeroize secret keys
|
||||||
drop(config);
|
drop(config);
|
||||||
|
|
||||||
let warp_service = warp::service(root);
|
|
||||||
|
|
||||||
let service = mas_http::ServerLayer::default().layer(warp_service);
|
|
||||||
|
|
||||||
info!("Listening on http://{}", listener.local_addr().unwrap());
|
info!("Listening on http://{}", listener.local_addr().unwrap());
|
||||||
|
|
||||||
Server::from_tcp(listener)?
|
Server::from_tcp(listener)?
|
||||||
.serve(Shared::new(service))
|
.serve(router.into_make_service())
|
||||||
.with_graceful_shutdown(shutdown_signal())
|
.with_graceful_shutdown(shutdown_signal())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@@ -22,6 +22,8 @@ anyhow = "1.0.56"
|
|||||||
# Web server
|
# Web server
|
||||||
warp = "0.3.2"
|
warp = "0.3.2"
|
||||||
hyper = { version = "0.14.17", features = ["full"] }
|
hyper = { version = "0.14.17", features = ["full"] }
|
||||||
|
tower = "0.4.12"
|
||||||
|
axum = "0.4.8"
|
||||||
|
|
||||||
# Emails
|
# Emails
|
||||||
lettre = { version = "0.10.0-rc.4", default-features = false, features = ["builder"] }
|
lettre = { version = "0.10.0-rc.4", default-features = false, features = ["builder"] }
|
||||||
@@ -63,7 +65,7 @@ mas-static-files = { path = "../static-files" }
|
|||||||
mas-storage = { path = "../storage" }
|
mas-storage = { path = "../storage" }
|
||||||
mas-templates = { path = "../templates" }
|
mas-templates = { path = "../templates" }
|
||||||
mas-warp-utils = { path = "../warp-utils" }
|
mas-warp-utils = { path = "../warp-utils" }
|
||||||
tower = "0.4.12"
|
mas-axum-utils = { path = "../axum-utils" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
indoc = "1.0.4"
|
indoc = "1.0.4"
|
||||||
|
@@ -21,12 +21,11 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use axum::{extract::Extension, routing::get, Router};
|
||||||
use mas_config::{Encrypter, RootConfig};
|
use mas_config::{Encrypter, RootConfig};
|
||||||
use mas_email::Mailer;
|
use mas_email::Mailer;
|
||||||
use mas_jose::StaticKeystore;
|
use mas_jose::StaticKeystore;
|
||||||
use mas_static_files::filter as static_files;
|
|
||||||
use mas_templates::Templates;
|
use mas_templates::Templates;
|
||||||
use mas_warp_utils::filters;
|
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use warp::{filters::BoxedFilter, Filter, Reply};
|
use warp::{filters::BoxedFilter, Filter, Reply};
|
||||||
|
|
||||||
@@ -55,10 +54,26 @@ pub fn root(
|
|||||||
&config.http,
|
&config.http,
|
||||||
&config.csrf,
|
&config.csrf,
|
||||||
);
|
);
|
||||||
let static_files =
|
|
||||||
static_files(config.http.web_root.clone()).and(filters::trace::name("GET static file"));
|
|
||||||
|
|
||||||
let filter = health.or(views).unify().or(static_files).unify().or(oauth2);
|
let filter = health.or(views).unify().or(oauth2);
|
||||||
|
|
||||||
filter.with(warp::log(module_path!())).boxed()
|
filter.with(warp::log(module_path!())).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn router<B: Send + 'static>(
|
||||||
|
pool: &PgPool,
|
||||||
|
templates: &Templates,
|
||||||
|
key_store: &Arc<StaticKeystore>,
|
||||||
|
encrypter: &Encrypter,
|
||||||
|
mailer: &Mailer,
|
||||||
|
config: &RootConfig,
|
||||||
|
) -> Router<B> {
|
||||||
|
Router::new()
|
||||||
|
.route("/", get(self::views::index::get))
|
||||||
|
.fallback(mas_static_files::Assets)
|
||||||
|
.layer(Extension(pool.clone()))
|
||||||
|
.layer(Extension(templates.clone()))
|
||||||
|
.layer(Extension(key_store.clone()))
|
||||||
|
.layer(Extension(encrypter.clone()))
|
||||||
|
.layer(Extension(mailer.clone()))
|
||||||
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
// Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -12,6 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
extract::Extension,
|
||||||
|
response::{Html, IntoResponse},
|
||||||
|
};
|
||||||
|
use mas_axum_utils::{fancy_error, FancyError};
|
||||||
use mas_config::{CsrfConfig, Encrypter, HttpConfig};
|
use mas_config::{CsrfConfig, Encrypter, HttpConfig};
|
||||||
use mas_data_model::BrowserSession;
|
use mas_data_model::BrowserSession;
|
||||||
use mas_storage::PostgresqlBackend;
|
use mas_storage::PostgresqlBackend;
|
||||||
@@ -25,8 +32,10 @@ use mas_warp_utils::filters::{
|
|||||||
with_templates, CsrfToken,
|
with_templates, CsrfToken,
|
||||||
};
|
};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
use url::Url;
|
||||||
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
|
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
|
||||||
|
|
||||||
|
/*
|
||||||
pub(super) fn filter(
|
pub(super) fn filter(
|
||||||
pool: &PgPool,
|
pool: &PgPool,
|
||||||
templates: &Templates,
|
templates: &Templates,
|
||||||
@@ -62,3 +71,20 @@ async fn get(
|
|||||||
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?;
|
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?;
|
||||||
Ok(Box::new(reply))
|
Ok(Box::new(reply))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub async fn get(
|
||||||
|
Extension(templates): Extension<Templates>,
|
||||||
|
) -> Result<impl IntoResponse, FancyError> {
|
||||||
|
let ctx = IndexContext::new(
|
||||||
|
Url::from_str("https://example.com/.well-known/openid-discovery").unwrap(),
|
||||||
|
)
|
||||||
|
.maybe_with_session::<PostgresqlBackend>(None)
|
||||||
|
.with_csrf("csrf_token".to_string());
|
||||||
|
|
||||||
|
let content = templates
|
||||||
|
.render_index(&ctx)
|
||||||
|
.await
|
||||||
|
.map_err(fancy_error(templates))?;
|
||||||
|
Ok(Html(content))
|
||||||
|
}
|
||||||
|
@@ -18,19 +18,18 @@ use mas_templates::Templates;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use warp::{filters::BoxedFilter, Filter, Reply};
|
use warp::{filters::BoxedFilter, Filter, Reply};
|
||||||
|
|
||||||
mod account;
|
pub mod account;
|
||||||
mod index;
|
pub mod index;
|
||||||
mod login;
|
pub mod login;
|
||||||
mod logout;
|
pub mod logout;
|
||||||
mod reauth;
|
pub mod reauth;
|
||||||
mod register;
|
pub mod register;
|
||||||
mod shared;
|
pub mod shared;
|
||||||
mod verify;
|
pub mod verify;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
account::filter as account, index::filter as index, login::filter as login,
|
account::filter as account, login::filter as login, logout::filter as logout,
|
||||||
logout::filter as logout, reauth::filter as reauth, register::filter as register,
|
reauth::filter as reauth, register::filter as register, verify::filter as verify,
|
||||||
verify::filter as verify,
|
|
||||||
};
|
};
|
||||||
pub(crate) use self::{
|
pub(crate) use self::{
|
||||||
login::LoginRequest, reauth::ReauthRequest, register::RegisterRequest, shared::PostAuthAction,
|
login::LoginRequest, reauth::ReauthRequest, register::RegisterRequest, shared::PostAuthAction,
|
||||||
@@ -44,7 +43,6 @@ pub(super) fn filter(
|
|||||||
http_config: &HttpConfig,
|
http_config: &HttpConfig,
|
||||||
csrf_config: &CsrfConfig,
|
csrf_config: &CsrfConfig,
|
||||||
) -> BoxedFilter<(Box<dyn Reply>,)> {
|
) -> BoxedFilter<(Box<dyn Reply>,)> {
|
||||||
let index = index(pool, templates, encrypter, http_config, csrf_config);
|
|
||||||
let account = account(pool, templates, mailer, encrypter, http_config, csrf_config);
|
let account = account(pool, templates, mailer, encrypter, http_config, csrf_config);
|
||||||
let login = login(pool, templates, encrypter, csrf_config);
|
let login = login(pool, templates, encrypter, csrf_config);
|
||||||
let register = register(pool, templates, encrypter, csrf_config);
|
let register = register(pool, templates, encrypter, csrf_config);
|
||||||
@@ -52,9 +50,7 @@ pub(super) fn filter(
|
|||||||
let reauth = reauth(pool, templates, encrypter, csrf_config);
|
let reauth = reauth(pool, templates, encrypter, csrf_config);
|
||||||
let verify = verify(pool, templates, encrypter, csrf_config);
|
let verify = verify(pool, templates, encrypter, csrf_config);
|
||||||
|
|
||||||
index
|
account
|
||||||
.or(account)
|
|
||||||
.unify()
|
|
||||||
.or(login)
|
.or(login)
|
||||||
.unify()
|
.unify()
|
||||||
.or(register)
|
.or(register)
|
||||||
|
@@ -9,7 +9,10 @@ license = "Apache-2.0"
|
|||||||
dev = []
|
dev = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
axum = "0.4.8"
|
||||||
headers = "0.3.7"
|
headers = "0.3.7"
|
||||||
|
http = "0.2.6"
|
||||||
mime_guess = "2.0.4"
|
mime_guess = "2.0.4"
|
||||||
rust-embed = "6.3.0"
|
rust-embed = "6.3.0"
|
||||||
warp = "0.3.2"
|
tokio = { version = "1.17.0", features = ["fs"] }
|
||||||
|
tower = "0.4.12"
|
||||||
|
@@ -18,95 +18,60 @@
|
|||||||
#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)]
|
#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)]
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::{
|
||||||
|
convert::Infallible,
|
||||||
|
future::{ready, Ready},
|
||||||
|
};
|
||||||
|
|
||||||
use warp::{filters::BoxedFilter, Filter, Reply};
|
use axum::{
|
||||||
|
body::{boxed, Full},
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
};
|
||||||
|
use headers::{ContentLength, ContentType, HeaderMapExt};
|
||||||
|
use http::{Request, StatusCode};
|
||||||
|
use rust_embed::RustEmbed;
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
#[cfg(not(feature = "dev"))]
|
// TODO: read the assets live from the filesystem
|
||||||
mod builtin {
|
|
||||||
use std::{fmt::Write, str::FromStr};
|
|
||||||
|
|
||||||
use headers::{ContentLength, ContentType, ETag, HeaderMapExt};
|
/// Embedded public assets
|
||||||
use rust_embed::RustEmbed;
|
#[derive(RustEmbed, Clone)]
|
||||||
use warp::{
|
#[folder = "public/"]
|
||||||
filters::BoxedFilter, hyper::StatusCode, path::Tail, reply::Response, Filter, Rejection,
|
pub struct Assets;
|
||||||
Reply,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
impl Assets {
|
||||||
#[folder = "public/"]
|
fn get_response(path: &str) -> Option<Response> {
|
||||||
struct Asset;
|
let asset = Self::get(path)?;
|
||||||
|
|
||||||
#[allow(clippy::unused_async)]
|
|
||||||
async fn serve_embed(
|
|
||||||
path: Tail,
|
|
||||||
if_none_match: Option<String>,
|
|
||||||
) -> Result<Box<dyn Reply>, Rejection> {
|
|
||||||
let path = path.as_str();
|
|
||||||
let asset = Asset::get(path).ok_or_else(warp::reject::not_found)?;
|
|
||||||
|
|
||||||
// TODO: this etag calculation is ugly
|
|
||||||
let etag = {
|
|
||||||
let mut s = String::with_capacity(32 * 2 + 2);
|
|
||||||
write!(s, "\"").unwrap();
|
|
||||||
for b in asset.metadata.sha256_hash() {
|
|
||||||
write!(s, "{:02x}", b).unwrap();
|
|
||||||
}
|
|
||||||
write!(s, "\"").unwrap();
|
|
||||||
s
|
|
||||||
};
|
|
||||||
|
|
||||||
if Some(&etag) == if_none_match.as_ref() {
|
|
||||||
return Ok(Box::new(StatusCode::NOT_MODIFIED));
|
|
||||||
};
|
|
||||||
|
|
||||||
let len = asset.data.len().try_into().unwrap();
|
let len = asset.data.len().try_into().unwrap();
|
||||||
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||||
|
|
||||||
let mut res = Response::new(asset.data.into());
|
let mut res = Response::new(boxed(Full::from(asset.data)));
|
||||||
res.headers_mut().typed_insert(ContentType::from(mime));
|
res.headers_mut().typed_insert(ContentType::from(mime));
|
||||||
res.headers_mut().typed_insert(ContentLength(len));
|
res.headers_mut().typed_insert(ContentLength(len));
|
||||||
res.headers_mut()
|
Some(res)
|
||||||
.typed_insert(ETag::from_str(&etag).unwrap());
|
|
||||||
Ok(Box::new(res))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn filter() -> BoxedFilter<(impl Reply,)> {
|
|
||||||
warp::path::tail()
|
|
||||||
.and(warp::filters::header::optional("If-None-Match"))
|
|
||||||
.and_then(serve_embed)
|
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dev")]
|
impl<B> Service<Request<B>> for Assets {
|
||||||
mod builtin {
|
type Response = Response;
|
||||||
use std::path::PathBuf;
|
type Error = Infallible;
|
||||||
|
type Future = Ready<Result<Self::Response, Self::Error>>;
|
||||||
|
|
||||||
use warp::{filters::BoxedFilter, Reply};
|
fn poll_ready(
|
||||||
|
&mut self,
|
||||||
|
_cx: &mut std::task::Context<'_>,
|
||||||
|
) -> std::task::Poll<Result<(), Self::Error>> {
|
||||||
|
std::task::Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn filter() -> BoxedFilter<(impl Reply,)> {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
let path = PathBuf::from(format!("{}/public", env!("CARGO_MANIFEST_DIR")));
|
let path = req.uri().path().trim_start_matches('/');
|
||||||
super::filter_for_path(path)
|
// TODO: support HEAD requests
|
||||||
}
|
// TODO: support ETag
|
||||||
}
|
// TODO: support range requests
|
||||||
|
let response =
|
||||||
fn box_reply(reply: impl Reply + 'static) -> Box<dyn Reply> {
|
Self::get_response(path).unwrap_or_else(|| StatusCode::NOT_FOUND.into_response());
|
||||||
Box::new(reply)
|
ready(Ok(response))
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_for_path(path: PathBuf) -> BoxedFilter<(impl Reply,)> {
|
|
||||||
warp::fs::dir(path).boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [`warp`] filter that serves static files
|
|
||||||
#[must_use]
|
|
||||||
pub fn filter(path: Option<PathBuf>) -> BoxedFilter<(Box<dyn Reply>,)> {
|
|
||||||
let f = self::builtin::filter();
|
|
||||||
|
|
||||||
if let Some(path) = path {
|
|
||||||
f.or(filter_for_path(path)).map(box_reply).boxed()
|
|
||||||
} else {
|
|
||||||
f.map(box_reply).boxed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user