"chrono",
"clap",
"diqwest",
- "env_logger",
"futures",
"get_if_addrs",
"headers",
"cfg-if",
]
-[[package]]
-name = "env_logger"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
-dependencies = [
- "humantime",
- "log",
-]
-
[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
[[package]]
name = "hyper"
version = "0.14.19"
uuid = { version = "1.1", features = ["v4", "fast-rng"] }
urlencoding = "2.1"
xml-rs = "0.8"
-env_logger = { version = "0.9", default-features = false, features = ["humantime"] }
log = "0.4"
socket2 = "0.4"
async-stream = "0.3"
--- /dev/null
+use chrono::{Local, SecondsFormat};
+use log::{Level, Metadata, Record};
+use log::{LevelFilter, SetLoggerError};
+
+struct SimpleLogger;
+
+impl log::Log for SimpleLogger {
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ metadata.level() <= Level::Info
+ }
+
+ fn log(&self, record: &Record) {
+ if self.enabled(record.metadata()) {
+ let timestamp = Local::now().to_rfc3339_opts(SecondsFormat::Secs, true);
+ if record.level() < Level::Info {
+ eprintln!("{} {} - {}", timestamp, record.level(), record.args());
+ } else {
+ println!("{} {} - {}", timestamp, record.level(), record.args());
+ }
+ }
+ }
+
+ fn flush(&self) {}
+}
+
+static LOGGER: SimpleLogger = SimpleLogger;
+
+pub fn init() -> Result<(), SetLoggerError> {
+ log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info))
+}
mod args;
mod auth;
+mod logger;
mod server;
mod streamer;
mod tls;
use crate::server::{Request, Server};
use crate::tls::{TlsAcceptor, TlsStream};
-use std::io::Write;
use std::net::{IpAddr, SocketAddr, TcpListener as StdTcpListener};
-use std::{env, sync::Arc};
+use std::sync::Arc;
use futures::future::join_all;
use tokio::net::TcpListener;
}
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_millis();
- writeln!(buf, "[{} {}] {}", timestamp, record.level(), record.args())
- })
- .init();
-
+ logger::init().map_err(|e| format!("Failed to init logger, {}", e))?;
let args = Args::parse(matches())?;
let args = Arc::new(args);
let handles = serve(args.clone())?;
#[case("index.html")]
fn serve_single_file(tmpdir: TempDir, port: u16, #[case] file: &str) -> Result<(), Error> {
let mut child = Command::cargo_bin("dufs")?
- .env("RUST_LOG", "false")
.arg(tmpdir.path().join(file))
.arg("-p")
.arg(port.to_string())
use assert_fs::fixture::TempDir;
use regex::Regex;
use rstest::rstest;
-use std::io::{BufRead, BufReader};
+use std::io::Read;
use std::process::{Command, Stdio};
#[rstest]
#[case(&["-b", "20.205.243.166"])]
fn bind_fails(tmpdir: TempDir, port: u16, #[case] args: &[&str]) -> Result<(), Error> {
Command::cargo_bin("dufs")?
- .env("RUST_LOG", "false")
.arg(tmpdir.path())
.arg("-p")
.arg(port.to_string())
#[case(&["--path-prefix", "/prefix"])]
fn validate_printed_urls(tmpdir: TempDir, port: u16, #[case] args: &[&str]) -> Result<(), Error> {
let mut child = Command::cargo_bin("dufs")?
- .env("RUST_LOG", "false")
.arg(tmpdir.path())
.arg("-p")
.arg(port.to_string())
wait_for_port(port);
- // WARN assumes urls list is terminated by an empty line
- let url_lines = BufReader::new(child.stdout.take().unwrap())
+ let stdout = child.stdout.as_mut().expect("Failed to get stdout");
+ let mut buf = [0; 1000];
+ let buf_len = stdout.read(&mut buf)?;
+ let output = std::str::from_utf8(&buf[0..buf_len])?;
+ let url_lines = output
.lines()
- .map(|line| line.expect("Error reading stdout"))
.take_while(|line| !line.is_empty()) /* non-empty lines */
- .collect::<Vec<_>>();
- let url_lines = url_lines.join("\n");
+ .collect::<Vec<_>>()
+ .join("\n");
let urls = Regex::new(r"http://[a-zA-Z0-9\.\[\]:/]+")
.unwrap()
.captures_iter(url_lines.as_str())
- .map(|caps| caps.get(0).unwrap().as_str())
+ .filter_map(|caps| caps.get(0).map(|v| v.as_str()))
.collect::<Vec<_>>();
assert!(!urls.is_empty());
-
for url in urls {
reqwest::blocking::get(url)?.error_for_status()?;
}
/// File names for testing purpose
#[allow(dead_code)]
-pub static FILES: &[&str] = &[
- "test.txt",
- "test.html",
- "index.html",
- "test.mkv",
- #[cfg(not(windows))]
- "test \" \' & < >.csv",
- "😀.data",
- "⎙.mp4",
- "#[]{}()@!$&'`+,;= %20.test",
- #[cfg(unix)]
- ":?#[]{}<>()@!$&'`|*+,;= %20.test",
- #[cfg(not(windows))]
- "foo\\bar.test",
-];
+pub static FILES: &[&str] = &["test.txt", "test.html", "index.html", "😀.bin"];
/// Directory names for testing diretory don't exist
#[allow(dead_code)]
#[allow(dead_code)]
pub static DIRECTORIES: &[&str] = &["dira/", "dirb/", "dirc/", DIR_NO_INDEX];
-/// Name of a deeply nested file
-#[allow(dead_code)]
-pub static DEEPLY_NESTED_FILE: &str = "very/deeply/nested/test.rs";
-
/// Test fixture which creates a temporary directory with a few files and directories inside.
/// The directories also contain files.
#[fixture]
}
}
- tmpdir
- .child(&DEEPLY_NESTED_FILE)
- .write_str("File in a deeply nested directory.")
- .expect("Couldn't write to file");
tmpdir
}
let tmpdir = tmpdir();
let child = Command::cargo_bin("dufs")
.expect("Couldn't find test binary")
- .env("RUST_LOG", "false")
.arg(tmpdir.path())
.arg("-p")
.arg(port.to_string())
let tmpdir = tmpdir();
let child = Command::cargo_bin("dufs")
.expect("Couldn't find test binary")
- .env("RUST_LOG", "false")
.arg(tmpdir.path())
.arg("-p")
.arg(port.to_string())
#[rstest]
fn get_dir_search2(#[with(&["-A"])] server: TestServer) -> Result<(), Error> {
- let resp = reqwest::blocking::get(format!("{}?q={}", server.url(), "😀.data"))?;
+ let resp = reqwest::blocking::get(format!("{}?q={}", server.url(), "😀.bin"))?;
assert_eq!(resp.status(), 200);
let paths = utils::retrive_index_paths(&resp.text()?);
assert!(!paths.is_empty());
for p in paths {
- assert!(p.contains(&"😀.data"));
+ assert!(p.contains(&"😀.bin"));
}
Ok(())
}