diff options
-rw-r--r-- | src/main.rs | 111 |
1 files changed, 75 insertions, 36 deletions
diff --git a/src/main.rs b/src/main.rs index 34714b5..d8c0f1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,16 @@ extern crate actix; extern crate actix_web; -extern crate simplelog; extern crate base64; -#[macro_use] extern crate clap; +extern crate simplelog; +#[macro_use] +extern crate clap; use actix_web::http::header; -use actix_web::{server, App, fs, middleware, HttpRequest, HttpResponse, HttpMessage, Result}; use actix_web::middleware::{Middleware, Response}; -use simplelog::{TermLogger, LevelFilter, Config}; -use std::path::PathBuf; +use actix_web::{fs, middleware, server, App, HttpMessage, HttpRequest, HttpResponse, Result}; +use simplelog::{Config, LevelFilter, TermLogger}; use std::net::{IpAddr, Ipv4Addr}; +use std::path::PathBuf; enum BasicAuthError { Base64DecodeError, @@ -32,7 +33,9 @@ pub struct MiniserveConfig { } /// Decode a HTTP basic auth string into a tuple of username and password. -fn parse_basic_auth(authorization_header: &header::HeaderValue) -> Result<BasicAuthParams, BasicAuthError> { +fn parse_basic_auth( + authorization_header: &header::HeaderValue, +) -> Result<BasicAuthParams, BasicAuthError> { let basic_removed = authorization_header.to_str().unwrap().replace("Basic ", ""); let decoded = base64::decode(&basic_removed).map_err(|_| BasicAuthError::Base64DecodeError)?; let decoded_str = String::from_utf8_lossy(&decoded); @@ -40,7 +43,10 @@ fn parse_basic_auth(authorization_header: &header::HeaderValue) -> Result<BasicA if strings.len() != 2 { return Err(BasicAuthError::InvalidUsernameFormat); } - Ok(BasicAuthParams { username: strings[0].to_owned(), password: strings[1].to_owned() }) + Ok(BasicAuthParams { + username: strings[0].to_owned(), + password: strings[1].to_owned(), + }) } fn is_valid_path(path: String) -> Result<(), String> { @@ -48,19 +54,28 @@ fn is_valid_path(path: String) -> Result<(), String> { if path_to_check.is_file() || path_to_check.is_dir() { return Ok(()); } - Err(String::from("Path either doesn't exist or is not a regular file or a directory")) + Err(String::from( + "Path either doesn't exist or is not a regular file or a directory", + )) } fn is_valid_port(port: String) -> Result<(), String> { - port.parse::<u16>().and(Ok(())).or_else(|e| Err(e.to_string())) + port.parse::<u16>() + .and(Ok(())) + .or_else(|e| Err(e.to_string())) } fn is_valid_interface(interface: String) -> Result<(), String> { - interface.parse::<IpAddr>().and(Ok(())).or_else(|e| Err(e.to_string())) + interface + .parse::<IpAddr>() + .and(Ok(())) + .or_else(|e| Err(e.to_string())) } fn is_valid_auth(auth: String) -> Result<(), String> { - auth.find(':').ok_or("Correct format is username:password".to_owned()).map(|_| ()) + auth.find(':') + .ok_or("Correct format is username:password".to_owned()) + .map(|_| ()) } pub fn parse_args() -> MiniserveConfig { @@ -78,7 +93,7 @@ pub fn parse_args() -> MiniserveConfig { ) .arg( Arg::with_name("PATH") - .required(true) + .required(true) .validator(is_valid_path) .help("Which path to serve"), ) @@ -119,7 +134,10 @@ pub fn parse_args() -> MiniserveConfig { let auth = if let Some(auth_split) = matches.value_of("auth").map(|x| x.splitn(2, ':')) { let auth_vec = auth_split.collect::<Vec<&str>>(); if auth_vec.len() == 2 { - Some(BasicAuthParams { username: auth_vec[0].to_owned(), password: auth_vec[1].to_owned() }) + Some(BasicAuthParams { + username: auth_vec[0].to_owned(), + password: auth_vec[1].to_owned(), + }) } else { None } @@ -161,29 +179,39 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> { struct Auth; impl Middleware<MiniserveConfig> for Auth { - fn response(&self, req: &mut HttpRequest<MiniserveConfig>, resp: HttpResponse) -> Result<Response> { + fn response( + &self, + req: &mut HttpRequest<MiniserveConfig>, + resp: HttpResponse, + ) -> Result<Response> { if let Some(ref required_auth) = req.state().auth { if let Some(auth_headers) = req.headers().get(header::AUTHORIZATION) { let auth_req = match parse_basic_auth(auth_headers) { Ok(auth_req) => auth_req, - Err(BasicAuthError::Base64DecodeError) => - return Ok(Response::Done(HttpResponse::BadRequest() - .body(format!("Error decoding basic auth base64: '{}'", - auth_headers.to_str().unwrap())))), - Err(BasicAuthError::InvalidUsernameFormat) => - return Ok(Response::Done(HttpResponse::BadRequest() - .body("Invalid basic auth format"))), + Err(BasicAuthError::Base64DecodeError) => { + return Ok(Response::Done(HttpResponse::BadRequest().body(format!( + "Error decoding basic auth base64: '{}'", + auth_headers.to_str().unwrap() + )))) + } + Err(BasicAuthError::InvalidUsernameFormat) => { + return Ok(Response::Done( + HttpResponse::BadRequest().body("Invalid basic auth format"), + )) + } }; if auth_req.username != required_auth.username - || auth_req.password != required_auth.password { - let new_resp = HttpResponse::Forbidden() - .finish(); + || auth_req.password != required_auth.password + { + let new_resp = HttpResponse::Forbidden().finish(); return Ok(Response::Done(new_resp)); } } else { let new_resp = HttpResponse::Unauthorized() - .header(header::WWW_AUTHENTICATE, - header::HeaderValue::from_static("Basic realm=\"miniserve\"")) + .header( + header::WWW_AUTHENTICATE, + header::HeaderValue::from_static("Basic realm=\"miniserve\""), + ) .finish(); return Ok(Response::Done(new_resp)); } @@ -201,27 +229,38 @@ fn main() { let sys = actix::System::new("miniserve"); let inside_config = miniserve_config.clone(); - server::new( - move || App::with_state(inside_config.clone()) + server::new(move || { + App::with_state(inside_config.clone()) .middleware(Auth) .middleware(middleware::Logger::default()) - .configure(configure_app)) - .bind(format!("{}:{}", &miniserve_config.interface, miniserve_config.port)).expect("Couldn't bind server") - .shutdown_timeout(0) - .start(); + .configure(configure_app) + }).bind(format!( + "{}:{}", + &miniserve_config.interface, miniserve_config.port + )) + .expect("Couldn't bind server") + .shutdown_timeout(0) + .start(); // If the interface is 0.0.0.0, we'll change it to localhost so that clicking the link will // also work on Windows. Why can't Windows interpret 0.0.0.0? - let interface = if miniserve_config.interface == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { + let interface = if miniserve_config.interface == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { String::from("localhost") } else { format!("{}", miniserve_config.interface) }; let canon_path = miniserve_config.path.canonicalize().unwrap(); - println!("miniserve is serving your files at http://{interface}:{port}", interface=interface, port=miniserve_config.port); - println!("Currently serving path {path}", path=canon_path.to_string_lossy()); + println!( + "miniserve is serving your files at http://{interface}:{port}", + interface = interface, + port = miniserve_config.port + ); + println!( + "Currently serving path {path}", + path = canon_path.to_string_lossy() + ); println!("Quit by pressing CTRL-C"); - let _ = sys.run(); + let _ = sys.run(); } |