git_http_backend/actix/
refs.rs

1use crate::GitConfig;
2use actix_web::http::header::HeaderValue;
3use actix_web::http::StatusCode;
4use actix_web::{web, HttpRequest, HttpResponseBuilder, Responder};
5use std::process::Command;
6use tracing::info;
7
8pub async fn info_refs(request: HttpRequest, service: web::Data<impl GitConfig>) -> impl Responder {
9    let uri = request.uri();
10    let path = uri.path().to_string().replace("/info/refs", "");
11    let path = service.rewrite(path).await;
12    let query = uri.query().unwrap_or("");
13    let service = query.split('=').map(|x| x.to_string()).collect::<Vec<_>>();
14    let service = service[1].clone();
15    if !(service != "git-upload-pack" || service != "git-receive-pack") {
16        return Err(actix_web::error::ErrorUnsupportedMediaType(
17            "service not git-upload-pack",
18        ));
19    }
20    let service_name = service.replace("git-", "");
21    let version = request
22        .headers()
23        .get("Git-Protocol")
24        .unwrap_or(&HeaderValue::from_str("").unwrap())
25        .to_str()
26        .map(|s| s.to_string())
27        .unwrap_or("".to_string());
28    let mut cmd = Command::new("git");
29    cmd.arg(service_name.clone());
30    cmd.arg("--stateless-rpc");
31    cmd.arg("--advertise-refs");
32    cmd.arg(".");
33    cmd.current_dir(path);
34    if !version.is_empty() {
35        cmd.env("GIT_PROTOCOL", version.clone());
36    }
37
38    let output = match cmd.output() {
39        Ok(output) => {
40            info!("Command status: {:?}", output.status);
41            output
42        }
43        Err(e) => {
44            eprintln!("Error running command: {}", e);
45            return Err(actix_web::error::ErrorInternalServerError(
46                "Error running command",
47            ));
48        }
49    };
50    let mut resp = HttpResponseBuilder::new(StatusCode::OK);
51    resp.append_header((
52        "Content-Type",
53        format!("application/x-git-{}-advertisement", service_name),
54    ));
55    resp.append_header(("Pragma", "no-cache"));
56    resp.append_header(("Cache-Control", "no-cache, max-age=0, must-revalidate"));
57    resp.append_header(("Expires", "Fri, 01 Jan 1980 00:00:00 GMT"));
58
59    let mut body = String::new();
60
61    match service_name.as_str() {
62        "upload-pack" => {
63            body.push_str(&"001e# service=git-upload-pack\n".to_string());
64            body.push_str("0000");
65        }
66        "receive-pack" => {
67            body.push_str(&"001f# service=git-receive-pack\n".to_string());
68            body.push_str("0000");
69        }
70        _ => {}
71    }
72    body.push_str(&String::from_utf8(output.stdout).unwrap());
73    Ok(resp.body(body.as_bytes().to_vec()))
74}