upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/git/handlers.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-07 21:35:56 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-07 21:35:56 +0000
commit457e296d90e2f7c2808e216f2ef0608b70f76553 (patch)
tree8b6529cb9db3bb562842a4cfb0bf8c217ed7db1a /src/git/handlers.rs
parent0550b3229f35ef3ee125bac47d85bbd08d1250b1 (diff)
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
Diffstat (limited to 'src/git/handlers.rs')
-rw-r--r--src/git/handlers.rs10
1 files changed, 7 insertions, 3 deletions
diff --git a/src/git/handlers.rs b/src/git/handlers.rs
index ff55e34..017eee4 100644
--- a/src/git/handlers.rs
+++ b/src/git/handlers.rs
@@ -26,6 +26,7 @@ use crate::purgatory::Purgatory;
26pub async fn handle_info_refs( 26pub async fn handle_info_refs(
27 repo_path: PathBuf, 27 repo_path: PathBuf,
28 service: GitService, 28 service: GitService,
29 git_protocol: Option<&str>,
29) -> Result<Response<Full<Bytes>>, GitError> { 30) -> Result<Response<Full<Bytes>>, GitError> {
30 debug!( 31 debug!(
31 "Handling info/refs for {:?} with service {:?}", 32 "Handling info/refs for {:?} with service {:?}",
@@ -39,7 +40,7 @@ pub async fn handle_info_refs(
39 } 40 }
40 41
41 // Spawn git with --advertise-refs 42 // Spawn git with --advertise-refs
42 let mut git = GitSubprocess::spawn(service, &repo_path, true).map_err(|e| { 43 let mut git = GitSubprocess::spawn(service, &repo_path, true, git_protocol).map_err(|e| {
43 error!("Failed to spawn git process: {}", e); 44 error!("Failed to spawn git process: {}", e);
44 GitError::ProcessSpawnFailed(e) 45 GitError::ProcessSpawnFailed(e)
45 })?; 46 })?;
@@ -102,6 +103,7 @@ pub async fn handle_info_refs(
102pub async fn handle_upload_pack( 103pub async fn handle_upload_pack(
103 repo_path: PathBuf, 104 repo_path: PathBuf,
104 request_body: Bytes, 105 request_body: Bytes,
106 git_protocol: Option<&str>,
105) -> Result<Response<Full<Bytes>>, GitError> { 107) -> Result<Response<Full<Bytes>>, GitError> {
106 debug!("Handling upload-pack for {:?}", repo_path); 108 debug!("Handling upload-pack for {:?}", repo_path);
107 109
@@ -110,7 +112,7 @@ pub async fn handle_upload_pack(
110 } 112 }
111 113
112 // Spawn git upload-pack 114 // Spawn git upload-pack
113 let mut git = GitSubprocess::spawn(GitService::UploadPack, &repo_path, false) 115 let mut git = GitSubprocess::spawn(GitService::UploadPack, &repo_path, false, git_protocol)
114 .map_err(GitError::ProcessSpawnFailed)?; 116 .map_err(GitError::ProcessSpawnFailed)?;
115 117
116 // Write request to git's stdin 118 // Write request to git's stdin
@@ -181,6 +183,7 @@ pub async fn handle_upload_pack(
181/// * `identifier` - The repository identifier (d tag) for authorization lookup 183/// * `identifier` - The repository identifier (d tag) for authorization lookup
182/// * `owner_pubkey` - The owner's public key (hex) from the URL path, scoping authorization 184/// * `owner_pubkey` - The owner's public key (hex) from the URL path, scoping authorization
183/// * `git_data_path` - Base path for git repositories (for syncing to other owner repos) 185/// * `git_data_path` - Base path for git repositories (for syncing to other owner repos)
186/// * `git_protocol` - Optional Git protocol version (e.g., "version=2")
184#[allow(clippy::too_many_arguments)] 187#[allow(clippy::too_many_arguments)]
185pub async fn handle_receive_pack( 188pub async fn handle_receive_pack(
186 repo_path: PathBuf, 189 repo_path: PathBuf,
@@ -191,6 +194,7 @@ pub async fn handle_receive_pack(
191 owner_pubkey: &str, 194 owner_pubkey: &str,
192 purgatory: Arc<Purgatory>, 195 purgatory: Arc<Purgatory>,
193 git_data_path: &str, 196 git_data_path: &str,
197 git_protocol: Option<&str>,
194) -> Result<Response<Full<Bytes>>, GitError> { 198) -> Result<Response<Full<Bytes>>, GitError> {
195 debug!("Handling receive-pack for {:?}", repo_path); 199 debug!("Handling receive-pack for {:?}", repo_path);
196 200
@@ -236,7 +240,7 @@ pub async fn handle_receive_pack(
236 }; 240 };
237 241
238 // Spawn git receive-pack 242 // Spawn git receive-pack
239 let mut git = GitSubprocess::spawn(GitService::ReceivePack, &repo_path, false) 243 let mut git = GitSubprocess::spawn(GitService::ReceivePack, &repo_path, false, git_protocol)
240 .map_err(GitError::ProcessSpawnFailed)?; 244 .map_err(GitError::ProcessSpawnFailed)?;
241 245
242 // Write request to git's stdin 246 // Write request to git's stdin