-use actix_web::{get, web, App, HttpRequest, HttpServer, Result};
+use std::path::Path;
+
+use actix_web::{get, web, App, HttpRequest, HttpServer, Responder, Result};
use actix_web::http::header;
use actix_web::middleware::Logger;
+use actix_files::{Files, NamedFile};
#[get("/hello/{name}")]
async fn hello(params: web::Path<String>, req: HttpRequest) -> Result<String> {
}
}
+#[get("/file/{path:.*}")]
+async fn static_file(params: web::Path<String>, req: HttpRequest) -> Result<impl Responder> {
+ let request_path = params.into_inner();
+ let disk_path = "../static/".to_string() + &request_path;
+
+ // if the client accepts gzip encoding, try that first
+ if let Some(accept_encoding) = req.headers().get(header::ACCEPT_ENCODING) {
+ if accept_encoding.to_str().unwrap().contains("gzip") {
+ let path_gz = disk_path.clone() + ".gz";
+ if Path::new(&path_gz).is_file() {
+ log::debug!("client accepts gzip encoding, sending pre-compressed file {}", &path_gz);
+ return Ok(NamedFile::open_async(path_gz).await?
+ .customize()
+ .insert_header(header::ContentEncoding::Gzip));
+ }
+ }
+ }
+
+ // uncompressed file
+ Ok(NamedFile::open_async(disk_path).await?.customize())
+}
+
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
HttpServer::new(|| {
App::new()
.service(hello)
- .service(actix_files::Files::new("/dir", "../static"))
+ .service(static_file)
+ .service(Files::new("/dir", "../static"))
.wrap(Logger::default())
})
.bind(("127.0.0.1", 3030))?
use actix_web::{App, body, test, web};
use actix_web::http::{header, StatusCode};
- use super::{hello};
+ use super::{hello, static_file};
#[actix_web::test]
async fn test_hello() {
let res = test::call_service(&app, req).await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
+
+ #[actix_web::test]
+ async fn test_static_file() {
+ // FIXME: duplicating the .service() call from main() here is super ugly, but it's hard to move that into a fn
+ let app = test::init_service(App::new().service(static_file)).await;
+
+ // uncompressed
+ let req = test::TestRequest::get().uri("/file/dir1/optzip.txt").to_request();
+ let res = test::call_service(&app, req).await;
+ assert!(res.status().is_success());
+ assert_eq!(body::to_bytes(res.into_body()).await.unwrap(),
+ web::Bytes::from_static(b"This file is available uncompressed or compressed\n\
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"));
+
+ // gzipped
+ let req = test::TestRequest::get()
+ .uri("/file/dir1/optzip.txt")
+ .insert_header((header::ACCEPT_ENCODING, "deflate, gzip"))
+ .to_request();
+ let res = test::call_service(&app, req).await;
+ assert!(res.status().is_success());
+ let res_bytes = body::to_bytes(res.into_body()).await.unwrap();
+ assert_eq!(res_bytes.len(), 63); // file size of ../static/dir1/optzip.txt.gz
+ assert_eq!(res_bytes[0], 31);
+ }
}