From 9a9c7637f88a93c26d0a346ee054f94b73273205 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Tue, 8 Aug 2023 16:42:56 -0700 Subject: [PATCH] feat: add Content-Length headers when writing to a sphere. --- .../noosphere-core/src/data/headers/header.rs | 3 + rust/noosphere-sphere/src/content/write.rs | 13 +++- rust/noosphere-sphere/src/context.rs | 62 ++++++++++++++++++- 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/rust/noosphere-core/src/data/headers/header.rs b/rust/noosphere-core/src/data/headers/header.rs index 9a9ce3547..01e5245c8 100644 --- a/rust/noosphere-core/src/data/headers/header.rs +++ b/rust/noosphere-core/src/data/headers/header.rs @@ -1,6 +1,7 @@ use std::{convert::Infallible, fmt::Display, ops::Deref, str::FromStr}; pub enum Header { + ContentLength, ContentType, Proof, Author, @@ -23,6 +24,7 @@ impl FromStr for Header { fn from_str(s: &str) -> Result { Ok(match s.to_lowercase().as_str() { + "content-length" => Header::ContentLength, "content-type" => Header::ContentType, "file-extension" => Header::FileExtension, "proof" => Header::Proof, @@ -41,6 +43,7 @@ impl Deref for Header { fn deref(&self) -> &Self::Target { match self { + Header::ContentLength => "Content-Length", Header::ContentType => "Content-Type", Header::Proof => "Proof", Header::Author => "Author", diff --git a/rust/noosphere-sphere/src/content/write.rs b/rust/noosphere-sphere/src/content/write.rs index 2904d21e9..38e60af6b 100644 --- a/rust/noosphere-sphere/src/content/write.rs +++ b/rust/noosphere-sphere/src/content/write.rs @@ -158,7 +158,18 @@ where let body_cid = BodyChunkIpld::store_bytes(&bytes, self.sphere_context_mut().await?.db_mut()).await?; - self.link(slug, content_type, &body_cid, additional_headers) + let header = ( + Header::ContentLength.to_string(), + format!("{}", bytes.len()), + ); + let additional_headers = if let Some(mut headers) = additional_headers { + headers.push(header); + headers + } else { + vec![header] + }; + + self.link(slug, content_type, &body_cid, Some(additional_headers)) .await } diff --git a/rust/noosphere-sphere/src/context.rs b/rust/noosphere-sphere/src/context.rs index 93da7ff74..2a84e3dc2 100644 --- a/rust/noosphere-sphere/src/context.rs +++ b/rust/noosphere-sphere/src/context.rs @@ -257,10 +257,12 @@ mod tests { use noosphere_core::{ authority::{generate_capability, SphereAbility}, - data::{ContentType, LinkRecord, LINK_RECORD_FACT_NAME}, + data::{ContentType, Header, LinkRecord, LINK_RECORD_FACT_NAME}, tracing::initialize_tracing, }; + use noosphere_storage::Storage; + use serde_json::json; use ucan::builder::UcanBuilder; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test; @@ -273,6 +275,64 @@ mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn it_sets_content_length_and_type_on_write() -> Result<()> { + initialize_tracing(None); + + let (mut sphere_context, _) = + simulated_sphere_context(SimulationAccess::ReadWrite, None).await?; + + check_headers( + &mut sphere_context, + "note", + ContentType::Text, + "hello".as_ref(), + "5", + ) + .await?; + + check_headers( + &mut sphere_context, + "note", + ContentType::Json, + json!({"foo":true}).to_string().as_ref(), + "12", + ) + .await?; + + async fn check_headers( + sphere_context: &mut C, + slug: &str, + content_type: ContentType, + content: F, + expected_length: &str, + ) -> Result<()> + where + C: HasMutableSphereContext, + S: Storage + 'static, + F: crate::AsyncFileBody, + { + let db = sphere_context.sphere_context().await?.db().clone(); + let link = sphere_context + .write(slug, &content_type, content, None) + .await?; + let memo = link.load_from(&db).await?; + assert_eq!( + memo.headers, + vec![ + ( + Header::ContentLength.to_string(), + expected_length.to_owned() + ), + (Header::ContentType.to_string(), content_type.to_string()) + ] + ); + Ok(()) + } + Ok(()) + } + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn it_validates_slug_names_when_writing() -> Result<()> {