rustfs_rsc/
data.rs

1use std::pin::Pin;
2
3use bytes::{Bytes, BytesMut};
4use futures_core::Stream;
5use futures_util::StreamExt;
6use std::result::Result;
7
8use crate::{signer::sha256_hash, utils::EMPTY_CONTENT_SHA256};
9
10/// adding the `x-amz-content-sha256` header with one of the following values
11#[allow(unused)]
12pub(crate) enum PayloadHash {
13    /// This value is the actual checksum of your object and is only possible when you are uploading the data in a single chunk.
14    Checksum(String),
15    /// Use this when you are uploading the object as a single unsigned chunk.
16    Unsigned,
17    /// Use this when sending a payload over multiple chunks, and the chunks are signed using `AWS4-HMAC-SHA256`. This produces a SigV4 signature.
18    Streaming,
19    /// Use this when sending a payload over multiple chunks, and the chunks are signed using `AWS4-HMAC-SHA256`. This produces a SigV4 signature.
20    /// In addition, the digest for the chunks is included as a trailing header.
21    StreamingTrailer,
22    EmptySha256,
23}
24
25impl PayloadHash {
26    pub fn checksum(hash: String) -> Self {
27        Self::Checksum(hash)
28    }
29
30    pub fn as_str(&self) -> &str {
31        match self {
32            PayloadHash::Checksum(v) => v.as_str(),
33            PayloadHash::EmptySha256 => EMPTY_CONTENT_SHA256,
34            PayloadHash::Unsigned => "UNSIGNED-PAYLOAD",
35            PayloadHash::Streaming => "STREAMING-AWS4-HMAC-SHA256-PAYLOAD",
36            PayloadHash::StreamingTrailer => "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER",
37        }
38    }
39}
40
41/// Payload for http request
42pub enum Data<E> {
43    /// Transferring Payload in a Single Chunk
44    Bytes(Bytes),
45    /// Transferring Payload in Multiple Chunks, `usize` the total byte length of the stream.
46    Stream(
47        Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
48        usize,
49    ),
50}
51
52impl<E> Data<E> {
53    /// get an empty Bytes Data.
54    #[inline]
55    pub fn empty() -> Self {
56        Self::Bytes(Bytes::new())
57    }
58
59    /// convert Stream Data into Bytes Data
60    pub async fn convert(self) -> Result<Self, E> {
61        Ok(match self {
62            Data::Stream(mut s, l) => {
63                let mut buf = BytesMut::with_capacity(l);
64                while let Some(data) = s.next().await {
65                    buf.extend_from_slice(&data?);
66                }
67                Data::Bytes(buf.freeze())
68            }
69            _ => self,
70        })
71    }
72
73    #[inline]
74    pub fn len(&self) -> usize {
75        match self {
76            Data::Bytes(data) => data.len(),
77            Data::Stream(_, len) => len.clone(),
78        }
79    }
80
81    pub(crate) fn payload_hash(&self) -> PayloadHash {
82        match self {
83            Data::Stream(_, _) => PayloadHash::Streaming,
84            Data::Bytes(data) if data.len() == 0 => PayloadHash::EmptySha256,
85            Data::Bytes(data) => PayloadHash::checksum(sha256_hash(data)),
86        }
87    }
88}
89
90impl<E> Default for Data<E> {
91    fn default() -> Self {
92        Self::empty()
93    }
94}
95
96impl<E> From<Option<Bytes>> for Data<E> {
97    fn from(value: Option<Bytes>) -> Self {
98        match value {
99            Some(v) => Self::Bytes(v),
100            None => Self::empty(),
101        }
102    }
103}
104
105impl<E> From<Bytes> for Data<E> {
106    fn from(value: Bytes) -> Self {
107        Self::Bytes(value)
108    }
109}
110
111impl<E> From<String> for Data<E> {
112    fn from(value: String) -> Self {
113        Self::Bytes(value.into())
114    }
115}
116
117impl<E> From<&'static str> for Data<E> {
118    fn from(value: &'static str) -> Self {
119        Self::Bytes(value.into())
120    }
121}
122
123impl<E> From<Vec<u8>> for Data<E> {
124    fn from(value: Vec<u8>) -> Self {
125        Self::Bytes(value.into())
126    }
127}
128
129impl<E>
130    From<(
131        Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
132        usize,
133    )> for Data<E>
134{
135    fn from(
136        value: (
137            Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
138            usize,
139        ),
140    ) -> Self {
141        Self::Stream(value.0, value.1)
142    }
143}