[bug] For bug 50657; add createReadStream interface to storage; wopi putfile via stream

This commit is contained in:
Sergey Konovalov
2021-06-15 14:24:37 +03:00
parent abe77cfaa3
commit ca3ea6a2fd
8 changed files with 164 additions and 46 deletions

View File

@ -42,6 +42,9 @@ function getStoragePath(strPath) {
exports.getObject = function(strPath) { exports.getObject = function(strPath) {
return storage.getObject(getStoragePath(strPath)); return storage.getObject(getStoragePath(strPath));
}; };
exports.createReadStream = function(strPath) {
return storage.createReadStream(getStoragePath(strPath));
};
exports.putObject = function(strPath, buffer, contentLength) { exports.putObject = function(strPath, buffer, contentLength) {
return storage.putObject(getStoragePath(strPath), buffer, contentLength); return storage.putObject(getStoragePath(strPath), buffer, contentLength);
}; };
@ -78,13 +81,13 @@ exports.deletePath = function(strPath) {
return exports.deleteObjects(list); return exports.deleteObjects(list);
}); });
}; };
exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_type, opt_creationDate) { exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_creationDate) {
return storage.getSignedUrl(baseUrl, getStoragePath(strPath), urlType, optFilename, opt_type, opt_creationDate); return storage.getSignedUrl(baseUrl, getStoragePath(strPath), urlType, optFilename, opt_creationDate);
}; };
exports.getSignedUrls = function(baseUrl, strPath, urlType, opt_creationDate) { exports.getSignedUrls = function(baseUrl, strPath, urlType, opt_creationDate) {
return exports.listObjects(getStoragePath(strPath)).then(function(list) { return exports.listObjects(getStoragePath(strPath)).then(function(list) {
return Promise.all(list.map(function(curValue) { return Promise.all(list.map(function(curValue) {
return exports.getSignedUrl(baseUrl, curValue, urlType, undefined, undefined, opt_creationDate); return exports.getSignedUrl(baseUrl, curValue, urlType, undefined, opt_creationDate);
})).then(function(urls) { })).then(function(urls) {
var outputMap = {}; var outputMap = {};
for (var i = 0; i < list.length && i < urls.length; ++i) { for (var i = 0; i < list.length && i < urls.length; ++i) {
@ -94,9 +97,9 @@ exports.getSignedUrls = function(baseUrl, strPath, urlType, opt_creationDate) {
}); });
}); });
}; };
exports.getSignedUrlsArrayByArray = function(baseUrl, list, urlType, opt_type) { exports.getSignedUrlsArrayByArray = function(baseUrl, list, urlType) {
return Promise.all(list.map(function(curValue) { return Promise.all(list.map(function(curValue) {
return exports.getSignedUrl(baseUrl, curValue, urlType, undefined, opt_type); return exports.getSignedUrl(baseUrl, curValue, urlType, undefined);
})); }));
}; };
exports.getSignedUrlsByArray = function(baseUrl, list, optPath, urlType) { exports.getSignedUrlsByArray = function(baseUrl, list, optPath, urlType) {

View File

@ -45,7 +45,6 @@ var config = require('config');
var configStorage = config.get('storage'); var configStorage = config.get('storage');
var cfgBucketName = configStorage.get('bucketName'); var cfgBucketName = configStorage.get('bucketName');
var cfgStorageFolderName = configStorage.get('storageFolderName'); var cfgStorageFolderName = configStorage.get('storageFolderName');
var cfgStorageExternalHost = configStorage.get('externalHost');
var configFs = configStorage.get('fs'); var configFs = configStorage.get('fs');
var cfgStorageFolderPath = configFs.get('folderPath'); var cfgStorageFolderPath = configFs.get('folderPath');
var cfgStorageSecretString = configFs.get('secretString'); var cfgStorageSecretString = configFs.get('secretString');
@ -89,6 +88,27 @@ function removeEmptyParent(strPath, done) {
exports.getObject = function(strPath) { exports.getObject = function(strPath) {
return utils.readFile(getFilePath(strPath)); return utils.readFile(getFilePath(strPath));
}; };
exports.createReadStream = function(strPath) {
let fsPath = getFilePath(strPath);
let contentLength;
return new Promise(function(resolve, reject) {
fs.stat(fsPath, function(err, stats) {
if (err) {
reject(err);
} else {
resolve(stats);
}
});
}).then(function(stats){
contentLength = stats.size;
return utils.promiseCreateReadStream(fsPath);
}).then(function(readStream, stats){
return {
contentLength: contentLength,
readStream: readStream
};
});
};
exports.putObject = function(strPath, buffer, contentLength) { exports.putObject = function(strPath, buffer, contentLength) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
@ -155,12 +175,12 @@ exports.deleteObject = function(strPath) {
exports.deleteObjects = function(strPaths) { exports.deleteObjects = function(strPaths) {
return Promise.all(strPaths.map(exports.deleteObject)); return Promise.all(strPaths.map(exports.deleteObject));
}; };
exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_type, opt_creationDate) { exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_creationDate) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
//replace '/' with %2f before encodeURIComponent becase nginx determine %2f as '/' and get wrong system path //replace '/' with %2f before encodeURIComponent becase nginx determine %2f as '/' and get wrong system path
var userFriendlyName = optFilename ? encodeURIComponent(optFilename.replace(/\//g, "%2f")) : path.basename(strPath); var userFriendlyName = optFilename ? encodeURIComponent(optFilename.replace(/\//g, "%2f")) : path.basename(strPath);
var uri = '/' + cfgBucketName + '/' + cfgStorageFolderName + '/' + strPath + '/' + userFriendlyName; var uri = '/' + cfgBucketName + '/' + cfgStorageFolderName + '/' + strPath + '/' + userFriendlyName;
var url = (cfgStorageExternalHost ? cfgStorageExternalHost : baseUrl) + uri; var url = utils.checkBaseUrl(baseUrl) + uri;
var date = Date.now(); var date = Date.now();
let creationDate = opt_creationDate || date; let creationDate = opt_creationDate || date;
@ -175,7 +195,6 @@ exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_type
url += '?md5=' + encodeURIComponent(md5); url += '?md5=' + encodeURIComponent(md5);
url += '&expires=' + encodeURIComponent(expires); url += '&expires=' + encodeURIComponent(expires);
url += '&disposition=' + encodeURIComponent(utils.getContentDisposition(null, null, opt_type));
url += '&filename=' + userFriendlyName; url += '&filename=' + userFriendlyName;
resolve(url); resolve(url);
}); });

View File

@ -51,7 +51,6 @@ var cfgAccessKeyId = configStorage.get('accessKeyId');
var cfgSecretAccessKey = configStorage.get('secretAccessKey'); var cfgSecretAccessKey = configStorage.get('secretAccessKey');
var cfgUseRequestToGetUrl = configStorage.get('useRequestToGetUrl'); var cfgUseRequestToGetUrl = configStorage.get('useRequestToGetUrl');
var cfgUseSignedUrl = configStorage.get('useSignedUrl'); var cfgUseSignedUrl = configStorage.get('useSignedUrl');
var cfgExternalHost = configStorage.get('externalHost');
var cfgSslEnabled = configStorage.get('sslEnabled'); var cfgSslEnabled = configStorage.get('sslEnabled');
var cfgS3ForcePathStyle = configStorage.get('s3ForcePathStyle'); var cfgS3ForcePathStyle = configStorage.get('s3ForcePathStyle');
var configFs = configStorage.get('fs'); var configFs = configStorage.get('fs');
@ -143,6 +142,25 @@ exports.getObject = function(strPath) {
}); });
}); });
}; };
exports.createReadStream = function(strPath) {
return new Promise(function(resolve, reject) {
var params = {Bucket: cfgBucketName, Key: getFilePath(strPath)};
s3Client.getObject(params)
.on('error', (err) => {
reject(err);
})
.on('httpHeaders', function(statusCode, headers, resp, statusMessage) {
//retries are possible
if (statusCode < 300) {
let responseObject = {
contentLength: headers['content-length'],
readStream: this.response.httpResponse.createUnbufferedStream()
};
resolve(responseObject);
}
}).send();
});
};
exports.putObject = function(strPath, buffer, contentLength) { exports.putObject = function(strPath, buffer, contentLength) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
//todo рассмотреть Expires //todo рассмотреть Expires
@ -204,11 +222,11 @@ exports.deleteObjects = function(strPaths) {
} }
return Promise.all(deletePromises); return Promise.all(deletePromises);
}; };
exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_type, opt_creationDate) { exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_creationDate) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var expires = (commonDefines.c_oAscUrlTypes.Session === urlType ? cfgExpSessionAbsolute : cfgStorageUrlExpires) || 31536000; var expires = (commonDefines.c_oAscUrlTypes.Session === urlType ? cfgExpSessionAbsolute : cfgStorageUrlExpires) || 31536000;
var userFriendlyName = optFilename ? optFilename.replace(/\//g, "%2f") : path.basename(strPath); var userFriendlyName = optFilename ? optFilename.replace(/\//g, "%2f") : path.basename(strPath);
var contentDisposition = utils.getContentDisposition(userFriendlyName, null, opt_type); var contentDisposition = utils.getContentDisposition(userFriendlyName, null, null);
if (cfgUseRequestToGetUrl) { if (cfgUseRequestToGetUrl) {
//default Expires 900 seconds //default Expires 900 seconds
var params = { var params = {
@ -228,7 +246,7 @@ exports.getSignedUrl = function(baseUrl, strPath, urlType, optFilename, opt_type
} else if (cfgEndpointParsed && } else if (cfgEndpointParsed &&
(cfgEndpointParsed.hostname == 'localhost' || cfgEndpointParsed.hostname == '127.0.0.1') && (cfgEndpointParsed.hostname == 'localhost' || cfgEndpointParsed.hostname == '127.0.0.1') &&
80 == cfgEndpointParsed.port) { 80 == cfgEndpointParsed.port) {
host = (cfgExternalHost ? cfgExternalHost : baseUrl) + cfgEndpointParsed.path; host = utils.checkBaseUrl(baseUrl) + cfgEndpointParsed.path;
} else { } else {
host = cfgEndpoint; host = cfgEndpoint;
} }

View File

@ -83,6 +83,7 @@ const cfgPasswordEncrypt = config.get('openpgpjs.encrypt');
const cfgPasswordDecrypt = config.get('openpgpjs.decrypt'); const cfgPasswordDecrypt = config.get('openpgpjs.decrypt');
const cfgPasswordConfig = config.get('openpgpjs.config'); const cfgPasswordConfig = config.get('openpgpjs.config');
const cfgRequesFilteringAgent = config.get('services.CoAuthoring.request-filtering-agent'); const cfgRequesFilteringAgent = config.get('services.CoAuthoring.request-filtering-agent');
const cfgStorageExternalHost = config.get('storage.externalHost');
Object.assign(openpgp.config, cfgPasswordConfig); Object.assign(openpgp.config, cfgPasswordConfig);
@ -355,7 +356,7 @@ function downloadUrlPromiseWithoutRedirect(uri, optTimeout, optLimit, opt_Author
} }
}); });
} }
function postRequestPromise(uri, postData, optTimeout, opt_Authorization, opt_header) { function postRequestPromise(uri, postData, postDataStream, optTimeout, opt_Authorization, opt_header) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
//IRI to URI //IRI to URI
uri = URI.serialize(URI.parse(uri)); uri = URI.serialize(URI.parse(uri));
@ -366,7 +367,10 @@ function postRequestPromise(uri, postData, optTimeout, opt_Authorization, opt_he
} }
headers = opt_header || headers; headers = opt_header || headers;
let connectionAndInactivity = optTimeout && optTimeout.connectionAndInactivity && ms(optTimeout.connectionAndInactivity); let connectionAndInactivity = optTimeout && optTimeout.connectionAndInactivity && ms(optTimeout.connectionAndInactivity);
var options = {uri: urlParsed, body: postData, encoding: 'utf8', headers: headers, timeout: connectionAndInactivity}; var options = {uri: urlParsed, encoding: 'utf8', headers: headers, timeout: connectionAndInactivity};
if (postData) {
options.body = postData;
}
let executed = false; let executed = false;
let ro = baseRequest.post(options, function(err, response, body) { let ro = baseRequest.post(options, function(err, response, body) {
@ -394,6 +398,9 @@ function postRequestPromise(uri, postData, optTimeout, opt_Authorization, opt_he
raiseError(ro, 'ETIMEDOUT', 'Error whole request cycle timeout'); raiseError(ro, 'ETIMEDOUT', 'Error whole request cycle timeout');
}, ms(optTimeout.wholeCycle)); }, ms(optTimeout.wholeCycle));
} }
if (postDataStream && !postData) {
postDataStream.pipe(ro);
}
}); });
} }
exports.postRequestPromise = postRequestPromise; exports.postRequestPromise = postRequestPromise;
@ -934,3 +941,6 @@ exports.convertLicenseInfoToServerParams = function(licenseInfo) {
license.buildNumber = commonDefines.buildNumber; license.buildNumber = commonDefines.buildNumber;
return license; return license;
}; };
exports.checkBaseUrl = function(baseUrl) {
return cfgStorageExternalHost ? cfgStorageExternalHost : baseUrl;
};

View File

@ -459,6 +459,11 @@ let changeConnectionInfo = co.wrap(function*(conn, cmd) {
} }
return false; return false;
}); });
function signToken(payload, algorithm, expiresIn, secretElem) {
var options = {algorithm: algorithm, expiresIn: expiresIn};
var secret = utils.getSecretByElem(secretElem);
return jwt.sign(payload, secret, options);
}
function fillJwtByConnection(conn) { function fillJwtByConnection(conn) {
var docId = conn.docId; var docId = conn.docId;
var payload = {document: {}, editorConfig: {user: {}}}; var payload = {document: {}, editorConfig: {user: {}}};
@ -481,9 +486,7 @@ function fillJwtByConnection(conn) {
edit.ds_isEnterCorrectPassword = conn.isEnterCorrectPassword; edit.ds_isEnterCorrectPassword = conn.isEnterCorrectPassword;
edit.ds_denyChangeName = conn.denyChangeName; edit.ds_denyChangeName = conn.denyChangeName;
var options = {algorithm: cfgTokenSessionAlgorithm, expiresIn: cfgTokenSessionExpires / 1000}; return signToken(payload, cfgTokenSessionAlgorithm, cfgTokenSessionExpires / 1000, cfgSecretSession);
var secret = utils.getSecretByElem(cfgSecretSession);
return jwt.sign(payload, secret, options);
} }
function sendData(conn, data) { function sendData(conn, data) {
@ -650,7 +653,7 @@ function* sendServerRequest(docId, uri, dataObject, opt_checkAuthorization) {
logger.warn('authorization reduced to: docId = %s; length=%d', docId, auth.length); logger.warn('authorization reduced to: docId = %s; length=%d', docId, auth.length);
} }
} }
let postRes = yield utils.postRequestPromise(uri, JSON.stringify(dataObject), cfgCallbackRequestTimeout, auth); let postRes = yield utils.postRequestPromise(uri, JSON.stringify(dataObject), undefined, cfgCallbackRequestTimeout, auth);
logger.debug('postData response: docId = %s;data = %s', docId, postRes.body); logger.debug('postData response: docId = %s;data = %s', docId, postRes.body);
return postRes.body; return postRes.body;
} }
@ -1231,6 +1234,7 @@ exports.parseReplyData = parseReplyData;
exports.sendServerRequest = sendServerRequest; exports.sendServerRequest = sendServerRequest;
exports.createSaveTimerPromise = co.wrap(_createSaveTimer); exports.createSaveTimerPromise = co.wrap(_createSaveTimer);
exports.changeConnectionInfo = changeConnectionInfo; exports.changeConnectionInfo = changeConnectionInfo;
exports.signToken = signToken;
exports.publish = publish; exports.publish = publish;
exports.addTask = addTask; exports.addTask = addTask;
exports.addDelayed = addDelayed; exports.addDelayed = addDelayed;
@ -2958,10 +2962,15 @@ exports.install = function(server, callbackFunction) {
if (0 == data.needUrlMethod) { if (0 == data.needUrlMethod) {
outputData.setData(yield storage.getSignedUrls(participant.baseUrl, data.needUrlKey, data.needUrlType, data.creationDate)); outputData.setData(yield storage.getSignedUrls(participant.baseUrl, data.needUrlKey, data.needUrlType, data.creationDate));
} else if (1 == data.needUrlMethod) { } else if (1 == data.needUrlMethod) {
outputData.setData(yield storage.getSignedUrl(participant.baseUrl, data.needUrlKey, data.needUrlType, undefined, undefined, data.creationDate)); outputData.setData(yield storage.getSignedUrl(participant.baseUrl, data.needUrlKey, data.needUrlType, undefined, data.creationDate));
} else { } else {
var contentDisposition = cmd.getInline() ? constants.CONTENT_DISPOSITION_INLINE : constants.CONTENT_DISPOSITION_ATTACHMENT; let url;
outputData.setData(yield storage.getSignedUrl(participant.baseUrl, data.needUrlKey, data.needUrlType, cmd.getTitle(), contentDisposition, data.creationDate)); if (cmd.getInline()) {
url = canvasService.getPrintFileUrl(data.needUrlKey, participant.baseUrl, cmd.getTitle());
} else {
url = yield storage.getSignedUrl(participant.baseUrl, data.needUrlKey, data.needUrlType, cmd.getTitle(), data.creationDate)
}
outputData.setData(url);
} }
modifyConnectionForPassword(participant, data.needUrlIsCorrectPassword); modifyConnectionForPassword(participant, data.needUrlIsCorrectPassword);
} }

View File

@ -59,6 +59,9 @@ var cfgImageSize = config_server.get('limits_image_size');
var cfgImageDownloadTimeout = config_server.get('limits_image_download_timeout'); var cfgImageDownloadTimeout = config_server.get('limits_image_download_timeout');
var cfgRedisPrefix = config.get('services.CoAuthoring.redis.prefix'); var cfgRedisPrefix = config.get('services.CoAuthoring.redis.prefix');
var cfgTokenEnableBrowser = config.get('services.CoAuthoring.token.enable.browser'); var cfgTokenEnableBrowser = config.get('services.CoAuthoring.token.enable.browser');
const cfgTokenSessionAlgorithm = config.get('services.CoAuthoring.token.session.algorithm');
const cfgTokenSessionExpires = ms(config.get('services.CoAuthoring.token.session.expires'));
const cfgSecretSession = config.get('services.CoAuthoring.secret.session');
const cfgForgottenFiles = config_server.get('forgottenfiles'); const cfgForgottenFiles = config_server.get('forgottenfiles');
const cfgForgottenFilesName = config_server.get('forgottenfilesname'); const cfgForgottenFilesName = config_server.get('forgottenfilesname');
const cfgOpenProtectedFile = config_server.get('openProtectedFile'); const cfgOpenProtectedFile = config_server.get('openProtectedFile');
@ -178,13 +181,16 @@ var getOutputData = co.wrap(function* (cmd, outputData, key, optConn, optAdditio
if ('open' != command && 'reopen' != command && !cmd.getOutputUrls()) { if ('open' != command && 'reopen' != command && !cmd.getOutputUrls()) {
var strPath = key + '/' + cmd.getOutputPath(); var strPath = key + '/' + cmd.getOutputPath();
if (optConn) { if (optConn) {
var contentDisposition = cmd.getInline() ? constants.CONTENT_DISPOSITION_INLINE : constants.CONTENT_DISPOSITION_ATTACHMENT; let url;
let url = yield storage.getSignedUrl(optConn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary, if(cmd.getInline()) {
cmd.getTitle(), url = getPrintFileUrl(key, optConn.baseUrl, cmd.getTitle());
contentDisposition); } else {
url = yield storage.getSignedUrl(optConn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary,
cmd.getTitle());
}
outputData.setData(url); outputData.setData(url);
} else if (optAdditionalOutput) { } else if (optAdditionalOutput) {
optAdditionalOutput.needUrlKey = strPath; optAdditionalOutput.needUrlKey = cmd.getInline() ? key : strPath;
optAdditionalOutput.needUrlMethod = 2; optAdditionalOutput.needUrlMethod = 2;
optAdditionalOutput.needUrlType = commonDefines.c_oAscUrlTypes.Temporary; optAdditionalOutput.needUrlType = commonDefines.c_oAscUrlTypes.Temporary;
} }
@ -689,22 +695,16 @@ function* commandImgurls(conn, cmd, outputData) {
} }
} }
function* commandPathUrls(conn, cmd, outputData) { function* commandPathUrls(conn, cmd, outputData) {
let contentDisposition = cmd.getInline() ? constants.CONTENT_DISPOSITION_INLINE :
constants.CONTENT_DISPOSITION_ATTACHMENT;
let listImages = cmd.getData().map(function callback(currentValue) { let listImages = cmd.getData().map(function callback(currentValue) {
return conn.docId + '/' + currentValue; return conn.docId + '/' + currentValue;
}); });
let urls = yield storage.getSignedUrlsArrayByArray(conn.baseUrl, listImages, commonDefines.c_oAscUrlTypes.Session, let urls = yield storage.getSignedUrlsArrayByArray(conn.baseUrl, listImages, commonDefines.c_oAscUrlTypes.Session);
contentDisposition);
outputData.setStatus('ok'); outputData.setStatus('ok');
outputData.setData(urls); outputData.setData(urls);
} }
function* commandPathUrl(conn, cmd, outputData) { function* commandPathUrl(conn, cmd, outputData) {
var contentDisposition = cmd.getInline() ? constants.CONTENT_DISPOSITION_INLINE :
constants.CONTENT_DISPOSITION_ATTACHMENT;
var strPath = conn.docId + '/' + cmd.getData(); var strPath = conn.docId + '/' + cmd.getData();
var url = yield storage.getSignedUrl(conn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary, cmd.getTitle(), var url = yield storage.getSignedUrl(conn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary, cmd.getTitle());
contentDisposition);
var errorCode = constants.NO_ERROR; var errorCode = constants.NO_ERROR;
if (constants.NO_ERROR !== errorCode) { if (constants.NO_ERROR !== errorCode) {
outputData.setStatus('err'); outputData.setStatus('err');
@ -934,8 +934,8 @@ function* commandSfcCallback(cmd, isSfcm, isEncrypted) {
} }
try { try {
if (wopiParams) { if (wopiParams) {
let data = yield storage.getObject(savePathDoc); let streamObj = yield storage.createReadStream(savePathDoc);
replyStr = yield wopiClient.putFile(wopiParams, data, userLastChangeId); replyStr = yield wopiClient.putFile(wopiParams, null, streamObj.readStream, userLastChangeId);
} else { } else {
replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength); replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength);
} }
@ -967,8 +967,8 @@ function* commandSfcCallback(cmd, isSfcm, isEncrypted) {
updateMask.statusInfo = updateIfTask.statusInfo; updateMask.statusInfo = updateIfTask.statusInfo;
try { try {
if (wopiParams) { if (wopiParams) {
let data = yield storage.getObject(savePathDoc); let streamObj = yield storage.createReadStream(savePathDoc);
replyStr = yield wopiClient.putFile(wopiParams, data, userLastChangeId); replyStr = yield wopiClient.putFile(wopiParams, null, streamObj.readStream, userLastChangeId);
} else { } else {
replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength); replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength);
} }
@ -1320,6 +1320,65 @@ exports.saveFile = function(req, res) {
} }
}); });
}; };
function getPrintFileUrl(docId, baseUrl, filename) {
baseUrl = utils.checkBaseUrl(baseUrl);
let token = '';
if (cfgTokenEnableBrowser) {
let payload = {document: {key: docId}};
token = docsCoServer.signToken(payload, cfgTokenSessionAlgorithm, cfgTokenSessionExpires / 1000, cfgSecretSession);
}
return `${baseUrl}/printfile/${encodeURIComponent(docId)}?filename=${encodeURIComponent(filename)}&token=${encodeURIComponent(token)}`;
};
exports.getPrintFileUrl = getPrintFileUrl;
exports.printFile = function(req, res) {
return co(function*() {
let docId = 'null';
try {
let startDate = null;
if (clientStatsD) {
startDate = new Date();
}
let filename = req.query['filename'];
let token = req.query['token'];
docId = req.params.docid;
logger.info('Start printFile: docId = %s', docId);
if (cfgTokenEnableBrowser) {
let checkJwtRes = docsCoServer.checkJwt(docId, token, commonDefines.c_oAscSecretType.Session);
if (checkJwtRes.decoded) {
let docIdBase = checkJwtRes.decoded.document.key;
if (!docId.startsWith(docIdBase)) {
logger.warn('Error printFile jwt: docId = %s description = %s', docId, 'access deny');
res.sendStatus(403);
return;
}
} else {
logger.warn('Error printFile jwt: docId = %s description = %s', docId, checkJwtRes.description);
res.sendStatus(403);
return;
}
}
let streamObj = yield storage.createReadStream(`${docId}/${constants.OUTPUT_NAME}.pdf`);
res.setHeader('Content-Disposition', utils.getContentDisposition(filename, null, constants.CONTENT_DISPOSITION_INLINE));
res.setHeader('Content-Length', streamObj.contentLength);
res.setHeader('Content-Type', 'application/pdf');
yield utils.pipeStreams(streamObj.readStream, res, true);
if (clientStatsD) {
clientStatsD.timing('coauth.printFile', new Date() - startDate);
}
}
catch (e) {
logger.error('Error printFile: docId = %s %s', docId, e.stack);
res.sendStatus(400);
}
finally {
logger.info('End printFile: docId = %s', docId);
}
});
};
exports.saveFromChanges = function(docId, statusInfo, optFormat, opt_userId, opt_userIndex, opt_queue) { exports.saveFromChanges = function(docId, statusInfo, optFormat, opt_userId, opt_userIndex, opt_queue) {
return co(function* () { return co(function* () {
try { try {

View File

@ -106,10 +106,9 @@ if (configStorage.has('fs.folderPath')) {
app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => { app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
const index = req.url.lastIndexOf('/'); const index = req.url.lastIndexOf('/');
if ('GET' === req.method && -1 != index) { if ('GET' === req.method && -1 != index) {
const contentDisposition = req.query['disposition'] || 'attachment';
let sendFileOptions = { let sendFileOptions = {
root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: { root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: {
'Content-Disposition': contentDisposition 'Content-Disposition': 'attachment'
} }
}; };
const urlParsed = urlModule.parse(req.url); const urlParsed = urlModule.parse(req.url);
@ -187,6 +186,7 @@ docsCoServer.install(server, () => {
app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs); app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
app.post('/savefile/:docid', rawFileParser, canvasService.saveFile); app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
app.get('/printfile/:docid', rawFileParser, canvasService.printFile);
app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck); app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);
app.get('/baseurl', (req, res) => { app.get('/baseurl', (req, res) => {

View File

@ -283,7 +283,7 @@ function getEditorHtml(req, res) {
} }
}); });
} }
function putFile(wopiParams, data, userLastChangeId) { function putFile(wopiParams, data, dataStream, userLastChangeId) {
return co(function* () { return co(function* () {
try { try {
logger.info('wopi PutFile start'); logger.info('wopi PutFile start');
@ -298,7 +298,7 @@ function putFile(wopiParams, data, userLastChangeId) {
fillStandardHeaders(headers, uri, userAuth.access_token); fillStandardHeaders(headers, uri, userAuth.access_token);
logger.debug('wopi PutFile request uri=%s headers=%j', uri, headers); logger.debug('wopi PutFile request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(uri, data, cfgCallbackRequestTimeout, undefined, headers); let postRes = yield utils.postRequestPromise(uri, data, dataStream, cfgCallbackRequestTimeout, undefined, headers);
logger.debug('wopi PutFile response headers=%j', postRes.response.headers); logger.debug('wopi PutFile response headers=%j', postRes.response.headers);
} else { } else {
logger.info('wopi SupportsUpdate = false'); logger.info('wopi SupportsUpdate = false');
@ -329,7 +329,7 @@ function renameFile(wopiParams, name) {
fillStandardHeaders(headers, uri, userAuth.access_token); fillStandardHeaders(headers, uri, userAuth.access_token);
logger.debug('wopi RenameFile request uri=%s headers=%j', uri, headers); logger.debug('wopi RenameFile request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(uri, undefined, cfgCallbackRequestTimeout, undefined, headers); let postRes = yield utils.postRequestPromise(uri, undefined, undefined, cfgCallbackRequestTimeout, undefined, headers);
logger.debug('wopi RenameFile response headers=%j body=%s', postRes.response.headers, postRes.body); logger.debug('wopi RenameFile response headers=%j body=%s', postRes.response.headers, postRes.body);
if (postRes.body) { if (postRes.body) {
res = JSON.parse(postRes.body); res = JSON.parse(postRes.body);
@ -382,7 +382,7 @@ function lock(lockId, fileInfo, userAuth) {
let headers = {"X-WOPI-Override": "LOCK", "X-WOPI-Lock": lockId}; let headers = {"X-WOPI-Override": "LOCK", "X-WOPI-Lock": lockId};
fillStandardHeaders(headers, uri, access_token); fillStandardHeaders(headers, uri, access_token);
logger.debug('wopi Lock request uri=%s headers=%j', uri, headers); logger.debug('wopi Lock request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(uri, undefined, cfgCallbackRequestTimeout, undefined, headers); let postRes = yield utils.postRequestPromise(uri, undefined, undefined, cfgCallbackRequestTimeout, undefined, headers);
logger.debug('wopi Lock response headers=%j', postRes.response.headers); logger.debug('wopi Lock response headers=%j', postRes.response.headers);
} else { } else {
logger.info('wopi SupportsLocks = false'); logger.info('wopi SupportsLocks = false');
@ -410,7 +410,7 @@ function unlock(wopiParams) {
let headers = {"X-WOPI-Override": "UNLOCK", "X-WOPI-Lock": lockId}; let headers = {"X-WOPI-Override": "UNLOCK", "X-WOPI-Lock": lockId};
fillStandardHeaders(headers, uri, access_token); fillStandardHeaders(headers, uri, access_token);
logger.debug('wopi Unlock request uri=%s headers=%j', uri, headers); logger.debug('wopi Unlock request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(uri, undefined, cfgCallbackRequestTimeout, undefined, headers); let postRes = yield utils.postRequestPromise(uri, undefined, undefined, cfgCallbackRequestTimeout, undefined, headers);
logger.debug('wopi Unlock response headers=%j', postRes.response.headers); logger.debug('wopi Unlock response headers=%j', postRes.response.headers);
} else { } else {
logger.info('wopi SupportsLocks = false'); logger.info('wopi SupportsLocks = false');