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
This commit is contained in:
Дамјан Георгиевски 2019-06-16 17:27:09 +02:00
parent 6e76b4c5df
commit 85f1df81a1
3 changed files with 40 additions and 43 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "http-server" name = "http-server"
version = "0.9.0" version = "0.10.0"
authors = ["Damjan Georgievski <gdamjan@gmail.com>"] authors = ["Damjan Georgievski <gdamjan@gmail.com>"]
license = "MIT" license = "MIT"
readme = "README.md" readme = "README.md"
@ -8,7 +8,8 @@ homepage = "https://github.com/gdamjan/http-server-rs"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
actix-web = "0.7" actix-web = "1.0"
actix-files = "0.1.1"
bytes = "0.4" bytes = "0.4"
clap = "2" clap = "2"
env_logger = "*" env_logger = "*"

View file

@ -1,13 +1,7 @@
use actix_web::server;
use actix_web::actix;
use env_logger;
use log;
use clap;
mod channel; mod channel;
mod web; mod web;
fn main() -> Result<(), std::io::Error> { fn main() -> std::io::Result<()> {
let app = clap::App::new(clap::crate_name!()) let app = clap::App::new(clap::crate_name!())
.author(clap::crate_authors!("\n")) .author(clap::crate_authors!("\n"))
.version(clap::crate_version!()) .version(clap::crate_version!())
@ -42,14 +36,5 @@ fn main() -> Result<(), std::io::Error> {
let root = std::path::PathBuf::from(chdir).canonicalize()?; let root = std::path::PathBuf::from(chdir).canonicalize()?;
std::env::set_current_dir(&root)?; std::env::set_current_dir(&root)?;
web::run(&bind_addr, &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(())
} }

View file

@ -1,5 +1,6 @@
use actix_web::{error, fs, App, HttpRequest, HttpResponse, Responder, middleware}; use actix_web::{error, HttpRequest, HttpResponse, Responder, web};
use actix_web::dev::FromParam; use actix_web::dev::ServiceResponse;
use actix_files as fs;
use futures::Stream; use futures::Stream;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use htmlescape::encode_minimal as escape_html_entity; use htmlescape::encode_minimal as escape_html_entity;
@ -8,26 +9,34 @@ use crate::channel;
use std::fmt::Write; use std::fmt::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std;
use bytes;
pub fn create_app(directory: &PathBuf) -> Result<App<PathBuf>, error::Error> {
let root = directory.to_path_buf(); // practically makes a copy, so it can be used as state pub fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> {
let static_files = fs::StaticFiles::new(&root)? let root = root.clone();
.show_files_listing() actix_web::HttpServer::new(move || {
.files_listing_renderer(handle_directory); log::info!("Serving files from {:?}", &root);
let app = App::with_state(root)
.middleware(middleware::Logger::default()) let static_files = fs::Files::new("/", &root)
.resource(r"/{tail:.*}.tar", |r| r.get().f(handle_tar)) .show_files_listing()
.resource(r"/favicon.ico", |r| r.get().f(favicon_ico)) .files_listing_renderer(handle_directory);
.handler("/", static_files);
Ok(app) 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>( fn handle_directory<'a, 'b>(
dir: &'a fs::Directory, dir: &'a fs::Directory,
req: &'b HttpRequest<PathBuf>, req: &'b HttpRequest,
) -> std::io::Result<HttpResponse> { ) -> Result<ServiceResponse, std::io::Error> {
let rd = std::fs::read_dir(&dir.path)?; 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())); 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 tar_url = utf8_percent_encode(&dir_tar_path, DEFAULT_ENCODE_SET).to_string();
let mut body = String::new(); let mut body = String::new();
@ -77,13 +86,15 @@ fn handle_directory<'a, 'b>(
writeln!(html, "<body>\n{}</body>", body).unwrap(); writeln!(html, "<body>\n{}</body>", body).unwrap();
writeln!(html, "</html>").unwrap(); writeln!(html, "</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<PathBuf>) -> impl Responder { fn handle_tar(req: HttpRequest) -> impl Responder {
let root = req.state(); let root = req.app_data::<PathBuf>().unwrap();
let tail: String = req.match_info().query("tail")?; let tail = req.match_info().query("tail");
let relpath = PathBuf::from_param(tail.trim_left_matches('/'))?; let relpath = PathBuf::from(tail.trim_end_matches('/'));
let fullpath = root.join(&relpath).canonicalize()?; let fullpath = root.join(&relpath).canonicalize()?;
if !(fullpath.is_dir()) { if !(fullpath.is_dir()) {
@ -97,7 +108,7 @@ fn handle_tar(req: &HttpRequest<PathBuf>) -> impl Responder {
Ok(resp) Ok(resp)
} }
fn favicon_ico(_req: &HttpRequest<PathBuf>) -> impl Responder { fn favicon_ico() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
.content_type("image/png") .content_type("image/png")
.header("Cache-Control", "only-if-cached, max-age=86400") .header("Cache-Control", "only-if-cached, max-age=86400")