From 85f1df81a1ea1159280c5b5b6cdb01b285a9e748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Sun, 16 Jun 2019 17:27:09 +0200 Subject: [PATCH] refactor with actix-web 1.0.0 * actix-web 1.0.0 brought some changes in how associated data is accessed, and how handlers are written. * static files are now a separate crate `actix-files`. * web::run now creates the App and the Server and runs the server. they really want to have HttpServer::new and App::new in the same scope (I couldn't find a proper signature for the create_app function) * replace .trim_right_matches (depreceated in rust 1.33) with .trim_end_matches https://github.com/actix/actix-web/blob/web-v1.0.0/MIGRATION.md --- Cargo.toml | 5 +++-- src/main.rs | 19 ++--------------- src/web.rs | 59 +++++++++++++++++++++++++++++++---------------------- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f6885a..335c36c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http-server" -version = "0.9.0" +version = "0.10.0" authors = ["Damjan Georgievski "] license = "MIT" readme = "README.md" @@ -8,7 +8,8 @@ homepage = "https://github.com/gdamjan/http-server-rs" edition = "2018" [dependencies] -actix-web = "0.7" +actix-web = "1.0" +actix-files = "0.1.1" bytes = "0.4" clap = "2" env_logger = "*" diff --git a/src/main.rs b/src/main.rs index 3ea74bd..1bde576 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,7 @@ -use actix_web::server; -use actix_web::actix; -use env_logger; -use log; -use clap; - mod channel; mod web; -fn main() -> Result<(), std::io::Error> { +fn main() -> std::io::Result<()> { let app = clap::App::new(clap::crate_name!()) .author(clap::crate_authors!("\n")) .version(clap::crate_version!()) @@ -42,14 +36,5 @@ fn main() -> Result<(), std::io::Error> { let root = std::path::PathBuf::from(chdir).canonicalize()?; std::env::set_current_dir(&root)?; - - let sys = actix::System::new("http_server_rs"); - - log::info!("Serving files from {:?}", root); - server::new(move || web::create_app(&root).unwrap()) - .bind(&bind_addr)? - .start(); - - let _ = sys.run(); - Ok(()) + web::run(&bind_addr, &root) } diff --git a/src/web.rs b/src/web.rs index e4cd9c4..3c7c55d 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,5 +1,6 @@ -use actix_web::{error, fs, App, HttpRequest, HttpResponse, Responder, middleware}; -use actix_web::dev::FromParam; +use actix_web::{error, HttpRequest, HttpResponse, Responder, web}; +use actix_web::dev::ServiceResponse; +use actix_files as fs; use futures::Stream; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use htmlescape::encode_minimal as escape_html_entity; @@ -8,26 +9,34 @@ use crate::channel; use std::fmt::Write; use std::path::PathBuf; -use std; -use bytes; -pub fn create_app(directory: &PathBuf) -> Result, error::Error> { - let root = directory.to_path_buf(); // practically makes a copy, so it can be used as state - let static_files = fs::StaticFiles::new(&root)? - .show_files_listing() - .files_listing_renderer(handle_directory); - let app = App::with_state(root) - .middleware(middleware::Logger::default()) - .resource(r"/{tail:.*}.tar", |r| r.get().f(handle_tar)) - .resource(r"/favicon.ico", |r| r.get().f(favicon_ico)) - .handler("/", static_files); - Ok(app) + +pub fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> { + let root = root.clone(); + actix_web::HttpServer::new(move || { + log::info!("Serving files from {:?}", &root); + + let static_files = fs::Files::new("/", &root) + .show_files_listing() + .files_listing_renderer(handle_directory); + + actix_web::App::new() + .data(root.clone()) + .wrap(actix_web::middleware::Logger::default()) + .service(web::resource(r"/{tail:.*}.tar").to(handle_tar)) + .service(web::resource(r"/favicon.ico").to(favicon_ico)) + .service(static_files) + }) + .bind(bind_addr)? + .workers(1) + .run() } + fn handle_directory<'a, 'b>( dir: &'a fs::Directory, - req: &'b HttpRequest, -) -> std::io::Result { + req: &'b HttpRequest, +) -> Result { let rd = std::fs::read_dir(&dir.path)?; @@ -39,7 +48,7 @@ fn handle_directory<'a, 'b>( paths.sort_by_key(|entry| (!optimistic_is_dir(entry), entry.file_name())); - let dir_tar_path = String::from(req.path().trim_right_matches('/')) + ".tar"; + let dir_tar_path = String::from(req.path().trim_end_matches('/')) + ".tar"; let tar_url = utf8_percent_encode(&dir_tar_path, DEFAULT_ENCODE_SET).to_string(); let mut body = String::new(); @@ -77,13 +86,15 @@ fn handle_directory<'a, 'b>( writeln!(html, "\n{}", body).unwrap(); writeln!(html, "").unwrap(); - Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html)) + let resp = HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html); + + Ok(ServiceResponse::new(req.clone(), resp)) } -fn handle_tar(req: &HttpRequest) -> impl Responder { - let root = req.state(); - let tail: String = req.match_info().query("tail")?; - let relpath = PathBuf::from_param(tail.trim_left_matches('/'))?; +fn handle_tar(req: HttpRequest) -> impl Responder { + let root = req.app_data::().unwrap(); + let tail = req.match_info().query("tail"); + let relpath = PathBuf::from(tail.trim_end_matches('/')); let fullpath = root.join(&relpath).canonicalize()?; if !(fullpath.is_dir()) { @@ -97,7 +108,7 @@ fn handle_tar(req: &HttpRequest) -> impl Responder { Ok(resp) } -fn favicon_ico(_req: &HttpRequest) -> impl Responder { +fn favicon_ico() -> impl Responder { HttpResponse::Ok() .content_type("image/png") .header("Cache-Control", "only-if-cached, max-age=86400")