Ghost/core/server/web/site/middleware/serve-public-file.js
Hannah Wolfe 61633d48ee Moved serve-public-file mw into site app
- Moved serve-public-file from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
2020-04-21 17:23:07 +01:00

85 lines
3.1 KiB
JavaScript

const crypto = require('crypto');
const fs = require('fs-extra');
const path = require('path');
const errors = require('@tryghost/errors');
const config = require('../../../config');
const urlUtils = require('../../../lib/url-utils');
const {i18n} = require('../../../lib/common');
function createPublicFileMiddleware(file, type, maxAge) {
let content;
const publicFilePath = config.get('paths').publicFilePath;
const filePath = file.match(/^public/) ? path.join(publicFilePath, file.replace(/^public/, '')) : path.join(publicFilePath, file);
const blogRegex = /(\{\{blog-url\}\})/g;
const adminRegex = /(\{\{admin-url\}\})/g;
return function servePublicFile(req, res, next) {
if (content) {
res.writeHead(200, content.headers);
return res.end(content.body);
}
// send image files directly and let express handle content-length, etag, etc
if (type.match(/^image/)) {
return res.sendFile(filePath, (err) => {
if (err && err.status === 404) {
// ensure we're triggering basic asset 404 and not a templated 404
return next(new errors.NotFoundError({
message: i18n.t('errors.errors.imageNotFound'),
code: 'STATIC_FILE_NOT_FOUND',
property: err.path
}));
}
if (err) {
return next(err);
}
});
}
// modify text files before caching+serving to ensure URL placeholders are transformed
fs.readFile(filePath, (err, buf) => {
if (err) {
return next(err);
}
let str = buf.toString();
if (type === 'text/xsl' || type === 'text/plain' || type === 'application/javascript') {
str = str.replace(blogRegex, urlUtils.urlFor('home', true).replace(/\/$/, ''));
str = str.replace(adminRegex, urlUtils.urlFor('admin', true).replace(/\/$/, ''));
}
content = {
headers: {
'Content-Type': type,
'Content-Length': Buffer.from(str).length,
ETag: `"${crypto.createHash('md5').update(str, 'utf8').digest('hex')}"`,
'Cache-Control': `public, max-age=${maxAge}`
},
body: str
};
res.writeHead(200, content.headers);
res.end(content.body);
});
};
}
// ### servePublicFile Middleware
// Handles requests to robots.txt and favicon.ico (and caches them)
function servePublicFile(file, type, maxAge) {
const publicFileMiddleware = createPublicFileMiddleware(file, type, maxAge);
return function servePublicFile(req, res, next) {
if (req.path === '/' + file) {
return publicFileMiddleware(req, res, next);
} else {
return next();
}
};
}
module.exports = servePublicFile;
module.exports.servePublicFile = servePublicFile;
module.exports.createPublicFileMiddleware = createPublicFileMiddleware;