diff options
Diffstat (limited to 'js/bin/HttpServer.js')
-rw-r--r-- | js/bin/HttpServer.js | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/js/bin/HttpServer.js b/js/bin/HttpServer.js new file mode 100644 index 00000000000..05a64abdc2e --- /dev/null +++ b/js/bin/HttpServer.js @@ -0,0 +1,409 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +var http = require("http"); +var https = require("https"); +var url = require("url"); +var crypto = require("crypto"); +var fs = require("fs"); +var path = require("path"); + +var httpProxy = null; +try +{ + httpProxy = require("http-proxy"); +} +catch(e) +{ + console.warn("Warning: couldn't find http-proxy module, it's necessary to run the demos,\n" + + "you can run the following command to install it: npm install http-proxy\n"); +} + +var MimeTypes = +{ + css: "text/css", + html: "text/html", + ico: "image/x-icon", + jpeg: "image/jpeg", + jpg: "image/jpeg", + js: "text/javascript", + png: "image/png", +}; + +var iceJsHome = process.env.ICE_JS_HOME; +var useBinDist = process.env.USE_BIN_DIST && process.env.USE_BIN_DIST == "yes"; +var srcDist; +try +{ + srcDist = fs.statSync(path.join(__dirname, "..", "lib")).isDirectory(); +} +catch(e) +{ +} + +var iceJs = process.env.OPTIMIZE == "yes" ? "Ice.min.js" : "Ice.js"; + +// +// If this is a source distribution and ICE_JS_HOME isn't set ensure +// that Ice libraries has been build. +// +if(srcDist && !iceJsHome && !useBinDist) +{ + var build; + try + { + build = fs.statSync(path.join(__dirname, "..", "lib", iceJs)).isFile() + } + catch(e) + { + } + + if(!build) + { + console.error("error Unable to find " + iceJs + " in " + path.join(__dirname, "..", "lib") + ", please verify " + + "that the sources has been build or configure ICE_JS_HOME to use a binary distribution."); + process.exit(1); + } +} + +// +// If this is a demo distribution ensure that ICE_JS_HOME is set or install in a default location. +// +if(!srcDist || useBinDist) +{ + // + // if ICE_JS_HOME is not set check if it is install in the default location. + // + if(!process.env.ICE_JS_HOME) + { + var dist = "IceJS-0.1.0"; + [ + "C:\\Program Files\\ZeroC", + "C:\\Program Files (x86)\\ZeroC", + "/Library/Developer", + "/opt" + ].some( + function(basePath) + { + try + { + if(fs.statSync(path.join(basePath, dist, "lib", iceJs)).isFile()) + { + iceJsHome = path.join(basePath, dist); + return true; + } + } + catch(e) + { + } + return false; + }); + } + + if(!iceJsHome) + { + console.error("error Ice for JavaScript not found in the default installation directories\n" + + "ICE_JS_HOME environment variable must be set, and point to the Ice for\n" + + "JavaScript installation directory."); + process.exit(1); + } +} + +// +// If ICE_JS_HOME is set ensure that Ice libraries exists in that location. +// +if(iceJsHome) +{ + var iceJsHomeValid; + try + { + iceJsHomeValid = fs.statSync(path.join(iceJsHome, "lib", iceJs)).isFile(); + } + catch(e) + { + } + + if(!iceJsHomeValid) + { + console.error("error Unable to find " + iceJs + " in " + path.join(iceJsHome, "lib") + + ", please verify ICE_JS_HOME is properly configured and Ice for JavaScript " + + "is correctly installed"); + process.exit(1); + } + console.log("Using Ice libraries from " + path.join(iceJsHome, "lib")); +} + +var libraries = ["/lib/Ice.js", "/lib/Ice.min.js", + "/lib/Glacier2.js", "/lib/Glacier2.min.js", + "/lib/IceStorm.js", "/lib/IceStorm.min.js", + "/lib/IceGrid.js", "/lib/IceGrid.min.js",]; + +var HttpServer = function(host, ports) +{ + this._host = host; + this._ports = ports; + this._basePath = path.resolve(path.join(__dirname, "..")); +}; + +HttpServer.prototype.processRequest = function(req, res) +{ + var filePath; + + var iceLib = libraries.indexOf(req.url.pathname) !== -1; + // + // If ICE_JS_HOME has been set resolve Ice libraries paths into ICE_JS_HOME. + // + if(iceJsHome && iceLib) + { + filePath = path.join(iceJsHome, req.url.pathname); + } + else + { + filePath = path.resolve(path.join(this._basePath, req.url.pathname)); + } + + // + // If OPTIMIZE is set resolve Ice libraries to the corresponding minified + // versions. + // + if(process.env.OPTIMIZE == "yes" && iceLib && filePath.substr(-7) !== ".min.js") + { + filePath = filePath.replace(".js", ".min.js"); + } + + var ext = path.extname(filePath).slice(1); + + // + // When the browser ask for a .js or .css file and it has support for gzip content + // check if a gzip version (.js.gz or .css.gz) of the file exists and use that instead. + // + if((ext == "js" || ext == "css") && req.headers["accept-encoding"].indexOf("gzip") !== -1) + { + fs.stat(filePath + ".gz", + function(err, stats) + { + if(err || !stats.isFile()) + { + fs.stat(filePath, + function(err, stats) + { + doRequest(err, stats, filePath); + }); + } + else + { + doRequest(err, stats, filePath + ".gz"); + } + }); + } + else + { + fs.stat(filePath, + function(err, stats) + { + doRequest(err, stats, filePath); + }); + } + + var doRequest = function(err, stats, filePath) + { + if(err) + { + if(err.code === "ENOENT") + { + res.writeHead(404); + res.end("404 Page Not Found"); + console.log("HTTP/404 (Page Not Found)" + req.method + " " + req.url.pathname + " -> " + filePath); + } + else + { + res.writeHead(500); + res.end("500 Internal Server Error"); + console.log("HTTP/500 (Internal Server Error) " + req.method + " " + req.url.pathname + " -> " + + filePath); + } + } + else + { + if(!stats.isFile()) + { + res.writeHead(403); + res.end("403 Forbiden"); + console.log("HTTP/403 (Forbiden) " + req.method + " " + req.url.pathname + " -> " + filePath); + } + else + { + // + // Create a md5 using the stats attributes + // to be used as Etag header. + // + var hash = crypto.createHash("md5"); + hash.update(stats.ino.toString()); + hash.update(stats.mtime.toString()); + hash.update(stats.size.toString()); + + var headers = + { + "Content-Type": MimeTypes[ext] || "text/plain", + "Content-Length": stats.size, + "Last-Modified": new Date(stats.mtime).toUTCString(), + "Etag": hash.digest("hex") + }; + + if(path.extname(filePath).slice(1) == "gz") + { + headers["Content-Encoding"] = "gzip"; + } + + // + // Check for conditional request headers, if-modified-since + // and if-none-match. + // + var modified = true; + if(Date.parse(req.headers["if-modified-since"]) == stats.mtime.getTime()) + { + modified = false; + } + else if(req.headers["if-none-match"] !== undefined) + { + modified = req.headers["if-none-match"].split(" ").every( + function(element, index, array) + { + return element !== headers["Etag"]; + }); + } + + // + // Not Modified + // + if(!modified) + { + res.writeHead(304, headers); + res.end(); + console.log("HTTP/304 (Not Modified) " + req.method + " " + req.url.pathname + " -> " + filePath); + } + else + { + res.writeHead(200, headers); + if(req.method === "HEAD") + { + res.end(); + } + else + { + fs.createReadStream(filePath, { "bufferSize": 4 * 1024 }).pipe(res); + } + console.log("HTTP/200 (Ok) " + req.method + " " + req.url.pathname + " -> " + filePath); + } + } + } + } +}; + +// +// Proxy configuration for the different demos. +// +var proxyConfig = [ + {resource: "/demows", target: "http://localhost:10002", protocol: "ws"}, + {resource: "/demowss", target: "https://localhost:10003", protocol: "wss"}, + {resource: "/chatws", target: "http://localhost:5063", protocol: "ws"}, + {resource: "/chatwss", target: "https://localhost:5064", protocol: "wss"} +]; + +var proxies = {}; + +HttpServer.prototype.start = function() +{ + var baseDir; + if(!["../../certs", "../certs"].some( + function(p) + { + return fs.existsSync(baseDir = path.join(__dirname, p)); + })) + { + console.error("Cannot find wss certificates directory") + process.exit(1); + } + var options = { + passphrase: "password", + key: fs.readFileSync(path.join(baseDir, "s_rsa1024_priv.pem")), + cert: fs.readFileSync(path.join(baseDir, "s_rsa1024_pub.pem")) + }; + + httpServer = http.createServer(); + httpsServer = https.createServer(options); + + if(httpProxy) + { + proxyConfig.forEach( + function(conf) + { + proxies[conf.resource] = { + server: httpProxy.createProxyServer({target : conf.target, secure : false}), + protocol: conf.protocol }; + }); + } + + var self = this; + [httpServer, httpsServer].forEach(function(server) + { + server.on("request", function(req, res) + { + // + // Dummy data callback required so request end event is emitted. + // + var dataCB = function(data) + { + }; + + var endCB = function() + { + req.url = url.parse(req.url); + self.processRequest(req, res); + }; + + req.on("data", dataCB); + req.on("end", endCB); + }); + }); + + if(httpProxy) + { + function requestCB(protocols) + { + return function(req, socket, head) + { + var errCB = function(err) + { + socket.end(); + }; + var proxy = proxies[req.url]; + if(proxy && protocols.indexOf(proxy.protocol) !== -1) + { + proxy.server.ws(req, socket, head, errCB); + } + else + { + socket.end(); + } + }; + } + + httpServer.on("upgrade", requestCB(["ws"])); + httpsServer.on("upgrade", requestCB(["ws", "wss"])); + } + + httpServer.listen(8080, this._host); + httpsServer.listen(9090, this._host); + console.log("listening on ports 8080 (http) and 9090 (https)..."); +}; + +var server = new HttpServer("0.0.0.0", [8080, 9090]); +server.start(); + |