Skip to content
Snippets Groups Projects
Commit f52ac361 authored by Kevin Abel's avatar Kevin Abel
Browse files

Initial commit

A JavaScript implementation of a proxy that will fetch the navigation UL
from WDN Framework pages.
parents
Branches
No related tags found
No related merge requests found
.DS_Store
.htaccess
/node_modules
{
"name": "nav-proxy",
"version": "1.0.0",
"description": "A proxy for the WDN Framework that returns the navigation list from the requested page.",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "UNL Web Developer Network <wdn@unl.edu> (http://wdn.unl.edu/)",
"license": "BSD-3-Clause",
"dependencies": {
"jquery": "^2.1.4",
"jsdom": "^7.1.1",
"negotiator": "^0.6.0",
"request": "^2.67.0"
},
"config": {
"port": 8080,
"allowedDomains": "",
},
"repository": {
"type": "git",
"url": "git@git.unl.edu:iim/UNL_Navigation_Proxy.git"
}
}
server.js 0 → 100644
var zlib = require('zlib');
var http = require('http');
var request = require('request');
var Neg = require('negotiator');
var url = require('url');
var jsdom = require("jsdom").jsdom;
require("jsdom").defaultDocumentFeatures = {
FetchExternalResources: false,
ProcessExternalResources: false
};
var port = process.env.npm_package_config_port || 8080;
var allowedDomainsConf = process.env.npm_package_config_allowedDomains;
var allowedDomains = allowedDomainsConf && allowedDomainsConf.length && allowedDomainsConf.slice() || [
'unl.edu',
'nebraska.edu',
'buros.org',
];
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function send404(res, message, req) {
res.statusCode = 404;
if (message && message.length) {
if (getGz(req)) {
res.setHeader('content-encoding', 'gzip');
message = zlib.gzipSync(message);
}
res.write(message);
}
res.end();
}
function sendHtml(res, html, req) {
res.statusCode = 200;
res.setHeader('content-type', 'text/html');
if (getGz(req)) {
res.setHeader('content-encoding', 'gzip');
html = zlib.gzipSync(html);
}
res.setHeader('content-length', html.length);
res.end(html);
}
function parseNavigation(html, baseUrl, callback) {
try {
var doc = jsdom(html);
var global = doc.defaultView;
var $ = require('jquery')(global);
// check for a document provided URL base
var baseElement;
baseElement = $('head > base')[0];
if (baseElement) {
baseUrl = url.resolve(baseUrl, baseElement.getAttribute('href'));
}
// find the navigation list element
var navListElement;
navListElement = $('#navigation > ul, #navigation > * > ul')[0];
if (!navListElement) {
callback(true, false);
}
var elements, element, realUrl;
// sanitize the elements of css attributes
elements = $('*', navListElement);
elements.removeAttr('style class');
// resolve the elements' href attributes using the baseUrl
elements = $('[href]', navListElement);
elements.each(function() {
element = this;
realUrl = url.resolve(baseUrl, element.getAttribute('href'));
element.setAttribute('href', realUrl);
});
callback(false, navListElement.outerHTML);
} catch (err) {
callback('Bad navigation HTML found. ' + err, false);
}
}
function getGz (req) {
var gz = false;
var neg = req.negotiator || new Neg(req);
gz = neg.preferredEncoding(['gzip', 'identity']) === 'gzip';
return gz;
}
var allowedDomainsRegExp = new RegExp('(?:^|\\.)(?:' + allowedDomains.map(escapeRegExp).join('|') + ')$');
http.createServer(function handler(req, res) {
var reqUrl = url.parse(req.url, true);
var baseUrl = reqUrl.query.u;
var parsedBaseUrl;
// is this a CORS request, only allow specific origins
if (req.headers.origin && allowedDomainsRegExp.test(url.parse(req.headers.origin).hostname)) {
res.setHeader('access-control-allow-origin', req.headers.origin);
res.setHeader('access-control-allow-headers', 'X-Requested-With');
res.setHeader('access-control-allow-methods', 'GET, OPTIONS');
}
if (reqUrl.pathname !== '/') {
send404(res, 'bad path', req);
return;
}
if (!baseUrl) {
send404(res, 'no url', req);
return;
}
parsedBaseUrl = url.parse(baseUrl || '');
if (!/^https?:$/.test(parsedBaseUrl.protocol)) {
send404(res, 'bad protocol', req);
return;
}
if (!allowedDomainsRegExp.test(parsedBaseUrl.hostname)) {
send404(res, 'bad host', req);
return;
}
var clientReq = request({
url: parsedBaseUrl,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; UNL_Navigation_Proxy/1.0; http://wdn.unl.edu/)'
},
qzip: true,
time: true
}, function(err, clientRes, body) {
if (err || clientRes.statusCode !== 200) {
send404(res, 'proxy failed', req);
return;
}
var startTime = Date.now();
parseNavigation(body, clientReq.uri.href, function(err, output) {
console.log('processed navigation in %dms (%dms)', Date.now() - startTime, clientRes.elapsedTime);
if (err) {
send404(res, err, req);
return;
}
sendHtml(res, output, req);
});
});
}).listen(port);
console.log('Navigation Proxy listening on port ' + port);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment