mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 03:42:27 +03:00
Switch from multipart to busboy
Fixes #1227 - Removed deprecated `multipart` references. - Setup `busboy` to pass along file streams and do a naive parse of form values. - Updated logic in file storage and db import to handle file streams instead of the temporary files created by `multipart`.
This commit is contained in:
parent
96f246533b
commit
bf7692b151
1
.gitignore
vendored
1
.gitignore
vendored
@ -41,6 +41,7 @@ projectFilesBackup
|
||||
/core/server/data/export/exported*
|
||||
/docs
|
||||
/_site
|
||||
/content/tmp/*
|
||||
/content/data/*
|
||||
/content/plugins/**/*
|
||||
/content/themes/**/*
|
||||
|
@ -239,6 +239,10 @@ var path = require('path'),
|
||||
]
|
||||
},
|
||||
|
||||
storage: {
|
||||
src: ['core/test/unit/**/storage*_spec.js']
|
||||
},
|
||||
|
||||
integration: {
|
||||
src: ['core/test/integration/**/model*_spec.js']
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
var dataExport = require('../data/export'),
|
||||
dataImport = require('../data/import'),
|
||||
api = require('../api'),
|
||||
apiNotifications = require('./notifications'),
|
||||
apiSettings = require('./settings'),
|
||||
fs = require('fs-extra'),
|
||||
path = require('path'),
|
||||
when = require('when'),
|
||||
@ -27,57 +28,58 @@ db = {
|
||||
res.download(exportedFilePath, 'GhostData.json');
|
||||
}).otherwise(function (error) {
|
||||
// Notify of an error if it occurs
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
return apiNotifications.browse().then(function (notifications) {
|
||||
var notification = {
|
||||
type: 'error',
|
||||
message: error.message || error,
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
return api.notifications.add(notification).then(function () {
|
||||
|
||||
return apiNotifications.add(notification).then(function () {
|
||||
res.redirect(debugPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
'import': function (req, res) {
|
||||
var notification;
|
||||
var notification,
|
||||
databaseVersion;
|
||||
|
||||
if (!req.files.importfile || req.files.importfile.size === 0 || req.files.importfile.name.indexOf('json') === -1) {
|
||||
if (!req.files.importfile || !req.files.importfile.path || req.files.importfile.name.indexOf('json') === -1) {
|
||||
/**
|
||||
* Notify of an error if it occurs
|
||||
*
|
||||
* - If there's no file (although if you don't select anything, the input is still submitted, so
|
||||
* !req.files.importfile will always be false)
|
||||
* - If the size is 0
|
||||
* - If there is no path
|
||||
* - If the name doesn't have json in it
|
||||
*/
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
return apiNotifications.browse().then(function (notifications) {
|
||||
notification = {
|
||||
type: 'error',
|
||||
message: "Must select a .json file to import",
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
return api.notifications.add(notification).then(function () {
|
||||
|
||||
return apiNotifications.add(notification).then(function () {
|
||||
res.redirect(debugPath);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Get the current version for importing
|
||||
api.settings.read({ key: 'databaseVersion' })
|
||||
.then(function (setting) {
|
||||
apiSettings.read({ key: 'databaseVersion' }).then(function (setting) {
|
||||
return when(setting.value);
|
||||
}, function () {
|
||||
return when('001');
|
||||
})
|
||||
.then(function (databaseVersion) {
|
||||
}).then(function (version) {
|
||||
databaseVersion = version;
|
||||
// Read the file contents
|
||||
return nodefn.call(fs.readFile, req.files.importfile.path)
|
||||
.then(function (fileContents) {
|
||||
return nodefn.call(fs.readFile, req.files.importfile.path);
|
||||
}).then(function (fileContents) {
|
||||
var importData,
|
||||
error = "",
|
||||
error = '',
|
||||
tableKeys = _.keys(schema);
|
||||
|
||||
// Parse the json data
|
||||
@ -124,10 +126,9 @@ db = {
|
||||
}
|
||||
// Import for the current version
|
||||
return dataImport(databaseVersion, importData);
|
||||
});
|
||||
})
|
||||
.then(function importSuccess() {
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
}).then(function importSuccess() {
|
||||
return apiNotifications.browse();
|
||||
}).then(function (notifications) {
|
||||
notification = {
|
||||
type: 'success',
|
||||
message: "Data imported. Log in with the user details you imported",
|
||||
@ -135,16 +136,15 @@ db = {
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
return apiNotifications.add(notification).then(function () {
|
||||
req.session.destroy();
|
||||
res.set({
|
||||
"X-Cache-Invalidate": "/*"
|
||||
});
|
||||
res.redirect(config.paths().webroot + '/ghost/signin/');
|
||||
});
|
||||
});
|
||||
}, function importFailure(error) {
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
}).otherwise(function importFailure(error) {
|
||||
return apiNotifications.browse().then(function (notifications) {
|
||||
// Notify of an error if it occurs
|
||||
notification = {
|
||||
type: 'error',
|
||||
@ -153,7 +153,7 @@ db = {
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
return apiNotifications.add(notification).then(function () {
|
||||
res.redirect(debugPath);
|
||||
});
|
||||
});
|
||||
|
66
core/server/middleware/ghost-busboy.js
Normal file
66
core/server/middleware/ghost-busboy.js
Normal file
@ -0,0 +1,66 @@
|
||||
var BusBoy = require('busboy'),
|
||||
fs = require('fs-extra'),
|
||||
path = require('path'),
|
||||
os = require('os');
|
||||
|
||||
// ### ghostBusboy
|
||||
// Process multipart file streams and copies them to a memory stream to be
|
||||
// processed later.
|
||||
function ghostBusBoy(req, res, next) {
|
||||
var busboy,
|
||||
tmpDir,
|
||||
hasError = false;
|
||||
|
||||
if (req.method && req.method.match(/get/i)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
busboy = new BusBoy({ headers: req.headers });
|
||||
tmpDir = os.tmpdir();
|
||||
|
||||
req.files = req.files || {};
|
||||
req.body = req.body || {};
|
||||
|
||||
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
|
||||
var filePath;
|
||||
|
||||
// If the filename is invalid, mark an error
|
||||
if (!filename) {
|
||||
hasError = true;
|
||||
}
|
||||
// If we've flagged any errors, do not process any streams
|
||||
if (hasError) {
|
||||
return file.emit('end');
|
||||
}
|
||||
|
||||
filePath = path.join(tmpDir, filename || 'temp.tmp');
|
||||
|
||||
file.on('end', function () {
|
||||
req.files[fieldname] = {
|
||||
type: mimetype,
|
||||
encoding: encoding,
|
||||
name: filename,
|
||||
path: filePath
|
||||
};
|
||||
});
|
||||
|
||||
busboy.on('limit', function () {
|
||||
hasError = true;
|
||||
res.send(413, { errorCode: 413, message: 'File size limit breached.' });
|
||||
});
|
||||
|
||||
file.pipe(fs.createWriteStream(filePath));
|
||||
});
|
||||
|
||||
busboy.on('field', function (fieldname, val) {
|
||||
req.body[fieldname] = val;
|
||||
});
|
||||
|
||||
busboy.on('end', function () {
|
||||
next();
|
||||
});
|
||||
|
||||
req.pipe(busboy);
|
||||
}
|
||||
|
||||
module.exports = ghostBusBoy;
|
@ -237,9 +237,8 @@ module.exports = function (server, dbHash) {
|
||||
expressServer.use(express.json());
|
||||
expressServer.use(express.urlencoded());
|
||||
|
||||
expressServer.use(root + '/ghost/upload/', express.multipart());
|
||||
expressServer.use(root + '/ghost/upload/', express.multipart({uploadDir: __dirname + '/content/images'}));
|
||||
expressServer.use(root + '/ghost/api/v0.1/db/', express.multipart());
|
||||
expressServer.use('/ghost/upload/', middleware.busboy);
|
||||
expressServer.use('/ghost/api/v0.1/db/', middleware.busboy);
|
||||
|
||||
// Session handling
|
||||
expressServer.use(express.cookieParser());
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
var _ = require('underscore'),
|
||||
express = require('express'),
|
||||
busboy = require('./ghost-busboy'),
|
||||
config = require('../config'),
|
||||
path = require('path'),
|
||||
api = require('../api'),
|
||||
@ -139,7 +140,9 @@ var middleware = {
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
},
|
||||
|
||||
busboy: busboy
|
||||
};
|
||||
|
||||
module.exports = middleware;
|
||||
|
@ -20,24 +20,25 @@ localFileStore = _.extend(baseStore, {
|
||||
// - returns a promise which ultimately returns the full url to the uploaded image
|
||||
'save': function (image) {
|
||||
var saved = when.defer(),
|
||||
targetDir = this.getTargetDir(config.paths().imagesRelPath);
|
||||
targetDir = this.getTargetDir(config.paths().imagesRelPath),
|
||||
targetFilename;
|
||||
|
||||
this.getUniqueFileName(this, image, targetDir).then(function (filename) {
|
||||
nodefn.call(fs.mkdirs, targetDir).then(function () {
|
||||
return nodefn.call(fs.copy, image.path, filename);
|
||||
targetFilename = filename;
|
||||
return nodefn.call(fs.mkdirs, targetDir);
|
||||
}).then(function () {
|
||||
return nodefn.call(fs.copy, image.path, targetFilename);
|
||||
}).then(function () {
|
||||
// we should remove the temporary image
|
||||
return nodefn.call(fs.unlink, image.path).otherwise(errors.logError);
|
||||
}).then(function () {
|
||||
// The src for the image must be in URI format, not a file system path, which in Windows uses \
|
||||
// For local file system storage can use relative path so add a slash
|
||||
var fullUrl = ('/' + filename).replace(new RegExp('\\' + path.sep, 'g'), '/');
|
||||
var fullUrl = ('/' + targetFilename).replace(new RegExp('\\' + path.sep, 'g'), '/');
|
||||
return saved.resolve(fullUrl);
|
||||
}).otherwise(function (e) {
|
||||
errors.logError(e);
|
||||
return saved.reject(e);
|
||||
});
|
||||
}).otherwise(errors.logError);
|
||||
|
||||
return saved.promise;
|
||||
},
|
||||
|
@ -34,6 +34,7 @@
|
||||
"dependencies": {
|
||||
"bcryptjs": "0.7.10",
|
||||
"bookshelf": "0.6.1",
|
||||
"busboy": "0.0.12",
|
||||
"colors": "0.6.2",
|
||||
"connect-slashes": "1.0.2",
|
||||
"downsize": "0.0.4",
|
||||
|
Loading…
Reference in New Issue
Block a user