PageRenderTime 266ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/chrome/content/libs/xmppsocket.js

https://github.com/processone/oneweb
JavaScript | 337 lines | 244 code | 51 blank | 42 comment | 43 complexity | 741641b4c263dd236ceb8bce16c72858 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is OneWeb.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * ProcessOne.
  18. * Portions created by the Initial Developer are Copyright (C) 2009
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. var EXPORTED_SYMBOLS = ["XMPPSocket"];
  37. function XMPPSocket(listener, host, port, ssl, domain, authhost)
  38. {
  39. this.listener = listener;
  40. this.host = host;
  41. this.port = port;
  42. this.ssl = ssl;
  43. this.domain = domain;
  44. this.authhost = authhost;
  45. this.converter = new CharsetConverter("UTF-8");
  46. }
  47. _DECL_(XMPPSocket).prototype =
  48. {
  49. tlsProblemHandled: {},
  50. connect: function() {
  51. if (this.host == this.domain) {
  52. try {
  53. var dnsSrv = Components.classes["@process-one.net/dns;1"].
  54. getService(Components.interfaces.otIDNSService);
  55. var mainThread = Components.classes["@mozilla.org/thread-manager;1"].
  56. getService(Components.interfaces.nsIThreadManager).mainThread;
  57. var _this = this;
  58. dnsSrv.asyncResolveSRV("_xmpp-client._tcp."+this.domain, this,
  59. mainThread);
  60. return;
  61. } catch (ex) {}
  62. }
  63. this.onLookupComplete();
  64. },
  65. onLookupComplete: function(request, response) {
  66. if (response && response.hasMore())
  67. [this.host, this.port] = response.getNextAddrAsString().split(":");
  68. this.doConnect();
  69. this.listener._handleConnectionEstabilished();
  70. },
  71. doConnect: function() {
  72. var ioSrv = Components.classes["@mozilla.org/network/io-service;1"].
  73. getService(Components.interfaces.nsIIOService);
  74. var pps = Components.classes["@mozilla.org/network/protocol-proxy-service;1"].
  75. getService(Components.interfaces.nsIProtocolProxyService);
  76. var proxyUri = ioSrv.newURI((this.ssl == "ssl" ? "https://" : "http://")+this.host,
  77. null, null);
  78. var proxyInfo = pps.resolve(proxyUri, pps.RESOLVE_NON_BLOCKING);
  79. var mainThread = Components.classes["@mozilla.org/event-queue-service;1"] ?
  80. Components.classes["@mozilla.org/event-queue-service;1"].
  81. getService(Components.interfaces.nsIEventQueueService).
  82. getSpecialEventQueue(eqs.CURRENT_THREAD_EVENT_QUEUE) :
  83. Components.classes["@mozilla.org/thread-manager;1"].
  84. getService().mainThread;
  85. var stSrv = Components.classes["@mozilla.org/network/socket-transport-service;1"].
  86. getService(Components.interfaces.nsISocketTransportService);
  87. this.reset();
  88. this.transport = stSrv.createTransport([this.ssl ? "ssl" : "starttls"], 1,
  89. this.host, this.port, proxyInfo);
  90. this.transport.setEventSink(this, mainThread);
  91. this.is = this.transport.openInputStream(0, 0, 0);
  92. var pump = Components.classes['@mozilla.org/network/input-stream-pump;1'].
  93. createInstance(Components.interfaces.nsIInputStreamPump);
  94. pump.init(this.is, -1, -1, 0, 0, false);
  95. pump.asyncRead(this, null);
  96. this.os = this.transport.openOutputStream(1, 0, 0);
  97. this.bos = Components.classes["@mozilla.org/binaryoutputstream;1"].
  98. createInstance(Components.interfaces.nsIBinaryOutputStream);
  99. this.bos.setOutputStream(this.os);
  100. this._pingInterval = window.setInterval(function(t){t.send(" ")}, 50000, this);
  101. this.reconnect = false;
  102. },
  103. send: function(data) {
  104. try {
  105. data = this.converter.encode(data);
  106. this.bos.writeBytes(data, data.length);
  107. } catch(ex) {}
  108. },
  109. startTLS: function() {
  110. this.transport.securityInfo.
  111. QueryInterface(Components.interfaces.nsISSLSocketControl).
  112. StartTLS();
  113. // some servers (like gmail.com) have problems with handling TLS1.0
  114. // (they just stuck on initial hello), to failback to SSL3.0 we needs
  115. // to reconnect after some time
  116. if (!(this.domain in this.tlsProblemHandled)) {
  117. this._sslDowngradeTimeout = setTimeout(function(_this) {
  118. _this.tlsProblemHandled[_this.domain] = true;
  119. _this.reconnect = true;
  120. _this.disconnect();
  121. }, 1000, this);
  122. }
  123. },
  124. reset: function() {
  125. if (!this._afterReset) {
  126. this.saxParser = Components.classes["@mozilla.org/saxparser/xmlreader;1"].
  127. createInstance(Components.interfaces.nsISAXXMLReader);
  128. this.saxParser.contentHandler = this;
  129. this.saxParser.errorHandler = this;
  130. this.saxParser.parseAsync(null);
  131. this.parent = null;
  132. this._afterReset = true;
  133. }
  134. },
  135. disconnect: function() {
  136. if (this.is)
  137. this.is.close();
  138. if (this.bos)
  139. this.bos.close();
  140. if (this.transport)
  141. this.transport.close(0);
  142. if (this._pingInterval)
  143. window.clearInterval(this._pingInterval);
  144. this.is = this.os = this.bos = this.transport = null;
  145. },
  146. // nsISAXContentHandler
  147. startDocument: function() {
  148. this._afterReset = false;
  149. this.doc = Components.classes["@mozilla.org/xml/xml-document;1"].
  150. createInstance(Components.interfaces.nsIDOMXMLDocument);
  151. },
  152. endDocument: function() {
  153. },
  154. startElement: function(ns, localName, qName, attrs)
  155. {
  156. var el = this.doc.createElementNS(ns, localName);
  157. for (var i = 0; i < attrs.length; i++)
  158. el.setAttribute(attrs.getQName(i), attrs.getValue(i));
  159. if (ns == "http://etherx.jabber.org/streams" && qName == "stream:stream") {
  160. this.listener._handleInitialElement(el);
  161. this.parent = null;
  162. } else {
  163. if (this.parent)
  164. this.parent.appendChild(el);
  165. this.parent = el;
  166. }
  167. },
  168. endElement: function(ns, localName, qName)
  169. {
  170. var el = this.parent;
  171. if (this.parent)
  172. this.parent = this.parent.parentNode;
  173. if (el && !this.parent)
  174. this.listener._handleElement(el);
  175. },
  176. characters: function(data)
  177. {
  178. if (!this.parent)
  179. return;
  180. if (this.parent.lastChild && this.parent.lastChild.nodeType == this.parent.TEXT_NODE)
  181. this.parent.lastChild.appendData(data);
  182. else
  183. this.parent.appendChild(this.doc.createTextNode(data));
  184. },
  185. processingInstruction: function(target, data) { },
  186. ignorableWhitespace: function(data) { },
  187. startPrefixMapping: function(prefix, uri) { },
  188. endPrefixMapping: function(prefix) { },
  189. // nsISAXErrorHandler
  190. error: function(locator, error)
  191. {
  192. this.listener._handleError();
  193. },
  194. fatalError: function(locator, error)
  195. {
  196. if (this.is || this.os)
  197. this.listener._handleError();
  198. },
  199. ignorableWarning: function(locator, error)
  200. {
  201. },
  202. // nsIStreamListener
  203. onStartRequest: function(request, context)
  204. {
  205. this.saxParser.onStartRequest.apply(this.saxParser, arguments);
  206. },
  207. onDataAvailable: function(request, context, is, offset, count)
  208. {
  209. if (this._sslDowngradeTimeout) {
  210. clearTimeout(this._sslDowngradeTimeout)
  211. delete this._sslDowngradeTimeout;
  212. this.tlsProblemHandled[this.domain] = false;
  213. }
  214. if (this._afterReset)
  215. this.saxParser.onStartRequest(request, context);
  216. this.saxParser.onDataAvailable.apply(this.saxParser, arguments);
  217. },
  218. onStopRequest: function(request, context, status)
  219. {
  220. if (this.reconnect) {
  221. this.disconnect();
  222. this.doConnect();
  223. this.listener._handleReconnect();
  224. return;
  225. }
  226. this.listener._handleDisconnect();
  227. try {
  228. this.saxParser.onStopRequest.apply(this.saxParser, arguments);
  229. } catch(ex) { }
  230. },
  231. // EventSink
  232. onTransportStatus: function(transport, status, progress, progressMax)
  233. {
  234. if (status != transport.STATUS_CONNECTING_TO)
  235. return;
  236. try {
  237. var si = this.transport.securityInfo.
  238. QueryInterface(Components.interfaces.nsISSLSocketControl);
  239. if (si)
  240. si.notificationCallbacks = {
  241. socket: this,
  242. notifyCertProblem: function(info, status, host) {
  243. var srv = Components.classes["@mozilla.org/security/certoverride;1"].
  244. getService(Components.interfaces.nsICertOverrideService);
  245. var promptSrv = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
  246. getService(Components.interfaces.nsIPromptService);
  247. var flags = 0, msg = "", check = {value: false};
  248. status = status.QueryInterface(Components.interfaces.nsISSLStatus);
  249. if (status.isUntrusted) {
  250. flags |= srv.ERROR_UNTRUSTED;
  251. msg += "\n "+_("Hasn't been verified by recognized authority");
  252. }
  253. if (status.isDomainMismatch && status.serverCert.commonName != this.socket.domain) {
  254. flags |= srv.ERROR_MISMATCH;
  255. msg += "\n "+_("Belongs to different domain");
  256. }
  257. if (status.isNotValidAtThisTime) {
  258. flags |= srv.ERROR_TIME;
  259. msg += "\n "+_("Has been expired");
  260. }
  261. if (flags == 0)
  262. check.value = true;
  263. else if (promptSrv.confirmEx(null, _("Invalid certificate"),
  264. _("Certificate used by server is invalid because:")+msg,
  265. 127+256*2, _("Continue"), "", "",
  266. _("Always skip this dialog"), check))
  267. return true;
  268. srv.rememberValidityOverride(this.socket.host, this.socket.port,
  269. status.serverCert, flags, !check.value);
  270. this.socket.reconnect = true;
  271. return true;
  272. },
  273. getInterface: function(iid) {
  274. return this.QueryInterface(iid);
  275. },
  276. QueryInterface: function(iid) {
  277. if (!iid.equals(Components.interfaces.nsISupports) &&
  278. !iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
  279. !iid.equals(Components.interfaces.nsIBadCertListener2))
  280. throw Components.results.NS_ERROR_NO_INTERFACE;
  281. return this;
  282. }
  283. }
  284. } catch (ex) {alert(ex)}
  285. }
  286. };