httpServ.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. const http = require("http")
  2. ,https = require("https")
  3. ,Url = require("./url.js").Url
  4. ,config = require("../config.js")
  5. ,sessionManager = require("./session.js").SessionManager
  6. ,IrcConnection = require("./ircServer/ircConnection.js").IrcConnection
  7. ,AccountController = require("./controller/accountController.js").AccountController
  8. ,ApiController = require("./controller/apiController.js").ApiController
  9. ,MultiChatManager = require("./multichatManager.js").MultiChatManager
  10. ,AccountManager = require("./models/accounts.js").accountManager
  11. ,Slack = require("./slack.js").Slack
  12. ,slackManager = require("./slackManager.js").SlackManager
  13. ,FaviconWriter = require("./faviconWriter.js").FaviconWriter;
  14. function Server() {
  15. var ctx = this,
  16. errSocks = [],
  17. ircSocks = [],
  18. lastSockId = 0;
  19. this.httpServ = http.createServer(function(req, res) {
  20. res.ended = false;
  21. res.once('end', () => {
  22. res.ended = true;
  23. });
  24. ctx.onRequest(req, res);
  25. });
  26. this.httpServ.on("connection", (sock) => {
  27. sock.id = ++lastSockId;
  28. sock.once('close', () => {
  29. let i = ircSocks.indexOf(sock.id);
  30. if (i !== -1)
  31. ircSocks.splice(i, 1);
  32. i = errSocks.indexOf(sock.id);
  33. if (i !== -1)
  34. errSocks.splice(i, 1);
  35. });
  36. sock.on("data", (data) => {
  37. var dataStrArr = data.toString("utf-8").split(/\r?\n/g);
  38. for (var i =0, nbLines =dataStrArr.length; i < nbLines; i++)
  39. if ((/^(NICK|PASS) /).test(dataStrArr[i])) {
  40. var i = errSocks.indexOf(sock.id);
  41. if (i >= 0) {
  42. errSocks.splice(i, 1);
  43. ircSocks.push(sock.id);
  44. var con = new IrcConnection(sock);
  45. dataStrArr.forEach((str) => { con.parse(str); });
  46. }
  47. break;
  48. }
  49. });
  50. });
  51. // Default behaviour is to destroy connection, we would like to switch to IRC protocol instead
  52. this.httpServ.removeAllListeners("clientError");
  53. this.httpServ.on("clientError", (err, sock) => {
  54. if (ircSocks.indexOf(sock.id) === -1 && errSocks.indexOf(sock.id) === -1) {
  55. errSocks.push(sock.id);
  56. setTimeout(() => {
  57. if (errSocks.indexOf(sock.id) !== -1) {
  58. sock.destroy(err);
  59. }
  60. }, 1);
  61. }
  62. });
  63. this.httpServ.listen(config.port, ctx.onListen);
  64. }
  65. Server.parseCookies = function(req) {
  66. var cookies = req.headers.cookie
  67. ,cookieObj = null;
  68. if (cookies) {
  69. cookieObj = {};
  70. cookies = cookies.split(";");
  71. for (var cookieIndex =0, nbCookies =cookies.length; cookieIndex < nbCookies; cookieIndex++) {
  72. var cookieParts = cookies[cookieIndex].indexOf("=")
  73. ,cookieKey = null
  74. ,cookieValue = null;
  75. if (cookieParts === -1) {
  76. cookieKey = cookies[cookieIndex].trim();
  77. } else {
  78. cookieKey = cookies[cookieIndex].substr(0, cookieParts).trim();
  79. cookieValue = cookies[cookieIndex].substr(cookieParts +1).trim();
  80. }
  81. cookieObj[cookieKey] = cookieValue;
  82. }
  83. }
  84. return cookieObj;
  85. };
  86. Server.stringifyCookies = function(cookies) {
  87. var cookieString = "";
  88. for (var cookieKey in cookies) {
  89. cookieString += cookieString;
  90. if (cookies[cookieString] !== null) {
  91. cookieString += "=";
  92. }
  93. cookieString += "; ";
  94. }
  95. return cookieString;
  96. };
  97. Server.prototype.onListen = function() {
  98. console.log("onListen");
  99. };
  100. Server.prototype.execTemplate = function(template, req, res) {
  101. var resp = template.exec(req, res, this);
  102. if (resp && resp.body) {
  103. if (resp.status)
  104. res.writeHeader(resp.status);
  105. res.end(resp.body);
  106. }
  107. // else something is running asynchronously, let template close request later..
  108. };
  109. Server.prototype.execRequest = function(req, res) {
  110. if (req.urlObj.isTemplate() && req.urlObj.template.needLogin === false) {
  111. return this.execTemplate(req.urlObj.template, req, res);
  112. } else if (req.urlObj.isPublic()) {
  113. if (!config.isDebug)
  114. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  115. res.setHeader('Content-Length', req.urlObj.serve.stat.size);
  116. res.writeHeader("200");
  117. req.urlObj.getReadStream().pipe(res, { end: true });
  118. sessionManager.saveSession(req.session);
  119. return; // async pipe will close when finished
  120. } else if (!req.account) {
  121. res.writeHeader("302", { Location: "login" });
  122. res.end();
  123. } else if (req.urlObj.isTemplate()) {
  124. return this.execTemplate(req.urlObj.template, req, res);
  125. } else if (req.urlObj.match(["favicon.png"])) {
  126. if (!config.isDebug)
  127. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  128. var unreadHi = (req.urlObj.queryTokens.h && req.urlObj.queryTokens.h[0]) ? parseInt(req.urlObj.queryTokens.h[0], 10) : 0
  129. ,unread = (req.urlObj.queryTokens.m && req.urlObj.queryTokens.m[0]) ? parseInt(req.urlObj.queryTokens.m[0], 10) : 0;
  130. FaviconWriter.write(unreadHi, unread, (buf) => {
  131. res.writeHeader("200");
  132. res.end(buf);
  133. });
  134. sessionManager.saveSession(req.session);
  135. return;
  136. } else {
  137. // Api / dynamic content
  138. var apiSuccess = false;
  139. res.chatContext = new MultiChatManager();
  140. var services = req.account.getServices();
  141. for (var serviceId in services) {
  142. switch (services[serviceId].type) {
  143. case "Slack":
  144. res.chatContext.push(slackManager.lazyGet(serviceId, services[serviceId].oauthParam, req.reqT));
  145. break;
  146. default:
  147. console.error("Unknown service type for ", services[serviceId], " with account #" +req.account.id);
  148. }
  149. }
  150. if (req.urlObj.urlParts[0] === "account") {
  151. AccountController.onRequest(req, res, this);
  152. } else if (req.urlObj.urlParts[0] === "api") {
  153. ApiController.onRequest(req, res, this);
  154. } else {
  155. this.execTemplate(require('./template/_404.js'), req, res);
  156. }
  157. }
  158. };
  159. Server.prototype.onRequest = function(req, res) {
  160. req.reqT = Date.now();
  161. req.cookies = Server.parseCookies(req);
  162. req.session = sessionManager.forRequest(req);
  163. req.urlObj = new Url(req.url);
  164. req.account = null;
  165. if (req.session) {
  166. var self = this;
  167. AccountManager.fromId(req.session.accountId, (acc) => {
  168. req.account = acc;
  169. self.execRequest(req, res);
  170. });
  171. } else {
  172. this.execRequest(req, res);
  173. }
  174. };
  175. module.exports.HttpServ = Server;