diff options
author | HampusM <hampus@hampusmat.com> | 2021-06-24 22:50:38 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2021-06-24 22:50:38 +0200 |
commit | a13786d6cc185822f5940582efde2349ef729145 (patch) | |
tree | 7d4f49b50fc30ced65c5661b22b027456b79948e /packages/server/src/git/http.ts | |
parent | 01e5d215dbc152e34ecd005111171457f87c235d (diff) |
Refactored the backend yet again
Diffstat (limited to 'packages/server/src/git/http.ts')
-rw-r--r-- | packages/server/src/git/http.ts | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/packages/server/src/git/http.ts b/packages/server/src/git/http.ts new file mode 100644 index 0000000..2d707cb --- /dev/null +++ b/packages/server/src/git/http.ts @@ -0,0 +1,84 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { IncomingMessage } from "http"; +import { Repository } from "./repository"; +import { Route } from "../fastify_types"; +import { join } from "path"; +import { spawn } from "child_process"; +import { verifyGitRequest } from "../api/util"; + +export type RequestInfo = { + repo: string, + url_path: string, + parsed_url: URL, + url_path_parts: string[], + is_discovery: boolean, + service: string | null, + content_type: string +} + +export interface Request extends FastifyRequest { + params: Route["Params"], +} + +function getRequestInfo(req: Request): RequestInfo { + const repo = req.params.repo + ".git"; + const url_path = req.url.replace(req.params.repo, repo); + + const parsed_url = new URL(`${req.protocol}://${req.hostname}${url_path}`); + const url_path_parts = parsed_url.pathname.split("/"); + + const is_discovery = (/\/info\/refs$/u).test(parsed_url.pathname); + + const service = is_discovery ? parsed_url.searchParams.get("service") : url_path_parts[url_path_parts.length - 1]; + + const content_type = `application/x-${service}-${is_discovery ? "advertisement" : "result"}`; + + return { + repo, + url_path, + parsed_url, + is_discovery, + url_path_parts, + service, + content_type + }; +} + +export function connect(repository: Repository, req: Request, reply: FastifyReply): void { + const request_info = getRequestInfo(req); + + const valid_request = verifyGitRequest(request_info); + if(valid_request.success === false && valid_request.code) { + reply.header("Content-Type", request_info.content_type); + reply.code(valid_request.code).send(valid_request.message); + return; + } + + reply.raw.writeHead(200, { "Content-Type": request_info.content_type }); + + const spawn_args = [ "--stateless-rpc", join(repository.base_dir, request_info.repo) ]; + if(request_info.is_discovery) { + spawn_args.push("--advertise-refs"); + } + + const git_pack = spawn(<string>request_info.service, spawn_args); + + if(request_info.is_discovery) { + const s = "# service=" + request_info.service + "\n"; + const n = (4 + s.length).toString(16); + reply.raw.write(Buffer.from((Array(4 - n.length + 1).join("0") + n + s) + "0000")); + } + else { + const request_body: IncomingMessage = req.raw; + + request_body.on("data", data => git_pack.stdin.write(data)); + request_body.on("close", () => git_pack.stdin.end()); + } + + git_pack.on("error", err => console.log(err)); + + git_pack.stderr.on("data", (stderr: Buffer) => console.log(stderr.toString())); + git_pack.stdout.on("data", data => reply.raw.write(data)); + + git_pack.on("close", () => reply.raw.end()); +}
\ No newline at end of file |