openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
163 lines (146 loc) • 5.84 kB
JavaScript
var Channel, Q, config, invertPathTransform, rewriteUrls, router, routerConf, url, utils, winston;
url = require('url');
winston = require('winston');
Q = require('q');
Channel = (require('../../lib/model/channels')).Channel;
config = require('../config/config');
routerConf = config.get('router');
utils = require('../../lib/utils');
router = require('../../lib/middleware/router');
invertPathTransform = function(pathTransform) {
return pathTransform.replace(/s\/(.*?)\/(.*?)(?:$|\/(.*)$)/, 's/$2/$1/$3');
};
exports.fetchRewriteConfig = function(channel, authType, callback) {
var rwConfig;
rwConfig = [];
if (channel.rewriteUrlsConfig != null) {
rwConfig = rwConfig.concat(channel.rewriteUrlsConfig);
}
if (channel.addAutoRewriteRules) {
/*
* Add in default (virtual) rewrite rules for hosts we proxy
*
* For example if the SHR for some reason sent back a link to a patient in the CR
* (using a direct link to the CR), then if we have a channel that points to the
* CR on a primary route we are able to rewrite the link to point to us instead
* because we know that host.
*/
return utils.getAllChannelsInPriorityOrder(function(err, channels) {
var fn, i, j, len, len1, ref, route;
if (err != null) {
return callback(err);
}
for (i = 0, len = channels.length; i < len; i++) {
channel = channels[i];
ref = channel.routes;
fn = function() {
var inverseTransform, toPort;
if (route.primary) {
/*
* if this channel has a pathTranform on its primary route then
* invert the path transform so that links that point to this route
* have the path transform reversed when they are rewritten
*
* For example, say we have a channel with urlPattern=/CSD/ and a
* pathTransform on the primary route as follows pathTransform=s/CSD/ihris/
* (ie. the actual server we are proxying is running on http://<host>:<port>/ihirs/).
* If we get links back from this server it will be something like
* http://<host>:<port>/ihirs/something/123 but we need it to be
* http://<him_host>:<him_port>/CSD/something/123. To do this we can reverse
* the pathTransform on the route (s/ihris/CSD/) and apply it while doing the
* rewrite.
*/
if (route.pathTransform) {
inverseTransform = invertPathTransform(route.pathTransform);
}
if ((authType != null) === 'tls') {
toPort = routerConf.httpsPort;
} else {
toPort = routerConf.httpPort;
}
return rwConfig.push({
'fromHost': route.host,
'toHost': routerConf.externalHostname,
'fromPort': route.port,
'toPort': toPort,
'pathTransform': inverseTransform ? inverseTransform : null
});
}
};
for (j = 0, len1 = ref.length; j < len1; j++) {
route = ref[j];
fn();
}
}
return callback(null, rwConfig);
});
} else {
return callback(null, rwConfig);
}
};
rewriteUrls = function(body, channel, authType, callback) {
return exports.fetchRewriteConfig(channel, authType, function(err, rwConfig) {
var newBody;
if (err != null) {
return callback(err);
}
newBody = body.replace(/["|']?(?:href|src|fullUrl)["|']?[:|=]\s?["|'](\S*?)["|']/g, function(match, hrefUrl) {
var hrefUrlObj, i, j, len, len1, ref, relativePath, replacement, rewriteRule, route;
hrefUrlObj = url.parse(hrefUrl);
if (hrefUrlObj.host == null) {
ref = channel.routes;
for (i = 0, len = ref.length; i < len; i++) {
route = ref[i];
if (route.primary) {
hrefUrlObj.hostname = route.host;
hrefUrlObj.port = route.port.toString();
relativePath = true;
break;
}
}
}
for (j = 0, len1 = rwConfig.length; j < len1; j++) {
rewriteRule = rwConfig[j];
if (rewriteRule.fromHost.toLowerCase() === hrefUrlObj.hostname && (rewriteRule.fromPort.toString() === hrefUrlObj.port || (rewriteRule.fromPort === 80 && hrefUrlObj.port === null))) {
hrefUrlObj.host = null;
hrefUrlObj.hostname = rewriteRule.toHost;
hrefUrlObj.port = rewriteRule.toPort;
if (hrefUrlObj.protocol) {
if (rewriteRule.toPort === routerConf.httpsPort) {
hrefUrlObj.protocol = 'https';
} else {
hrefUrlObj.protocol = 'http';
}
}
if (rewriteRule.pathTransform) {
hrefUrlObj.pathname = router.transformPath(hrefUrlObj.pathname, rewriteRule.pathTransform);
}
break;
}
}
if (relativePath) {
hrefUrlObj.host = null;
hrefUrlObj.hostname = null;
hrefUrlObj.port = null;
}
replacement = url.format(hrefUrlObj);
winston.debug("Rewriting url " + hrefUrl + " as " + replacement);
return match.replace(hrefUrl, replacement);
});
return callback(null, newBody);
});
};
if (process.env.NODE_ENV === 'test') {
exports.invertPathTransform = invertPathTransform;
exports.rewriteUrls = rewriteUrls;
}
exports.koaMiddleware = function*(next) {
var rewrite;
(yield next);
if (this.authorisedChannel.rewriteUrls) {
rewrite = Q.denodeify(rewriteUrls);
this.response.body = (yield rewrite(this.response.body.toString(), this.authorisedChannel, this.authenticationType));
return winston.info("Rewrote url in the response of transaction: " + this.transactionId);
}
};
//# sourceMappingURL=rewriteUrls.js.map