From b0ff49e4562ce1546dbd50c05d0ddafef5f076f5 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Fri, 6 Nov 2015 21:52:35 +0100 Subject: [PATCH] Improve reliability of the test server - replace // with / (otherwise http://localhost:8888// links to e.g. http://src/ instead of http://localhost:8888/src). - Solve XSS issue (file names should be sanitized, not output as-is). - Prevent server from crashing if there is a stat error (e.g. permission error or file not found (e.g. broken symlink)). --- test/webserver.js | 52 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/test/webserver.js b/test/webserver.js index 9fac55ca4..c108d689f 100644 --- a/test/webserver.js +++ b/test/webserver.js @@ -66,7 +66,7 @@ WebServer.prototype = { this.server = null; }, _handler: function (req, res) { - var url = req.url; + var url = req.url.replace(/\/\//g, '/'); var urlParts = /([^?]*)((?:\?(.*))?)/.exec(url); var pathPart = decodeURI(urlParts[1]), queryPart = urlParts[3]; var verbose = this.verbose; @@ -158,6 +158,17 @@ WebServer.prototype = { serveRequestedFile(filePath); } + function escapeHTML(untrusted) { + // Escape untrusted input so that it can safely be used in a HTML response + // in HTML and in HTML attributes. + return untrusted + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + function serveDirectoryIndex(dir) { res.setHeader('Content-Type', 'text/html'); res.writeHead(200); @@ -180,21 +191,34 @@ WebServer.prototype = { res.write('..
\n'); } files.forEach(function (file) { - var stat = fs.statSync(path.join(dir, file)); + var stat; var item = pathPart + file; - if (stat.isDirectory()) { - res.write('' + - file + '
\n'); - return; + var href = ''; + var label = ''; + var extraAttributes = ''; + try { + stat = fs.statSync(path.join(dir, file)); + } catch (e) { + href = encodeURI(item); + label = file + ' (' + e + ')'; + extraAttributes = ' style="color:red"'; } - var ext = path.extname(file).toLowerCase(); - if (ext === '.pdf') { - res.write('' + - file + '
\n'); - } else if (all) { - res.write('' + - file + '
\n'); + if (stat) { + if (stat.isDirectory()) { + href = encodeURI(item); + label = file; + } else if (path.extname(file).toLowerCase() === '.pdf') { + href = '/web/viewer.html?file=' + encodeURIComponent(item); + label = file; + extraAttributes = ' target="pdf"'; + } else if (all) { + href = encodeURI(item); + label = file; + } + } + if (label) { + res.write('' + escapeHTML(label) + '
\n'); } }); if (files.length === 0) {