var PORT1 = 8004; var PORT2 = 8003; var http = require("http"); var fs = require("fs"); var url = require("url"); var util = require("util"); var EventEmitter = require("events").EventEmitter; util.puts("Version: " + process.version); util.puts("Starting server at http://localhost:" + PORT1); process.on("uncaughtException", function (e) { try { util.puts("Caught exception: " + e + " " + (typeof(e) === "object" ? e.stack : "")); } catch (e0) {} }); var emitter = new EventEmitter(); var history = []; var heartbeatTimeout = 9000; var firstId = Number(new Date()); setInterval(function () { emitter.emit("message"); }, heartbeatTimeout / 2); function onTest(response, lastEventId, test, cookies) { var i = lastEventId + 1; if (test === 0) { var onPing = function (x) { response.write("event: pong\ndata: " + x + "\n\n"); }; emitter.addListener("ping", onPing); response.connection.once("close", function () { emitter.removeListener("ping", onPing); }); } if (test === 1) { if (lastEventId === 0) { response.write("id: 1\n"); response.write("data: data0;\n\n"); response.write("id: 2\n"); response.write("drop connection test"); response.end(); } else { response.write("data: xxx\n\n"); response.end(); } } if (test === 2) { response.write("data: data0;\n\ndata: data1;\n\ndata: data2;\n\n"); response.end(); } if (test === 3) { response.write("data: data0"); response.end(); } if (test === 4) { response.write("data\n\n"); setTimeout(function () { response.write("data\n\n"); setTimeout(function () { response.write("data\n\n"); }, 25); }, 25); setTimeout(function () { response.end(); }, 10000); } if (test === 8) { if (lastEventId === 100) { response.write("data: ok\n\n"); } else { response.write("id: 100\n"); response.write("data: data0;\n\n"); } response.end(); } if (test === 9) { response.write("data: x" + cookies.testCookie + "\n\n"); response.end(); } if (test === 10) { while (i < 6) { response.write("retry: 500\n"); response.write("id: " + i + "\n"); response.write("data: " + i + ";\n\n"); if (i === 3) { response.end(); return; } i += 1; } response.end(); } if (test === 11) { response.write("data: a\n\n"); response.write("event: open\ndata: b\n\n"); response.write("event: message\ndata: c\n\n"); response.write("event: error\ndata: d\n\n"); response.write("event:\ndata: e\n\n"); response.write("event: end\ndata: f\n\n"); response.end(); } if (test === 800) { response.write("retry: 800\n\n"); response.end(); } if (test === 12) { response.write("data: a\n\n"); response.write("data: \x00\n\n"); response.write("data: b\n\n"); response.end(); } if (test === 13) { var message = "data:\\0\ndata: 2\rData:1\ndata\\0:2\ndata:1\r\\0data:4\nda-ta:3\rdata_5\ndata:3\rdata:\r\n data:32\ndata:4\n\n"; response.write(message); response.end(); } } function eventStream(request, response) { var lastEventId = ""; var parsedURL = url.parse(request.url, true); var test = Number(parsedURL.query.test); var cookies = {}; (request.headers.cookie || "").split(";").forEach(function (cookie) { cookie = cookie.split("="); cookies[decodeURIComponent(cookie[0].trim())] = decodeURIComponent((cookie[1] || "").trim()); }); function sendMessages() { lastEventId = Math.max(lastEventId, firstId); while (lastEventId - firstId < history.length) { response.write("id: " + (lastEventId + 1) + "\n" + "data: " + (history[lastEventId - firstId]).replace(/[\r\n\x00]/g, "\ndata: ") + "\n\n"); lastEventId += 1; } response.write(":\n"); } response.on("close", function () { emitter.removeListener("message", sendMessages); response.end(); }); response.socket.setTimeout(0); // see http://contourline.wordpress.com/2011/03/30/preventing-server-timeout-in-node-js/ var headers = { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "Access-Control-Allow-Origin": "*" }; if (test === 9) { headers["Access-Control-Allow-Credentials"] = "true"; } if (test === 16) { headers["Cache-Control"] = "max-age=3600"; headers["Expires"] = new Date(Date.now() + 3600000).toUTCString(); response.writeHead(200, headers); response.write("retry:1000\ndata:" + Math.random() + "\n\n"); response.end(); return; } response.writeHead(200, headers); lastEventId = Number(request.headers["last-event-id"]) || Number(parsedURL.query.lastEventId) || 0; if (test !== -1) { response.write(":" + Array(2049).join(" ") + "\n"); // 2kB padding for IE response.write("retry: 1000\n"); response.write("retryLimit: 60000\n"); response.write("heartbeatTimeout: " + heartbeatTimeout + "\n");//! } if (!isNaN(test)) { if (test === -1) { response.write(parsedURL.query.stream); setTimeout(function () { response.end(); }, Number(parsedURL.query.delay) || 0); } else { onTest(response, lastEventId, test, cookies); } } else { emitter.addListener("message", sendMessages); emitter.setMaxListeners(0); sendMessages(); } } function onRequest(request, response) { var parsedURL = url.parse(request.url, true); var query = parsedURL.query; var pathname = parsedURL.pathname; var time = ""; var data = ""; if (query.message) { time = new Date(); data = "[" + time.toISOString() + "][IP: " + request.connection.remoteAddress + "] " + query.message; response.writeHead(200, { "Content-Type": "text/plain" }); response.end(String(firstId + history.push(data))); emitter.emit("message"); return; } if (query.ping) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("ok"); emitter.emit("ping", query.ping); return; } if (pathname === "/events") { eventStream(request, response); } else { var files = [ "/example.html", "/nodechat.css", "/eventsource.js", "/nodechat.js", "/tests.html", "/qunit.css", "/qunit.js", "/tests.js" ]; if (files.indexOf(pathname) === -1) { pathname = files[0]; } fs.stat(__dirname + pathname, function (error, stats) { if (error) { response.writeHead(404); response.end(); } else { var mtime = Date.parse(request.headers["if-modified-since"]) || 0; if (stats.mtime <= mtime) { response.writeHead(304); response.end(); } else { var raw = fs.createReadStream(__dirname + pathname); response.writeHead(200, { "Content-Type": (pathname.indexOf(".js") !== -1 ? "text/javascript" : (pathname.indexOf(".css") !== -1 ? "text/css" : "text/html")), "Last-Modified": stats.mtime }); raw.pipe(response); } } }); } } http.createServer(onRequest).listen(PORT1); http.createServer(onRequest).listen(PORT2);