diff --git a/src/api/s3_delete.rs b/src/api/s3_delete.rs
index 93271579..b243d982 100644
--- a/src/api/s3_delete.rs
+++ b/src/api/s3_delete.rs
@@ -80,11 +80,11 @@ pub async fn handle_delete_objects(
req: Request
,
content_sha256: Option,
) -> Result, Error> {
- let content_sha256 =
- content_sha256.ok_or_bad_request("Request content hash not signed, aborting.")?;
-
let body = hyper::body::to_bytes(req.into_body()).await?;
- verify_signed_content(content_sha256, &body[..])?;
+
+ if let Some(content_sha256) = content_sha256 {
+ verify_signed_content(content_sha256, &body[..])?;
+ }
let cmd_xml = roxmltree::Document::parse(std::str::from_utf8(&body)?)?;
let cmd = parse_delete_objects_xml(&cmd_xml).ok_or_bad_request("Invalid delete XML query")?;
diff --git a/src/api/s3_put.rs b/src/api/s3_put.rs
index 00771638..7ebbdb12 100644
--- a/src/api/s3_put.rs
+++ b/src/api/s3_put.rs
@@ -1,9 +1,7 @@
use std::collections::{BTreeMap, VecDeque};
-use std::pin::Pin;
use std::sync::Arc;
use chrono::{DateTime, NaiveDateTime, Utc};
-use futures::task;
use futures::{prelude::*, TryFutureExt};
use hyper::body::{Body, Bytes};
use hyper::{Request, Response};
@@ -24,8 +22,9 @@ use garage_model::version_table::*;
use crate::error::*;
use crate::s3_xml;
+use crate::signature::streaming::SignedPayloadStream;
+use crate::signature::verify_signed_content;
use crate::signature::LONG_DATETIME;
-use crate::signature::{streaming::check_streaming_payload_signature, verify_signed_content};
pub async fn handle_put(
garage: Arc,
@@ -59,6 +58,7 @@ pub async fn handle_put(
// Parse body of uploaded file
let (head, body) = req.into_parts();
+ let body = body.map_err(Error::from);
let body = if let Some(signature) = payload_seed_signature {
let secret_key = &api_key
@@ -76,11 +76,11 @@ pub async fn handle_put(
NaiveDateTime::parse_from_str(date, LONG_DATETIME).ok_or_bad_request("Invalid date")?;
let date: DateTime = DateTime::from_utc(date, Utc);
- SignedPayloadChunker::new(body, garage.clone(), date, secret_key, signature)
+ SignedPayloadStream::new(body, garage.clone(), date, secret_key, signature)?
.map_err(Error::from)
.boxed()
} else {
- body.map_err(Error::from).boxed()
+ body.boxed()
};
let mut chunker = StreamChunker::new(body, garage.config.block_size);
@@ -217,13 +217,13 @@ fn ensure_checksum_matches(
Ok(())
}
-async fn read_and_put_blocks, S: Stream- > + Unpin>(
+async fn read_and_put_blocks> + Unpin>(
garage: &Garage,
version: &Version,
part_number: u64,
first_block: Vec,
first_block_hash: Hash,
- chunker: &mut StreamChunker
,
+ chunker: &mut StreamChunker,
) -> Result<(u64, GenericArray, Hash), Error> {
let mut md5hasher = Md5::new();
let mut sha256hasher = Sha256::new();
@@ -245,9 +245,9 @@ async fn read_and_put_blocks, S: Stream- >
loop {
let (_, _, next_block) = futures::try_join!(
- put_curr_block.map_err(Into::into),
- put_curr_version_block.map_err(Into::into),
- chunker.next().map_err(Into::into)
+ put_curr_block.map_err(Error::from),
+ put_curr_version_block.map_err(Error::from),
+ chunker.next(),
)?;
if let Some(block) = next_block {
md5hasher.update(&block[..]);
@@ -308,214 +308,14 @@ async fn put_block_meta(
Ok(())
}
-mod payload {
- use std::fmt;
-
- pub struct Header {
- pub size: usize,
- pub signature: Box<[u8]>,
- }
-
- impl Header {
- pub fn parse(input: &[u8]) -> nom::IResult<&[u8], Self> {
- use nom::bytes::streaming::tag;
- use nom::character::streaming::hex_digit1;
- use nom::combinator::map_res;
- use nom::number::streaming::hex_u32;
-
- let (input, size) = hex_u32(input)?;
- let (input, _) = tag(";")(input)?;
-
- let (input, _) = tag("chunk-signature=")(input)?;
- let (input, data) = map_res(hex_digit1, hex::decode)(input)?;
-
- let (input, _) = tag("\r\n")(input)?;
-
- let header = Header {
- size: size as usize,
- signature: data.into_boxed_slice(),
- };
-
- Ok((input, header))
- }
- }
-
- impl fmt::Debug for Header {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Header")
- .field("size", &self.size)
- .field("signature", &hex::encode(&self.signature))
- .finish()
- }
- }
-}
-
-enum SignedPayloadChunkerError {
- Stream(StreamE),
- InvalidSignature,
- Message(String),
-}
-
-impl SignedPayloadChunkerError {
- fn message(msg: &str) -> Self {
- SignedPayloadChunkerError::Message(msg.into())
- }
-}
-
-impl From> for Error
-where
- StreamE: Into,
-{
- fn from(err: SignedPayloadChunkerError) -> Self {
- match err {
- SignedPayloadChunkerError::Stream(e) => e.into(),
- SignedPayloadChunkerError::InvalidSignature => {
- Error::BadRequest("Invalid payload signature".into())
- }
- SignedPayloadChunkerError::Message(e) => {
- Error::BadRequest(format!("Chunk format error: {}", e))
- }
- }
- }
-}
-
-impl From> for SignedPayloadChunkerError {
- fn from(err: nom::error::Error) -> Self {
- Self::message(err.code.description())
- }
-}
-
-#[pin_project::pin_project]
-struct SignedPayloadChunker
-where
- S: Stream- >,
-{
- #[pin]
- stream: S,
- buf: bytes::BytesMut,
- garage: Arc,
- datetime: DateTime,
- secret_key: String,
- previous_signature: Hash,
-}
-
-impl
SignedPayloadChunker
-where
- S: Stream- >,
-{
- fn new(
- stream: S,
- garage: Arc,
- datetime: DateTime,
- secret_key: &str,
- seed_signature: Hash,
- ) -> Self {
- Self {
- stream,
- buf: bytes::BytesMut::new(),
- garage,
- datetime,
- secret_key: secret_key.into(),
- previous_signature: seed_signature,
- }
- }
-}
-
-impl
Stream for SignedPayloadChunker
-where
- S: Stream- > + Unpin,
-{
- type Item = Result>;
-
- fn poll_next(
- self: Pin<&mut Self>,
- cx: &mut task::Context<'_>,
- ) -> task::Poll