UNPKG

3.77 kBJavaScriptView Raw
1/*
2 * Copyright 2018 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12
13'use strict';
14
15const mime = require('mime');
16const path = require('path');
17
18const {
19 isCheckedOut, resolveBlob, createBlobReadStream, determineRefPathName, NotFoundError,
20} = require('./git');
21const { resolveRepositoryPath } = require('./utils');
22
23/**
24 * Export the raw content handler (express middleware) through a parameterizable function
25 *
26 * @param {object} options configuration hash
27 * @returns {function(*, *, *)} handler function
28 */
29function createMiddleware(options) {
30 /**
31 * Express middleware handling raw content requests
32 *
33 * @param {Request} req Request object
34 * @param {Response} res Response object
35 * @param {callback} next next middleware in chain
36 */
37 return async (req, res, next) => {
38 const { owner } = req.params;
39 const repoName = req.params.repo;
40 let refName = req.params.ref;
41 let fpath = req.params[0];
42
43 let repPath = resolveRepositoryPath(options, owner, repoName);
44 // temporary fix until isomorphic git can handle windows paths
45 // see https://github.com/isomorphic-git/isomorphic-git/issues/783
46 repPath = repPath.replace(/\\/g, '/');
47
48 // issue: #53: handle branch names containing '/' (e.g. 'foo/bar')
49 const parsed = await determineRefPathName(repPath, `${req.params.ref}/${req.params[0]}`);
50 if (parsed) {
51 refName = parsed.ref;
52 fpath = parsed.pathName;
53 }
54
55 // issue #68: lenient handling of redundant slashes in path
56 fpath = path.normalize(fpath);
57 // temporary fix until isomorphic git can handle windows paths
58 // see https://github.com/isomorphic-git/isomorphic-git/issues/783
59 fpath = fpath.replace(/\\/g, '/');
60
61 // remove leading slash
62 if (fpath.length && fpath[0] === '/') {
63 fpath = fpath.substr(1);
64 }
65
66 if (options.onRawRequest && typeof options.onRawRequest === 'function') {
67 try {
68 options.onRawRequest({
69 req,
70 repoPath: path.normalize(repPath),
71 filePath: path.normalize(fpath),
72 ref: refName,
73 });
74 } catch {
75 // ignore errors from listener
76 }
77 }
78
79 // project-helix/#187: serve modified content only if the requested ref is currently checked out
80 isCheckedOut(repPath, refName)
81 .then((serveUncommitted) => resolveBlob(repPath, refName, fpath, serveUncommitted))
82 .then((oid) => {
83 const mimeType = mime.getType(fpath) || 'text/plain';
84 res.writeHead(200, {
85 'Content-Type': mimeType,
86 ETag: oid,
87 // TODO: review cache-control header
88 'Cache-Control': 'max-age=0, private, must-revalidate',
89 });
90 createBlobReadStream(repPath, oid)
91 .then((stream) => stream.pipe(res));
92 })
93 .catch((err) => {
94 // TODO: use generic errors
95 if (err instanceof NotFoundError) {
96 options.logger.debug(`[rawHandler] resource not found: ${err.message}`);
97 res.status(404).send('not found.');
98 } else {
99 options.logger.debug(`[rawHandler] code: ${err.code} message: ${err.message} stack: ${err.stack}`);
100 next(err);
101 }
102 });
103 };
104}
105module.exports = createMiddleware;