github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/sockjs-client-1.1.0/dist/sockjs-0.3.4.js (about) 1 /* SockJS client, version 0.3.4, http://sockjs.org, MIT License 2 3 Copyright (c) 2011-2012 VMware, Inc. 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to deal 7 in the Software without restriction, including without limitation the rights 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 copies of the Software, and to permit persons to whom the Software is 10 furnished to do so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 THE SOFTWARE. 22 */ 23 24 // JSON2 by Douglas Crockford (minified). 25 var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}() 26 27 28 // [*] Including lib/index.js 29 // Public object 30 SockJS = (function(){ 31 var _document = document; 32 var _window = window; 33 var utils = {}; 34 35 36 // [*] Including lib/reventtarget.js 37 /* 38 * ***** BEGIN LICENSE BLOCK ***** 39 * Copyright (c) 2011-2012 VMware, Inc. 40 * 41 * For the license see COPYING. 42 * ***** END LICENSE BLOCK ***** 43 */ 44 45 /* Simplified implementation of DOM2 EventTarget. 46 * http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget 47 */ 48 var REventTarget = function() {}; 49 REventTarget.prototype.addEventListener = function (eventType, listener) { 50 if(!this._listeners) { 51 this._listeners = {}; 52 } 53 if(!(eventType in this._listeners)) { 54 this._listeners[eventType] = []; 55 } 56 var arr = this._listeners[eventType]; 57 if(utils.arrIndexOf(arr, listener) === -1) { 58 arr.push(listener); 59 } 60 return; 61 }; 62 63 REventTarget.prototype.removeEventListener = function (eventType, listener) { 64 if(!(this._listeners && (eventType in this._listeners))) { 65 return; 66 } 67 var arr = this._listeners[eventType]; 68 var idx = utils.arrIndexOf(arr, listener); 69 if (idx !== -1) { 70 if(arr.length > 1) { 71 this._listeners[eventType] = arr.slice(0, idx).concat( arr.slice(idx+1) ); 72 } else { 73 delete this._listeners[eventType]; 74 } 75 return; 76 } 77 return; 78 }; 79 80 REventTarget.prototype.dispatchEvent = function (event) { 81 var t = event.type; 82 var args = Array.prototype.slice.call(arguments, 0); 83 if (this['on'+t]) { 84 this['on'+t].apply(this, args); 85 } 86 if (this._listeners && t in this._listeners) { 87 for(var i=0; i < this._listeners[t].length; i++) { 88 this._listeners[t][i].apply(this, args); 89 } 90 } 91 }; 92 // [*] End of lib/reventtarget.js 93 94 95 // [*] Including lib/simpleevent.js 96 /* 97 * ***** BEGIN LICENSE BLOCK ***** 98 * Copyright (c) 2011-2012 VMware, Inc. 99 * 100 * For the license see COPYING. 101 * ***** END LICENSE BLOCK ***** 102 */ 103 104 var SimpleEvent = function(type, obj) { 105 this.type = type; 106 if (typeof obj !== 'undefined') { 107 for(var k in obj) { 108 if (!obj.hasOwnProperty(k)) continue; 109 this[k] = obj[k]; 110 } 111 } 112 }; 113 114 SimpleEvent.prototype.toString = function() { 115 var r = []; 116 for(var k in this) { 117 if (!this.hasOwnProperty(k)) continue; 118 var v = this[k]; 119 if (typeof v === 'function') v = '[function]'; 120 r.push(k + '=' + v); 121 } 122 return 'SimpleEvent(' + r.join(', ') + ')'; 123 }; 124 // [*] End of lib/simpleevent.js 125 126 127 // [*] Including lib/eventemitter.js 128 /* 129 * ***** BEGIN LICENSE BLOCK ***** 130 * Copyright (c) 2011-2012 VMware, Inc. 131 * 132 * For the license see COPYING. 133 * ***** END LICENSE BLOCK ***** 134 */ 135 136 var EventEmitter = function(events) { 137 var that = this; 138 that._events = events || []; 139 that._listeners = {}; 140 }; 141 EventEmitter.prototype.emit = function(type) { 142 var that = this; 143 that._verifyType(type); 144 if (that._nuked) return; 145 146 var args = Array.prototype.slice.call(arguments, 1); 147 if (that['on'+type]) { 148 that['on'+type].apply(that, args); 149 } 150 if (type in that._listeners) { 151 for(var i = 0; i < that._listeners[type].length; i++) { 152 that._listeners[type][i].apply(that, args); 153 } 154 } 155 }; 156 157 EventEmitter.prototype.on = function(type, callback) { 158 var that = this; 159 that._verifyType(type); 160 if (that._nuked) return; 161 162 if (!(type in that._listeners)) { 163 that._listeners[type] = []; 164 } 165 that._listeners[type].push(callback); 166 }; 167 168 EventEmitter.prototype._verifyType = function(type) { 169 var that = this; 170 if (utils.arrIndexOf(that._events, type) === -1) { 171 utils.log('Event ' + JSON.stringify(type) + 172 ' not listed ' + JSON.stringify(that._events) + 173 ' in ' + that); 174 } 175 }; 176 177 EventEmitter.prototype.nuke = function() { 178 var that = this; 179 that._nuked = true; 180 for(var i=0; i<that._events.length; i++) { 181 delete that[that._events[i]]; 182 } 183 that._listeners = {}; 184 }; 185 // [*] End of lib/eventemitter.js 186 187 188 // [*] Including lib/utils.js 189 /* 190 * ***** BEGIN LICENSE BLOCK ***** 191 * Copyright (c) 2011-2012 VMware, Inc. 192 * 193 * For the license see COPYING. 194 * ***** END LICENSE BLOCK ***** 195 */ 196 197 var random_string_chars = 'abcdefghijklmnopqrstuvwxyz0123456789_'; 198 utils.random_string = function(length, max) { 199 max = max || random_string_chars.length; 200 var i, ret = []; 201 for(i=0; i < length; i++) { 202 ret.push( random_string_chars.substr(Math.floor(Math.random() * max),1) ); 203 } 204 return ret.join(''); 205 }; 206 utils.random_number = function(max) { 207 return Math.floor(Math.random() * max); 208 }; 209 utils.random_number_string = function(max) { 210 var t = (''+(max - 1)).length; 211 var p = Array(t+1).join('0'); 212 return (p + utils.random_number(max)).slice(-t); 213 }; 214 215 // Assuming that url looks like: http://asdasd:111/asd 216 utils.getOrigin = function(url) { 217 url += '/'; 218 var parts = url.split('/').slice(0, 3); 219 return parts.join('/'); 220 }; 221 222 utils.isSameOriginUrl = function(url_a, url_b) { 223 // location.origin would do, but it's not always available. 224 if (!url_b) url_b = _window.location.href; 225 226 return (url_a.split('/').slice(0,3).join('/') 227 === 228 url_b.split('/').slice(0,3).join('/')); 229 }; 230 231 utils.getParentDomain = function(url) { 232 // ipv4 ip address 233 if (/^[0-9.]*$/.test(url)) return url; 234 // ipv6 ip address 235 if (/^\[/.test(url)) return url; 236 // no dots 237 if (!(/[.]/.test(url))) return url; 238 239 var parts = url.split('.').slice(1); 240 return parts.join('.'); 241 }; 242 243 utils.objectExtend = function(dst, src) { 244 for(var k in src) { 245 if (src.hasOwnProperty(k)) { 246 dst[k] = src[k]; 247 } 248 } 249 return dst; 250 }; 251 252 var WPrefix = '_jp'; 253 254 utils.polluteGlobalNamespace = function() { 255 if (!(WPrefix in _window)) { 256 _window[WPrefix] = {}; 257 } 258 }; 259 260 utils.closeFrame = function (code, reason) { 261 return 'c'+JSON.stringify([code, reason]); 262 }; 263 264 utils.userSetCode = function (code) { 265 return code === 1000 || (code >= 3000 && code <= 4999); 266 }; 267 268 // See: http://www.erg.abdn.ac.uk/~gerrit/dccp/notes/ccid2/rto_estimator/ 269 // and RFC 2988. 270 utils.countRTO = function (rtt) { 271 var rto; 272 if (rtt > 100) { 273 rto = 3 * rtt; // rto > 300msec 274 } else { 275 rto = rtt + 200; // 200msec < rto <= 300msec 276 } 277 return rto; 278 } 279 280 utils.log = function() { 281 if (_window.console && console.log && console.log.apply) { 282 console.log.apply(console, arguments); 283 } 284 }; 285 286 utils.bind = function(fun, that) { 287 if (fun.bind) { 288 return fun.bind(that); 289 } else { 290 return function() { 291 return fun.apply(that, arguments); 292 }; 293 } 294 }; 295 296 utils.flatUrl = function(url) { 297 return url.indexOf('?') === -1 && url.indexOf('#') === -1; 298 }; 299 300 utils.amendUrl = function(url) { 301 var dl = _document.location; 302 if (!url) { 303 throw new Error('Wrong url for SockJS'); 304 } 305 if (!utils.flatUrl(url)) { 306 throw new Error('Only basic urls are supported in SockJS'); 307 } 308 309 // '//abc' --> 'http://abc' 310 if (url.indexOf('//') === 0) { 311 url = dl.protocol + url; 312 } 313 // '/abc' --> 'http://localhost:80/abc' 314 if (url.indexOf('/') === 0) { 315 url = dl.protocol + '//' + dl.host + url; 316 } 317 // strip trailing slashes 318 url = url.replace(/[/]+$/,''); 319 return url; 320 }; 321 322 // IE doesn't support [].indexOf. 323 utils.arrIndexOf = function(arr, obj){ 324 for(var i=0; i < arr.length; i++){ 325 if(arr[i] === obj){ 326 return i; 327 } 328 } 329 return -1; 330 }; 331 332 utils.arrSkip = function(arr, obj) { 333 var idx = utils.arrIndexOf(arr, obj); 334 if (idx === -1) { 335 return arr.slice(); 336 } else { 337 var dst = arr.slice(0, idx); 338 return dst.concat(arr.slice(idx+1)); 339 } 340 }; 341 342 // Via: https://gist.github.com/1133122/2121c601c5549155483f50be3da5305e83b8c5df 343 utils.isArray = Array.isArray || function(value) { 344 return {}.toString.call(value).indexOf('Array') >= 0 345 }; 346 347 utils.delay = function(t, fun) { 348 if(typeof t === 'function') { 349 fun = t; 350 t = 0; 351 } 352 return setTimeout(fun, t); 353 }; 354 355 356 // Chars worth escaping, as defined by Douglas Crockford: 357 // https://github.com/douglascrockford/JSON-js/blob/47a9882cddeb1e8529e07af9736218075372b8ac/json2.js#L196 358 var json_escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 359 json_lookup = { 360 "\u0000":"\\u0000","\u0001":"\\u0001","\u0002":"\\u0002","\u0003":"\\u0003", 361 "\u0004":"\\u0004","\u0005":"\\u0005","\u0006":"\\u0006","\u0007":"\\u0007", 362 "\b":"\\b","\t":"\\t","\n":"\\n","\u000b":"\\u000b","\f":"\\f","\r":"\\r", 363 "\u000e":"\\u000e","\u000f":"\\u000f","\u0010":"\\u0010","\u0011":"\\u0011", 364 "\u0012":"\\u0012","\u0013":"\\u0013","\u0014":"\\u0014","\u0015":"\\u0015", 365 "\u0016":"\\u0016","\u0017":"\\u0017","\u0018":"\\u0018","\u0019":"\\u0019", 366 "\u001a":"\\u001a","\u001b":"\\u001b","\u001c":"\\u001c","\u001d":"\\u001d", 367 "\u001e":"\\u001e","\u001f":"\\u001f","\"":"\\\"","\\":"\\\\", 368 "\u007f":"\\u007f","\u0080":"\\u0080","\u0081":"\\u0081","\u0082":"\\u0082", 369 "\u0083":"\\u0083","\u0084":"\\u0084","\u0085":"\\u0085","\u0086":"\\u0086", 370 "\u0087":"\\u0087","\u0088":"\\u0088","\u0089":"\\u0089","\u008a":"\\u008a", 371 "\u008b":"\\u008b","\u008c":"\\u008c","\u008d":"\\u008d","\u008e":"\\u008e", 372 "\u008f":"\\u008f","\u0090":"\\u0090","\u0091":"\\u0091","\u0092":"\\u0092", 373 "\u0093":"\\u0093","\u0094":"\\u0094","\u0095":"\\u0095","\u0096":"\\u0096", 374 "\u0097":"\\u0097","\u0098":"\\u0098","\u0099":"\\u0099","\u009a":"\\u009a", 375 "\u009b":"\\u009b","\u009c":"\\u009c","\u009d":"\\u009d","\u009e":"\\u009e", 376 "\u009f":"\\u009f","\u00ad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601", 377 "\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f", 378 "\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d", 379 "\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029", 380 "\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d", 381 "\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061", 382 "\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065", 383 "\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069", 384 "\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d", 385 "\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0", 386 "\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4", 387 "\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8", 388 "\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc", 389 "\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"}; 390 391 // Some extra characters that Chrome gets wrong, and substitutes with 392 // something else on the wire. 393 var extra_escapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g, 394 extra_lookup; 395 396 // JSON Quote string. Use native implementation when possible. 397 var JSONQuote = (JSON && JSON.stringify) || function(string) { 398 json_escapable.lastIndex = 0; 399 if (json_escapable.test(string)) { 400 string = string.replace(json_escapable, function(a) { 401 return json_lookup[a]; 402 }); 403 } 404 return '"' + string + '"'; 405 }; 406 407 // This may be quite slow, so let's delay until user actually uses bad 408 // characters. 409 var unroll_lookup = function(escapable) { 410 var i; 411 var unrolled = {} 412 var c = [] 413 for(i=0; i<65536; i++) { 414 c.push( String.fromCharCode(i) ); 415 } 416 escapable.lastIndex = 0; 417 c.join('').replace(escapable, function (a) { 418 unrolled[ a ] = '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 419 return ''; 420 }); 421 escapable.lastIndex = 0; 422 return unrolled; 423 }; 424 425 // Quote string, also taking care of unicode characters that browsers 426 // often break. Especially, take care of unicode surrogates: 427 // http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates 428 utils.quote = function(string) { 429 var quoted = JSONQuote(string); 430 431 // In most cases this should be very fast and good enough. 432 extra_escapable.lastIndex = 0; 433 if(!extra_escapable.test(quoted)) { 434 return quoted; 435 } 436 437 if(!extra_lookup) extra_lookup = unroll_lookup(extra_escapable); 438 439 return quoted.replace(extra_escapable, function(a) { 440 return extra_lookup[a]; 441 }); 442 } 443 444 var _all_protocols = ['websocket', 445 'xdr-streaming', 446 'xhr-streaming', 447 'iframe-eventsource', 448 'iframe-htmlfile', 449 'xdr-polling', 450 'xhr-polling', 451 'iframe-xhr-polling', 452 'jsonp-polling']; 453 454 utils.probeProtocols = function() { 455 var probed = {}; 456 for(var i=0; i<_all_protocols.length; i++) { 457 var protocol = _all_protocols[i]; 458 // User can have a typo in protocol name. 459 probed[protocol] = SockJS[protocol] && 460 SockJS[protocol].enabled(); 461 } 462 return probed; 463 }; 464 465 utils.detectProtocols = function(probed, protocols_whitelist, info) { 466 var pe = {}, 467 protocols = []; 468 if (!protocols_whitelist) protocols_whitelist = _all_protocols; 469 for(var i=0; i<protocols_whitelist.length; i++) { 470 var protocol = protocols_whitelist[i]; 471 pe[protocol] = probed[protocol]; 472 } 473 var maybe_push = function(protos) { 474 var proto = protos.shift(); 475 if (pe[proto]) { 476 protocols.push(proto); 477 } else { 478 if (protos.length > 0) { 479 maybe_push(protos); 480 } 481 } 482 } 483 484 // 1. Websocket 485 if (info.websocket !== false) { 486 maybe_push(['websocket']); 487 } 488 489 // 2. Streaming 490 if (pe['xhr-streaming'] && !info.null_origin) { 491 protocols.push('xhr-streaming'); 492 } else { 493 if (pe['xdr-streaming'] && !info.cookie_needed && !info.null_origin) { 494 protocols.push('xdr-streaming'); 495 } else { 496 maybe_push(['iframe-eventsource', 497 'iframe-htmlfile']); 498 } 499 } 500 501 // 3. Polling 502 if (pe['xhr-polling'] && !info.null_origin) { 503 protocols.push('xhr-polling'); 504 } else { 505 if (pe['xdr-polling'] && !info.cookie_needed && !info.null_origin) { 506 protocols.push('xdr-polling'); 507 } else { 508 maybe_push(['iframe-xhr-polling', 509 'jsonp-polling']); 510 } 511 } 512 return protocols; 513 } 514 // [*] End of lib/utils.js 515 516 517 // [*] Including lib/dom.js 518 /* 519 * ***** BEGIN LICENSE BLOCK ***** 520 * Copyright (c) 2011-2012 VMware, Inc. 521 * 522 * For the license see COPYING. 523 * ***** END LICENSE BLOCK ***** 524 */ 525 526 // May be used by htmlfile jsonp and transports. 527 var MPrefix = '_sockjs_global'; 528 utils.createHook = function() { 529 var window_id = 'a' + utils.random_string(8); 530 if (!(MPrefix in _window)) { 531 var map = {}; 532 _window[MPrefix] = function(window_id) { 533 if (!(window_id in map)) { 534 map[window_id] = { 535 id: window_id, 536 del: function() {delete map[window_id];} 537 }; 538 } 539 return map[window_id]; 540 } 541 } 542 return _window[MPrefix](window_id); 543 }; 544 545 546 547 utils.attachMessage = function(listener) { 548 utils.attachEvent('message', listener); 549 }; 550 utils.attachEvent = function(event, listener) { 551 if (typeof _window.addEventListener !== 'undefined') { 552 _window.addEventListener(event, listener, false); 553 } else { 554 // IE quirks. 555 // According to: http://stevesouders.com/misc/test-postmessage.php 556 // the message gets delivered only to 'document', not 'window'. 557 _document.attachEvent("on" + event, listener); 558 // I get 'window' for ie8. 559 _window.attachEvent("on" + event, listener); 560 } 561 }; 562 563 utils.detachMessage = function(listener) { 564 utils.detachEvent('message', listener); 565 }; 566 utils.detachEvent = function(event, listener) { 567 if (typeof _window.addEventListener !== 'undefined') { 568 _window.removeEventListener(event, listener, false); 569 } else { 570 _document.detachEvent("on" + event, listener); 571 _window.detachEvent("on" + event, listener); 572 } 573 }; 574 575 576 var on_unload = {}; 577 // Things registered after beforeunload are to be called immediately. 578 var after_unload = false; 579 580 var trigger_unload_callbacks = function() { 581 for(var ref in on_unload) { 582 on_unload[ref](); 583 delete on_unload[ref]; 584 }; 585 }; 586 587 var unload_triggered = function() { 588 if(after_unload) return; 589 after_unload = true; 590 trigger_unload_callbacks(); 591 }; 592 593 // 'unload' alone is not reliable in opera within an iframe, but we 594 // can't use `beforeunload` as IE fires it on javascript: links. 595 utils.attachEvent('unload', unload_triggered); 596 597 utils.unload_add = function(listener) { 598 var ref = utils.random_string(8); 599 on_unload[ref] = listener; 600 if (after_unload) { 601 utils.delay(trigger_unload_callbacks); 602 } 603 return ref; 604 }; 605 utils.unload_del = function(ref) { 606 if (ref in on_unload) 607 delete on_unload[ref]; 608 }; 609 610 611 utils.createIframe = function (iframe_url, error_callback) { 612 var iframe = _document.createElement('iframe'); 613 var tref, unload_ref; 614 var unattach = function() { 615 clearTimeout(tref); 616 // Explorer had problems with that. 617 try {iframe.onload = null;} catch (x) {} 618 iframe.onerror = null; 619 }; 620 var cleanup = function() { 621 if (iframe) { 622 unattach(); 623 // This timeout makes chrome fire onbeforeunload event 624 // within iframe. Without the timeout it goes straight to 625 // onunload. 626 setTimeout(function() { 627 if(iframe) { 628 iframe.parentNode.removeChild(iframe); 629 } 630 iframe = null; 631 }, 0); 632 utils.unload_del(unload_ref); 633 } 634 }; 635 var onerror = function(r) { 636 if (iframe) { 637 cleanup(); 638 error_callback(r); 639 } 640 }; 641 var post = function(msg, origin) { 642 try { 643 // When the iframe is not loaded, IE raises an exception 644 // on 'contentWindow'. 645 if (iframe && iframe.contentWindow) { 646 iframe.contentWindow.postMessage(msg, origin); 647 } 648 } catch (x) {}; 649 }; 650 651 iframe.src = iframe_url; 652 iframe.style.display = 'none'; 653 iframe.style.position = 'absolute'; 654 iframe.onerror = function(){onerror('onerror');}; 655 iframe.onload = function() { 656 // `onload` is triggered before scripts on the iframe are 657 // executed. Give it few seconds to actually load stuff. 658 clearTimeout(tref); 659 tref = setTimeout(function(){onerror('onload timeout');}, 2000); 660 }; 661 _document.body.appendChild(iframe); 662 tref = setTimeout(function(){onerror('timeout');}, 15000); 663 unload_ref = utils.unload_add(cleanup); 664 return { 665 post: post, 666 cleanup: cleanup, 667 loaded: unattach 668 }; 669 }; 670 671 utils.createHtmlfile = function (iframe_url, error_callback) { 672 var doc = new ActiveXObject('htmlfile'); 673 var tref, unload_ref; 674 var iframe; 675 var unattach = function() { 676 clearTimeout(tref); 677 }; 678 var cleanup = function() { 679 if (doc) { 680 unattach(); 681 utils.unload_del(unload_ref); 682 iframe.parentNode.removeChild(iframe); 683 iframe = doc = null; 684 CollectGarbage(); 685 } 686 }; 687 var onerror = function(r) { 688 if (doc) { 689 cleanup(); 690 error_callback(r); 691 } 692 }; 693 var post = function(msg, origin) { 694 try { 695 // When the iframe is not loaded, IE raises an exception 696 // on 'contentWindow'. 697 if (iframe && iframe.contentWindow) { 698 iframe.contentWindow.postMessage(msg, origin); 699 } 700 } catch (x) {}; 701 }; 702 703 doc.open(); 704 doc.write('<html><s' + 'cript>' + 705 'document.domain="' + document.domain + '";' + 706 '</s' + 'cript></html>'); 707 doc.close(); 708 doc.parentWindow[WPrefix] = _window[WPrefix]; 709 var c = doc.createElement('div'); 710 doc.body.appendChild(c); 711 iframe = doc.createElement('iframe'); 712 c.appendChild(iframe); 713 iframe.src = iframe_url; 714 tref = setTimeout(function(){onerror('timeout');}, 15000); 715 unload_ref = utils.unload_add(cleanup); 716 return { 717 post: post, 718 cleanup: cleanup, 719 loaded: unattach 720 }; 721 }; 722 // [*] End of lib/dom.js 723 724 725 // [*] Including lib/dom2.js 726 /* 727 * ***** BEGIN LICENSE BLOCK ***** 728 * Copyright (c) 2011-2012 VMware, Inc. 729 * 730 * For the license see COPYING. 731 * ***** END LICENSE BLOCK ***** 732 */ 733 734 var AbstractXHRObject = function(){}; 735 AbstractXHRObject.prototype = new EventEmitter(['chunk', 'finish']); 736 737 AbstractXHRObject.prototype._start = function(method, url, payload, opts) { 738 var that = this; 739 740 try { 741 that.xhr = new XMLHttpRequest(); 742 } catch(x) {}; 743 744 if (!that.xhr) { 745 try { 746 that.xhr = new _window.ActiveXObject('Microsoft.XMLHTTP'); 747 } catch(x) {}; 748 } 749 if (_window.ActiveXObject || _window.XDomainRequest) { 750 // IE8 caches even POSTs 751 url += ((url.indexOf('?') === -1) ? '?' : '&') + 't='+(+new Date); 752 } 753 754 // Explorer tends to keep connection open, even after the 755 // tab gets closed: http://bugs.jquery.com/ticket/5280 756 that.unload_ref = utils.unload_add(function(){that._cleanup(true);}); 757 try { 758 that.xhr.open(method, url, true); 759 } catch(e) { 760 // IE raises an exception on wrong port. 761 that.emit('finish', 0, ''); 762 that._cleanup(); 763 return; 764 }; 765 766 if (!opts || !opts.no_credentials) { 767 // Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest : 768 // "This never affects same-site requests." 769 that.xhr.withCredentials = 'true'; 770 } 771 if (opts && opts.headers) { 772 for(var key in opts.headers) { 773 that.xhr.setRequestHeader(key, opts.headers[key]); 774 } 775 } 776 777 that.xhr.onreadystatechange = function() { 778 if (that.xhr) { 779 var x = that.xhr; 780 switch (x.readyState) { 781 case 3: 782 // IE doesn't like peeking into responseText or status 783 // on Microsoft.XMLHTTP and readystate=3 784 try { 785 var status = x.status; 786 var text = x.responseText; 787 } catch (x) {}; 788 // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450 789 if (status === 1223) status = 204; 790 791 // IE does return readystate == 3 for 404 answers. 792 if (text && text.length > 0) { 793 that.emit('chunk', status, text); 794 } 795 break; 796 case 4: 797 var status = x.status; 798 // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450 799 if (status === 1223) status = 204; 800 801 that.emit('finish', status, x.responseText); 802 that._cleanup(false); 803 break; 804 } 805 } 806 }; 807 that.xhr.send(payload); 808 }; 809 810 AbstractXHRObject.prototype._cleanup = function(abort) { 811 var that = this; 812 if (!that.xhr) return; 813 utils.unload_del(that.unload_ref); 814 815 // IE needs this field to be a function 816 that.xhr.onreadystatechange = function(){}; 817 818 if (abort) { 819 try { 820 that.xhr.abort(); 821 } catch(x) {}; 822 } 823 that.unload_ref = that.xhr = null; 824 }; 825 826 AbstractXHRObject.prototype.close = function() { 827 var that = this; 828 that.nuke(); 829 that._cleanup(true); 830 }; 831 832 var XHRCorsObject = utils.XHRCorsObject = function() { 833 var that = this, args = arguments; 834 utils.delay(function(){that._start.apply(that, args);}); 835 }; 836 XHRCorsObject.prototype = new AbstractXHRObject(); 837 838 var XHRLocalObject = utils.XHRLocalObject = function(method, url, payload) { 839 var that = this; 840 utils.delay(function(){ 841 that._start(method, url, payload, { 842 no_credentials: true 843 }); 844 }); 845 }; 846 XHRLocalObject.prototype = new AbstractXHRObject(); 847 848 849 850 // References: 851 // http://ajaxian.com/archives/100-line-ajax-wrapper 852 // http://msdn.microsoft.com/en-us/library/cc288060(v=VS.85).aspx 853 var XDRObject = utils.XDRObject = function(method, url, payload) { 854 var that = this; 855 utils.delay(function(){that._start(method, url, payload);}); 856 }; 857 XDRObject.prototype = new EventEmitter(['chunk', 'finish']); 858 XDRObject.prototype._start = function(method, url, payload) { 859 var that = this; 860 var xdr = new XDomainRequest(); 861 // IE caches even POSTs 862 url += ((url.indexOf('?') === -1) ? '?' : '&') + 't='+(+new Date); 863 864 var onerror = xdr.ontimeout = xdr.onerror = function() { 865 that.emit('finish', 0, ''); 866 that._cleanup(false); 867 }; 868 xdr.onprogress = function() { 869 that.emit('chunk', 200, xdr.responseText); 870 }; 871 xdr.onload = function() { 872 that.emit('finish', 200, xdr.responseText); 873 that._cleanup(false); 874 }; 875 that.xdr = xdr; 876 that.unload_ref = utils.unload_add(function(){that._cleanup(true);}); 877 try { 878 // Fails with AccessDenied if port number is bogus 879 that.xdr.open(method, url); 880 that.xdr.send(payload); 881 } catch(x) { 882 onerror(); 883 } 884 }; 885 886 XDRObject.prototype._cleanup = function(abort) { 887 var that = this; 888 if (!that.xdr) return; 889 utils.unload_del(that.unload_ref); 890 891 that.xdr.ontimeout = that.xdr.onerror = that.xdr.onprogress = 892 that.xdr.onload = null; 893 if (abort) { 894 try { 895 that.xdr.abort(); 896 } catch(x) {}; 897 } 898 that.unload_ref = that.xdr = null; 899 }; 900 901 XDRObject.prototype.close = function() { 902 var that = this; 903 that.nuke(); 904 that._cleanup(true); 905 }; 906 907 // 1. Is natively via XHR 908 // 2. Is natively via XDR 909 // 3. Nope, but postMessage is there so it should work via the Iframe. 910 // 4. Nope, sorry. 911 utils.isXHRCorsCapable = function() { 912 if (_window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) { 913 return 1; 914 } 915 // XDomainRequest doesn't work if page is served from file:// 916 if (_window.XDomainRequest && _document.domain) { 917 return 2; 918 } 919 if (IframeTransport.enabled()) { 920 return 3; 921 } 922 return 4; 923 }; 924 // [*] End of lib/dom2.js 925 926 927 // [*] Including lib/sockjs.js 928 /* 929 * ***** BEGIN LICENSE BLOCK ***** 930 * Copyright (c) 2011-2012 VMware, Inc. 931 * 932 * For the license see COPYING. 933 * ***** END LICENSE BLOCK ***** 934 */ 935 936 var SockJS = function(url, dep_protocols_whitelist, options) { 937 if (this === _window) { 938 // makes `new` optional 939 return new SockJS(url, dep_protocols_whitelist, options); 940 } 941 942 var that = this, protocols_whitelist; 943 that._options = {devel: false, debug: false, protocols_whitelist: [], 944 info: undefined, rtt: undefined}; 945 if (options) { 946 utils.objectExtend(that._options, options); 947 } 948 that._base_url = utils.amendUrl(url); 949 that._server = that._options.server || utils.random_number_string(1000); 950 if (that._options.protocols_whitelist && 951 that._options.protocols_whitelist.length) { 952 protocols_whitelist = that._options.protocols_whitelist; 953 } else { 954 // Deprecated API 955 if (typeof dep_protocols_whitelist === 'string' && 956 dep_protocols_whitelist.length > 0) { 957 protocols_whitelist = [dep_protocols_whitelist]; 958 } else if (utils.isArray(dep_protocols_whitelist)) { 959 protocols_whitelist = dep_protocols_whitelist 960 } else { 961 protocols_whitelist = null; 962 } 963 if (protocols_whitelist) { 964 that._debug('Deprecated API: Use "protocols_whitelist" option ' + 965 'instead of supplying protocol list as a second ' + 966 'parameter to SockJS constructor.'); 967 } 968 } 969 that._protocols = []; 970 that.protocol = null; 971 that.readyState = SockJS.CONNECTING; 972 that._ir = createInfoReceiver(that._base_url); 973 that._ir.onfinish = function(info, rtt) { 974 that._ir = null; 975 if (info) { 976 if (that._options.info) { 977 // Override if user supplies the option 978 info = utils.objectExtend(info, that._options.info); 979 } 980 if (that._options.rtt) { 981 rtt = that._options.rtt; 982 } 983 that._applyInfo(info, rtt, protocols_whitelist); 984 that._didClose(); 985 } else { 986 that._didClose(1002, 'Can\'t connect to server', true); 987 } 988 }; 989 }; 990 // Inheritance 991 SockJS.prototype = new REventTarget(); 992 993 SockJS.version = "0.3.4"; 994 995 SockJS.CONNECTING = 0; 996 SockJS.OPEN = 1; 997 SockJS.CLOSING = 2; 998 SockJS.CLOSED = 3; 999 1000 SockJS.prototype._debug = function() { 1001 if (this._options.debug) 1002 utils.log.apply(utils, arguments); 1003 }; 1004 1005 SockJS.prototype._dispatchOpen = function() { 1006 var that = this; 1007 if (that.readyState === SockJS.CONNECTING) { 1008 if (that._transport_tref) { 1009 clearTimeout(that._transport_tref); 1010 that._transport_tref = null; 1011 } 1012 that.readyState = SockJS.OPEN; 1013 that.dispatchEvent(new SimpleEvent("open")); 1014 } else { 1015 // The server might have been restarted, and lost track of our 1016 // connection. 1017 that._didClose(1006, "Server lost session"); 1018 } 1019 }; 1020 1021 SockJS.prototype._dispatchMessage = function(data) { 1022 var that = this; 1023 if (that.readyState !== SockJS.OPEN) 1024 return; 1025 that.dispatchEvent(new SimpleEvent("message", {data: data})); 1026 }; 1027 1028 SockJS.prototype._dispatchHeartbeat = function(data) { 1029 var that = this; 1030 if (that.readyState !== SockJS.OPEN) 1031 return; 1032 that.dispatchEvent(new SimpleEvent('heartbeat', {})); 1033 }; 1034 1035 SockJS.prototype._didClose = function(code, reason, force) { 1036 var that = this; 1037 if (that.readyState !== SockJS.CONNECTING && 1038 that.readyState !== SockJS.OPEN && 1039 that.readyState !== SockJS.CLOSING) 1040 throw new Error('INVALID_STATE_ERR'); 1041 if (that._ir) { 1042 that._ir.nuke(); 1043 that._ir = null; 1044 } 1045 1046 if (that._transport) { 1047 that._transport.doCleanup(); 1048 that._transport = null; 1049 } 1050 1051 var close_event = new SimpleEvent("close", { 1052 code: code, 1053 reason: reason, 1054 wasClean: utils.userSetCode(code)}); 1055 1056 if (!utils.userSetCode(code) && 1057 that.readyState === SockJS.CONNECTING && !force) { 1058 if (that._try_next_protocol(close_event)) { 1059 return; 1060 } 1061 close_event = new SimpleEvent("close", {code: 2000, 1062 reason: "All transports failed", 1063 wasClean: false, 1064 last_event: close_event}); 1065 } 1066 that.readyState = SockJS.CLOSED; 1067 1068 utils.delay(function() { 1069 that.dispatchEvent(close_event); 1070 }); 1071 }; 1072 1073 SockJS.prototype._didMessage = function(data) { 1074 var that = this; 1075 var type = data.slice(0, 1); 1076 switch(type) { 1077 case 'o': 1078 that._dispatchOpen(); 1079 break; 1080 case 'a': 1081 var payload = JSON.parse(data.slice(1) || '[]'); 1082 for(var i=0; i < payload.length; i++){ 1083 that._dispatchMessage(payload[i]); 1084 } 1085 break; 1086 case 'm': 1087 var payload = JSON.parse(data.slice(1) || 'null'); 1088 that._dispatchMessage(payload); 1089 break; 1090 case 'c': 1091 var payload = JSON.parse(data.slice(1) || '[]'); 1092 that._didClose(payload[0], payload[1]); 1093 break; 1094 case 'h': 1095 that._dispatchHeartbeat(); 1096 break; 1097 } 1098 }; 1099 1100 SockJS.prototype._try_next_protocol = function(close_event) { 1101 var that = this; 1102 if (that.protocol) { 1103 that._debug('Closed transport:', that.protocol, ''+close_event); 1104 that.protocol = null; 1105 } 1106 if (that._transport_tref) { 1107 clearTimeout(that._transport_tref); 1108 that._transport_tref = null; 1109 } 1110 1111 while(1) { 1112 var protocol = that.protocol = that._protocols.shift(); 1113 if (!protocol) { 1114 return false; 1115 } 1116 // Some protocols require access to `body`, what if were in 1117 // the `head`? 1118 if (SockJS[protocol] && 1119 SockJS[protocol].need_body === true && 1120 (!_document.body || 1121 (typeof _document.readyState !== 'undefined' 1122 && _document.readyState !== 'complete'))) { 1123 that._protocols.unshift(protocol); 1124 that.protocol = 'waiting-for-load'; 1125 utils.attachEvent('load', function(){ 1126 that._try_next_protocol(); 1127 }); 1128 return true; 1129 } 1130 1131 if (!SockJS[protocol] || 1132 !SockJS[protocol].enabled(that._options)) { 1133 that._debug('Skipping transport:', protocol); 1134 } else { 1135 var roundTrips = SockJS[protocol].roundTrips || 1; 1136 var to = ((that._options.rto || 0) * roundTrips) || 5000; 1137 that._transport_tref = utils.delay(to, function() { 1138 if (that.readyState === SockJS.CONNECTING) { 1139 // I can't understand how it is possible to run 1140 // this timer, when the state is CLOSED, but 1141 // apparently in IE everythin is possible. 1142 that._didClose(2007, "Transport timeouted"); 1143 } 1144 }); 1145 1146 var connid = utils.random_string(8); 1147 var trans_url = that._base_url + '/' + that._server + '/' + connid; 1148 that._debug('Opening transport:', protocol, ' url:'+trans_url, 1149 ' RTO:'+that._options.rto); 1150 that._transport = new SockJS[protocol](that, trans_url, 1151 that._base_url); 1152 return true; 1153 } 1154 } 1155 }; 1156 1157 SockJS.prototype.close = function(code, reason) { 1158 var that = this; 1159 if (code && !utils.userSetCode(code)) 1160 throw new Error("INVALID_ACCESS_ERR"); 1161 if(that.readyState !== SockJS.CONNECTING && 1162 that.readyState !== SockJS.OPEN) { 1163 return false; 1164 } 1165 that.readyState = SockJS.CLOSING; 1166 that._didClose(code || 1000, reason || "Normal closure"); 1167 return true; 1168 }; 1169 1170 SockJS.prototype.send = function(data) { 1171 var that = this; 1172 if (that.readyState === SockJS.CONNECTING) 1173 throw new Error('INVALID_STATE_ERR'); 1174 if (that.readyState === SockJS.OPEN) { 1175 that._transport.doSend(utils.quote('' + data)); 1176 } 1177 return true; 1178 }; 1179 1180 SockJS.prototype._applyInfo = function(info, rtt, protocols_whitelist) { 1181 var that = this; 1182 that._options.info = info; 1183 that._options.rtt = rtt; 1184 that._options.rto = utils.countRTO(rtt); 1185 that._options.info.null_origin = !_document.domain; 1186 var probed = utils.probeProtocols(); 1187 that._protocols = utils.detectProtocols(probed, protocols_whitelist, info); 1188 }; 1189 // [*] End of lib/sockjs.js 1190 1191 1192 // [*] Including lib/trans-websocket.js 1193 /* 1194 * ***** BEGIN LICENSE BLOCK ***** 1195 * Copyright (c) 2011-2012 VMware, Inc. 1196 * 1197 * For the license see COPYING. 1198 * ***** END LICENSE BLOCK ***** 1199 */ 1200 1201 var WebSocketTransport = SockJS.websocket = function(ri, trans_url) { 1202 var that = this; 1203 var url = trans_url + '/websocket'; 1204 if (url.slice(0, 5) === 'https') { 1205 url = 'wss' + url.slice(5); 1206 } else { 1207 url = 'ws' + url.slice(4); 1208 } 1209 that.ri = ri; 1210 that.url = url; 1211 var Constructor = _window.WebSocket || _window.MozWebSocket; 1212 1213 that.ws = new Constructor(that.url); 1214 that.ws.onmessage = function(e) { 1215 that.ri._didMessage(e.data); 1216 }; 1217 // Firefox has an interesting bug. If a websocket connection is 1218 // created after onunload, it stays alive even when user 1219 // navigates away from the page. In such situation let's lie - 1220 // let's not open the ws connection at all. See: 1221 // https://github.com/sockjs/sockjs-client/issues/28 1222 // https://bugzilla.mozilla.org/show_bug.cgi?id=696085 1223 that.unload_ref = utils.unload_add(function(){that.ws.close()}); 1224 that.ws.onclose = function() { 1225 that.ri._didMessage(utils.closeFrame(1006, "WebSocket connection broken")); 1226 }; 1227 }; 1228 1229 WebSocketTransport.prototype.doSend = function(data) { 1230 this.ws.send('[' + data + ']'); 1231 }; 1232 1233 WebSocketTransport.prototype.doCleanup = function() { 1234 var that = this; 1235 var ws = that.ws; 1236 if (ws) { 1237 ws.onmessage = ws.onclose = null; 1238 ws.close(); 1239 utils.unload_del(that.unload_ref); 1240 that.unload_ref = that.ri = that.ws = null; 1241 } 1242 }; 1243 1244 WebSocketTransport.enabled = function() { 1245 return !!(_window.WebSocket || _window.MozWebSocket); 1246 }; 1247 1248 // In theory, ws should require 1 round trip. But in chrome, this is 1249 // not very stable over SSL. Most likely a ws connection requires a 1250 // separate SSL connection, in which case 2 round trips are an 1251 // absolute minumum. 1252 WebSocketTransport.roundTrips = 2; 1253 // [*] End of lib/trans-websocket.js 1254 1255 1256 // [*] Including lib/trans-sender.js 1257 /* 1258 * ***** BEGIN LICENSE BLOCK ***** 1259 * Copyright (c) 2011-2012 VMware, Inc. 1260 * 1261 * For the license see COPYING. 1262 * ***** END LICENSE BLOCK ***** 1263 */ 1264 1265 var BufferedSender = function() {}; 1266 BufferedSender.prototype.send_constructor = function(sender) { 1267 var that = this; 1268 that.send_buffer = []; 1269 that.sender = sender; 1270 }; 1271 BufferedSender.prototype.doSend = function(message) { 1272 var that = this; 1273 that.send_buffer.push(message); 1274 if (!that.send_stop) { 1275 that.send_schedule(); 1276 } 1277 }; 1278 1279 // For polling transports in a situation when in the message callback, 1280 // new message is being send. If the sending connection was started 1281 // before receiving one, it is possible to saturate the network and 1282 // timeout due to the lack of receiving socket. To avoid that we delay 1283 // sending messages by some small time, in order to let receiving 1284 // connection be started beforehand. This is only a halfmeasure and 1285 // does not fix the big problem, but it does make the tests go more 1286 // stable on slow networks. 1287 BufferedSender.prototype.send_schedule_wait = function() { 1288 var that = this; 1289 var tref; 1290 that.send_stop = function() { 1291 that.send_stop = null; 1292 clearTimeout(tref); 1293 }; 1294 tref = utils.delay(25, function() { 1295 that.send_stop = null; 1296 that.send_schedule(); 1297 }); 1298 }; 1299 1300 BufferedSender.prototype.send_schedule = function() { 1301 var that = this; 1302 if (that.send_buffer.length > 0) { 1303 var payload = '[' + that.send_buffer.join(',') + ']'; 1304 that.send_stop = that.sender(that.trans_url, payload, function(success, abort_reason) { 1305 that.send_stop = null; 1306 if (success === false) { 1307 that.ri._didClose(1006, 'Sending error ' + abort_reason); 1308 } else { 1309 that.send_schedule_wait(); 1310 } 1311 }); 1312 that.send_buffer = []; 1313 } 1314 }; 1315 1316 BufferedSender.prototype.send_destructor = function() { 1317 var that = this; 1318 if (that._send_stop) { 1319 that._send_stop(); 1320 } 1321 that._send_stop = null; 1322 }; 1323 1324 var jsonPGenericSender = function(url, payload, callback) { 1325 var that = this; 1326 1327 if (!('_send_form' in that)) { 1328 var form = that._send_form = _document.createElement('form'); 1329 var area = that._send_area = _document.createElement('textarea'); 1330 area.name = 'd'; 1331 form.style.display = 'none'; 1332 form.style.position = 'absolute'; 1333 form.method = 'POST'; 1334 form.enctype = 'application/x-www-form-urlencoded'; 1335 form.acceptCharset = "UTF-8"; 1336 form.appendChild(area); 1337 _document.body.appendChild(form); 1338 } 1339 var form = that._send_form; 1340 var area = that._send_area; 1341 var id = 'a' + utils.random_string(8); 1342 form.target = id; 1343 form.action = url + '/jsonp_send?i=' + id; 1344 1345 var iframe; 1346 try { 1347 // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) 1348 iframe = _document.createElement('<iframe name="'+ id +'">'); 1349 } catch(x) { 1350 iframe = _document.createElement('iframe'); 1351 iframe.name = id; 1352 } 1353 iframe.id = id; 1354 form.appendChild(iframe); 1355 iframe.style.display = 'none'; 1356 1357 try { 1358 area.value = payload; 1359 } catch(e) { 1360 utils.log('Your browser is seriously broken. Go home! ' + e.message); 1361 } 1362 form.submit(); 1363 1364 var completed = function(e) { 1365 if (!iframe.onerror) return; 1366 iframe.onreadystatechange = iframe.onerror = iframe.onload = null; 1367 // Opera mini doesn't like if we GC iframe 1368 // immediately, thus this timeout. 1369 utils.delay(500, function() { 1370 iframe.parentNode.removeChild(iframe); 1371 iframe = null; 1372 }); 1373 area.value = ''; 1374 // It is not possible to detect if the iframe succeeded or 1375 // failed to submit our form. 1376 callback(true); 1377 }; 1378 iframe.onerror = iframe.onload = completed; 1379 iframe.onreadystatechange = function(e) { 1380 if (iframe.readyState == 'complete') completed(); 1381 }; 1382 return completed; 1383 }; 1384 1385 var createAjaxSender = function(AjaxObject) { 1386 return function(url, payload, callback) { 1387 var xo = new AjaxObject('POST', url + '/xhr_send', payload); 1388 xo.onfinish = function(status, text) { 1389 callback(status === 200 || status === 204, 1390 'http status ' + status); 1391 }; 1392 return function(abort_reason) { 1393 callback(false, abort_reason); 1394 }; 1395 }; 1396 }; 1397 // [*] End of lib/trans-sender.js 1398 1399 1400 // [*] Including lib/trans-jsonp-receiver.js 1401 /* 1402 * ***** BEGIN LICENSE BLOCK ***** 1403 * Copyright (c) 2011-2012 VMware, Inc. 1404 * 1405 * For the license see COPYING. 1406 * ***** END LICENSE BLOCK ***** 1407 */ 1408 1409 // Parts derived from Socket.io: 1410 // https://github.com/LearnBoost/socket.io/blob/0.6.17/lib/socket.io/transports/jsonp-polling.js 1411 // and jQuery-JSONP: 1412 // https://code.google.com/p/jquery-jsonp/source/browse/trunk/core/jquery.jsonp.js 1413 var jsonPGenericReceiver = function(url, callback) { 1414 var tref; 1415 var script = _document.createElement('script'); 1416 var script2; // Opera synchronous load trick. 1417 var close_script = function(frame) { 1418 if (script2) { 1419 script2.parentNode.removeChild(script2); 1420 script2 = null; 1421 } 1422 if (script) { 1423 clearTimeout(tref); 1424 // Unfortunately, you can't really abort script loading of 1425 // the script. 1426 script.parentNode.removeChild(script); 1427 script.onreadystatechange = script.onerror = 1428 script.onload = script.onclick = null; 1429 script = null; 1430 callback(frame); 1431 callback = null; 1432 } 1433 }; 1434 1435 // IE9 fires 'error' event after orsc or before, in random order. 1436 var loaded_okay = false; 1437 var error_timer = null; 1438 1439 script.id = 'a' + utils.random_string(8); 1440 script.src = url; 1441 script.type = 'text/javascript'; 1442 script.charset = 'UTF-8'; 1443 script.onerror = function(e) { 1444 if (!error_timer) { 1445 // Delay firing close_script. 1446 error_timer = setTimeout(function() { 1447 if (!loaded_okay) { 1448 close_script(utils.closeFrame( 1449 1006, 1450 "JSONP script loaded abnormally (onerror)")); 1451 } 1452 }, 1000); 1453 } 1454 }; 1455 script.onload = function(e) { 1456 close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (onload)")); 1457 }; 1458 1459 script.onreadystatechange = function(e) { 1460 if (/loaded|closed/.test(script.readyState)) { 1461 if (script && script.htmlFor && script.onclick) { 1462 loaded_okay = true; 1463 try { 1464 // In IE, actually execute the script. 1465 script.onclick(); 1466 } catch (x) {} 1467 } 1468 if (script) { 1469 close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (onreadystatechange)")); 1470 } 1471 } 1472 }; 1473 // IE: event/htmlFor/onclick trick. 1474 // One can't rely on proper order for onreadystatechange. In order to 1475 // make sure, set a 'htmlFor' and 'event' properties, so that 1476 // script code will be installed as 'onclick' handler for the 1477 // script object. Later, onreadystatechange, manually execute this 1478 // code. FF and Chrome doesn't work with 'event' and 'htmlFor' 1479 // set. For reference see: 1480 // http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html 1481 // Also, read on that about script ordering: 1482 // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order 1483 if (typeof script.async === 'undefined' && _document.attachEvent) { 1484 // According to mozilla docs, in recent browsers script.async defaults 1485 // to 'true', so we may use it to detect a good browser: 1486 // https://developer.mozilla.org/en/HTML/Element/script 1487 if (!/opera/i.test(navigator.userAgent)) { 1488 // Naively assume we're in IE 1489 try { 1490 script.htmlFor = script.id; 1491 script.event = "onclick"; 1492 } catch (x) {} 1493 script.async = true; 1494 } else { 1495 // Opera, second sync script hack 1496 script2 = _document.createElement('script'); 1497 script2.text = "try{var a = document.getElementById('"+script.id+"'); if(a)a.onerror();}catch(x){};"; 1498 script.async = script2.async = false; 1499 } 1500 } 1501 if (typeof script.async !== 'undefined') { 1502 script.async = true; 1503 } 1504 1505 // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty. 1506 tref = setTimeout(function() { 1507 close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (timeout)")); 1508 }, 35000); 1509 1510 var head = _document.getElementsByTagName('head')[0]; 1511 head.insertBefore(script, head.firstChild); 1512 if (script2) { 1513 head.insertBefore(script2, head.firstChild); 1514 } 1515 return close_script; 1516 }; 1517 // [*] End of lib/trans-jsonp-receiver.js 1518 1519 1520 // [*] Including lib/trans-jsonp-polling.js 1521 /* 1522 * ***** BEGIN LICENSE BLOCK ***** 1523 * Copyright (c) 2011-2012 VMware, Inc. 1524 * 1525 * For the license see COPYING. 1526 * ***** END LICENSE BLOCK ***** 1527 */ 1528 1529 // The simplest and most robust transport, using the well-know cross 1530 // domain hack - JSONP. This transport is quite inefficient - one 1531 // mssage could use up to one http request. But at least it works almost 1532 // everywhere. 1533 // Known limitations: 1534 // o you will get a spinning cursor 1535 // o for Konqueror a dumb timer is needed to detect errors 1536 1537 1538 var JsonPTransport = SockJS['jsonp-polling'] = function(ri, trans_url) { 1539 utils.polluteGlobalNamespace(); 1540 var that = this; 1541 that.ri = ri; 1542 that.trans_url = trans_url; 1543 that.send_constructor(jsonPGenericSender); 1544 that._schedule_recv(); 1545 }; 1546 1547 // Inheritnace 1548 JsonPTransport.prototype = new BufferedSender(); 1549 1550 JsonPTransport.prototype._schedule_recv = function() { 1551 var that = this; 1552 var callback = function(data) { 1553 that._recv_stop = null; 1554 if (data) { 1555 // no data - heartbeat; 1556 if (!that._is_closing) { 1557 that.ri._didMessage(data); 1558 } 1559 } 1560 // The message can be a close message, and change is_closing state. 1561 if (!that._is_closing) { 1562 that._schedule_recv(); 1563 } 1564 }; 1565 that._recv_stop = jsonPReceiverWrapper(that.trans_url + '/jsonp', 1566 jsonPGenericReceiver, callback); 1567 }; 1568 1569 JsonPTransport.enabled = function() { 1570 return true; 1571 }; 1572 1573 JsonPTransport.need_body = true; 1574 1575 1576 JsonPTransport.prototype.doCleanup = function() { 1577 var that = this; 1578 that._is_closing = true; 1579 if (that._recv_stop) { 1580 that._recv_stop(); 1581 } 1582 that.ri = that._recv_stop = null; 1583 that.send_destructor(); 1584 }; 1585 1586 1587 // Abstract away code that handles global namespace pollution. 1588 var jsonPReceiverWrapper = function(url, constructReceiver, user_callback) { 1589 var id = 'a' + utils.random_string(6); 1590 var url_id = url + '?c=' + escape(WPrefix + '.' + id); 1591 1592 // Unfortunately it is not possible to abort loading of the 1593 // script. We need to keep track of frake close frames. 1594 var aborting = 0; 1595 1596 // Callback will be called exactly once. 1597 var callback = function(frame) { 1598 switch(aborting) { 1599 case 0: 1600 // Normal behaviour - delete hook _and_ emit message. 1601 delete _window[WPrefix][id]; 1602 user_callback(frame); 1603 break; 1604 case 1: 1605 // Fake close frame - emit but don't delete hook. 1606 user_callback(frame); 1607 aborting = 2; 1608 break; 1609 case 2: 1610 // Got frame after connection was closed, delete hook, don't emit. 1611 delete _window[WPrefix][id]; 1612 break; 1613 } 1614 }; 1615 1616 var close_script = constructReceiver(url_id, callback); 1617 _window[WPrefix][id] = close_script; 1618 var stop = function() { 1619 if (_window[WPrefix][id]) { 1620 aborting = 1; 1621 _window[WPrefix][id](utils.closeFrame(1000, "JSONP user aborted read")); 1622 } 1623 }; 1624 return stop; 1625 }; 1626 // [*] End of lib/trans-jsonp-polling.js 1627 1628 1629 // [*] Including lib/trans-xhr.js 1630 /* 1631 * ***** BEGIN LICENSE BLOCK ***** 1632 * Copyright (c) 2011-2012 VMware, Inc. 1633 * 1634 * For the license see COPYING. 1635 * ***** END LICENSE BLOCK ***** 1636 */ 1637 1638 var AjaxBasedTransport = function() {}; 1639 AjaxBasedTransport.prototype = new BufferedSender(); 1640 1641 AjaxBasedTransport.prototype.run = function(ri, trans_url, 1642 url_suffix, Receiver, AjaxObject) { 1643 var that = this; 1644 that.ri = ri; 1645 that.trans_url = trans_url; 1646 that.send_constructor(createAjaxSender(AjaxObject)); 1647 that.poll = new Polling(ri, Receiver, 1648 trans_url + url_suffix, AjaxObject); 1649 }; 1650 1651 AjaxBasedTransport.prototype.doCleanup = function() { 1652 var that = this; 1653 if (that.poll) { 1654 that.poll.abort(); 1655 that.poll = null; 1656 } 1657 }; 1658 1659 // xhr-streaming 1660 var XhrStreamingTransport = SockJS['xhr-streaming'] = function(ri, trans_url) { 1661 this.run(ri, trans_url, '/xhr_streaming', XhrReceiver, utils.XHRCorsObject); 1662 }; 1663 1664 XhrStreamingTransport.prototype = new AjaxBasedTransport(); 1665 1666 XhrStreamingTransport.enabled = function() { 1667 // Support for CORS Ajax aka Ajax2? Opera 12 claims CORS but 1668 // doesn't do streaming. 1669 return (_window.XMLHttpRequest && 1670 'withCredentials' in new XMLHttpRequest() && 1671 (!/opera/i.test(navigator.userAgent))); 1672 }; 1673 XhrStreamingTransport.roundTrips = 2; // preflight, ajax 1674 1675 // Safari gets confused when a streaming ajax request is started 1676 // before onload. This causes the load indicator to spin indefinetely. 1677 XhrStreamingTransport.need_body = true; 1678 1679 1680 // According to: 1681 // http://stackoverflow.com/questions/1641507/detect-browser-support-for-cross-domain-xmlhttprequests 1682 // http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/ 1683 1684 1685 // xdr-streaming 1686 var XdrStreamingTransport = SockJS['xdr-streaming'] = function(ri, trans_url) { 1687 this.run(ri, trans_url, '/xhr_streaming', XhrReceiver, utils.XDRObject); 1688 }; 1689 1690 XdrStreamingTransport.prototype = new AjaxBasedTransport(); 1691 1692 XdrStreamingTransport.enabled = function() { 1693 return !!_window.XDomainRequest; 1694 }; 1695 XdrStreamingTransport.roundTrips = 2; // preflight, ajax 1696 1697 1698 1699 // xhr-polling 1700 var XhrPollingTransport = SockJS['xhr-polling'] = function(ri, trans_url) { 1701 this.run(ri, trans_url, '/xhr', XhrReceiver, utils.XHRCorsObject); 1702 }; 1703 1704 XhrPollingTransport.prototype = new AjaxBasedTransport(); 1705 1706 XhrPollingTransport.enabled = XhrStreamingTransport.enabled; 1707 XhrPollingTransport.roundTrips = 2; // preflight, ajax 1708 1709 1710 // xdr-polling 1711 var XdrPollingTransport = SockJS['xdr-polling'] = function(ri, trans_url) { 1712 this.run(ri, trans_url, '/xhr', XhrReceiver, utils.XDRObject); 1713 }; 1714 1715 XdrPollingTransport.prototype = new AjaxBasedTransport(); 1716 1717 XdrPollingTransport.enabled = XdrStreamingTransport.enabled; 1718 XdrPollingTransport.roundTrips = 2; // preflight, ajax 1719 // [*] End of lib/trans-xhr.js 1720 1721 1722 // [*] Including lib/trans-iframe.js 1723 /* 1724 * ***** BEGIN LICENSE BLOCK ***** 1725 * Copyright (c) 2011-2012 VMware, Inc. 1726 * 1727 * For the license see COPYING. 1728 * ***** END LICENSE BLOCK ***** 1729 */ 1730 1731 // Few cool transports do work only for same-origin. In order to make 1732 // them working cross-domain we shall use iframe, served form the 1733 // remote domain. New browsers, have capabilities to communicate with 1734 // cross domain iframe, using postMessage(). In IE it was implemented 1735 // from IE 8+, but of course, IE got some details wrong: 1736 // http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx 1737 // http://stevesouders.com/misc/test-postmessage.php 1738 1739 var IframeTransport = function() {}; 1740 1741 IframeTransport.prototype.i_constructor = function(ri, trans_url, base_url) { 1742 var that = this; 1743 that.ri = ri; 1744 that.origin = utils.getOrigin(base_url); 1745 that.base_url = base_url; 1746 that.trans_url = trans_url; 1747 1748 var iframe_url = base_url + '/iframe.html'; 1749 if (that.ri._options.devel) { 1750 iframe_url += '?t=' + (+new Date); 1751 } 1752 that.window_id = utils.random_string(8); 1753 iframe_url += '#' + that.window_id; 1754 1755 that.iframeObj = utils.createIframe(iframe_url, function(r) { 1756 that.ri._didClose(1006, "Unable to load an iframe (" + r + ")"); 1757 }); 1758 1759 that.onmessage_cb = utils.bind(that.onmessage, that); 1760 utils.attachMessage(that.onmessage_cb); 1761 }; 1762 1763 IframeTransport.prototype.doCleanup = function() { 1764 var that = this; 1765 if (that.iframeObj) { 1766 utils.detachMessage(that.onmessage_cb); 1767 try { 1768 // When the iframe is not loaded, IE raises an exception 1769 // on 'contentWindow'. 1770 if (that.iframeObj.iframe.contentWindow) { 1771 that.postMessage('c'); 1772 } 1773 } catch (x) {} 1774 that.iframeObj.cleanup(); 1775 that.iframeObj = null; 1776 that.onmessage_cb = that.iframeObj = null; 1777 } 1778 }; 1779 1780 IframeTransport.prototype.onmessage = function(e) { 1781 var that = this; 1782 if (e.origin !== that.origin) return; 1783 var window_id = e.data.slice(0, 8); 1784 var type = e.data.slice(8, 9); 1785 var data = e.data.slice(9); 1786 1787 if (window_id !== that.window_id) return; 1788 1789 switch(type) { 1790 case 's': 1791 that.iframeObj.loaded(); 1792 that.postMessage('s', JSON.stringify([SockJS.version, that.protocol, that.trans_url, that.base_url])); 1793 break; 1794 case 't': 1795 that.ri._didMessage(data); 1796 break; 1797 } 1798 }; 1799 1800 IframeTransport.prototype.postMessage = function(type, data) { 1801 var that = this; 1802 that.iframeObj.post(that.window_id + type + (data || ''), that.origin); 1803 }; 1804 1805 IframeTransport.prototype.doSend = function (message) { 1806 this.postMessage('m', message); 1807 }; 1808 1809 IframeTransport.enabled = function() { 1810 // postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with 1811 // huge delay, or not at all. 1812 var konqueror = navigator && navigator.userAgent && navigator.userAgent.indexOf('Konqueror') !== -1; 1813 return ((typeof _window.postMessage === 'function' || 1814 typeof _window.postMessage === 'object') && (!konqueror)); 1815 }; 1816 // [*] End of lib/trans-iframe.js 1817 1818 1819 // [*] Including lib/trans-iframe-within.js 1820 /* 1821 * ***** BEGIN LICENSE BLOCK ***** 1822 * Copyright (c) 2011-2012 VMware, Inc. 1823 * 1824 * For the license see COPYING. 1825 * ***** END LICENSE BLOCK ***** 1826 */ 1827 1828 var curr_window_id; 1829 1830 var postMessage = function (type, data) { 1831 if(parent !== _window) { 1832 parent.postMessage(curr_window_id + type + (data || ''), '*'); 1833 } else { 1834 utils.log("Can't postMessage, no parent window.", type, data); 1835 } 1836 }; 1837 1838 var FacadeJS = function() {}; 1839 FacadeJS.prototype._didClose = function (code, reason) { 1840 postMessage('t', utils.closeFrame(code, reason)); 1841 }; 1842 FacadeJS.prototype._didMessage = function (frame) { 1843 postMessage('t', frame); 1844 }; 1845 FacadeJS.prototype._doSend = function (data) { 1846 this._transport.doSend(data); 1847 }; 1848 FacadeJS.prototype._doCleanup = function () { 1849 this._transport.doCleanup(); 1850 }; 1851 1852 utils.parent_origin = undefined; 1853 1854 SockJS.bootstrap_iframe = function() { 1855 var facade; 1856 curr_window_id = _document.location.hash.slice(1); 1857 var onMessage = function(e) { 1858 if(e.source !== parent) return; 1859 if(typeof utils.parent_origin === 'undefined') 1860 utils.parent_origin = e.origin; 1861 if (e.origin !== utils.parent_origin) return; 1862 1863 var window_id = e.data.slice(0, 8); 1864 var type = e.data.slice(8, 9); 1865 var data = e.data.slice(9); 1866 if (window_id !== curr_window_id) return; 1867 switch(type) { 1868 case 's': 1869 var p = JSON.parse(data); 1870 var version = p[0]; 1871 var protocol = p[1]; 1872 var trans_url = p[2]; 1873 var base_url = p[3]; 1874 if (version !== SockJS.version) { 1875 utils.log("Incompatibile SockJS! Main site uses:" + 1876 " \"" + version + "\", the iframe:" + 1877 " \"" + SockJS.version + "\"."); 1878 } 1879 if (!utils.flatUrl(trans_url) || !utils.flatUrl(base_url)) { 1880 utils.log("Only basic urls are supported in SockJS"); 1881 return; 1882 } 1883 1884 if (!utils.isSameOriginUrl(trans_url) || 1885 !utils.isSameOriginUrl(base_url)) { 1886 utils.log("Can't connect to different domain from within an " + 1887 "iframe. (" + JSON.stringify([_window.location.href, trans_url, base_url]) + 1888 ")"); 1889 return; 1890 } 1891 facade = new FacadeJS(); 1892 facade._transport = new FacadeJS[protocol](facade, trans_url, base_url); 1893 break; 1894 case 'm': 1895 facade._doSend(data); 1896 break; 1897 case 'c': 1898 if (facade) 1899 facade._doCleanup(); 1900 facade = null; 1901 break; 1902 } 1903 }; 1904 1905 // alert('test ticker'); 1906 // facade = new FacadeJS(); 1907 // facade._transport = new FacadeJS['w-iframe-xhr-polling'](facade, 'http://host.com:9999/ticker/12/basd'); 1908 1909 utils.attachMessage(onMessage); 1910 1911 // Start 1912 postMessage('s'); 1913 }; 1914 // [*] End of lib/trans-iframe-within.js 1915 1916 1917 // [*] Including lib/info.js 1918 /* 1919 * ***** BEGIN LICENSE BLOCK ***** 1920 * Copyright (c) 2011-2012 VMware, Inc. 1921 * 1922 * For the license see COPYING. 1923 * ***** END LICENSE BLOCK ***** 1924 */ 1925 1926 var InfoReceiver = function(base_url, AjaxObject) { 1927 var that = this; 1928 utils.delay(function(){that.doXhr(base_url, AjaxObject);}); 1929 }; 1930 1931 InfoReceiver.prototype = new EventEmitter(['finish']); 1932 1933 InfoReceiver.prototype.doXhr = function(base_url, AjaxObject) { 1934 var that = this; 1935 var t0 = (new Date()).getTime(); 1936 var xo = new AjaxObject('GET', base_url + '/info'); 1937 1938 var tref = utils.delay(8000, 1939 function(){xo.ontimeout();}); 1940 1941 xo.onfinish = function(status, text) { 1942 clearTimeout(tref); 1943 tref = null; 1944 if (status === 200) { 1945 var rtt = (new Date()).getTime() - t0; 1946 var info = JSON.parse(text); 1947 if (typeof info !== 'object') info = {}; 1948 that.emit('finish', info, rtt); 1949 } else { 1950 that.emit('finish'); 1951 } 1952 }; 1953 xo.ontimeout = function() { 1954 xo.close(); 1955 that.emit('finish'); 1956 }; 1957 }; 1958 1959 var InfoReceiverIframe = function(base_url) { 1960 var that = this; 1961 var go = function() { 1962 var ifr = new IframeTransport(); 1963 ifr.protocol = 'w-iframe-info-receiver'; 1964 var fun = function(r) { 1965 if (typeof r === 'string' && r.substr(0,1) === 'm') { 1966 var d = JSON.parse(r.substr(1)); 1967 var info = d[0], rtt = d[1]; 1968 that.emit('finish', info, rtt); 1969 } else { 1970 that.emit('finish'); 1971 } 1972 ifr.doCleanup(); 1973 ifr = null; 1974 }; 1975 var mock_ri = { 1976 _options: {}, 1977 _didClose: fun, 1978 _didMessage: fun 1979 }; 1980 ifr.i_constructor(mock_ri, base_url, base_url); 1981 } 1982 if(!_document.body) { 1983 utils.attachEvent('load', go); 1984 } else { 1985 go(); 1986 } 1987 }; 1988 InfoReceiverIframe.prototype = new EventEmitter(['finish']); 1989 1990 1991 var InfoReceiverFake = function() { 1992 // It may not be possible to do cross domain AJAX to get the info 1993 // data, for example for IE7. But we want to run JSONP, so let's 1994 // fake the response, with rtt=2s (rto=6s). 1995 var that = this; 1996 utils.delay(function() { 1997 that.emit('finish', {}, 2000); 1998 }); 1999 }; 2000 InfoReceiverFake.prototype = new EventEmitter(['finish']); 2001 2002 var createInfoReceiver = function(base_url) { 2003 if (utils.isSameOriginUrl(base_url)) { 2004 // If, for some reason, we have SockJS locally - there's no 2005 // need to start up the complex machinery. Just use ajax. 2006 return new InfoReceiver(base_url, utils.XHRLocalObject); 2007 } 2008 switch (utils.isXHRCorsCapable()) { 2009 case 1: 2010 // XHRLocalObject -> no_credentials=true 2011 return new InfoReceiver(base_url, utils.XHRLocalObject); 2012 case 2: 2013 return new InfoReceiver(base_url, utils.XDRObject); 2014 case 3: 2015 // Opera 2016 return new InfoReceiverIframe(base_url); 2017 default: 2018 // IE 7 2019 return new InfoReceiverFake(); 2020 }; 2021 }; 2022 2023 2024 var WInfoReceiverIframe = FacadeJS['w-iframe-info-receiver'] = function(ri, _trans_url, base_url) { 2025 var ir = new InfoReceiver(base_url, utils.XHRLocalObject); 2026 ir.onfinish = function(info, rtt) { 2027 ri._didMessage('m'+JSON.stringify([info, rtt])); 2028 ri._didClose(); 2029 } 2030 }; 2031 WInfoReceiverIframe.prototype.doCleanup = function() {}; 2032 // [*] End of lib/info.js 2033 2034 2035 // [*] Including lib/trans-iframe-eventsource.js 2036 /* 2037 * ***** BEGIN LICENSE BLOCK ***** 2038 * Copyright (c) 2011-2012 VMware, Inc. 2039 * 2040 * For the license see COPYING. 2041 * ***** END LICENSE BLOCK ***** 2042 */ 2043 2044 var EventSourceIframeTransport = SockJS['iframe-eventsource'] = function () { 2045 var that = this; 2046 that.protocol = 'w-iframe-eventsource'; 2047 that.i_constructor.apply(that, arguments); 2048 }; 2049 2050 EventSourceIframeTransport.prototype = new IframeTransport(); 2051 2052 EventSourceIframeTransport.enabled = function () { 2053 return ('EventSource' in _window) && IframeTransport.enabled(); 2054 }; 2055 2056 EventSourceIframeTransport.need_body = true; 2057 EventSourceIframeTransport.roundTrips = 3; // html, javascript, eventsource 2058 2059 2060 // w-iframe-eventsource 2061 var EventSourceTransport = FacadeJS['w-iframe-eventsource'] = function(ri, trans_url) { 2062 this.run(ri, trans_url, '/eventsource', EventSourceReceiver, utils.XHRLocalObject); 2063 } 2064 EventSourceTransport.prototype = new AjaxBasedTransport(); 2065 // [*] End of lib/trans-iframe-eventsource.js 2066 2067 2068 // [*] Including lib/trans-iframe-xhr-polling.js 2069 /* 2070 * ***** BEGIN LICENSE BLOCK ***** 2071 * Copyright (c) 2011-2012 VMware, Inc. 2072 * 2073 * For the license see COPYING. 2074 * ***** END LICENSE BLOCK ***** 2075 */ 2076 2077 var XhrPollingIframeTransport = SockJS['iframe-xhr-polling'] = function () { 2078 var that = this; 2079 that.protocol = 'w-iframe-xhr-polling'; 2080 that.i_constructor.apply(that, arguments); 2081 }; 2082 2083 XhrPollingIframeTransport.prototype = new IframeTransport(); 2084 2085 XhrPollingIframeTransport.enabled = function () { 2086 return _window.XMLHttpRequest && IframeTransport.enabled(); 2087 }; 2088 2089 XhrPollingIframeTransport.need_body = true; 2090 XhrPollingIframeTransport.roundTrips = 3; // html, javascript, xhr 2091 2092 2093 // w-iframe-xhr-polling 2094 var XhrPollingITransport = FacadeJS['w-iframe-xhr-polling'] = function(ri, trans_url) { 2095 this.run(ri, trans_url, '/xhr', XhrReceiver, utils.XHRLocalObject); 2096 }; 2097 2098 XhrPollingITransport.prototype = new AjaxBasedTransport(); 2099 // [*] End of lib/trans-iframe-xhr-polling.js 2100 2101 2102 // [*] Including lib/trans-iframe-htmlfile.js 2103 /* 2104 * ***** BEGIN LICENSE BLOCK ***** 2105 * Copyright (c) 2011-2012 VMware, Inc. 2106 * 2107 * For the license see COPYING. 2108 * ***** END LICENSE BLOCK ***** 2109 */ 2110 2111 // This transport generally works in any browser, but will cause a 2112 // spinning cursor to appear in any browser other than IE. 2113 // We may test this transport in all browsers - why not, but in 2114 // production it should be only run in IE. 2115 2116 var HtmlFileIframeTransport = SockJS['iframe-htmlfile'] = function () { 2117 var that = this; 2118 that.protocol = 'w-iframe-htmlfile'; 2119 that.i_constructor.apply(that, arguments); 2120 }; 2121 2122 // Inheritance. 2123 HtmlFileIframeTransport.prototype = new IframeTransport(); 2124 2125 HtmlFileIframeTransport.enabled = function() { 2126 return IframeTransport.enabled(); 2127 }; 2128 2129 HtmlFileIframeTransport.need_body = true; 2130 HtmlFileIframeTransport.roundTrips = 3; // html, javascript, htmlfile 2131 2132 2133 // w-iframe-htmlfile 2134 var HtmlFileTransport = FacadeJS['w-iframe-htmlfile'] = function(ri, trans_url) { 2135 this.run(ri, trans_url, '/htmlfile', HtmlfileReceiver, utils.XHRLocalObject); 2136 }; 2137 HtmlFileTransport.prototype = new AjaxBasedTransport(); 2138 // [*] End of lib/trans-iframe-htmlfile.js 2139 2140 2141 // [*] Including lib/trans-polling.js 2142 /* 2143 * ***** BEGIN LICENSE BLOCK ***** 2144 * Copyright (c) 2011-2012 VMware, Inc. 2145 * 2146 * For the license see COPYING. 2147 * ***** END LICENSE BLOCK ***** 2148 */ 2149 2150 var Polling = function(ri, Receiver, recv_url, AjaxObject) { 2151 var that = this; 2152 that.ri = ri; 2153 that.Receiver = Receiver; 2154 that.recv_url = recv_url; 2155 that.AjaxObject = AjaxObject; 2156 that._scheduleRecv(); 2157 }; 2158 2159 Polling.prototype._scheduleRecv = function() { 2160 var that = this; 2161 var poll = that.poll = new that.Receiver(that.recv_url, that.AjaxObject); 2162 var msg_counter = 0; 2163 poll.onmessage = function(e) { 2164 msg_counter += 1; 2165 that.ri._didMessage(e.data); 2166 }; 2167 poll.onclose = function(e) { 2168 that.poll = poll = poll.onmessage = poll.onclose = null; 2169 if (!that.poll_is_closing) { 2170 if (e.reason === 'permanent') { 2171 that.ri._didClose(1006, 'Polling error (' + e.reason + ')'); 2172 } else { 2173 that._scheduleRecv(); 2174 } 2175 } 2176 }; 2177 }; 2178 2179 Polling.prototype.abort = function() { 2180 var that = this; 2181 that.poll_is_closing = true; 2182 if (that.poll) { 2183 that.poll.abort(); 2184 } 2185 }; 2186 // [*] End of lib/trans-polling.js 2187 2188 2189 // [*] Including lib/trans-receiver-eventsource.js 2190 /* 2191 * ***** BEGIN LICENSE BLOCK ***** 2192 * Copyright (c) 2011-2012 VMware, Inc. 2193 * 2194 * For the license see COPYING. 2195 * ***** END LICENSE BLOCK ***** 2196 */ 2197 2198 var EventSourceReceiver = function(url) { 2199 var that = this; 2200 var es = new EventSource(url); 2201 es.onmessage = function(e) { 2202 that.dispatchEvent(new SimpleEvent('message', 2203 {'data': unescape(e.data)})); 2204 }; 2205 that.es_close = es.onerror = function(e, abort_reason) { 2206 // ES on reconnection has readyState = 0 or 1. 2207 // on network error it's CLOSED = 2 2208 var reason = abort_reason ? 'user' : 2209 (es.readyState !== 2 ? 'network' : 'permanent'); 2210 that.es_close = es.onmessage = es.onerror = null; 2211 // EventSource reconnects automatically. 2212 es.close(); 2213 es = null; 2214 // Safari and chrome < 15 crash if we close window before 2215 // waiting for ES cleanup. See: 2216 // https://code.google.com/p/chromium/issues/detail?id=89155 2217 utils.delay(200, function() { 2218 that.dispatchEvent(new SimpleEvent('close', {reason: reason})); 2219 }); 2220 }; 2221 }; 2222 2223 EventSourceReceiver.prototype = new REventTarget(); 2224 2225 EventSourceReceiver.prototype.abort = function() { 2226 var that = this; 2227 if (that.es_close) { 2228 that.es_close({}, true); 2229 } 2230 }; 2231 // [*] End of lib/trans-receiver-eventsource.js 2232 2233 2234 // [*] Including lib/trans-receiver-htmlfile.js 2235 /* 2236 * ***** BEGIN LICENSE BLOCK ***** 2237 * Copyright (c) 2011-2012 VMware, Inc. 2238 * 2239 * For the license see COPYING. 2240 * ***** END LICENSE BLOCK ***** 2241 */ 2242 2243 var _is_ie_htmlfile_capable; 2244 var isIeHtmlfileCapable = function() { 2245 if (_is_ie_htmlfile_capable === undefined) { 2246 if ('ActiveXObject' in _window) { 2247 try { 2248 _is_ie_htmlfile_capable = !!new ActiveXObject('htmlfile'); 2249 } catch (x) {} 2250 } else { 2251 _is_ie_htmlfile_capable = false; 2252 } 2253 } 2254 return _is_ie_htmlfile_capable; 2255 }; 2256 2257 2258 var HtmlfileReceiver = function(url) { 2259 var that = this; 2260 utils.polluteGlobalNamespace(); 2261 2262 that.id = 'a' + utils.random_string(6, 26); 2263 url += ((url.indexOf('?') === -1) ? '?' : '&') + 2264 'c=' + escape(WPrefix + '.' + that.id); 2265 2266 var constructor = isIeHtmlfileCapable() ? 2267 utils.createHtmlfile : utils.createIframe; 2268 2269 var iframeObj; 2270 _window[WPrefix][that.id] = { 2271 start: function () { 2272 iframeObj.loaded(); 2273 }, 2274 message: function (data) { 2275 that.dispatchEvent(new SimpleEvent('message', {'data': data})); 2276 }, 2277 stop: function () { 2278 that.iframe_close({}, 'network'); 2279 } 2280 }; 2281 that.iframe_close = function(e, abort_reason) { 2282 iframeObj.cleanup(); 2283 that.iframe_close = iframeObj = null; 2284 delete _window[WPrefix][that.id]; 2285 that.dispatchEvent(new SimpleEvent('close', {reason: abort_reason})); 2286 }; 2287 iframeObj = constructor(url, function(e) { 2288 that.iframe_close({}, 'permanent'); 2289 }); 2290 }; 2291 2292 HtmlfileReceiver.prototype = new REventTarget(); 2293 2294 HtmlfileReceiver.prototype.abort = function() { 2295 var that = this; 2296 if (that.iframe_close) { 2297 that.iframe_close({}, 'user'); 2298 } 2299 }; 2300 // [*] End of lib/trans-receiver-htmlfile.js 2301 2302 2303 // [*] Including lib/trans-receiver-xhr.js 2304 /* 2305 * ***** BEGIN LICENSE BLOCK ***** 2306 * Copyright (c) 2011-2012 VMware, Inc. 2307 * 2308 * For the license see COPYING. 2309 * ***** END LICENSE BLOCK ***** 2310 */ 2311 2312 var XhrReceiver = function(url, AjaxObject) { 2313 var that = this; 2314 var buf_pos = 0; 2315 2316 that.xo = new AjaxObject('POST', url, null); 2317 that.xo.onchunk = function(status, text) { 2318 if (status !== 200) return; 2319 while (1) { 2320 var buf = text.slice(buf_pos); 2321 var p = buf.indexOf('\n'); 2322 if (p === -1) break; 2323 buf_pos += p+1; 2324 var msg = buf.slice(0, p); 2325 that.dispatchEvent(new SimpleEvent('message', {data: msg})); 2326 } 2327 }; 2328 that.xo.onfinish = function(status, text) { 2329 that.xo.onchunk(status, text); 2330 that.xo = null; 2331 var reason = status === 200 ? 'network' : 'permanent'; 2332 that.dispatchEvent(new SimpleEvent('close', {reason: reason})); 2333 } 2334 }; 2335 2336 XhrReceiver.prototype = new REventTarget(); 2337 2338 XhrReceiver.prototype.abort = function() { 2339 var that = this; 2340 if (that.xo) { 2341 that.xo.close(); 2342 that.dispatchEvent(new SimpleEvent('close', {reason: 'user'})); 2343 that.xo = null; 2344 } 2345 }; 2346 // [*] End of lib/trans-receiver-xhr.js 2347 2348 2349 // [*] Including lib/test-hooks.js 2350 /* 2351 * ***** BEGIN LICENSE BLOCK ***** 2352 * Copyright (c) 2011-2012 VMware, Inc. 2353 * 2354 * For the license see COPYING. 2355 * ***** END LICENSE BLOCK ***** 2356 */ 2357 2358 // For testing 2359 SockJS.getUtils = function(){ 2360 return utils; 2361 }; 2362 2363 SockJS.getIframeTransport = function(){ 2364 return IframeTransport; 2365 }; 2366 // [*] End of lib/test-hooks.js 2367 2368 return SockJS; 2369 })(); 2370 if ('_sockjs_onload' in window) setTimeout(_sockjs_onload, 1); 2371 2372 // AMD compliance 2373 if (typeof define === 'function' && define.amd) { 2374 define('sockjs', [], function(){return SockJS;}); 2375 } 2376 // [*] End of lib/index.js 2377 2378 // [*] End of lib/all.js 2379