feat: add api to get the hash of a file (#375)
This commit is contained in:
parent
a277698322
commit
9353b2e759
4 changed files with 55 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -507,6 +507,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha-crypt",
|
||||
"sha2",
|
||||
"smart-default",
|
||||
"socket2",
|
||||
"tokio",
|
||||
|
|
|
@ -52,6 +52,7 @@ hyper-util = { version = "0.1", features = ["server-auto", "tokio"] }
|
|||
http-body-util = "0.1"
|
||||
bytes = "1.5"
|
||||
pin-project-lite = "0.2"
|
||||
sha2 = "0.10.8"
|
||||
|
||||
[features]
|
||||
default = ["tls"]
|
||||
|
|
|
@ -29,6 +29,7 @@ use hyper::{
|
|||
Method, StatusCode, Uri,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
|
@ -307,6 +308,8 @@ impl Server {
|
|||
} else if query_params.contains_key("view") {
|
||||
self.handle_edit_file(path, DataKind::View, head_only, user, &mut res)
|
||||
.await?;
|
||||
} else if query_params.contains_key("hash") {
|
||||
self.handle_hash_file(path, head_only, &mut res).await?;
|
||||
} else {
|
||||
self.handle_send_file(path, headers, head_only, &mut res)
|
||||
.await?;
|
||||
|
@ -915,6 +918,24 @@ impl Server {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_hash_file(
|
||||
&self,
|
||||
path: &Path,
|
||||
head_only: bool,
|
||||
res: &mut Response,
|
||||
) -> Result<()> {
|
||||
let output = sha256_file(path).await?;
|
||||
res.headers_mut()
|
||||
.typed_insert(ContentType::from(mime_guess::mime::TEXT_HTML_UTF_8));
|
||||
res.headers_mut()
|
||||
.typed_insert(ContentLength(output.as_bytes().len() as u64));
|
||||
if head_only {
|
||||
return Ok(());
|
||||
}
|
||||
*res.body_mut() = body_full(output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_propfind_dir(
|
||||
&self,
|
||||
path: &Path,
|
||||
|
@ -1716,3 +1737,20 @@ fn parse_upload_offset(headers: &HeaderMap<HeaderValue>, size: u64) -> Result<Op
|
|||
let (start, _) = parse_range(value, size).ok_or_else(err)?;
|
||||
Ok(Some(start))
|
||||
}
|
||||
|
||||
async fn sha256_file(path: &Path) -> Result<String> {
|
||||
let mut file = fs::File::open(path).await?;
|
||||
let mut hasher = Sha256::new();
|
||||
let mut buffer = [0u8; 8192];
|
||||
|
||||
loop {
|
||||
let bytes_read = file.read(&mut buffer).await?;
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..bytes_read]);
|
||||
}
|
||||
|
||||
let result = hasher.finalize();
|
||||
Ok(format!("{:x}", result))
|
||||
}
|
||||
|
|
|
@ -189,6 +189,21 @@ fn head_file(server: TestServer) -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn hash_file(server: TestServer) -> Result<(), Error> {
|
||||
let resp = reqwest::blocking::get(format!("{}index.html?hash", server.url()))?;
|
||||
assert_eq!(
|
||||
resp.headers().get("content-type").unwrap(),
|
||||
"text/html; charset=utf-8"
|
||||
);
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_eq!(
|
||||
resp.text()?,
|
||||
"c8dd395e3202674b9512f7b7f956e0d96a8ba8f572e785b0d5413ab83766dbc4"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn get_file_404(server: TestServer) -> Result<(), Error> {
|
||||
let resp = reqwest::blocking::get(format!("{}404", server.url()))?;
|
||||
|
|
Loading…
Reference in a new issue