mirror of
https://github.com/sigoden/dufs.git
synced 2026-04-09 17:13:02 +03:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c4c264206 | ||
|
|
c1e0c6bb2f | ||
|
|
f138915f20 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.13.1] - 2022-06-05
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Escape filename ([#21](https://github.com/sigoden/duf/issues/21))
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- Use logger ([#22](https://github.com/sigoden/duf/issues/22))
|
||||||
|
|
||||||
## [0.13.0] - 2022-06-05
|
## [0.13.0] - 2022-06-05
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
27
Cargo.lock
generated
27
Cargo.lock
generated
@@ -286,18 +286,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "duf"
|
name = "duf"
|
||||||
version = "0.13.0"
|
version = "0.13.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-walkdir",
|
"async-walkdir",
|
||||||
"async_zip",
|
"async_zip",
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"get_if_addrs",
|
"get_if_addrs",
|
||||||
"headers",
|
"headers",
|
||||||
"hyper",
|
"hyper",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"log",
|
||||||
"md5",
|
"md5",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
@@ -309,9 +311,20 @@ dependencies = [
|
|||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
"urlencoding",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||||
|
dependencies = [
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
@@ -572,6 +585,12 @@ 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 = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.19"
|
version = "0.14.19"
|
||||||
@@ -1154,6 +1173,12 @@ version = "0.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urlencoding"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "duf"
|
name = "duf"
|
||||||
version = "0.13.0"
|
version = "0.13.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["sigoden <sigoden@gmail.com>"]
|
authors = ["sigoden <sigoden@gmail.com>"]
|
||||||
description = "Duf is a simple file server."
|
description = "Duf is a simple file server."
|
||||||
@@ -34,6 +34,9 @@ rustls-pemfile = "1"
|
|||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
uuid = { version = "1.1.1", features = ["v4", "fast-rng"] }
|
uuid = { version = "1.1.1", features = ["v4", "fast-rng"] }
|
||||||
|
urlencoding = "2.1.0"
|
||||||
|
env_logger = { version = "0.9.0", default-features = false, features = ["humantime"] }
|
||||||
|
log = "0.4.17"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ impl Args {
|
|||||||
let uri_prefix = if path_prefix.is_empty() {
|
let uri_prefix = if path_prefix.is_empty() {
|
||||||
"/".to_owned()
|
"/".to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("/{}/", &path_prefix)
|
format!("/{}/", encode_uri(&path_prefix))
|
||||||
};
|
};
|
||||||
let cors = matches.is_present("cors");
|
let cors = matches.is_present("cors");
|
||||||
let auth = match matches.value_of("auth") {
|
let auth = match matches.value_of("auth") {
|
||||||
@@ -237,3 +237,8 @@ pub fn load_private_key(filename: &str) -> BoxResult<PrivateKey> {
|
|||||||
}
|
}
|
||||||
Ok(PrivateKey(keys[0].to_owned()))
|
Ok(PrivateKey(keys[0].to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encode_uri(v: &str) -> String {
|
||||||
|
let parts: Vec<_> = v.split('/').map(urlencoding::encode).collect();
|
||||||
|
parts.join("/")
|
||||||
|
}
|
||||||
|
|||||||
18
src/main.rs
18
src/main.rs
@@ -2,9 +2,15 @@ mod args;
|
|||||||
mod auth;
|
mod auth;
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
pub type BoxResult<T> = Result<T, Box<dyn std::error::Error>>;
|
pub type BoxResult<T> = Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
use crate::args::{matches, Args};
|
use std::env;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
use crate::args::{encode_uri, matches, Args};
|
||||||
use crate::server::serve;
|
use crate::server::serve;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -13,6 +19,16 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run() -> BoxResult<()> {
|
async fn run() -> BoxResult<()> {
|
||||||
|
if env::var("RUST_LOG").is_err() {
|
||||||
|
env::set_var("RUST_LOG", "info")
|
||||||
|
}
|
||||||
|
env_logger::builder()
|
||||||
|
.format(|buf, record| {
|
||||||
|
let timestamp = buf.timestamp();
|
||||||
|
writeln!(buf, "[{} {}] {}", timestamp, record.level(), record.args())
|
||||||
|
})
|
||||||
|
.init();
|
||||||
|
|
||||||
let args = Args::parse(matches())?;
|
let args = Args::parse(matches())?;
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
ret = serve(args) => {
|
ret = serve(args) => {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::auth::{generate_www_auth, valid_digest};
|
use crate::auth::{generate_www_auth, valid_digest};
|
||||||
use crate::{Args, BoxResult};
|
use crate::{encode_uri, Args, BoxResult};
|
||||||
|
|
||||||
use async_walkdir::WalkDir;
|
use async_walkdir::WalkDir;
|
||||||
use async_zip::write::{EntryOptions, ZipFileWriter};
|
use async_zip::write::{EntryOptions, ZipFileWriter};
|
||||||
use async_zip::Compression;
|
use async_zip::Compression;
|
||||||
use chrono::{Local, TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use get_if_addrs::get_if_addrs;
|
use get_if_addrs::get_if_addrs;
|
||||||
@@ -120,20 +120,16 @@ impl InnerService {
|
|||||||
let uri = req.uri().clone();
|
let uri = req.uri().clone();
|
||||||
let cors = self.args.cors;
|
let cors = self.args.cors;
|
||||||
|
|
||||||
let timestamp = Local::now().format("%d/%b/%Y %H:%M:%S");
|
|
||||||
let mut res = match self.handle(req).await {
|
let mut res = match self.handle(req).await {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
println!(r#"[{}] "{} {}" - {}"#, timestamp, method, uri, res.status());
|
info!(r#""{} {}" - {}"#, method, uri, res.status());
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let mut res = Response::default();
|
let mut res = Response::default();
|
||||||
let status = StatusCode::INTERNAL_SERVER_ERROR;
|
let status = StatusCode::INTERNAL_SERVER_ERROR;
|
||||||
status!(res, status);
|
status!(res, status);
|
||||||
eprintln!(
|
error!(r#""{} {}" - {} {}"#, method, uri, status, err);
|
||||||
r#"[{}] "{} {}" - {} {}"#,
|
|
||||||
timestamp, method, uri, status, err
|
|
||||||
);
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -363,14 +359,18 @@ impl InnerService {
|
|||||||
let path = path.to_owned();
|
let path = path.to_owned();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = zip_dir(&mut writer, &path).await {
|
if let Err(e) = zip_dir(&mut writer, &path).await {
|
||||||
eprintln!("Failed to zip {}, {}", path.display(), e);
|
error!("Failed to zip {}, {}", path.display(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let stream = ReaderStream::new(reader);
|
let stream = ReaderStream::new(reader);
|
||||||
*res.body_mut() = Body::wrap_stream(stream);
|
*res.body_mut() = Body::wrap_stream(stream);
|
||||||
res.headers_mut().insert(
|
res.headers_mut().insert(
|
||||||
CONTENT_DISPOSITION,
|
CONTENT_DISPOSITION,
|
||||||
HeaderValue::from_str(&format!("attachment; filename=\"{}.zip\"", filename,)).unwrap(),
|
HeaderValue::from_str(&format!(
|
||||||
|
"attachment; filename=\"{}.zip\"",
|
||||||
|
encode_uri(filename),
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -821,7 +821,10 @@ impl PathItem {
|
|||||||
<D:status>HTTP/1.1 200 OK</D:status>
|
<D:status>HTTP/1.1 200 OK</D:status>
|
||||||
</D:propstat>
|
</D:propstat>
|
||||||
</D:response>"#,
|
</D:response>"#,
|
||||||
prefix, self.name, self.base_name, mtime
|
prefix,
|
||||||
|
encode_uri(&self.name),
|
||||||
|
urlencoding::encode(&self.base_name),
|
||||||
|
mtime
|
||||||
),
|
),
|
||||||
PathType::File | PathType::SymlinkFile => format!(
|
PathType::File | PathType::SymlinkFile => format!(
|
||||||
r#"<D:response>
|
r#"<D:response>
|
||||||
@@ -837,8 +840,8 @@ impl PathItem {
|
|||||||
</D:propstat>
|
</D:propstat>
|
||||||
</D:response>"#,
|
</D:response>"#,
|
||||||
prefix,
|
prefix,
|
||||||
self.name,
|
encode_uri(&self.name),
|
||||||
self.base_name,
|
urlencoding::encode(&self.base_name),
|
||||||
self.size.unwrap_or_default(),
|
self.size.unwrap_or_default(),
|
||||||
mtime
|
mtime
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user