mirror of
https://github.com/flibusta-apps/books_downloader.git
synced 2025-12-06 06:55:37 +01:00
Add Content-Length header
This commit is contained in:
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -775,9 +775,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40"
|
checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
@@ -1080,9 +1080,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.4.1"
|
version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6"
|
checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
@@ -1150,7 +1150,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.3.3",
|
"regex-automata 0.3.4",
|
||||||
"regex-syntax 0.7.4",
|
"regex-syntax 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1165,9 +1165,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
|
checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -1297,18 +1297,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.175"
|
version = "1.0.178"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b"
|
checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.175"
|
version = "1.0.178"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4"
|
checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1317,9 +1317,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.103"
|
version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
|
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ serde_json = "1.0.96"
|
|||||||
axum = "0.6.18"
|
axum = "0.6.18"
|
||||||
translit = "0.5.0"
|
translit = "0.5.0"
|
||||||
zip = "0.6.6"
|
zip = "0.6.6"
|
||||||
tempfile = "3.5.0"
|
tempfile = "3.7.0"
|
||||||
bytes = "1.4.0"
|
bytes = "1.4.0"
|
||||||
axum-prometheus = "0.4.0"
|
axum-prometheus = "0.4.0"
|
||||||
base64 = "0.21.2"
|
base64 = "0.21.2"
|
||||||
|
|||||||
@@ -96,11 +96,14 @@ pub async fn download_chain<'a>(
|
|||||||
if is_zip && book.file_type.to_lowercase() == "html" {
|
if is_zip && book.file_type.to_lowercase() == "html" {
|
||||||
let filename = get_filename_by_book(book, file_type, true, false);
|
let filename = get_filename_by_book(book, file_type, true, false);
|
||||||
let filename_ascii = get_filename_by_book(book, file_type, true, true);
|
let filename_ascii = get_filename_by_book(book, file_type, true, true);
|
||||||
|
let data_size: usize = response.headers().get("Content-Length").unwrap().to_str().unwrap().parse().unwrap();
|
||||||
|
|
||||||
return Some(
|
return Some(
|
||||||
DownloadResult::new(
|
DownloadResult::new(
|
||||||
Data::Response(response),
|
Data::Response(response),
|
||||||
filename,
|
filename,
|
||||||
filename_ascii
|
filename_ascii,
|
||||||
|
data_size
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -108,19 +111,22 @@ pub async fn download_chain<'a>(
|
|||||||
if !is_zip && !final_need_zip && !converting {
|
if !is_zip && !final_need_zip && !converting {
|
||||||
let filename = get_filename_by_book(book, &book.file_type, false, false);
|
let filename = get_filename_by_book(book, &book.file_type, false, false);
|
||||||
let filename_ascii = get_filename_by_book(book, file_type, false, true);
|
let filename_ascii = get_filename_by_book(book, file_type, false, true);
|
||||||
|
let data_size: usize = response.headers().get("Content-Length").unwrap().to_str().unwrap().parse().unwrap();
|
||||||
|
|
||||||
return Some(
|
return Some(
|
||||||
DownloadResult::new(
|
DownloadResult::new(
|
||||||
Data::Response(response),
|
Data::Response(response),
|
||||||
filename,
|
filename,
|
||||||
filename_ascii,
|
filename_ascii,
|
||||||
|
data_size,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let unziped_temp_file = {
|
let (unziped_temp_file, data_size) = {
|
||||||
let temp_file_to_unzip_result = response_to_tempfile(&mut response).await;
|
let temp_file_to_unzip_result = response_to_tempfile(&mut response).await;
|
||||||
let temp_file_to_unzip = match temp_file_to_unzip_result {
|
let temp_file_to_unzip = match temp_file_to_unzip_result {
|
||||||
Some(v) => v,
|
Some(v) => v.0,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -131,7 +137,7 @@ pub async fn download_chain<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut clean_file = if converting {
|
let (mut clean_file, data_size) = if converting {
|
||||||
match convert_file(unziped_temp_file, file_type.to_string()).await {
|
match convert_file(unziped_temp_file, file_type.to_string()).await {
|
||||||
Some(mut response) => {
|
Some(mut response) => {
|
||||||
match response_to_tempfile(&mut response).await {
|
match response_to_tempfile(&mut response).await {
|
||||||
@@ -142,18 +148,20 @@ pub async fn download_chain<'a>(
|
|||||||
None => return None,
|
None => return None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unziped_temp_file
|
(unziped_temp_file, data_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
if !final_need_zip {
|
if !final_need_zip {
|
||||||
let t = SpooledTempAsyncRead::new(clean_file);
|
let t = SpooledTempAsyncRead::new(clean_file);
|
||||||
let filename = get_filename_by_book(book, file_type, false, false);
|
let filename = get_filename_by_book(book, file_type, false, false);
|
||||||
let filename_ascii = get_filename_by_book(book, file_type, false, true);
|
let filename_ascii = get_filename_by_book(book, file_type, false, true);
|
||||||
|
|
||||||
return Some(
|
return Some(
|
||||||
DownloadResult::new(
|
DownloadResult::new(
|
||||||
Data::SpooledTempAsyncRead(t),
|
Data::SpooledTempAsyncRead(t),
|
||||||
filename,
|
filename,
|
||||||
filename_ascii
|
filename_ascii,
|
||||||
|
data_size
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -161,15 +169,17 @@ pub async fn download_chain<'a>(
|
|||||||
let t_file_type = if file_type == "fb2zip" { "fb2" } else { file_type };
|
let t_file_type = if file_type == "fb2zip" { "fb2" } else { file_type };
|
||||||
let filename = get_filename_by_book(book, t_file_type, false, false);
|
let filename = get_filename_by_book(book, t_file_type, false, false);
|
||||||
match zip(&mut clean_file, filename.as_str()) {
|
match zip(&mut clean_file, filename.as_str()) {
|
||||||
Some(v) => {
|
Some((t_file, data_size)) => {
|
||||||
let t = SpooledTempAsyncRead::new(v);
|
let t = SpooledTempAsyncRead::new(t_file);
|
||||||
let filename = get_filename_by_book(book, file_type, true, false);
|
let filename = get_filename_by_book(book, file_type, true, false);
|
||||||
let filename_ascii = get_filename_by_book(book, file_type, true, true);
|
let filename_ascii = get_filename_by_book(book, file_type, true, true);
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
DownloadResult::new(
|
DownloadResult::new(
|
||||||
Data::SpooledTempAsyncRead(t),
|
Data::SpooledTempAsyncRead(t),
|
||||||
filename,
|
filename,
|
||||||
filename_ascii
|
filename_ascii,
|
||||||
|
data_size
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub struct DownloadResult {
|
|||||||
pub data: Data,
|
pub data: Data,
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
pub filename_ascii: String,
|
pub filename_ascii: String,
|
||||||
|
pub data_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_response_async_read(it: Response) -> impl AsyncRead {
|
pub fn get_response_async_read(it: Response) -> impl AsyncRead {
|
||||||
@@ -25,8 +26,8 @@ pub fn get_response_async_read(it: Response) -> impl AsyncRead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DownloadResult {
|
impl DownloadResult {
|
||||||
pub fn new(data: Data, filename: String, filename_ascii: String) -> Self {
|
pub fn new(data: Data, filename: String, filename_ascii: String, data_size: usize) -> Self {
|
||||||
Self { data, filename, filename_ascii }
|
Self { data, filename, filename_ascii, data_size }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_async_read(self) -> Pin<Box<dyn AsyncRead + Send>> {
|
pub fn get_async_read(self) -> Pin<Box<dyn AsyncRead + Send>> {
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ use bytes::Buf;
|
|||||||
use std::io::{Seek, SeekFrom, Write};
|
use std::io::{Seek, SeekFrom, Write};
|
||||||
|
|
||||||
|
|
||||||
pub async fn response_to_tempfile(res: &mut Response) -> Option<SpooledTempFile> {
|
pub async fn response_to_tempfile(res: &mut Response) -> Option<(SpooledTempFile, usize)> {
|
||||||
let mut tmp_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
let mut tmp_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
||||||
|
|
||||||
|
let mut data_size: usize = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
let chunk = res.chunk().await;
|
let chunk = res.chunk().await;
|
||||||
@@ -23,6 +25,8 @@ pub async fn response_to_tempfile(res: &mut Response) -> Option<SpooledTempFile>
|
|||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
data_size += data.len();
|
||||||
|
|
||||||
match tmp_file.write(data.chunk()) {
|
match tmp_file.write(data.chunk()) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
@@ -32,5 +36,5 @@ pub async fn response_to_tempfile(res: &mut Response) -> Option<SpooledTempFile>
|
|||||||
tmp_file.seek(SeekFrom::Start(0)).unwrap();
|
tmp_file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(tmp_file)
|
Some((tmp_file, data_size))
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::io::{Seek, SeekFrom};
|
use std::io::Seek;
|
||||||
|
|
||||||
use tempfile::SpooledTempFile;
|
use tempfile::SpooledTempFile;
|
||||||
use zip::write::FileOptions;
|
use zip::write::FileOptions;
|
||||||
|
|
||||||
|
|
||||||
pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option<SpooledTempFile> {
|
pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option<(SpooledTempFile, usize)> {
|
||||||
let mut archive = zip::ZipArchive::new(tmp_file).unwrap();
|
let mut archive = zip::ZipArchive::new(tmp_file).unwrap();
|
||||||
|
|
||||||
let file_type_lower = file_type.to_lowercase();
|
let file_type_lower = file_type.to_lowercase();
|
||||||
@@ -16,21 +16,21 @@ pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option<SpooledTempFi
|
|||||||
if filename.contains(&file_type_lower) || file.name().to_lowercase() == "elector" {
|
if filename.contains(&file_type_lower) || file.name().to_lowercase() == "elector" {
|
||||||
let mut output_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
let mut output_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
||||||
|
|
||||||
match std::io::copy(&mut file, &mut output_file) {
|
let size: usize = match std::io::copy(&mut file, &mut output_file) {
|
||||||
Ok(_) => (),
|
Ok(v) => v.try_into().unwrap(),
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
output_file.seek(SeekFrom::Start(0)).unwrap();
|
output_file.rewind().unwrap();
|
||||||
|
|
||||||
return Some(output_file);
|
return Some((output_file, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option<SpooledTempFile> {
|
pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option<(SpooledTempFile, usize)> {
|
||||||
let output_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
let output_file = tempfile::spooled_tempfile(5 * 1024 * 1024);
|
||||||
let mut archive = zip::ZipWriter::new(output_file);
|
let mut archive = zip::ZipWriter::new(output_file);
|
||||||
|
|
||||||
@@ -54,7 +54,9 @@ pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option<SpooledTemp
|
|||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
archive_result.seek(SeekFrom::Start(0)).unwrap();
|
let data_size: usize = archive_result.stream_position().unwrap().try_into().unwrap();
|
||||||
|
|
||||||
Some(archive_result)
|
archive_result.rewind().unwrap();
|
||||||
|
|
||||||
|
Some((archive_result, data_size))
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,7 @@ pub async fn download(
|
|||||||
|
|
||||||
let filename = data.filename.clone();
|
let filename = data.filename.clone();
|
||||||
let filename_ascii = data.filename_ascii.clone();
|
let filename_ascii = data.filename_ascii.clone();
|
||||||
|
let file_size = data.data_size;
|
||||||
|
|
||||||
let reader = data.get_async_read();
|
let reader = data.get_async_read();
|
||||||
let stream = ReaderStream::new(reader);
|
let stream = ReaderStream::new(reader);
|
||||||
@@ -52,6 +53,10 @@ pub async fn download(
|
|||||||
header::CONTENT_DISPOSITION,
|
header::CONTENT_DISPOSITION,
|
||||||
format!("attachment; filename={filename_ascii}"),
|
format!("attachment; filename={filename_ascii}"),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
header::CONTENT_LENGTH,
|
||||||
|
format!("{file_size}")
|
||||||
|
),
|
||||||
(
|
(
|
||||||
header::HeaderName::from_static("x-filename-b64"),
|
header::HeaderName::from_static("x-filename-b64"),
|
||||||
encoder.encode(filename),
|
encoder.encode(filename),
|
||||||
|
|||||||
Reference in New Issue
Block a user