packages/kie-sandbox-accelerator-quarkus/dev-server/server.mjs (180 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import * as __http from "http"; import * as __url from "url"; import * as __path from "path"; import * as __fs from "fs"; import { spawn as __spawn } from "child_process"; import __serveStatic from "serve-static"; import __finalhandler from "finalhandler"; // // // // validate args const portArg = process.argv[2]; const port = Number.parseInt(portArg); if (isNaN(port)) { console.error(`[git-repo-http-dev-server] Invalid port number '${portArg}'.`); printUsage(); process.exit(1); } const contentRootArg = process.argv[3]; const contentRoot = __path.resolve(contentRootArg); if (!__fs.existsSync(contentRoot)) { console.error(`[git-repo-http-dev-server] Can't serve content from non-existent directory '${contentRoot}'.`); printUsage(); process.exit(1); } // // // // main const serveAsStaticContent = __serveStatic(contentRoot); __http .createServer((req, res) => { // bare git repos if (req.url?.split("/")[1].endsWith(".git")) { console.log(`[git-repo-http-dev-server] Received request for '${req.url}'...`); console.log(`[git-repo-http-dev-server] Serving as "smart" HTTP for Git.`); serveAsGitSmartHttp(req, res); } // static content else { console.log(`[git-repo-http-dev-server] Received request for '${req.url}'...`); console.log("[git-repo-http-dev-server] Serving as static content."); serveAsStaticContent(req, res, __finalhandler(req, res)); } }) .listen(port, () => { printSummary(); }); // // // // functions function serveAsGitSmartHttp(req, res) { const gitHttpBackend = __spawn("git", ["http-backend"], { env: getEnvForGitHttpBackend(req) }); req.pipe(gitHttpBackend.stdin); const buffers = { header: [], body: [], completedHeader: false, }; gitHttpBackend.stdout.on("data", (chunk) => writeData(chunk, buffers, res)); gitHttpBackend.on("close", () => { res.end(); }); } const gitHttpBackendVariableNames = [ "QUERY_STRING", "REMOTE_USER", "CONTENT_LENGTH", "HTTP_CONTENT_ENCODING", "REMOTE_USER", "REMOTE_ADDR", "GIT_COMMITTER_NAME", "GIT_COMMITTER_EMAIL", "CONTENT_TYPE", "PATH_INFO", "GIT_PROJECT_ROOT", "PATH_TRANSLATED", "SERVER_PROTOCOL", "REQUEST_METHOD", "GIT_HTTP_EXPORT_ALL", "GIT_HTTP_MAX_REQUEST_BUFFER", ]; function getEnvForGitHttpBackend(req) { const url = __url.parse(req.url); const envVars = {}; for (let header in req.headers) { const name = header.toUpperCase().replace(/-/g, "_"); if (gitHttpBackendVariableNames.includes(name)) { envVars[name] = req.headers[header]; } } envVars["GIT_PROJECT_ROOT"] = contentRoot; envVars["PATH_TRANSLATED"] = contentRoot + url.pathname; envVars["PATH_INFO"] = url.pathname; envVars["REQUEST_METHOD"] = req.method; envVars["GIT_HTTP_EXPORT_ALL"] = "1"; envVars["QUERY_STRING"] = url.query; return envVars; } // // // // plumbing methods function writeData(chunk, buffers, res) { if (buffers.completedHeader) { res.write(chunk); } else { buffers.completedHeader = readMaybeHeaderBuffer(chunk, buffers); if (buffers.completedHeader) { writeHeader(buffers.header, res); writeBody(buffers.body, res); } } } function writeHeader(header, res) { const headerLines = Buffer.concat(header).toString().split("\r\n"); for (let headerLine of headerLines) { const headerSplit = headerLine.split(":"); const headerKey = headerSplit[0]; const headerVal = headerSplit[1]; res.setHeader(headerKey, headerVal); } } function writeBody(body, res) { body.forEach((b) => res.write(b)); } function readMaybeHeaderBuffer(nextBuffer, buffers) { const length = Buffer.from("\r\n\r\n", "utf-8").length; const offset = nextBuffer.indexOf("\r\n\r\n", 0, "utf-8"); if (offset <= 0) { return false; } const headerLines = nextBuffer.slice(0, offset); buffers.header.push(headerLines); buffers.body.push(nextBuffer.slice(offset + length)); return true; } // logs function printSummary() { const dirs = __fs.readdirSync(contentRoot); console.log(`[git-repo-http-dev-server] Starting...`); const bareGitRepoDirs = dirs.filter((s) => s.endsWith(".git")); console.log(`[git-repo-http-dev-server] Found ${bareGitRepoDirs.length} bare Git repo(s):`); bareGitRepoDirs.forEach((d) => console.log( `[git-repo-http-dev-server] ./${__path.join(__path.relative(".", contentRoot), d)} (clone with 'git clone http://localhost:${port}/${d}')` ) ); const staticContentDirs = dirs.filter((s) => !s.endsWith(".git")); console.log(`[git-repo-http-dev-server] Found ${staticContentDirs.length} static content dir(s):`); staticContentDirs.forEach((d) => console.log( `[git-repo-http-dev-server] ./${__path.join(__path.relative(".", contentRoot), d)}/ (access via http://localhost:${port}/${d}/*)` ) ); console.log(`[git-repo-http-dev-server] Listening to HTTP port ${port}.`); console.log(`[git-repo-http-dev-server] ========================================`); } function printUsage() { console.error(`[git-repo-http-dev-server] Usage: node server.mjs [port] [content-root-path]`); }