diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs index 2c067d493..5bde5cf99 100644 --- a/dapps/src/apps/fetcher/installers.rs +++ b/dapps/src/apps/fetcher/installers.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use ethereum_types::H256; use fetch; use futures_cpupool::CpuPool; -use hash::keccak_buffer; +use hash::keccak_pipe; use mime_guess::Mime; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; @@ -55,15 +55,15 @@ fn write_response_and_check_hash( // Now write the response let mut file = io::BufWriter::new(fs::File::create(&content_path)?); let mut reader = io::BufReader::new(fetch::BodyReader::new(response)); - io::copy(&mut reader, &mut file)?; + let hash = keccak_pipe(&mut reader, &mut file)?; + let mut file = file.into_inner()?; file.flush()?; // Validate hash - // TODO [ToDr] calculate keccak in-flight while reading the response - let mut file = io::BufReader::new(fs::File::open(&content_path)?); - let hash = keccak_buffer(&mut file)?; if id == hash { - Ok((file.into_inner(), content_path)) + // The writing above changed the file Read position, which we need later. So we just create a new file handle + // here. + Ok((fs::File::open(&content_path)?, content_path)) } else { Err(ValidationError::HashMismatch { expected: id, @@ -266,3 +266,9 @@ impl From for ValidationError { ValidationError::Zip(err) } } + +impl From>> for ValidationError { + fn from(err: io::IntoInnerError>) -> Self { + ValidationError::Io(err.into()) + } +} diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index d00396501..526d22aed 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -52,7 +52,7 @@ pub fn write_keccak>(s: T, dest: &mut [u8]) { } } -pub fn keccak_buffer(r: &mut io::BufRead) -> Result { +pub fn keccak_pipe(r: &mut io::BufRead, w: &mut io::Write) -> Result { let mut output = [0u8; 32]; let mut input = [0u8; 1024]; let mut keccak = Keccak::new_keccak256(); @@ -64,12 +64,17 @@ pub fn keccak_buffer(r: &mut io::BufRead) -> Result { break; } keccak.update(&input[0..some]); + w.write_all(&input[0..some])?; } keccak.finalize(&mut output); Ok(output.into()) } +pub fn keccak_buffer(r: &mut io::BufRead) -> Result { + keccak_pipe(r, &mut io::sink()) +} + #[cfg(test)] mod tests { extern crate tempdir;