diff options
Diffstat (limited to 'src/listing.rs')
-rw-r--r-- | src/listing.rs | 76 |
1 files changed, 38 insertions, 38 deletions
diff --git a/src/listing.rs b/src/listing.rs index 2ffcf2f..ba2e58e 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -1,7 +1,7 @@ -use actix_web::http::StatusCode; -use actix_web::{fs, http, Body, FromRequest, HttpRequest, HttpResponse, Query, Result}; +use actix_web::{fs, Body, FromRequest, HttpRequest, HttpResponse, Query, Result}; use bytesize::ByteSize; -use futures::stream::once; +use failure::Fail; +use futures::Stream; use htmlescape::encode_minimal as escape_html_entity; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use serde::Deserialize; @@ -235,46 +235,46 @@ pub fn directory_listing<S>( let color_scheme = query_params.theme.unwrap_or(default_color_scheme); - if let Some(compression_method) = &query_params.download { + if let Some(compression_method) = query_params.download { log::info!( "Creating an archive ({extension}) of {path}...", extension = compression_method.extension(), path = &dir.path.display().to_string() ); - match compression_method.create_archive(&dir.path, skip_symlinks) { - Ok((filename, content)) => { - log::info!("{file} successfully created !", file = &filename); - Ok(HttpResponse::Ok() - .content_type(compression_method.content_type()) - .content_encoding(compression_method.content_encoding()) - .header("Content-Transfer-Encoding", "binary") - .header( - "Content-Disposition", - format!("attachment; filename={:?}", filename), - ) - .chunked() - .body(Body::Streaming(Box::new(once(Ok(content)))))) - } - Err(err) => { - errors::log_error_chain(err.to_string()); - Ok(HttpResponse::Ok() - .status(http::StatusCode::INTERNAL_SERVER_ERROR) - .body( - renderer::render_error( - &err.to_string(), - StatusCode::INTERNAL_SERVER_ERROR, - serve_path, - query_params.sort, - query_params.order, - color_scheme, - default_color_scheme, - false, - true, - ) - .into_string(), - )) + + let filename = format!( + "{}.{}", + dir.path.file_name().unwrap().to_str().unwrap(), + compression_method.extension() + ); + + // Create a pipe to connect the archive creation thread and the response. + // Include 10 messages of buffer for erratic connection speeds. + let (tx, rx) = futures::sync::mpsc::channel(10); + let pipe = crate::pipe::Pipe::new(tx); + + // Start the actual archive creation in a separate thread. + let dir = dir.path.to_path_buf(); + std::thread::spawn(move || { + if let Err(err) = compression_method.create_archive(dir, skip_symlinks, pipe) { + log::error!("Error during archive creation: {:?}", err); } - } + }); + + // `<rx as Stream>::Error == ()` but we want `actix_web::error::Error` + // It can't happen, so let's just please the type checker. + let rx = rx.map_err(|_| unreachable!("pipes never fail")); + + Ok(HttpResponse::Ok() + .content_type(compression_method.content_type()) + .content_encoding(compression_method.content_encoding()) + .header("Content-Transfer-Encoding", "binary") + .header( + "Content-Disposition", + format!("attachment; filename={:?}", filename), + ) + .chunked() + .body(Body::Streaming(Box::new(rx)))) } else { Ok(HttpResponse::Ok() .content_type("text/html; charset=utf-8") @@ -302,7 +302,7 @@ pub fn extract_query_parameters<S>(req: &HttpRequest<S>) -> QueryParameters { Ok(query) => QueryParameters { sort: query.sort, order: query.order, - download: query.download.clone(), + download: query.download, theme: query.theme, path: query.path.clone(), }, |