httpd/raw: Stream the result of git archive

The result of `git archive` is written to memory and only then sent off
via the network.

Instead of buffering potentially large archives, stream the response
body.

Co-authored-by: Rūdolfs Ošiņš <rudolfs@osins.org>
This commit is contained in:
Lorenz Leutgeb
2026-06-11 13:07:03 +02:00
committed by Lorenz Leutgeb
co-authored by Rūdolfs Ošiņš
parent 3c5e970bad
commit 09cb50bbf1
2 changed files with 18 additions and 16 deletions
-4
View File
@@ -81,10 +81,6 @@ pub enum RawError {
#[error(transparent)]
Io(#[from] std::io::Error),
/// Archive error.
#[error("`git archive` exited with status {0}:\n{1}")]
Archive(ExitStatus, String),
/// Git error.
#[error(transparent)]
Git(#[from] radicle::git::raw::Error),
+18 -12
View File
@@ -1,4 +1,3 @@
use std::process::Command;
use std::str::FromStr;
use std::sync::Arc;
@@ -11,11 +10,15 @@ use axum::Router;
use hyper::HeaderMap;
use radicle_surf::blob::{Blob, BlobRef};
use radicle::git::raw::ErrorCode;
use radicle::git::Oid;
use radicle::prelude::RepoId;
use radicle::profile::Profile;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle_surf::Repository;
use tokio::io::BufReader;
use tokio::process::Command;
use tokio_util::io::ReaderStream;
use crate::api::query::RawQuery;
use crate::axum_extra::Path;
@@ -205,6 +208,14 @@ async fn archive_by_committish(
.into(),
};
if let Err(e) = repo.backend.find_object(oid.into(), None) {
return Err(if e.code() == ErrorCode::NotFound {
Error::NotFound
} else {
Error::Git(e)
});
}
// Build a prefix for the archive, which includes the
// refname (if one was given):
//
@@ -252,22 +263,17 @@ async fn archive_by_committish(
command.arg(format!("--prefix={prefix}/"));
}
let output = command
let mut child = command
.arg(oid.to_string())
.arg("--")
.current_dir(repo.path())
.output()?;
if !output.status.success() {
return Err(Error::Archive(
output.status,
String::from_utf8_lossy(&output.stderr).to_string(),
));
}
.stdout(std::process::Stdio::piped())
.spawn()?;
let mut response = response;
let body = response.body_mut();
*body = Body::from(output.stdout);
*response.body_mut() = Body::from_stream(ReaderStream::new(BufReader::new(
child.stdout.take().expect("stdout was captured"),
)));
Ok(response)
}