Skip to content

Commit 53b9220

Browse files
authored
fix: force raw codec if requested (#644)
1 parent 3f74a12 commit 53b9220

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

iroh-gateway/src/client.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,18 @@ impl<T: ContentLoader + std::marker::Unpin> Client<T> {
9999
pub async fn retrieve_path_metadata(
100100
&self,
101101
path: iroh_resolver::resolver::Path,
102+
format: Option<ResponseFormat>,
102103
) -> Result<Out, String> {
103104
info!("retrieve path metadata {}", path);
105+
if let Some(f) = format {
106+
if f == ResponseFormat::Raw {
107+
return self
108+
.resolver
109+
.resolve_raw(path)
110+
.await
111+
.map_err(|e| e.to_string());
112+
}
113+
}
104114
self.resolver.resolve(path).await.map_err(|e| e.to_string())
105115
}
106116

@@ -116,7 +126,7 @@ impl<T: ContentLoader + std::marker::Unpin> Client<T> {
116126
let path_metadata = if let Some(path_metadata) = path_metadata {
117127
path_metadata
118128
} else {
119-
self.retrieve_path_metadata(path.clone()).await?
129+
self.retrieve_path_metadata(path.clone(), None).await?
120130
};
121131
let metadata = path_metadata.metadata().clone();
122132
record_ttfb_metrics(start_time, &metadata.source);

iroh-gateway/src/core.rs

+36
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,42 @@ mod tests {
396396
assert!(body.starts_with(b"<!DOCTYPE html>"));
397397
}
398398

399+
#[tokio::test]
400+
async fn test_raw_fetch() {
401+
let files = &[(
402+
"hello.txt".to_string(),
403+
Alphanumeric
404+
.sample_string(&mut SmallRng::seed_from_u64(42), 8 * 1024 * 1024)
405+
.bytes()
406+
.collect(),
407+
)];
408+
let large_file = &files[0].1;
409+
let test_setup = setup_test(false, files).await;
410+
411+
let res = do_request(
412+
"GET",
413+
&format!("localhost:{}", test_setup.gateway_addr.port()),
414+
&format!("/ipfs/{}/hello.txt", test_setup.root_cid),
415+
None,
416+
)
417+
.await;
418+
assert_eq!(http::StatusCode::OK, res.status());
419+
let body = hyper::body::to_bytes(res.into_body()).await.unwrap();
420+
assert_eq!(&body[..], large_file);
421+
422+
let res = do_request(
423+
"GET",
424+
&format!("localhost:{}", test_setup.gateway_addr.port()),
425+
&format!("/ipfs/{}/hello.txt?format=raw", test_setup.root_cid),
426+
None,
427+
)
428+
.await;
429+
assert_eq!(http::StatusCode::OK, res.status());
430+
let body = hyper::body::to_bytes(res.into_body()).await.unwrap();
431+
let ufs = iroh_unixfs::unixfs::UnixfsNode::decode(&test_setup.root_cid, body).unwrap();
432+
assert_eq!(ufs.typ().unwrap(), iroh_unixfs::unixfs::DataType::File);
433+
}
434+
399435
// TODO(b5) - refactor to return anyhow::Result<()>
400436
#[tokio::test]
401437
async fn test_fetch_car_recursive() {

iroh-gateway/src/handlers.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,15 @@ async fn request_preprocessing<T: ContentLoader + Unpin>(
180180
}
181181
}
182182

183-
let path_metadata = match state.client.retrieve_path_metadata(path.clone()).await {
183+
// parse query params
184+
let format = get_response_format(request_headers, &query_params.format)
185+
.map_err(|err| GatewayError::new(StatusCode::BAD_REQUEST, &err))?;
186+
187+
let path_metadata = match state
188+
.client
189+
.retrieve_path_metadata(path.clone(), Some(format.clone()))
190+
.await
191+
{
184192
Ok(metadata) => metadata,
185193
Err(e) => {
186194
if e == "offline" {
@@ -217,10 +225,6 @@ async fn request_preprocessing<T: ContentLoader + Unpin>(
217225
));
218226
}
219227

220-
// parse query params
221-
let format = get_response_format(request_headers, &query_params.format)
222-
.map_err(|err| GatewayError::new(StatusCode::BAD_REQUEST, &err))?;
223-
224228
if let Some(resp) = etag_check(request_headers, &CidOrDomain::Cid(*resolved_cid), &format) {
225229
return Ok(RequestPreprocessingResult::RespondImmediately(resp));
226230
}

iroh-resolver/src/resolver.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ impl<T: ContentLoader> Resolver<T> {
695695
let this = self.clone();
696696
self.resolve_recursive_mapped(root, None, move |cid, ctx| {
697697
let this = this.clone();
698-
async move { this.resolve_with_ctx(ctx, Path::from_cid(cid)).await }
698+
async move { this.resolve_with_ctx(ctx, Path::from_cid(cid), false).await }
699699
})
700700
}
701701

@@ -781,18 +781,35 @@ impl<T: ContentLoader> Resolver<T> {
781781
pub async fn resolve(&self, path: Path) -> Result<Out> {
782782
let ctx = LoaderContext::from_path(self.next_id(), self.session_closer.clone());
783783

784-
self.resolve_with_ctx(ctx, path).await
784+
self.resolve_with_ctx(ctx, path, false).await
785785
}
786786

787-
pub async fn resolve_with_ctx(&self, mut ctx: LoaderContext, path: Path) -> Result<Out> {
787+
/// Resolves through a given path, returning the [`Cid`] and raw bytes of the final leaf.
788+
/// Forces the RAW codec.
789+
#[tracing::instrument(skip(self))]
790+
pub async fn resolve_raw(&self, path: Path) -> Result<Out> {
791+
let ctx = LoaderContext::from_path(self.next_id(), self.session_closer.clone());
792+
793+
self.resolve_with_ctx(ctx, path, true).await
794+
}
795+
796+
pub async fn resolve_with_ctx(
797+
&self,
798+
mut ctx: LoaderContext,
799+
path: Path,
800+
force_raw: bool,
801+
) -> Result<Out> {
788802
// Resolve the root block.
789803
let (root_cid, loaded_cid) = self.resolve_root(&path, &mut ctx).await?;
790804
match loaded_cid.source {
791805
Source::Store(_) => inc!(ResolverMetrics::CacheHit),
792806
_ => inc!(ResolverMetrics::CacheMiss),
793807
}
794808

795-
let codec = Codec::try_from(root_cid.codec()).context("unknown codec")?;
809+
let codec = match force_raw {
810+
true => Codec::Raw,
811+
false => Codec::try_from(root_cid.codec()).context("unknown codec")?,
812+
};
796813

797814
match codec {
798815
Codec::DagPb => {

0 commit comments

Comments
 (0)