00001 #!/usr/bin/node
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 var fs = require('fs');
00014 var path_module = require('path');
00015 var module_holder = {};
00016 var workerData = {};
00017 var child_process = require('child_process');
00018
00019 var util = require('util');
00020 var log_file = fs.createWriteStream('/tmp/server.' + process.env["USER"] + '.log', { flags : 'a' });
00021 var log_stdout = process.stdout;
00022
00023 var getversion = function () {
00024 console.log("Getting Server Version");
00025 if (fs.existsSync("./version.txt")) {
00026 console.log("Reading Server Version from File");
00027 return "" + fs.readFileSync("./version.txt");
00028 }
00029 else {
00030 child_process.exec("git describe --tags", function (error, stdout, stderr) {
00031 version = stdout.trim() + "-Git";
00032 child_process.exec("git status --porcelain", function (error, stdout) {
00033 if (stdout.length > 0) {
00034 version += "*";
00035 }
00036 });
00037 });
00038 }
00039 }
00040 var version = getversion();
00041
00042 var config = {
00043 ignored_modules: [],
00044 baseport: 8080,
00045 portOffset: 80,
00046 hostname: "localhost",
00047 module_config: []
00048 };
00049 function loadConfig() {
00050 if (fs.existsSync("config.json")) {
00051 config = JSON.parse(fs.readFileSync("config.json"));
00052 } else {
00053 fs.writeFileSync("config.json", JSON.stringify(config));
00054 }
00055
00056 if (process.env.ARTDAQDEMO_BASE_PORT) {
00057 config.baseport = parseInt(process.env["ARTDAQDEMO_BASE_PORT"]) + config.portOffset;
00058 }
00059
00060 if (config.hostname === "localhost" && cluster.isMaster) {
00061 console.log("Listening only on localhost. To listen on a different address, set \"hostname\" in config.json.\nUse \"0.0.0.0\" to listen on all interfaces.");
00062 }
00063 }
00064
00065 loadConfig();
00066
00067 console.log = function (d) {
00068 log_file.write(util.format(d) + '\n');
00069 log_stdout.write(util.format(d) + '\n');
00070 };
00071
00072 function LoadCerts(path) {
00073 var output = [];
00074 var files = fs.readdirSync(path);
00075 for (var i = 0; i < files.length; i++) {
00076 if (files[i].search(".pem") > 0 || files[i].search(".crt") > 0) {
00077 output.push(fs.readFileSync(path + "/" + files[i]));
00078 }
00079 }
00080 return output;
00081 }
00082
00083
00084
00085 function LoadModules(path) {
00086 var stat = fs.lstatSync(path);
00087 if (stat.isDirectory()) {
00088
00089 var files = fs.readdirSync(path);
00090 var f, l = files.length;
00091 for (var i = 0; i < l; i++) {
00092 f = path_module.join(path, files[i]);
00093 LoadModules(f);
00094 }
00095 } else if (path.search("_module.js") > 0 && path.search("js~") < 0) {
00096 console.log("Loading Submodule " + path);
00097
00098
00099 require(path)(module_holder);
00100 console.log("Initialized Submodule " + path);
00101 }
00102 }
00103 var DIR = path_module.join(__dirname, "modules");
00104 LoadModules(DIR);
00105
00106
00107 var https = require('https');
00108 var http = require('http');
00109 var url = require('url');
00110 var qs = require('querystring');
00111
00112 for (var name in module_holder) {
00113 if (module_holder.hasOwnProperty(name)) {
00114 module_holder[name].on("message", function (data) {
00115
00116
00117
00118 });
00119 try {
00120 module_holder[name].MasterInitFunction(workerData, config.module_config[name]);
00121 module_holder[name].WorkerInitFunction(workerData);
00122 } catch (err) {
00123 ;
00124 }
00125 }
00126 }
00127
00128 function serve(req, res, readOnly, username) {
00129
00130
00131 var pathname = url.parse(req.url, true).pathname;
00132 if (pathname[0] === '/') {
00133 pathname = pathname.substr(1);
00134 }
00135
00136 var moduleName = pathname.substr(0, pathname.indexOf('/'));
00137 var functionName = pathname.substr(pathname.indexOf('/') + 1);
00138
00139 var dnsDone = false;
00140
00141 require('dns').reverse(req.connection.remoteAddress, function (err, domains) {
00142 dnsDone = true;
00143 if (!err) {
00144 if (functionName.search(".min.map") < 0) {
00145
00146 console.log("Received " + req.method + ", Client: " + domains[0] + " [" + req.connection.remoteAddress + "], PID: " + process.pid + " Module: " + moduleName + ", function: " + functionName);
00147
00148 }
00149 return domains[0];
00150 } else {
00151 if (functionName.search(".min.map") < 0) {
00152
00153 console.log("Received " + req.method + ", Client: " + req.connection.remoteAddress + ", PID: " + process.pid + " Module: " + moduleName + ", function: " + functionName);
00154
00155 }
00156 return "";
00157 }
00158 });
00159 if (functionName.search("GET_ServerVersion") >= 0) {
00160 res.setHeader("Content-Type", "text/plain");
00161 res.statusCode = 200;
00162 res.end(version);
00163 return;
00164 }
00165 if (moduleName === ".." || functionName.search("\\.\\.") >= 0) {
00166 console.log("Possible break-in attempt!: " + pathname);
00167 res.writeHeader(404, { 'Content-Type': 'text/html' });
00168 res.end("Error");
00169 return;
00170 }
00171 res.setHeader("Content-Type", "application/json");
00172 res.statusCode = 200;
00173
00174
00175
00176
00177
00178
00179 if (req.method === "POST") {
00180 var body = "";
00181
00182
00183 req.on('data', function (data) {
00184 body += data;
00185 });
00186
00187 req.on('end', function () {
00188
00189 var post;
00190 try {
00191 post = JSON.parse(body);
00192 } catch (e) {
00193 post = qs.parse(body);
00194 }
00195 post.who = username;
00196
00197 if (module_holder[moduleName] != null) {
00198 console.log("Module " + moduleName + ", function " + functionName + " accessType " + (readOnly ? "RO" : "RW"));
00199 var dataTemp = "";
00200 module_holder[moduleName].removeAllListeners('data').on('data', function (data) {
00201 dataTemp += data;
00202 });
00203 module_holder[moduleName].removeAllListeners('end').on('end', function (data) {
00204
00205 res.end(JSON.stringify(dataTemp + data));
00206 });
00207 module_holder[moduleName].removeAllListeners('stream').on('stream', function (str, hdrs, code) {
00208 console.log("Stream message received: " + hdrs + " CODE: " + code);
00209 res.writeHead(code, hdrs);
00210 str.pipe(res);
00211 });
00212 var data;
00213 if (readOnly) {
00214 try {
00215 data = module_holder[moduleName]["RO_" + functionName](post, workerData[moduleName]);
00216 if (data != null) {
00217
00218 res.end(JSON.stringify(data));
00219 }
00220 } catch (err) {
00221 console.log("Error caught: " + err.stack);
00222 if (err instanceof TypeError) {
00223
00224 res.end(JSON.stringify(null));
00225 }
00226 }
00227 } else {
00228 try {
00229 data = module_holder[moduleName]["RW_" + functionName](post, workerData[moduleName]);
00230 if (data != null) {
00231
00232 res.end(JSON.stringify(data));
00233 }
00234 } catch (err2) {
00235 console.log("Error caught; text: " + JSON.stringify(err2));
00236 console.log("Error caught: " + err2.stack);
00237 if (err2 instanceof TypeError) {
00238
00239 data = module_holder[moduleName]["RO_" + functionName](post, workerData[moduleName]);
00240 if (data != null) {
00241
00242 res.end(JSON.stringify(data));
00243 }
00244 }
00245 }
00246 }
00247 } else {
00248 console.log("Unknown POST URL: " + pathname);
00249 res.writeHeader(404, { 'Content-Type': 'text/html' });
00250 res.end("Error");
00251 }
00252 });
00253 }
00254
00255 if (req.method === "GET" || req.method === "HEAD") {
00256
00257 if (functionName.indexOf(".") > 0) {
00258
00259 var ext = functionName.substr(functionName.lastIndexOf(".") + 1);
00260 res.setHeader("Content-Type", "text/plain");
00261
00262 switch (ext) {
00263 case "css":
00264 res.setHeader("Content-Type", "text/css");
00265 break;
00266 case "js":
00267 res.setHeader("Content-Type", "text/javascript");
00268 break;
00269 case "html":
00270 res.setHeader("Content-Type", "text/html");
00271 break;
00272 case "htm":
00273 res.setHeader("Content-Type", "text/html");
00274 break;
00275 case "root":
00276 res.setHeader("Content-Type", "application/root+root.exe");
00277 break;
00278 case "gif":
00279 res.setHeader("Content-Type", "image/gif");
00280 break;
00281 }
00282
00283 var filename = "./modules/" + moduleName + "/client/" + functionName;
00284 if (functionName.search("favicon.ico") >= 0) {
00285 filename = "./modules/base/client/images/favicon.ico";
00286 }
00287 if (fs.existsSync(filename)) {
00288 res.setHeader("Content-Length", fs.statSync(filename)["size"]);
00289 if (req.headers.range != null) {
00290 var range = req.headers.range;
00291 var offset = parseInt(range.substr(range.indexOf('=') + 1, range.indexOf('-') - (range.indexOf('=') + 1)));
00292 var endOffset = parseInt(range.substr(range.indexOf('-') + 1));
00293 console.log("Reading (" + offset + ", " + endOffset + ")");
00294
00295 res.setHeader("Content-Length", (endOffset - offset + 1).toString());
00296 var readStream = fs.createReadStream(filename, { start: parseInt(offset), end: parseInt(endOffset) });
00297 readStream.pipe(res);
00298 } else {
00299 res.end(fs.readFileSync(filename));
00300 }
00301
00302 } else {
00303 console.log("File not found: " + filename);
00304 res.setHeader("Content-Type", "text/plain");
00305 res.end("File Not Found.");
00306 }
00307 } else if (module_holder[moduleName] != null) {
00308 console.log("Module " + moduleName + ", function GET_" + functionName);
00309
00310 var dataTemp = "";
00311 module_holder[moduleName].removeAllListeners('data').on('data', function (data) {
00312
00313 dataTemp += data;
00314 });
00315 module_holder[moduleName].removeAllListeners('end').on('end', function (data) {
00316
00317 res.end(JSON.stringify(dataTemp + data));
00318 });
00319 module_holder[moduleName].removeAllListeners('stream').on('stream', function (str, hdrs, code) {
00320 res.writeHead(code, hdrs);
00321 str.pipe(res);
00322 });
00323 try {
00324 var data = module_holder[moduleName]["GET_" + functionName](workerData[moduleName]);
00325 if (data != null) {
00326
00327 res.end(JSON.stringify(data));
00328 }
00329 } catch (err) {
00330 console.log("Error caught: " + err.stack);
00331 }
00332 } else {
00333 console.log("Sending client.html");
00334
00335 res.setHeader("Content-Type", "text/html");
00336 res.end(fs.readFileSync("./client.html"), 'utf-8');
00337 console.log("Done sending client.html");
00338 }
00339 }
00340 };
00341
00342 console.log("Setting up options");
00343 var options = {
00344 key: fs.readFileSync('./certs/server.key'),
00345 cert: fs.readFileSync('./certs/server.crt'),
00346 ca: LoadCerts("./certs/certificates"),
00347 requestCert: true,
00348 rejectUnauthorized: false
00349 };
00350 var authlist = " " + fs.readFileSync("./certs/authorized_users");
00351 console.log("Done setting up options");
00352
00353
00354 var server = https.createServer(options, function (req, res) {
00355 var readOnly = true;
00356 var clientCertificate = req.connection.getPeerCertificate();
00357 var username = "HTTPS User";
00358 if (req.client.authorized) {
00359 username = clientCertificate.subject.CN[0];
00360 var useremail = clientCertificate.subject.CN[1].substr(4);
00361 if (authlist.search(username) > 0 || authlist.search(useremail) > 0) {
00362 readOnly = false;
00363 }
00364 }
00365
00366 try {
00367 serve(req, res, readOnly, username);
00368 } catch (e) {
00369 console.trace("Unhandled error in serve: " + JSON.stringify(e));
00370 }
00371 });
00372 var insecureServer = http.createServer(function (req, res) {
00373
00374 try {
00375 serve(req, res, false, "HTTP User");
00376 } catch (e) {
00377 console.trace("Unhandled error in serve: " + JSON.stringify(e));
00378 }
00379 });
00380
00381 var baseport = 8080;
00382 if (__dirname.search("dev") >= 0) {
00383 baseport = 9090;
00384 }
00385 console.log("Listening on ports " + baseport + " and " + (baseport + 1));
00386 server.listen(baseport + 1);
00387 insecureServer.listen(baseport);