Skip to content

Commit

Permalink
[FIX] Proxy upload to correct instance
Browse files Browse the repository at this point in the history
Proxy the file upload parts to the instance who created the file when running with multiple instances to prevent errors when sticky sessions does not works.
  • Loading branch information
rodrigok committed Jun 21, 2017
1 parent 8ea4a8b commit e7e0785
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 1 deletion.
6 changes: 6 additions & 0 deletions packages/rocketchat-lib/server/models/Avatars.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* globals InstanceStatus */

RocketChat.models.Avatars = new class extends RocketChat.models._Base {
constructor() {
super('avatars');

this.model.before.insert((userId, doc) => {
doc.instanceId = InstanceStatus.id();
});

this.tryEnsureIndex({ name: 1 });
}

Expand Down
6 changes: 6 additions & 0 deletions packages/rocketchat-lib/server/models/Uploads.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* globals InstanceStatus */

RocketChat.models.Uploads = new class extends RocketChat.models._Base {
constructor() {
super('uploads');

this.model.before.insert((userId, doc) => {
doc.instanceId = InstanceStatus.id();
});

this.tryEnsureIndex({ 'rid': 1 });
this.tryEnsureIndex({ 'uploadedAt': 1 });
}
Expand Down
93 changes: 92 additions & 1 deletion server/startup/avatar.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,95 @@
/* globals FileUpload */
/* globals FileUpload, UploadFS, InstanceStatus */

import http from 'http';
import URL from 'url';

const logger = new Logger('UploadProxy');

WebApp.connectHandlers.stack.unshift({
route: '',
handle: Meteor.bindEnvironment(function(req, res, next) {
// Quick check to see if request should be catch
if (req.url.indexOf(UploadFS.config.storesPath) === -1) {
return next();
}

logger.debug('Upload URL:', req.url);

if (req.method !== 'POST') {
return next();
}

// Remove store path
const parsedUrl = URL.parse(req.url);
const path = parsedUrl.pathname.substr(UploadFS.config.storesPath.length + 1);

// Get store
const regExp = new RegExp('^\/([^\/\?]+)\/([^\/\?]+)$');
const match = regExp.exec(path);

// Request is not valid
if (match === null) {
res.writeHead(400);
res.end();
return;
}

// Get store
const store = UploadFS.getStore(match[1]);
if (!store) {
res.writeHead(404);
res.end();
return;
}

// Get file
const fileId = match[2];
const file = store.getCollection().findOne({_id: fileId});
if (file === undefined) {
res.writeHead(404);
res.end();
return;
}

if (file.instanceId === InstanceStatus.id()) {
logger.debug('Correct instance');
return next();
}

// Proxy to other instance
const instance = InstanceStatus.getCollection().findOne({_id: file.instanceId});

if (instance == null) {
res.writeHead(404);
res.end();
return;
}

if (instance.extraInformation.host === process.env.INSTANCE_IP && RocketChat.isDocker() === false) {
instance.extraInformation.host = 'localhost';
}

logger.debug('Wrong instance, proxing to:', `${ instance.extraInformation.host }:${ instance.extraInformation.port }`);

const options = {
hostname: instance.extraInformation.host,
port: instance.extraInformation.port,
path: req.url,
method: 'POST'
};

const proxy = http.request(options, function(proxy_res) {
proxy_res.pipe(res, {
end: true
});
});

req.pipe(proxy, {
end: true
});
})
});

Meteor.startup(function() {
WebApp.connectHandlers.use('/avatar/', Meteor.bindEnvironment(function(req, res/*, next*/) {
const params = {
Expand Down

0 comments on commit e7e0785

Please sign in to comment.