diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-07 21:35:56 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-07 21:35:56 +0000 |
| commit | 457e296d90e2f7c2808e216f2ef0608b70f76553 (patch) | |
| tree | 8b6529cb9db3bb562842a4cfb0bf8c217ed7db1a /src/http/mod.rs | |
| parent | 0550b3229f35ef3ee125bac47d85bbd08d1250b1 (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/http/mod.rs')
| -rw-r--r-- | src/http/mod.rs | 27 |
1 files changed, 23 insertions, 4 deletions
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<Request<Incoming>> for HttpService { | |||
| 152 | let identifier = identifier.to_string(); | 152 | let identifier = identifier.to_string(); |
| 153 | let subpath = subpath.to_string(); | 153 | let subpath = subpath.to_string(); |
| 154 | 154 | ||
| 155 | // Extract Git-Protocol header for protocol v2 support | ||
| 156 | let git_protocol = req | ||
| 157 | .headers() | ||
| 158 | .get("git-protocol") | ||
| 159 | .and_then(|v| v.to_str().ok()) | ||
| 160 | .map(|s| s.to_string()); | ||
| 161 | |||
| 155 | tracing::debug!( | 162 | tracing::debug!( |
| 156 | "Git request: {} {} (npub={}, id={}, subpath={})", | 163 | "Git request: {} {} (npub={}, id={}, subpath={}, protocol={:?})", |
| 157 | method, | 164 | method, |
| 158 | path, | 165 | path, |
| 159 | npub, | 166 | npub, |
| 160 | identifier, | 167 | identifier, |
| 161 | subpath | 168 | subpath, |
| 169 | git_protocol | ||
| 162 | ); | 170 | ); |
| 163 | 171 | ||
| 164 | let repo_path = git::resolve_repo_path(&git_data_path, &npub, &identifier); | 172 | let repo_path = git::resolve_repo_path(&git_data_path, &npub, &identifier); |
| @@ -185,7 +193,12 @@ impl Service<Request<Incoming>> for HttpService { | |||
| 185 | 193 | ||
| 186 | match service { | 194 | match service { |
| 187 | Some(svc) => { | 195 | Some(svc) => { |
| 188 | let result = git::handlers::handle_info_refs(repo_path, svc).await; | 196 | let result = git::handlers::handle_info_refs( |
| 197 | repo_path, | ||
| 198 | svc, | ||
| 199 | git_protocol.as_deref(), | ||
| 200 | ) | ||
| 201 | .await; | ||
| 189 | // Track operation | 202 | // Track operation |
| 190 | if let Some(ref m) = metrics_clone { | 203 | if let Some(ref m) = metrics_clone { |
| 191 | let status = if result.is_ok() { "success" } else { "error" }; | 204 | let status = if result.is_ok() { "success" } else { "error" }; |
| @@ -203,7 +216,12 @@ impl Service<Request<Incoming>> for HttpService { | |||
| 203 | 216 | ||
| 204 | // POST /git-upload-pack (clone/fetch) | 217 | // POST /git-upload-pack (clone/fetch) |
| 205 | (m, "git-upload-pack") if m == Method::POST => { | 218 | (m, "git-upload-pack") if m == Method::POST => { |
| 206 | let result = git::handlers::handle_upload_pack(repo_path, body_bytes).await; | 219 | let result = git::handlers::handle_upload_pack( |
| 220 | repo_path, | ||
| 221 | body_bytes, | ||
| 222 | git_protocol.as_deref(), | ||
| 223 | ) | ||
| 224 | .await; | ||
| 207 | if let Some(ref m) = metrics_clone { | 225 | if let Some(ref m) = metrics_clone { |
| 208 | let status = if result.is_ok() { "success" } else { "error" }; | 226 | let status = if result.is_ok() { "success" } else { "error" }; |
| 209 | m.record_git_operation("clone", status); | 227 | m.record_git_operation("clone", status); |
| @@ -238,6 +256,7 @@ impl Service<Request<Incoming>> for HttpService { | |||
| 238 | &owner_pubkey_hex, | 256 | &owner_pubkey_hex, |
| 239 | purgatory.clone(), | 257 | purgatory.clone(), |
| 240 | &git_data_path, | 258 | &git_data_path, |
| 259 | git_protocol.as_deref(), | ||
| 241 | ) | 260 | ) |
| 242 | .await; | 261 | .await; |
| 243 | 262 | ||