Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
httpd: accept `/{rid}.git/{nid}/` paths as `GIT_NAMESPACE`-d remotes
Merged did:key:z6MkqbVu...UBAo opened 2 months ago

This patch adds support for serving /{rid}/{nid}/... paths as GIT_NAMESPACE-d http remotes, using {nid} as the namespace. Radicle’s on-disk repo storage already uses a Git-namespace-compatible notion for peer refs (refs/namespaces/*), so it is merely a matter of passing the right $GIT_NAMESPACE to the git http-backend process.

This way, it becomes possible to directly clone or fetch from URLs like http://httpd.domain.tld/z3gqcJUoA1n9HaHKufZs5FCSGazv5.git/z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM to directly access the given node’s ref namespace:

$ cd radicle-explorer
$ git remote add intelfx https://iris.radicle.xyz/z4V1sjrXqjvFdnCUbxPFqd5p4DtH5/z6MkqbVudjUcuxUmwWfW6U886CnhoX5wmkEDsAXju9F9UBAo
$ git pull intelfx work/httpd-git-namespace // or fetch, or ...

Instead of mucking about with

$ git fetch origin refs/namespaces/{nid}/refs/heads/{branch}:refs/heads/{branch}
1 file changed +14 -1 29b952a3 1b6d2830
modified radicle-httpd/src/git.rs
@@ -17,6 +17,7 @@ use flate2::write::GzDecoder;
use hyper::body::Buf as _;

use radicle::identity::RepoId;
+
use radicle::node::NodeId;
use radicle::profile::Profile;
use radicle::storage::{ReadRepository, ReadStorage};

@@ -49,8 +50,16 @@ async fn git_handler(
        }
    };

+
    let (nid, request): (Option<NodeId>, &str) = {
+
        let (first, rest) = request.split_once('/').unwrap_or((&request, ""));
+
        match first.parse::<NodeId>() {
+
            Ok(nid) => (Some(nid), rest),
+
            Err(_) => (None, &request),
+
        }
+
    };
+

    let (status, headers, body) = git_http_backend(
-
        &profile, method, headers, body, remote, rid, &request, query,
+
        &profile, method, headers, body, remote, rid, nid, &request, query,
    )
    .await?;

@@ -72,6 +81,7 @@ async fn git_http_backend(
    mut body: Bytes,
    remote: DualAddr,
    id: RepoId,
+
    nid: Option<NodeId>,
    path: &str,
    query: String,
) -> Result<(StatusCode, HashMap<String, Vec<String>>, Vec<u8>), Error> {
@@ -104,6 +114,9 @@ async fn git_http_backend(
    tracing::debug!("remote: {:?}", remote);

    let mut cmd = Command::new("git");
+
    if let Some(nid) = nid {
+
        cmd.env("GIT_NAMESPACE", nid.to_string());
+
    }
    let mut child = cmd
        // This is a workaround to allow fetching particular commits by their OID.
        // Otherwise, the client errors with "Server does not allow request for unadvertised object"