#!/usr/bin/env python3 """A git smart-HTTP server for tests: `git http-backend` behind a plain HTTP server that also takes chunked request bodies (the hosted service streams its pushes). It stands in for git.coline.app and takes any credentials. Usage: git-server.py """ import http.server import os import subprocess import sys ROOT, PORT = sys.argv[1], int(sys.argv[2]) class Handler(http.server.BaseHTTPRequestHandler): protocol_version = "HTTP/1.1" def log_message(self, *args): pass def body(self): if self.headers.get("transfer-encoding", "").lower() == "chunked": out = bytearray() while True: size = int(self.rfile.readline().split(b";")[0].strip(), 16) if size == 0: while self.rfile.readline() not in (b"\r\n", b"\n", b""): pass return bytes(out) out += self.rfile.read(size) self.rfile.readline() length = int(self.headers.get("content-length") or 0) return self.rfile.read(length) if length else b"" def serve(self): path, _, query = self.path.partition("?") data = self.body() env = dict( os.environ, GIT_PROJECT_ROOT=ROOT, GIT_HTTP_EXPORT_ALL="1", REMOTE_USER="vcs", REQUEST_METHOD=self.command, PATH_INFO=path, QUERY_STRING=query, CONTENT_TYPE=self.headers.get("content-type", ""), CONTENT_LENGTH=str(len(data)), ) if self.headers.get("content-encoding"): env["HTTP_CONTENT_ENCODING"] = self.headers["content-encoding"] out = subprocess.run(["git", "http-backend"], input=data, env=env, capture_output=True).stdout sep = b"\r\n\r\n" if b"\r\n\r\n" in out else b"\n\n" head, _, body = out.partition(sep) status = 200 headers = [] for line in head.decode().splitlines(): key, _, value = line.partition(":") if key.lower() == "status": status = int(value.strip().split()[0]) elif key: headers.append((key, value.strip())) self.send_response(status) for key, value in headers: self.send_header(key, value) self.send_header("content-length", str(len(body))) self.end_headers() self.wfile.write(body) do_GET = serve do_POST = serve http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler).serve_forever()