feat: add cors

This commit is contained in:
sigoden
2022-05-29 17:33:21 +08:00
parent 06ce7b0175
commit 10aabcb2f2
5 changed files with 146 additions and 20 deletions

View File

@@ -35,10 +35,10 @@ fn app() -> clap::Command<'static> {
.help("Path to a directory for serving files"),
)
.arg(
Arg::new("no-edit")
.short('E')
.long("no-edit")
.help("Disable editing operations such as update or delete"),
Arg::new("no-change")
.short('C')
.long("no-change")
.help("Disable change operations such as update or delete"),
)
.arg(
Arg::new("auth")
@@ -47,6 +47,11 @@ fn app() -> clap::Command<'static> {
.help("Authenticate with user and pass")
.value_name("user:pass"),
)
.arg(
Arg::new("cors")
.long("cors")
.help("Enable CORS, sets `Access-Control-Allow-Origin: *`"),
)
}
pub fn matches() -> ArgMatches {
@@ -60,6 +65,7 @@ pub struct Args {
pub path: PathBuf,
pub readonly: bool,
pub auth: Option<String>,
pub cors: bool,
}
impl Args {
@@ -72,7 +78,8 @@ impl Args {
let port = matches.value_of_t::<u16>("port")?;
let path = matches.value_of_os("path").unwrap_or_default();
let path = Args::parse_path(path)?;
let readonly = matches.is_present("no-edit");
let readonly = matches.is_present("no-change");
let cors = matches.is_present("cors");
let auth = matches.value_of("auth").map(|v| v.to_owned());
Ok(Args {
@@ -81,6 +88,7 @@ impl Args {
path,
readonly,
auth,
cors,
})
}

View File

@@ -5,7 +5,8 @@ use async_zip::write::{EntryOptions, ZipFileWriter};
use async_zip::Compression;
use futures::stream::StreamExt;
use futures::TryStreamExt;
use hyper::header::HeaderValue;
use headers::{AccessControlAllowHeaders, AccessControlAllowOrigin, HeaderMapExt};
use hyper::header::{HeaderValue, ACCEPT, CONTENT_TYPE, ORIGIN, RANGE, WWW_AUTHENTICATE};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, StatusCode};
use percent_encoding::percent_decode;
@@ -69,11 +70,15 @@ impl InnerService {
pub async fn call(self: Arc<Self>, req: Request) -> Result<Response, hyper::Error> {
let method = req.method().clone();
let uri = req.uri().clone();
let res = self
let cors = self.args.cors;
let mut res = self
.handle(req)
.await
.unwrap_or_else(|_| status_code!(StatusCode::INTERNAL_SERVER_ERROR));
info!(r#""{} {}" - {}"#, method, uri, res.status());
if cors {
add_cors(&mut res);
}
Ok(res)
}
@@ -81,21 +86,20 @@ impl InnerService {
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"));
.insert(WWW_AUTHENTICATE, HeaderValue::from_static("Basic"));
return Ok(res);
}
if req.method() == Method::GET {
self.handle_static(req).await
} else if req.method() == Method::PUT {
if self.args.readonly {
return Ok(status_code!(StatusCode::FORBIDDEN));
match *req.method() {
Method::GET => self.handle_static(req).await,
Method::PUT => {
if self.args.readonly {
return Ok(status_code!(StatusCode::FORBIDDEN));
}
self.handle_upload(req).await
}
self.handle_upload(req).await
} else if req.method() == Method::DELETE {
self.handle_delete(req).await
} else {
return Ok(status_code!(StatusCode::NOT_FOUND));
Method::OPTIONS => Ok(status_code!(StatusCode::NO_CONTENT)),
Method::DELETE => self.handle_delete(req).await,
_ => Ok(status_code!(StatusCode::NOT_FOUND)),
}
}
@@ -359,6 +363,16 @@ fn normalize_path<P: AsRef<Path>>(path: P) -> String {
}
}
fn add_cors(res: &mut Response) {
res.headers_mut()
.typed_insert(AccessControlAllowOrigin::ANY);
res.headers_mut().typed_insert(
vec![RANGE, CONTENT_TYPE, ACCEPT, ORIGIN, WWW_AUTHENTICATE]
.into_iter()
.collect::<AccessControlAllowHeaders>(),
);
}
async fn dir_zip<W: AsyncWrite + Unpin>(writer: &mut W, dir: &Path) -> BoxResult<()> {
let mut writer = ZipFileWriter::new(writer);
let mut walkdir = WalkDir::new(dir);