2020-08-26 04:54:58 +02:00
|
|
|
const winston = require('winston');
|
|
|
|
const Busboy = require('busboy');
|
2011-11-18 21:51:38 +01:00
|
|
|
|
|
|
|
// For handling serving stored documents
|
|
|
|
|
2020-08-28 04:39:03 +02:00
|
|
|
const DocumentHandler = function(options){
|
|
|
|
if (!options) options = new Object;
|
|
|
|
this.keyLength = options.keyLength || DocumentHandler.defaultKeyLength;
|
|
|
|
this.maxLength = options.maxLength; // none by default
|
|
|
|
this.store = options.store;
|
|
|
|
this.keyGenerator = options.keyGenerator;
|
2011-11-18 21:51:38 +01:00
|
|
|
};
|
|
|
|
|
2011-11-28 22:46:59 +01:00
|
|
|
DocumentHandler.defaultKeyLength = 10;
|
|
|
|
|
2011-11-18 22:45:48 +01:00
|
|
|
// Handle retrieving a document
|
2020-08-28 04:39:03 +02:00
|
|
|
DocumentHandler.prototype.handleGet = async function(key, res, skipExpire){
|
2020-09-02 16:16:54 +02:00
|
|
|
const data = await this.store.get(key, skipExpire);
|
|
|
|
|
|
|
|
//when data is null it means there was either no data or an error
|
|
|
|
if (!data){
|
|
|
|
winston.warn('document not found', { key: key });
|
|
|
|
res.status(404).json({ message: 'Document not found.' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
winston.verbose('retrieved document', { key: key });
|
|
|
|
res.status(200).json({ data: data, key: key });
|
|
|
|
return;
|
2011-11-18 21:51:38 +01:00
|
|
|
};
|
|
|
|
|
2011-12-16 13:57:09 +01:00
|
|
|
// Handle retrieving the raw version of a document
|
2020-08-28 04:39:03 +02:00
|
|
|
DocumentHandler.prototype.handleGetRaw = async function(key, res, skipExpire){
|
2020-09-02 16:16:54 +02:00
|
|
|
const data = await this.store.get(key, skipExpire);
|
|
|
|
|
|
|
|
if (!data){
|
|
|
|
winston.warn('raw document not found', { key: key });
|
|
|
|
res.status(404).json({ message: 'Document not found.' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
winston.verbose('retrieved raw document', { key: key });
|
|
|
|
res.status(200).end(data);
|
2011-12-16 13:57:09 +01:00
|
|
|
};
|
|
|
|
|
2011-11-18 22:45:48 +01:00
|
|
|
// Handle adding a new Document
|
2020-08-28 04:39:03 +02:00
|
|
|
DocumentHandler.prototype.handlePost = function (req, res){
|
|
|
|
let _this = this;
|
|
|
|
let buffer = '';
|
|
|
|
let cancelled = false;
|
2014-04-21 20:16:23 +02:00
|
|
|
|
2020-09-02 16:16:54 +02:00
|
|
|
//parse a form to grab the data
|
2020-08-28 04:39:03 +02:00
|
|
|
let ct = req.headers['content-type'];
|
|
|
|
if (ct && ct.split(';')[0] == 'multipart/form-data'){
|
2020-09-02 16:16:54 +02:00
|
|
|
winston.debug('okayge');
|
2020-08-28 04:39:03 +02:00
|
|
|
let busboy = new Busboy({ headers: req.headers });
|
2020-09-02 16:16:54 +02:00
|
|
|
busboy.on('field', (fieldname, val) => {
|
2020-08-28 04:39:03 +02:00
|
|
|
if (fieldname == 'data'){
|
|
|
|
buffer = val;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
busboy.on('finish', async function (){
|
|
|
|
await onSuccess();
|
|
|
|
});
|
|
|
|
req.pipe(busboy);
|
2020-09-02 16:16:54 +02:00
|
|
|
//otherwise, grab flat data from POST body
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
req.on('data', data => {
|
2020-08-28 04:39:03 +02:00
|
|
|
buffer += data.toString();
|
|
|
|
});
|
2020-09-02 16:16:54 +02:00
|
|
|
req.on('end', async () => {
|
|
|
|
if (cancelled) return;
|
2020-08-28 04:39:03 +02:00
|
|
|
await onSuccess();
|
|
|
|
});
|
2020-09-02 16:16:54 +02:00
|
|
|
req.on('error', error => {
|
|
|
|
winston.error(`busboy connection error: ${error.message}`);
|
|
|
|
res.status(500).json({ message: 'Internal server error occured while adding document.' });
|
2020-08-28 04:39:03 +02:00
|
|
|
cancelled = true;
|
|
|
|
});
|
|
|
|
}
|
2020-09-02 16:16:54 +02:00
|
|
|
|
|
|
|
let onSuccess = async function (){
|
|
|
|
//check length
|
2020-09-02 16:18:47 +02:00
|
|
|
if (!buffer.length){
|
|
|
|
cancelled = true;
|
|
|
|
winston.warn('document with no length was POSTed');
|
|
|
|
res.status(411).json({ message: 'Length required.' });
|
|
|
|
return;
|
|
|
|
}
|
2020-09-02 16:16:54 +02:00
|
|
|
if (_this.maxLength && buffer.length > _this.maxLength){
|
|
|
|
cancelled = true;
|
|
|
|
winston.warn('document >maxLength', { maxLength: _this.maxLength });
|
|
|
|
res.status(413).json({ message: 'Document exceeds maximum length.' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//and save
|
|
|
|
const key = await _this.chooseKey();
|
|
|
|
const success = await _this.store.set(key, buffer);
|
|
|
|
if (!success){
|
|
|
|
winston.verbose('error adding document');
|
|
|
|
res.status(500).json({ message: 'Internal server error occured while adding document.' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
winston.verbose('added document', { key: key });
|
|
|
|
res.status(200).json({ key: key });
|
|
|
|
};
|
2011-11-18 21:51:38 +01:00
|
|
|
};
|
|
|
|
|
2020-09-02 16:16:54 +02:00
|
|
|
//keep choosing keys until one isn't taken
|
|
|
|
DocumentHandler.prototype.chooseKey = async function(){
|
2020-08-28 04:39:03 +02:00
|
|
|
let key = this.acceptableKey();
|
2020-09-02 16:16:54 +02:00
|
|
|
let data = await this.store.get(key, true); //don't bump expirations on key searching
|
|
|
|
if (data) return this.chooseKey();
|
|
|
|
return key;
|
2011-11-22 03:48:09 +01:00
|
|
|
};
|
|
|
|
|
2020-08-28 04:39:03 +02:00
|
|
|
DocumentHandler.prototype.acceptableKey = function(){
|
|
|
|
return this.keyGenerator.createKey(this.keyLength);
|
2012-01-13 17:16:42 +01:00
|
|
|
};
|
|
|
|
|
2011-11-18 21:51:38 +01:00
|
|
|
module.exports = DocumentHandler;
|