From 457e296d90e2f7c2808e216f2ef0608b70f76553 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 7 Jan 2026 21:35:56 +0000 Subject: Add Git protocol v2 support to fix modern git client compatibility Modern git clients (2.51.0+) default to protocol v2 and send the Git-Protocol header. The server must pass this to git processes via the GIT_PROTOCOL environment variable for proper negotiation. Changes: - Extract Git-Protocol header in HTTP layer (src/http/mod.rs) - Pass git_protocol parameter through all handler functions - Set GIT_PROTOCOL env var when spawning git subprocesses - Update all tests to pass None for backward compatibility This fixes hangs/timeouts when modern git clients connect to the server. Fixes issue discovered in work/2025-01-07-pr-clone-tag-sync-investigation.md --- src/http/mod.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'src/http') diff --git a/src/http/mod.rs b/src/http/mod.rs index e2caf5d..9172e86 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -152,13 +152,21 @@ impl Service> for HttpService { let identifier = identifier.to_string(); let subpath = subpath.to_string(); + // Extract Git-Protocol header for protocol v2 support + let git_protocol = req + .headers() + .get("git-protocol") + .and_then(|v| v.to_str().ok()) + .map(|s| s.to_string()); + tracing::debug!( - "Git request: {} {} (npub={}, id={}, subpath={})", + "Git request: {} {} (npub={}, id={}, subpath={}, protocol={:?})", method, path, npub, identifier, - subpath + subpath, + git_protocol ); let repo_path = git::resolve_repo_path(&git_data_path, &npub, &identifier); @@ -185,7 +193,12 @@ impl Service> for HttpService { match service { Some(svc) => { - let result = git::handlers::handle_info_refs(repo_path, svc).await; + let result = git::handlers::handle_info_refs( + repo_path, + svc, + git_protocol.as_deref(), + ) + .await; // Track operation if let Some(ref m) = metrics_clone { let status = if result.is_ok() { "success" } else { "error" }; @@ -203,7 +216,12 @@ impl Service> for HttpService { // POST /git-upload-pack (clone/fetch) (m, "git-upload-pack") if m == Method::POST => { - let result = git::handlers::handle_upload_pack(repo_path, body_bytes).await; + let result = git::handlers::handle_upload_pack( + repo_path, + body_bytes, + git_protocol.as_deref(), + ) + .await; if let Some(ref m) = metrics_clone { let status = if result.is_ok() { "success" } else { "error" }; m.record_git_operation("clone", status); @@ -238,6 +256,7 @@ impl Service> for HttpService { &owner_pubkey_hex, purgatory.clone(), &git_data_path, + git_protocol.as_deref(), ) .await; -- cgit v1.2.3