upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/http/mod.rs42
1 files changed, 39 insertions, 3 deletions
diff --git a/src/http/mod.rs b/src/http/mod.rs
index 9172e86..ffb1562 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -159,14 +159,23 @@ impl Service<Request<Incoming>> for HttpService {
159 .and_then(|v| v.to_str().ok()) 159 .and_then(|v| v.to_str().ok())
160 .map(|s| s.to_string()); 160 .map(|s| s.to_string());
161 161
162 // Extract Content-Encoding header to handle gzip-compressed request bodies
163 // Modern git clients send gzip-compressed POST bodies for efficiency
164 let content_encoding = req
165 .headers()
166 .get("content-encoding")
167 .and_then(|v| v.to_str().ok())
168 .map(|s| s.to_lowercase());
169
162 tracing::debug!( 170 tracing::debug!(
163 "Git request: {} {} (npub={}, id={}, subpath={}, protocol={:?})", 171 "Git request: {} {} (npub={}, id={}, subpath={}, protocol={:?}, encoding={:?})",
164 method, 172 method,
165 path, 173 path,
166 npub, 174 npub,
167 identifier, 175 identifier,
168 subpath, 176 subpath,
169 git_protocol 177 git_protocol,
178 content_encoding
170 ); 179 );
171 180
172 let repo_path = git::resolve_repo_path(&git_data_path, &npub, &identifier); 181 let repo_path = git::resolve_repo_path(&git_data_path, &npub, &identifier);
@@ -175,12 +184,39 @@ impl Service<Request<Incoming>> for HttpService {
175 184
176 return Box::pin(async move { 185 return Box::pin(async move {
177 // Collect request body once before the match statement 186 // Collect request body once before the match statement
178 let body_bytes = req 187 let raw_body = req
179 .collect() 188 .collect()
180 .await 189 .await
181 .map(|collected| collected.to_bytes()) 190 .map(|collected| collected.to_bytes())
182 .unwrap_or_else(|_| Bytes::new()); 191 .unwrap_or_else(|_| Bytes::new());
183 192
193 // Decompress gzip-encoded request bodies
194 // Git clients send Content-Encoding: gzip for POST requests
195 let body_bytes = if content_encoding.as_deref() == Some("gzip") {
196 use flate2::read::GzDecoder;
197 use std::io::Read;
198
199 let mut decoder = GzDecoder::new(&raw_body[..]);
200 let mut decompressed = Vec::new();
201 match decoder.read_to_end(&mut decompressed) {
202 Ok(_) => {
203 tracing::debug!(
204 "Decompressed gzip body: {} -> {} bytes",
205 raw_body.len(),
206 decompressed.len()
207 );
208 Bytes::from(decompressed)
209 }
210 Err(e) => {
211 tracing::warn!("Failed to decompress gzip body: {}", e);
212 // Fall back to raw body (might work if not actually gzip)
213 raw_body
214 }
215 }
216 } else {
217 raw_body
218 };
219
184 let result = match (method.as_ref(), subpath.as_str()) { 220 let result = match (method.as_ref(), subpath.as_str()) {
185 // GET /info/refs?service=git-upload-pack or git-receive-pack 221 // GET /info/refs?service=git-upload-pack or git-receive-pack
186 (m, sp) if m == Method::GET && sp.starts_with("info/refs") => { 222 (m, sp) if m == Method::GET && sp.starts_with("info/refs") => {