]> OzVa Git service - ozva-cloud/commitdiff
feat: add cors
authorsigoden <sigoden@gmail.com>
Sun, 29 May 2022 09:33:21 +0000 (17:33 +0800)
committersigoden <sigoden@gmail.com>
Sun, 29 May 2022 09:33:21 +0000 (17:33 +0800)
Cargo.lock
Cargo.toml
README.md
src/args.rs
src/server.rs

index c2bcbb487d2fa7075647177a751eb9329d804c7c..58846d012e206b657816d802c8a752dd1f6a78db 100644 (file)
@@ -130,6 +130,15 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "block-buffer"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "blocking"
 version = "1.2.0"
@@ -247,6 +256,15 @@ dependencies = [
  "cache-padded",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "crc32fast"
 version = "1.3.2"
@@ -256,6 +274,26 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "crypto-common"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
 [[package]]
 name = "duf"
 version = "0.3.0"
@@ -265,6 +303,7 @@ dependencies = [
  "base64",
  "clap",
  "futures",
+ "headers",
  "hyper",
  "log",
  "percent-encoding",
@@ -412,12 +451,47 @@ dependencies = [
  "slab",
 ]
 
+[[package]]
+name = "generic-array"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 
+[[package]]
+name = "headers"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d"
+dependencies = [
+ "base64",
+ "bitflags",
+ "bytes",
+ "headers-core",
+ "http",
+ "httpdate",
+ "mime",
+ "sha-1",
+]
+
+[[package]]
+name = "headers-core"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
+dependencies = [
+ "http",
+]
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -556,6 +630,12 @@ version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
 [[package]]
 name = "miniz_oxide"
 version = "0.5.1"
@@ -712,6 +792,17 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "sha-1"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
 [[package]]
 name = "simple_logger"
 version = "2.1.0"
@@ -894,12 +985,24 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
 
+[[package]]
+name = "typenum"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
 
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
 [[package]]
 name = "waker-fn"
 version = "1.1.0"
index 2ef2d4b38cfbd329618fd6ffcc56ac044e720afa..dd755aeb4a5252e757b79c4218a0366f81a7cf1d 100644 (file)
@@ -25,6 +25,7 @@ log = "0.4"
 simple_logger = "2.1.0"
 async_zip = "0.0.7"
 async-walkdir = "0.2.0"
+headers = "0.3.7"
 
 [profile.release]
 lto = true
index 3452cd40f81a7320ce2089e0543d7b8de1c2d18f..47a16fe5869e6da9913492436872521cb1d30c8d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ duf folder_name
 
 Only serve static files, disable editing operations such as update or delete
 ```
-duf --no-edit
+duf --no-change
 ```
 
 Finally, run this command to see a list of all available option
index 12ba5ca3f701314229676eab954af4089facf0c8..f50f83b6056fcb3720150d39be770be9408395a3 100644 (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,
         })
     }
 
index 59ed997872f789abf502ae1b03bded184b36cc7b..e88da23b3a7d9ee838694d227ce827c8c56c3bfd 100644 (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);