Skip to content

Commit 3f1f783

Browse files
authored
Added support for R2 Checksums to GET and PUT. (#460)
* Added support for R2 Checksums to GET and PUT. * Fixed some clippy warnings.
1 parent 9328b29 commit 3f1f783

File tree

5 files changed

+109
-8
lines changed

5 files changed

+109
-8
lines changed

worker-sys/src/types/r2.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod bucket;
2+
mod checksums;
23
mod http_metadata;
34
mod multipart_upload;
45
mod object;
@@ -8,6 +9,7 @@ mod range;
89
mod uploaded_part;
910

1011
pub use bucket::*;
12+
pub use checksums::*;
1113
pub use http_metadata::*;
1214
pub use multipart_upload::*;
1315
pub use object::*;

worker-sys/src/types/r2/checksums.rs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use js_sys::{ArrayBuffer, Object, Reflect, Uint8Array};
2+
use wasm_bindgen::JsCast;
3+
4+
#[derive(Debug, Clone)]
5+
pub struct R2Checksums {
6+
pub md5: Option<Vec<u8>>,
7+
pub sha1: Option<Vec<u8>>,
8+
pub sha256: Option<Vec<u8>>,
9+
pub sha384: Option<Vec<u8>>,
10+
pub sha512: Option<Vec<u8>>,
11+
}
12+
13+
impl R2Checksums {
14+
pub fn new() -> Self {
15+
Self {
16+
md5: None,
17+
sha1: None,
18+
sha256: None,
19+
sha384: None,
20+
sha512: None,
21+
}
22+
}
23+
}
24+
25+
fn get(obj: &Object, key: &str) -> Option<Vec<u8>> {
26+
let value = Reflect::get(obj, &key.into());
27+
if value.is_err() {
28+
return None;
29+
}
30+
31+
let value = value.unwrap().dyn_into::<ArrayBuffer>();
32+
if value.is_err() {
33+
return None;
34+
}
35+
36+
let array_buffer: ArrayBuffer = value.unwrap();
37+
38+
let uint8_array = Uint8Array::new(&array_buffer);
39+
let mut vec = vec![0; uint8_array.length() as usize];
40+
uint8_array.copy_to(&mut vec);
41+
Some(vec)
42+
}
43+
44+
impl From<Object> for R2Checksums {
45+
fn from(obj: Object) -> Self {
46+
Self {
47+
md5: get(&obj, "md5"),
48+
sha1: get(&obj, "sha1"),
49+
sha256: get(&obj, "sha256"),
50+
sha384: get(&obj, "sha384"),
51+
sha512: get(&obj, "sha512"),
52+
}
53+
}
54+
}
55+
56+
impl Default for R2Checksums {
57+
fn default() -> Self {
58+
Self::new()
59+
}
60+
}

worker-sys/src/types/r2/object.rs

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ extern "C" {
2929
#[wasm_bindgen(method, getter, js_name=httpMetadata)]
3030
pub fn http_metadata(this: &R2Object) -> R2HttpMetadata;
3131

32+
#[wasm_bindgen(method, getter)]
33+
pub fn checksums(this: &R2Object) -> js_sys::Object;
34+
3235
#[wasm_bindgen(method, getter, js_name=customMetadata)]
3336
pub fn custom_metadata(this: &R2Object) -> js_sys::Object;
3437

worker/src/r2/builder.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ pub struct PutOptionsBuilder<'bucket> {
153153
pub(crate) value: Data,
154154
pub(crate) http_metadata: Option<HttpMetadata>,
155155
pub(crate) custom_metadata: Option<HashMap<String, String>>,
156-
pub(crate) md5: Option<Vec<u8>>,
156+
pub(crate) checksum: Option<Vec<u8>>,
157+
pub(crate) checksum_algorithm: String,
157158
}
158159

159160
impl<'bucket> PutOptionsBuilder<'bucket> {
@@ -169,12 +170,37 @@ impl<'bucket> PutOptionsBuilder<'bucket> {
169170
self
170171
}
171172

172-
/// A md5 hash to use to check the received object’s integrity.
173-
pub fn md5(mut self, bytes: impl Into<Vec<u8>>) -> Self {
174-
self.md5 = Some(bytes.into());
173+
fn checksum_set(mut self, algorithm: &str, checksum: impl Into<Vec<u8>>) -> Self {
174+
self.checksum_algorithm = algorithm.into();
175+
self.checksum = Some(checksum.into());
175176
self
176177
}
177178

179+
/// A md5 hash to use to check the received object’s integrity.
180+
pub fn md5(self, bytes: impl Into<Vec<u8>>) -> Self {
181+
self.checksum_set("md5", bytes)
182+
}
183+
184+
/// A sha1 hash to use to check the received object’s integrity.
185+
pub fn sha1(self, bytes: impl Into<Vec<u8>>) -> Self {
186+
self.checksum_set("sha1", bytes)
187+
}
188+
189+
/// A sha256 hash to use to check the received object’s integrity.
190+
pub fn sha256(self, bytes: impl Into<Vec<u8>>) -> Self {
191+
self.checksum_set("sha256", bytes)
192+
}
193+
194+
/// A sha384 hash to use to check the received object’s integrity.
195+
pub fn sha384(self, bytes: impl Into<Vec<u8>>) -> Self {
196+
self.checksum_set("sha384", bytes)
197+
}
198+
199+
/// A sha512 hash to use to check the received object’s integrity.
200+
pub fn sha512(self, bytes: impl Into<Vec<u8>>) -> Self {
201+
self.checksum_set("sha512", bytes)
202+
}
203+
178204
/// Executes the PUT operation on the R2 bucket.
179205
pub async fn execute(self) -> Result<Object> {
180206
let value: JsValue = self.value.into();
@@ -195,11 +221,11 @@ impl<'bucket> PutOptionsBuilder<'bucket> {
195221
}
196222
None => JsValue::UNDEFINED,
197223
},
198-
"md5" => self.md5.map(|bytes| {
224+
self.checksum_algorithm => self.checksum.map(|bytes| {
199225
let arr = Uint8Array::new_with_length(bytes.len() as _);
200226
arr.copy_from(&bytes);
201227
arr.buffer()
202-
})
228+
}),
203229
}
204230
.into(),
205231
);

worker/src/r2/mod.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use js_sys::{JsString, Reflect, Uint8Array};
66
use wasm_bindgen::{JsCast, JsValue};
77
use wasm_bindgen_futures::JsFuture;
88
use worker_sys::{
9-
FixedLengthStream as EdgeFixedLengthStream, R2Bucket as EdgeR2Bucket,
9+
FixedLengthStream as EdgeFixedLengthStream, R2Bucket as EdgeR2Bucket, R2Checksums,
1010
R2MultipartUpload as EdgeR2MultipartUpload, R2Object as EdgeR2Object,
1111
R2ObjectBody as EdgeR2ObjectBody, R2Objects as EdgeR2Objects,
1212
R2UploadedPart as EdgeR2UploadedPart,
@@ -19,6 +19,7 @@ use crate::{
1919
mod builder;
2020

2121
/// An instance of the R2 bucket binding.
22+
#[derive(Clone)]
2223
pub struct Bucket {
2324
inner: EdgeR2Bucket,
2425
}
@@ -62,7 +63,8 @@ impl Bucket {
6263
value: value.into(),
6364
http_metadata: None,
6465
custom_metadata: None,
65-
md5: None,
66+
checksum: None,
67+
checksum_algorithm: "md5".into(),
6668
}
6769
}
6870

@@ -215,6 +217,14 @@ impl Object {
215217
.into()
216218
}
217219

220+
pub fn checksum(&self) -> R2Checksums {
221+
match &self.inner {
222+
ObjectInner::NoBody(inner) => inner.checksums(),
223+
ObjectInner::Body(inner) => inner.checksums(),
224+
}
225+
.into()
226+
}
227+
218228
pub fn custom_metadata(&self) -> Result<HashMap<String, String>> {
219229
let metadata = match &self.inner {
220230
ObjectInner::NoBody(inner) => inner.custom_metadata(),

0 commit comments

Comments
 (0)