UNPKG

3.99 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 escape = require('escape-html');
16
17const git = require('isomorphic-git');
18git.plugins.set('fs', require('fs'));
19
20const { debug } = require('@adobe/helix-log');
21const { resolveCommit, determineRefPathName } = require('./git');
22const { resolveRepositoryPath } = require('./utils');
23
24/**
25 * Export the html handler (express middleware) through a parameterizable function
26 *
27 * @param {object} options configuration hash
28 * @param {string} urlType 'root', 'tree' (directory) or 'blob' (file)
29 * @returns {function(*, *, *)} handler function
30 */
31function createMiddleware(options, urlType) {
32 /**
33 * Express middleware handling html requests
34 *
35 * @param {Request} req Request object
36 * @param {Response} res Response object
37 * @param {callback} next next middleware in chain
38 */
39 return async (req, res, next) => {
40 const { owner } = req.params;
41 const repoName = req.params.repo;
42 let refName = req.params.ref || 'master';
43 let fpath = req.params[0] || '';
44
45 const repPath = resolveRepositoryPath(options, owner, repoName);
46
47 // issue: #53: handle branch names containing '/' (e.g. 'foo/bar')
48 const parsed = await determineRefPathName(repPath, `${req.params.ref}/${req.params[0]}`);
49 if (parsed) {
50 refName = parsed.ref;
51 fpath = parsed.pathName;
52 }
53
54 // issue #247: lenient handling of redundant leading slashes in path
55 while (fpath.length && fpath[0] === '/') {
56 // trim leading slash
57 fpath = fpath.substr(1);
58 }
59
60 // set response content type
61 res.header('Content-Type', 'text/html');
62
63 resolveCommit(repPath, refName)
64 .then((commitOid) => git.readObject({ dir: repPath, oid: commitOid, filepath: fpath })
65 .catch(() => null))
66 .then((blobOrTree) => {
67 if (!blobOrTree) {
68 if (!fpath.length && urlType === 'tree') {
69 // 'tree' view
70 res.send(`<!DOCTYPE html><html><body>owner: ${escape(owner)}<br>repo: ${escape(repoName)}<br>ref: ${escape(refName)}<p>tree view not implemented yet.</body></html>`);
71 } else {
72 res.status(404).send(`not found: ${escape(fpath)}`);
73 }
74 return;
75 }
76
77 const { type } = blobOrTree;
78 if (!fpath.length && type === 'tree' && urlType === 'root') {
79 // 'root' view
80 res.send(`<!DOCTYPE html><html><body>owner: ${escape(owner)}<br>repo: ${escape(repoName)}<br>ref: ${escape(refName)}<p>root view not implemented yet.</body></html>`);
81 } else if (type === 'tree' && urlType === 'tree') {
82 // directory view
83 res.send(`<!DOCTYPE html><html><body>owner: ${escape(owner)}<br>repo: ${escape(repoName)}<br>ref: ${escape(refName)}<br>path: ${escape(fpath)}<p>directory view not implemented yet.</body></html>`);
84 } else if (type === 'blob' && urlType === 'blob') {
85 // single file view
86 res.send(`<!DOCTYPE html><html><body>owner: ${escape(owner)}<br>repo: ${escape(repoName)}<br>ref: ${escape(refName)}<br>path: ${escape(fpath)}<p>file view not implemented yet.</body></html>`);
87 } else {
88 res.status(404).send(`not found: ${escape(fpath)}`);
89 }
90 })
91 .catch((err) => {
92 debug(`[htmlHandler] code: ${err.code} message: ${err.message} stack: ${err.stack}`);
93 next(err);
94 });
95 };
96}
97module.exports = createMiddleware;