Skip to content

Commit 259360d

Browse files
committed
feat: add ETag headers to KV read responses
Expose the existing Blake3-256 content hash as an ETag header on KV read responses. The hash was already computed and stored during writes; this change threads it through InvocationOutcome::KvRead and sets ETag: "blake3-<hex>" in the HTTP response. Enables client-side caching for the TinyCloud CLI.
1 parent 356a9c5 commit 259360d

4 files changed

Lines changed: 15 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ aws-types = "0.49"
1616
aws-smithy-http = "0.49"
1717
base64 = "0.13"
1818
futures = { default-features = false, version = "0.3", features = ["alloc", "std"] }
19+
hex.workspace = true
1920
hyper = "0.14" # Prometheus server
2021
lazy_static = "1.4.0"
2122
opentelemetry = { version = "0.29.1" }

src/auth_guards.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rocket::{
1111
use serde::{Deserialize, Serialize};
1212
use std::collections::{BTreeMap, HashMap};
1313
use tinycloud_core::{
14+
hash::Hash,
1415
types::Metadata,
1516
util::{Capability, DelegationInfo},
1617
InvocationOutcome,
@@ -82,7 +83,8 @@ where
8283
InvocationOutcome::KvMetadata(meta) => meta.map(ObjectHeaders).respond_to(request),
8384
InvocationOutcome::KvWrite => ().respond_to(request),
8485
InvocationOutcome::KvRead(data) => {
85-
data.map(|(md, c)| KVResponse(c, md)).respond_to(request)
86+
data.map(|(md, hash, c)| KVResponse(c, md, hash))
87+
.respond_to(request)
8688
}
8789
InvocationOutcome::OpenSessions(sessions) => Json(
8890
sessions
@@ -170,11 +172,11 @@ impl<'r> Responder<'r, 'static> for ObjectHeaders {
170172
}
171173
}
172174

173-
pub struct KVResponse<R>(R, pub Metadata);
175+
pub struct KVResponse<R>(R, pub Metadata, pub Hash);
174176

175177
impl<R> KVResponse<R> {
176-
pub fn new(md: Metadata, reader: R) -> Self {
177-
Self(reader, md)
178+
pub fn new(md: Metadata, hash: Hash, reader: R) -> Self {
179+
Self(reader, md, hash)
178180
}
179181
}
180182

@@ -183,7 +185,9 @@ where
183185
R: 'static + AsyncRead + Send,
184186
{
185187
fn respond_to(self, r: &'r Request<'_>) -> rocket::response::Result<'static> {
188+
let etag = format!("\"blake3-{}\"", hex::encode(self.2.as_ref()));
186189
Ok(Response::build_from(ObjectHeaders(self.1).respond_to(r)?)
190+
.header(Header::new("ETag", etag))
187191
// must ensure that Metadata::respond_to does not set the body of the response
188192
.streamed_body(self.0.compat())
189193
.finalize())

tinycloud-core/src/db.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ pub enum InvocationOutcome<R> {
369369
KvDelete,
370370
KvMetadata(Option<Metadata>),
371371
KvWrite,
372-
KvRead(Option<(Metadata, Content<R>)>),
372+
KvRead(Option<(Metadata, Hash, Content<R>)>),
373373
OpenSessions(HashMap<Hash, DelegationInfo>),
374374
/// Ordered delegation chain from leaf to root
375375
DelegationChain(Vec<DelegationInfo>),
@@ -729,23 +729,24 @@ async fn get_kv<C: ConnectionTrait, B: ImmutableReadStore>(
729729
space_id: &SpaceId,
730730
key: &Path,
731731
// TODO version: Option<(i64, Hash, i64)>,
732-
) -> Result<Option<(Metadata, Content<B::Readable>)>, EitherError<DbErr, B::Error>> {
732+
) -> Result<Option<(Metadata, Hash, Content<B::Readable>)>, EitherError<DbErr, B::Error>> {
733733
let e = match get_kv_entity(db, space_id, key)
734734
.await
735735
.map_err(EitherError::A)?
736736
{
737737
Some(entry) => entry,
738738
None => return Ok(None),
739739
};
740+
let content_hash = e.value;
740741
let c = match store
741-
.read(space_id, &e.value)
742+
.read(space_id, &content_hash)
742743
.await
743744
.map_err(EitherError::B)?
744745
{
745746
Some(c) => c,
746747
None => return Ok(None),
747748
};
748-
Ok(Some((e.metadata, c)))
749+
Ok(Some((e.metadata, content_hash, c)))
749750
}
750751

751752
async fn get_kv_entity<C: ConnectionTrait>(

0 commit comments

Comments
 (0)