@adobe/git-server
Version:
serve a git repository over http(s)
106 lines (95 loc) • 3.77 kB
JavaScript
/*
* Copyright 2018 Adobe. All rights reserved.
* This file is licensed 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
;
const mime = require('mime');
const path = require('path');
const {
isCheckedOut, resolveBlob, createBlobReadStream, determineRefPathName, NotFoundError,
} = require('./git');
const { resolveRepositoryPath } = require('./utils');
/**
* Export the raw content handler (express middleware) through a parameterizable function
*
* @param {object} options configuration hash
* @returns {function(*, *, *)} handler function
*/
function createMiddleware(options) {
/**
* Express middleware handling raw content requests
*
* @param {Request} req Request object
* @param {Response} res Response object
* @param {callback} next next middleware in chain
*/
return async (req, res, next) => {
const { owner } = req.params;
const repoName = req.params.repo;
let refName = req.params.ref;
let fpath = req.params[0];
let repPath = resolveRepositoryPath(options, owner, repoName);
// temporary fix until isomorphic git can handle windows paths
// see https://github.com/isomorphic-git/isomorphic-git/issues/783
repPath = repPath.replace(/\\/g, '/');
// issue: #53: handle branch names containing '/' (e.g. 'foo/bar')
const parsed = await determineRefPathName(repPath, `${req.params.ref}/${req.params[0]}`);
if (parsed) {
refName = parsed.ref;
fpath = parsed.pathName;
}
// issue #68: lenient handling of redundant slashes in path
fpath = path.normalize(fpath);
// temporary fix until isomorphic git can handle windows paths
// see https://github.com/isomorphic-git/isomorphic-git/issues/783
fpath = fpath.replace(/\\/g, '/');
// remove leading slash
if (fpath.length && fpath[0] === '/') {
fpath = fpath.substr(1);
}
if (options.onRawRequest && typeof options.onRawRequest === 'function') {
try {
options.onRawRequest({
req,
repoPath: path.normalize(repPath),
filePath: path.normalize(fpath),
ref: refName,
});
} catch {
// ignore errors from listener
}
}
// project-helix/#187: serve modified content only if the requested ref is currently checked out
isCheckedOut(repPath, refName)
.then((serveUncommitted) => resolveBlob(repPath, refName, fpath, serveUncommitted))
.then((oid) => {
const mimeType = mime.getType(fpath) || 'text/plain';
res.writeHead(200, {
'Content-Type': mimeType,
ETag: oid,
// TODO: review cache-control header
'Cache-Control': 'max-age=0, private, must-revalidate',
});
createBlobReadStream(repPath, oid)
.then((stream) => stream.pipe(res));
})
.catch((err) => {
// TODO: use generic errors
if (err instanceof NotFoundError) {
options.logger.debug(`[rawHandler] resource not found: ${err.message}`);
res.status(404).send('not found.');
} else {
options.logger.debug(`[rawHandler] code: ${err.code} message: ${err.message} stack: ${err.stack}`);
next(err);
}
});
};
}
module.exports = createMiddleware;