mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-22 10:21:36 +03:00
d9bdc444a3
- If we register the serve public file middleware for a file that doesn't exist, this will currently throw an ENOENT error - Instead, we want to fall back to a standard 404 so that this behaves normally - This will be useful for the card asset service, where the cards.min.css and cards.min.js files may or may not exist
96 lines
3.4 KiB
JavaScript
96 lines
3.4 KiB
JavaScript
const crypto = require('crypto');
|
|
const fs = require('fs-extra');
|
|
const path = require('path');
|
|
const errors = require('@tryghost/errors');
|
|
const config = require('../../../shared/config');
|
|
const urlUtils = require('../../../shared/url-utils');
|
|
const tpl = require('@tryghost/tpl');
|
|
|
|
const messages = {
|
|
imageNotFound: 'Image not found',
|
|
fileNotFound: 'File not found'
|
|
};
|
|
|
|
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;
|
|
|
|
return function servePublicFileMiddleware(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: tpl(messages.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) {
|
|
// Downgrade to a simple 404 if the file didn't exist
|
|
if (err.code === 'ENOENT') {
|
|
err = new errors.NotFoundError({
|
|
message: tpl(messages.fileNotFound),
|
|
code: 'PUBLIC_FILE_NOT_FOUND',
|
|
property: err.path
|
|
});
|
|
}
|
|
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(/\/$/, ''));
|
|
}
|
|
|
|
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 servePublicFileMiddleware(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;
|