Skip to content

Commit 30de226

Browse files
committed
feature: support http static file server
1 parent 94db5d7 commit 30de226

File tree

9 files changed

+847
-29
lines changed

9 files changed

+847
-29
lines changed

Cargo.lock

Lines changed: 740 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ license = "MIT"
99

1010
[dependencies]
1111
anyhow = "1.0.86"
12+
axum = { version = "0.7.5", features = ["http2", "query", "tracing"] }
1213
base64 = "0.22.1"
1314
blake3 = "1.5.1"
1415
clap = { version = "4.5.7", features = ["derive"] }
@@ -18,4 +19,7 @@ rand = "0.8.5"
1819
serde = { version = "1.0.203", features = ["derive"] }
1920
serde_json = "1.0.118"
2021
serde_yml = "0.0.10"
22+
tokio = { version = "1.38.0", features = ["fs", "macros", "net", "rt", "rt-multi-thread"] }
23+
tracing = "0.1.40"
24+
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
2125
zxcvbn = "3.0.1" # zxcvbn is a password strength estimator based off of Dropbox’s zxcvbn library.

src/cli/http.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use clap::Parser;
2+
use std::path::PathBuf;
3+
4+
use super::verify_path;
5+
6+
#[derive(Debug, Parser)]
7+
pub enum HttpSubCommand {
8+
#[command(about = "Serve a directory over HTTP")]
9+
Serve(HttpServeOpts),
10+
}
11+
12+
#[derive(Debug, Parser)]
13+
pub struct HttpServeOpts {
14+
#[arg(short, long, value_parser = verify_path, default_value = ".")]
15+
pub dir: PathBuf,
16+
#[arg(short, long, default_value_t = 8080)]
17+
pub port: u16,
18+
}

src/cli/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ use self::genpass::GenPassOpts;
77
pub use self::{
88
base64::{Base64Format, Base64SubCommand},
99
csv::OutputFormat,
10+
http::HttpSubCommand,
1011
text::{TextSignFormat, TextSubCommand},
1112
};
1213

1314
mod base64;
1415
mod csv;
1516
mod genpass;
17+
mod http;
1618
mod text;
1719

1820
#[derive(Debug, Parser)]
@@ -32,6 +34,8 @@ pub enum SubCommand {
3234
Base64(Base64SubCommand),
3335
#[command(subcommand, about = "Message Sign, or Verify")]
3436
Text(TextSubCommand),
37+
#[command(subcommand, about = "Serve a directory over HTTP")]
38+
Http(HttpSubCommand),
3539
}
3640

3741
pub fn verify_file(filename: &str) -> Result<String, &'static str> {

src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
pub use cli::{Base64Format, Base64SubCommand, Opts, SubCommand, TextSignFormat, TextSubCommand};
1+
pub use cli::{
2+
Base64Format, Base64SubCommand, HttpSubCommand, Opts, SubCommand, TextSignFormat,
3+
TextSubCommand,
4+
};
25
pub use process::{
3-
process_csv, process_decode, process_encode, process_genpass, process_text_generate,
4-
process_text_sign, process_text_verify,
6+
process_csv, process_decode, process_encode, process_genpass, process_http_serve,
7+
process_text_generate, process_text_sign, process_text_verify,
58
};
69
pub use utils::*;
710

src/main.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ use clap::Parser;
1010
use zxcvbn::zxcvbn;
1111

1212
use rcli::{
13-
process_csv, process_decode, process_encode, process_genpass, process_text_generate,
14-
process_text_sign, process_text_verify, Base64SubCommand, Opts, SubCommand, TextSubCommand,
13+
process_csv, process_decode, process_encode, process_genpass, process_http_serve,
14+
process_text_generate, process_text_sign, process_text_verify, Base64SubCommand,
15+
HttpSubCommand, Opts, SubCommand, TextSubCommand,
1516
};
1617

17-
fn main() -> anyhow::Result<()> {
18+
#[tokio::main]
19+
async fn main() -> anyhow::Result<()> {
20+
tracing_subscriber::fmt::init();
1821
let opts = Opts::parse();
1922
match opts.cmd {
2023
SubCommand::Csv(opts) => {
@@ -73,6 +76,9 @@ fn main() -> anyhow::Result<()> {
7376
}
7477
}
7578
},
79+
SubCommand::Http(cmd) => match cmd {
80+
HttpSubCommand::Serve(opts) => process_http_serve(opts.dir, opts.port).await?,
81+
},
7682
}
7783
Ok(())
7884
}

src/process/http_serve.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use anyhow::Result;
2+
use axum::extract::{Path, State};
3+
use axum::http::StatusCode;
4+
use axum::routing::get;
5+
use axum::Router;
6+
use std::net::SocketAddr;
7+
use std::path::PathBuf;
8+
use std::sync::Arc;
9+
use tracing::{info, warn};
10+
11+
#[derive(Debug)]
12+
struct HttpServeState {
13+
path: PathBuf,
14+
}
15+
16+
pub async fn process_http_serve(path: PathBuf, port: u16) -> Result<()> {
17+
let addr = SocketAddr::from(([0, 0, 0, 0], port));
18+
info!("Serving: {:?} on {}", path.as_path(), addr);
19+
let state = HttpServeState { path };
20+
// axum router
21+
let router = Router::new()
22+
.route("/*path", get(file_handler))
23+
.with_state(Arc::new(state));
24+
25+
// run our app with hyper, listening globally on port 3000
26+
let listener = tokio::net::TcpListener::bind(addr).await?;
27+
28+
axum::serve(listener, router).await?;
29+
Ok(())
30+
}
31+
32+
async fn file_handler(
33+
State(state): State<Arc<HttpServeState>>,
34+
Path(path): Path<String>,
35+
) -> (StatusCode, String) {
36+
let p = std::path::Path::new(&state.path).join(path);
37+
info!("Reading file {:?}", p);
38+
if !p.exists() {
39+
(
40+
StatusCode::NOT_FOUND,
41+
format!("File {} Not Found", p.display()),
42+
)
43+
} else {
44+
match tokio::fs::read_to_string(p).await {
45+
Ok(content) => {
46+
info!("Read {} bytes", content.len());
47+
(StatusCode::OK, content)
48+
}
49+
Err(e) => {
50+
warn!("Error reading file: {:?}", e);
51+
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
52+
}
53+
}
54+
}
55+
}

src/process/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
mod b64;
2-
mod csv_convert;
3-
mod gen_pass;
4-
mod text;
5-
61
pub use b64::{process_decode, process_encode};
72
pub use csv_convert::process_csv;
83
pub use gen_pass::process_genpass;
4+
pub use http_serve::process_http_serve;
95
pub use text::{process_text_generate, process_text_sign, process_text_verify};
6+
7+
mod b64;
8+
mod csv_convert;
9+
mod gen_pass;
10+
mod http_serve;
11+
mod text;

src/test.http

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
### GET request to example server
2+
GET http://localhost:8080/Cargo.toml
3+
4+
###

0 commit comments

Comments
 (0)