cloudcms-server
Version:
Cloud CMS Application Server Module
231 lines (188 loc) • 7.97 kB
JavaScript
// var http = require("http");
// var https = require("https");
var path = require("path");
var auth = require("./auth");
// var util = require("./util");
var oauth2 = require("./oauth2")();
var LRU = require("lru-cache");
var exports = module.exports;
var _LOCK = function(lockIdentifiers, workFunction)
{
var name = lockIdentifiers.join("_");
process.locks.lock(name, workFunction);
};
var NAMED_PROXY_HANDLERS_CACHE = new LRU({
max: 200,
ttl: 1000 * 60 * 60 // 60 minutes
});
var acquireProxyHandler = exports.acquireProxyHandler = function(proxyTarget, pathPrefix, callback)
{
var name = path.join(proxyTarget, (pathPrefix || "/"));
// is it already in LRU cache?
// if so hand it back
var _cachedHandler = NAMED_PROXY_HANDLERS_CACHE[name];
if (_cachedHandler)
{
return callback(null, _cachedHandler);
}
_cachedHandler = NAMED_PROXY_HANDLERS_CACHE[name] = createProxyHandler(proxyTarget, pathPrefix);
callback(null, _cachedHandler);
};
var createProxyHandler = function(proxyTarget, pathPrefix)
{
const { proxy, close } = require('fast-proxy')({
base: proxyTarget,
cacheURLs: 0,
keepAlive: true,
keepAliveMsecs: process.defaultKeepAliveMs,
maxSockets: 1024,
maxFreeSockets: 256,
timeout: process.defaultHttpTimeoutMs,
freeSocketTimeout: 5000
//http2: true,
//undici: true
});
var proxyOptions = {};
proxyOptions.onResponse = function(req, res, stream) {
if (req.gitana_user)
{
var chunks = [];
// triggers on data receive
stream.on('data', function(chunk) {
console.log("DATA!");
// add received chunk to chunks array
chunks.push(chunk);
});
stream.on("end", function () {
if (stream.statusCode === 401)
{
var text = "" + Buffer.concat(chunks);
if (text && (text.indexOf("invalid_token") > -1) || (text.indexOf("invalid_grant") > -1))
{
var identifier = req.identity_properties.provider_id + "/" + req.identity_properties.user_identifier;
_LOCK([identifier], function(err, releaseLockFn) {
if (err)
{
// failed to acquire lock
console.log("FAILED TO ACQUIRE LOCK", err);
req.log("FAILED TO ACQUIRE LOCK", err);
try { releaseLockFn(); } catch (e) { }
return;
}
var cleanup = function (full)
{
delete Gitana.APPS[req.identity_properties.token];
delete Gitana.PLATFORM_CACHE[req.identity_properties.token];
if (full) {
auth.removeUserCacheEntry(identifier);
}
};
// null out the access token
// this will force the refresh token to be used to get a new one on the next request
req.gitana_user.getDriver().http.refresh(function (err) {
if (err) {
cleanup(true);
req.log("Invalidated auth state for gitana user: " + req.identity_properties.token);
return releaseLockFn();
}
req.gitana_user.getDriver().reloadAuthInfo(function () {
cleanup(true);
req.log("Refreshed token for gitana user: " + req.identity_properties.token);
releaseLockFn();
});
});
});
}
}
});
}
//res.setHeader('x-powered-by', 'cloudcms');
if (stream.statusCode && stream.headers) {
res.writeHead(stream.statusCode, stream.headers)
}
stream.pipe(res)
};
proxyOptions.rewriteRequestHeaders = function(req, headers)
{
// used to auto-assign the client header for /oauth/token requests
oauth2.autoProxy(req);
if (req.headers && req.headers.authorization)
{
headers["authorization"] = req.headers.authorization;
}
// copy domain host into "x-cloudcms-domainhost"
if (req.domainHost) {
headers["x-cloudcms-domainhost"] = req.domainHost; // this could be "localhost"
}
// copy virtual host into "x-cloudcms-virtualhost"
if (req.virtualHost) {
headers["x-cloudcms-virtualhost"] = req.virtualHost; // this could be "root.cloudcms.net" or "abc.cloudcms.net"
}
// copy deployment descriptor info
if (req.descriptor)
{
if (req.descriptor.tenant)
{
if (req.descriptor.tenant.id)
{
headers["x-cloudcms-tenant-id"] = req.descriptor.tenant.id;
}
if (req.descriptor.tenant.title)
{
headers["x-cloudcms-tenant-title"] = req.descriptor.tenant.title;
}
}
if (req.descriptor.application)
{
if (req.descriptor.application.id)
{
headers["x-cloudcms-application-id"] = req.descriptor.application.id;
}
if (req.descriptor.application.title)
{
headers["x-cloudcms-application-title"] = req.descriptor.application.title;
}
}
}
// set optional "x-cloudcms-origin" header
var cloudcmsOrigin = null;
if (req.virtualHost)
{
cloudcmsOrigin = req.virtualHost;
}
if (cloudcmsOrigin)
{
headers["x-cloudcms-origin"] = cloudcmsOrigin;
}
// set x-cloudcms-server-version header
headers["x-cloudcms-server-version"] = process.env.CLOUDCMS_APPSERVER_PACKAGE_VERSION;
// keep alive
//req.headers["connection"] = "keep-alive";
// if the incoming request didn't have an "Authorization" header
// and we have a logged in Gitana User via Auth, then set authorization header to Bearer Access Token
if (!req.headers["authorization"])
{
if (req.gitana_user)
{
headers["authorization"] = "Bearer " + req.gitana_user.getDriver().http.accessToken();
}
else if (req.gitana_proxy_access_token)
{
headers["authorization"] = "Bearer " + req.gitana_proxy_access_token;
}
}
return headers;
};
// rewrite response headers
proxyOptions.rewriteHeaders = function(headers)
{
return headers;
};
// request invoke settings
//proxyOptions.request = {};
//////////////////////////////////////////////////////////////////////////
var proxyRequestHandler = function(req, res) {
proxy(req, res, pathPrefix, proxyOptions);
};
return proxyRequestHandler;
};