[Pkg-javascript-commits] [sockjs-client] 28/434: Heavy refactoring, open is now a protocol, not a transport thing. Close can be initiated only by the client.

Tonnerre Lombard tonnerre-guest at moszumanska.debian.org
Wed Jan 8 00:46:59 UTC 2014


This is an automated email from the git hooks/post-receive script.

tonnerre-guest pushed a commit to branch master
in repository sockjs-client.

commit 356aed0d949bb85f05700c8ccb70e39911178a77
Author: Marek Majkowski <majek04 at gmail.com>
Date:   Thu Jul 28 13:01:46 2011 +0100

    Heavy refactoring, open is now a protocol, not a transport thing. Close can be initiated only by the client.
---
 bin/minify.coffee               |   6 +-
 bin/render.coffee               |   2 +-
 lib/all.js                      |   3 +
 lib/sockjs.js                   | 171 +++++++++++++++++++++++-----------------
 lib/trans-iframe-eventsource.js |  16 ++--
 lib/trans-iframe-htmlfile.js    |   6 --
 lib/trans-iframe-within.js      |  13 +--
 lib/trans-iframe.js             |  27 +++----
 lib/trans-jsonp.js              | 117 ++++++++++++---------------
 lib/trans-websocket.js          |  23 +++---
 lib/utils.js                    |  45 ++++++++---
 tests-src/test-factory.coffee   |  26 ++++--
 12 files changed, 244 insertions(+), 211 deletions(-)

diff --git a/bin/minify.coffee b/bin/minify.coffee
index e5b1b1f..78da0e9 100644
--- a/bin/minify.coffee
+++ b/bin/minify.coffee
@@ -8,7 +8,7 @@ switches = [
     ['-p', '--pretty', 'Prettify javascript']
 ]
 
-minify_options = {}
+minify_options = {toplevel: true}
 parser = new optparse.OptionParser(switches)
 parser.on 'pretty', ->
                    minify_options.beautify = true
@@ -22,8 +22,8 @@ console.warn(" [.] Minifying:", filenames.join(', '))
 
 minify = (data, minify_options)->
     ast = uglify.parser.parse(data)
-    ast = uglify.uglify.ast_mangle(ast)
+    ast = uglify.uglify.ast_mangle(ast, minify_options)
     ast = uglify.uglify.ast_squeeze(ast)
     uglify.uglify.gen_code(ast, minify_options)
 
-process.stdout.write(minify(content.join('\n')))
+process.stdout.write(minify(content.join('\n'), minify_options))
diff --git a/bin/render.coffee b/bin/render.coffee
index 2bce25f..21ec25d 100644
--- a/bin/render.coffee
+++ b/bin/render.coffee
@@ -74,7 +74,7 @@ main = ->
         ['-p', '--pretty', 'Prettify javascript']
         ['-m', '--minify', 'Minify javascript']
     ]
-    options = {minify:false, toplevel:true}
+    options = {minify: false, toplevel: true}
     parser = new optparse.OptionParser(switches)
     parser.on 'pretty', ->
                    options.beautify = true
diff --git a/lib/all.js b/lib/all.js
index 8dcad34..e5d762e 100644
--- a/lib/all.js
+++ b/lib/all.js
@@ -1,4 +1,7 @@
 // SockJS client, version <!-- version -->, MIT License
 //     https://github.com/majek/sockjs-client
+
+// JSON2 by Douglas Crockford (minified).
 <!-- include lib/json2.min.js -->
+
 <!-- include_and_minify lib/main.js c -->
diff --git a/lib/sockjs.js b/lib/sockjs.js
index a95a164..de063ec 100644
--- a/lib/sockjs.js
+++ b/lib/sockjs.js
@@ -1,27 +1,27 @@
-// Public object.
 var SockJS = function(url, protocols, options) {
-    this._options = {devel: true, debug: true};
-    if (typeof options !== 'undefined') {
-        utils.objectExtend(this._options, options);
+    var that = this;
+    that._options = {devel: true, debug: true};
+    if (options) {
+        utils.objectExtend(that._options, options);
     }
-    this._base_url = url;
-    this._server = this._options.server || utils.random_number_string(1000);
-    this._connid = utils.random_string(8);
-    this._trans_url = this._base_url + '/' + this._server + '/' + this._connid;
-    this._protocols = ['websocket', 'iframe-eventsource', 'iframe-htmlfile', 'jsonp'];
+    that._base_url = url;
+    that._server = that._options.server || utils.random_number_string(1000);
+    that._connid = utils.random_string(8);
+    that._trans_url = that._base_url + '/' + that._server + '/' + that._connid;
+    that._protocols = ['websocket', 'iframe-eventsource', 'iframe-htmlfile', 'jsonp'];
     switch(typeof protocols) {
     case 'undefined': break;
-    case 'string': this._protocols = [protocols]; break;
-    default: this._protocols = protocols; break;
+    case 'string': that._protocols = [protocols]; break;
+    default: that._protocols = protocols; break;
     }
-    this.protocol = undefined;
-    this.readyState = SockJS.CONNECTING;
-    this._try_next_protocol();
+    that.protocol = null;
+    that.readyState = SockJS.CONNECTING;
+    that._try_next_protocol();
 };
 // Inheritance
 SockJS.prototype = new REventTarget();
 
-SockJS.version = "0.0.1";
+SockJS.version = "<!-- version -->";
 
 SockJS.CONNECTING = 0;
 SockJS.OPEN = 1;
@@ -29,89 +29,112 @@ SockJS.CLOSING = 2;
 SockJS.CLOSED = 3;
 
 SockJS.prototype._debug = function() {
-    if (this._options.debug && 'console' in _window && console.log) {
-        console.log.apply(console, arguments);
-    }
+    if (this._options.debug)
+        utils.log.apply(utils, arguments);
 };
 
-SockJS.prototype._didOpen = function() {
-    if (this.readyState !== SockJS.CONNECTING)
-            throw 'INVALID_STATE_ERR';
-    this.readyState = SockJS.OPEN;
-    this.dispatchEvent(new SimpleEvent("open"));
+SockJS.prototype._dispatchOpen = function() {
+    var that = this;
+    if (that.readyState !== SockJS.CONNECTING)
+            throw Error('INVALID_STATE_ERR');
+    that.readyState = SockJS.OPEN;
+    that.dispatchEvent(new SimpleEvent("open"));
+};
+
+SockJS.prototype._dispatchMessage = function(data) {
+    var that = this;
+    if (that.readyState !== SockJS.OPEN)
+            return;
+    that.dispatchEvent(new SimpleEvent("message", {data: data}));
 };
 
-SockJS.prototype._didClose = function(status, reason) {
-    if (this.readyState !== SockJS.CONNECTING &&
-        this.readyState !== SockJS.OPEN &&
-        this.readyState !== SockJS.CLOSING)
-            throw 'INVALID_STATE_ERR';
 
+SockJS.prototype._didClose = function(status, reason) {
+    var that = this;
+    if (that.readyState !== SockJS.CONNECTING &&
+        that.readyState !== SockJS.OPEN &&
+        that.readyState !== SockJS.CLOSING)
+            throw Error('INVALID_STATE_ERR');
+    that._transport.doCleanup();
+    that._transport = null;
     var close_event = new SimpleEvent("close", {status: status, reason: reason});
-    if (this.readyState === SockJS.CONNECTING) {
-        if (this._try_next_protocol(close_event) === false) {
-            this.readyState = SockJS.CLOSED;
-            var e = new SimpleEvent("close", {status: 2000,
-                                              reason: "All transports failed."});
-            this.dispatchEvent(e);
-        }
-    } else {
-        if (this.readyState === SockJS.CLOSING &&
-            status === 1001 && this._close_status) {
-            close_event = new SimpleEvent("close", {status: this._close_status,
-                                                    reason: this._close_reason});
-        }
-        this.readyState = SockJS.CLOSED;
-        this.dispatchEvent(close_event);
+
+    if (!utils.userSetStatus(status) && that.readyState === SockJS.CONNECTING) {
+        if (that._try_next_protocol(close_event))
+            return;
+        close_event = new SimpleEvent("close", {status: 2000,
+                                                reason: "All transports failed",
+                                                last_event: close_event});
     }
+    that.readyState = SockJS.CLOSE;
+
+    setTimeout(function() {
+                   that.dispatchEvent(close_event);
+               }, 0);
 };
 
 SockJS.prototype._didMessage = function(data) {
-    if (this.readyState !== SockJS.OPEN)
-            return;
-    this.dispatchEvent(new SimpleEvent("message", {data: data}));
+    var that = this;
+    var type = data.slice(0, 1);
+    var payload = JSON.parse(data.slice(1) || 'null');
+    switch(type) {
+    case 'o':
+        that._dispatchOpen();
+        break;
+    case 'a':
+        for(var i=0; i < payload.length; i++){
+            that._dispatchMessage(payload[i]);
+        }
+        break;
+    case 'm':
+        that._dispatchMessage(payload);
+        break;
+    case 'c':
+        that._didClose(payload[0], payload[1]);
+        break;
+    }
 };
 
 SockJS.prototype._try_next_protocol = function(close_event) {
-    if (this.protocol)
-        this._debug('Closed transport:', this.protocol, close_event);
-
-    if (this._transport) {
-        delete this._transport; this._transport = undefined;
-    }
+    var that = this;
+    if (that.protocol)
+        that._debug('Closed transport:', that.protocol, ''+close_event);
 
-    this.protocol = this._protocols.shift();
-    if (typeof this.protocol === 'undefined') {
-        return false;
-    }
-
-    this._debug('Opening transport:', this.protocol);
-    if (SockJS[this.protocol].enabled() === true) {
-        this._transport = new SockJS[this.protocol](this, this._trans_url, this._base_url);
-        return true;
+    while(1) {
+        that.protocol = that._protocols.shift();
+        if (!that.protocol) {
+            return false;
+        }
+        if (!SockJS[that.protocol].enabled()) {
+            that._debug('Skipping transport:', that.protocol);
+        } else {
+            that._debug('Opening transport:', that.protocol);
+            that._transport = new SockJS[that.protocol](that, that._trans_url,
+                                                        that._base_url);
+            return true;
+        }
     }
-    var e = new SimpleEvent("close", {status: 1000,
-                                      reason: "Transport unavailable"});
-    return this._try_next_protocol(e);
 };
 
 SockJS.prototype.close = function(status, reason) {
-    if(this.readyState !== SockJS.CONNECTING &&
-       this.readyState !== SockJS.OPEN) {
+    var that = this;
+    if (status && !utils.userSetStatus(status))
+        throw Error("INVALID_ACCESS_ERR");
+    if(that.readyState !== SockJS.CONNECTING &&
+       that.readyState !== SockJS.OPEN) {
         return false;
     }
-    this.readyState = SockJS.CLOSING;
-    this._close_status = status || 1000;
-    this._close_reason = reason || "Normal closure";
-    this._transport.doClose();
+    that.readyState = SockJS.CLOSING;
+    that._didClose(status || 1000, reason || "Normal closure");
     return true;
 };
 
 SockJS.prototype.send = function(data) {
-    if (this.readyState === SockJS.CONNECTING)
-            throw 'INVALID_STATE_ERR';
-    if (this.readyState === SockJS.OPEN) {
-        this._transport.doSend(data);
+    var that = this;
+    if (that.readyState === SockJS.CONNECTING)
+        throw Error('INVALID_STATE_ERR');
+    if (that.readyState === SockJS.OPEN) {
+        that._transport.doSend(data);
     }
     return true;
 };
diff --git a/lib/trans-iframe-eventsource.js b/lib/trans-iframe-eventsource.js
index bf5b782..359cad2 100644
--- a/lib/trans-iframe-eventsource.js
+++ b/lib/trans-iframe-eventsource.js
@@ -1,10 +1,12 @@
 var EventSourceIframeTransport = SockJS['iframe-eventsource'] = function () {
     var that = this;
     that.protocol = 'w-iframe-eventsource';
-    that.i_constructor.apply(this, arguments);
+    that.i_constructor.apply(that, arguments);
 };
+
 // Inheritance.
 EventSourceIframeTransport.prototype = new IframeTransport();
+
 EventSourceIframeTransport.enabled = function () {
     return (typeof EventSource === 'function') && IframeTransport.enabled();
 };
@@ -16,10 +18,9 @@ var EventSourceTransport = FacadeJS['w-iframe-eventsource'] = function (ri, tran
     that.trans_url = trans_url;
     var url = trans_url + '/eventsource';
     var es = that.es = new EventSource(url);
-    es.onopen = function(e){that.ri._didOpen();};
-    es.onmessage = function(e){that.ri._didMessage(unescape(e.data.slice(1)));};
-    es.onerror = function(e){
-        // EventSource reconnects automatically.
+    es.onmessage = function(e) {that.ri._didMessage(unescape(e.data));};
+    es.onerror = function(e) {
+        // EventSource reconnects automatically by default.
         that.cleanup();
         that.ri._didClose(1001, "Socket closed.");
     };
@@ -30,8 +31,9 @@ EventSourceTransport.prototype = new BufferedSender();
 
 EventSourceTransport.prototype.cleanup = function() {
     var that = this;
-    that.es.onopen = that.es.onmessage = that.es.onerror = null;
-    that.es.close();
+    var es = that.es;
+    es.onmessage = es.onerror = null;
+    es.close();
     that.es = null;
 };
 
diff --git a/lib/trans-iframe-htmlfile.js b/lib/trans-iframe-htmlfile.js
index 2348e9c..a1ef1be 100644
--- a/lib/trans-iframe-htmlfile.js
+++ b/lib/trans-iframe-htmlfile.js
@@ -25,13 +25,7 @@ var HtmlFileTransport = FacadeJS['w-iframe-htmlfile'] = function (ri, trans_url)
         // if (window.console)
         //     console.log('cb', e, t, typeof t);
         switch(t) {
-        case 'open':
-            // should get a proper messsage from now on.
-            that.iframeObj.loaded();
-            that.ri._didOpen();
-            break;
         case 'close':
-            that.cleanup();
             if (e) {
                 that.ri._didClose(e.status, e.reason);
             } else {
diff --git a/lib/trans-iframe-within.js b/lib/trans-iframe-within.js
index 0997b93..c0fce64 100644
--- a/lib/trans-iframe-within.js
+++ b/lib/trans-iframe-within.js
@@ -1,15 +1,12 @@
 var postMessage = function (type, messages) {
     var msg = JSON.stringify(messages);
-    if(parent !== window) {
+    if(parent !== _window) {
         parent.postMessage(type + msg, '*');
     }
 };
 
 var FacadeJS = function() {};
 FacadeJS.prototype._debug = function () {};
-FacadeJS.prototype._didOpen = function () {
-    postMessage('o', []);
-};
 FacadeJS.prototype._didClose = function (status, reason) {
     postMessage('c', [''+status, reason]);
 };
@@ -35,11 +32,9 @@ SockJS.bootstrap_iframe = function() {
             var protocol = messages[1];
             var trans_url = messages[2];
             if (version !== SockJS.version) {
-                if ('console' in _window && console.error) {
-                    console.error("Incompatibile SockJS! Main site uses:" +
-                                  " \"" + version + "\", the iframe:" +
-                                  " \"" + SockJS.version + "\".");
-                }
+                utils.log("Incompatibile SockJS! Main site uses:" +
+                          " \"" + version + "\", the iframe:" +
+                          " \"" + SockJS.version + "\".");
             }
             facade = new FacadeJS();
             facade._transport = new FacadeJS[protocol](facade, trans_url);
diff --git a/lib/trans-iframe.js b/lib/trans-iframe.js
index dfb7ea2..8ea1d41 100644
--- a/lib/trans-iframe.js
+++ b/lib/trans-iframe.js
@@ -14,26 +14,28 @@ IframeTransport.prototype.i_constructor = function(ri, trans_url, base_url) {
     that.origin = utils.getOrigin(base_url);
     that.trans_url = trans_url;
 
-    var iframe_url = base_url + '/iframe-' + SockJS.version + '.html';
+    var iframe_url = base_url + '/iframe.html';
     if (that.ri._options.devel) {
         iframe_url += '?t=' + (+new Date);
     }
 
-    that.iframeObj = utils.createIframe(iframe_url, function() {
-                                           that.cleanup();
-                                           that.ri._didClose(1001, "Can't load iframe");
-                                       });
+    that.iframeObj = utils.createIframe(iframe_url, function(r) {
+                                            that.ri._didClose(1006, "Unable to load an iframe (" + r + ")");
+                                        });
 
     that.onmessage_cb = function(e){that.onmessage(e);};
     utils.attachMessage(that.onmessage_cb);
 };
 
-IframeTransport.prototype.cleanup = function() {
+IframeTransport.prototype.doCleanup = function() {
     var that = this;
     if (that.iframeObj) {
-        that.iframeObj.cleanup();
         utils.detachMessage(that.onmessage_cb);
-        that.onmessage_cb  = that.iframeObj = undefined;
+        if (that.iframeObj.iframe.contentWindow){
+            that.postMessage('c', []);
+        }
+        that.iframeObj.cleanup();
+        that.onmessage_cb  = that.iframeObj = null;
     }
 };
 
@@ -41,20 +43,16 @@ IframeTransport.prototype.onmessage = function(e) {
     var that = this;
     if (e.origin !== that.origin) return;
     var type = e.data.slice(0, 1);
-    var msg = JSON.parse(e.data.slice(1));
+    var msg = JSON.parse(e.data.slice(1) || 'null');
     switch(type) {
     case 's':
         that.iframeObj.loaded();
         that.postMessage('s', [SockJS.version, that.protocol, that.trans_url]);
         break;
-    case 'o':
-        that.ri._didOpen();
-        break;
     case 'm':
         that.ri._didMessage(msg[0]);
         break;
     case 'c':
-        that.cleanup();
         that.ri._didClose(Number(msg[0]), msg[1]);
         break;
     }
@@ -69,9 +67,6 @@ IframeTransport.prototype.postMessage = function(type, messages) {
 IframeTransport.prototype.doSend = function (message) {
     this.postMessage('m', [message]);
 };
-IframeTransport.prototype.doClose = function () {
-    this.postMessage('c', []);
-};
 
 IframeTransport.enabled = function() {
     // postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
diff --git a/lib/trans-jsonp.js b/lib/trans-jsonp.js
index ce53c59..785d4c4 100644
--- a/lib/trans-jsonp.js
+++ b/lib/trans-jsonp.js
@@ -4,7 +4,7 @@
 // everywhere.
 // Known limitations:
 //   o you will get a spinning cursor
-//   o for Konqueror a dumb timer is needed to detect network error
+//   o for Konqueror a dumb timer is needed to detect errors
 
 
 var JsonPTransport = SockJS.jsonp = function(ri, trans_url){
@@ -21,30 +21,13 @@ JsonPTransport.prototype = new BufferedSender();
 
 JsonPTransport.prototype._schedule_recv = function() {
     var that = this;
-    var callback = function(e, t) {
-        that._recv_stop = undefined;
-        if (typeof t === 'undefined') {
-            // messages
-            for(var i=0; i < e.length; i++) {
-                that.ri._didMessage(e[i]);
-            }
-        } else {
-            switch (t) {
-            case 'open':
-                that.ri._didOpen();
-                break;
-            case 'heartbeat':
-                break;
-            case 'close':
-                if (e) {
-                    that.ri._didClose(e.status, e.reason);
-                } else {
-                    that.ri._didClose(1001, "Server closed connection");
-                }
-                break;
-            }
+    var callback = function(data) {
+        that._recv_stop = null;
+        if (!that._is_closing) {
+            that.ri._didMessage(data);
         }
-        if (t !== 'close' && !that._is_closing) {
+        // The message can be a close message, and change is_closing state.
+        if (!that._is_closing) {
             that._schedule_recv();
         }
     };
@@ -52,16 +35,16 @@ JsonPTransport.prototype._schedule_recv = function() {
                                            jsonPGenericReceiver, callback);
 };
 
-JsonPTransport.prototype.doClose = function(status, reason) {
-    this._is_closing = true;
-    if (this._recv_stop) {
-        this._recv_stop();
+JsonPTransport.prototype.doCleanup = function() {
+    var that = this;
+    that._is_closing = true;
+    if (that._recv_stop) {
+        that._recv_stop();
     }
-    if (this._send_stop) {
-        this._send_stop();
+    if (that._send_stop) {
+        that._send_stop();
     }
-    this._recv_stop = this._send_stop = undefined;
-    this.ri._didClose(1001, "User requested");
+    that.ri = that._recv_stop = that._send_stop = null;
 };
 
 JsonPTransport.enabled = function() {
@@ -69,19 +52,21 @@ JsonPTransport.enabled = function() {
 };
 
 
+// Abstract away code that handles global namespace pollution.
 var jsonPReceiverWrapper = function(url, constructReceiver, user_callback) {
     var id = 'a' + utils.random_string(6);
     var url_id = url + '?c=' + escape(WPrefix + '.' + id);
-    var callback = function(e, t) {
+    // Callback will be called exactly once.
+    var callback = function(frame) {
         delete _window[WPrefix][id];
-        user_callback(e, t);
+        user_callback(frame);
     };
 
     var close_script = constructReceiver(url_id, callback);
     _window[WPrefix][id] = close_script;
     var stop = function() {
         if (_window[WPrefix][id]) {
-            close_script({status:1000, reson:"Normal closure"}, 'stop');
+            _window[WPrefix][id](utils.closeFrame(1000, "JSONP user aborted read"));
         }
     };
     return stop;
@@ -92,45 +77,44 @@ var jsonPReceiverWrapper = function(url, constructReceiver, user_callback) {
 // and jQuery-JSONP:
 //    https://code.google.com/p/jquery-jsonp/source/browse/trunk/core/jquery.jsonp.js
 var jsonPGenericReceiver = function(url, callback) {
+    var tref;
     var script = _document.createElement('script');
-    var script2;
-    var close_script = function(v, t) {
-        setTimeout(function(){
-                       if (typeof script2 !== 'undefined') {
-                           script2.parentNode.removeChild(script2);
-                           script2 = undefined;
-                       }
-                       if (typeof script !== 'undefined') {
-                           callback(v, t);
-                           script.parentNode.removeChild(script);
-                           script.onreadystatechange = script.onerror = script.onload = script.onclick = null;
-                           delete script;
-                           script = callback = undefined;
-                       }
-                   }, 0);
+    var script2;  // Opera synchronous load trick.
+    var close_script = function(frame) {
+        if (script2) {
+            script2.parentNode.removeChild(script2);
+            script2 = null;
+        }
+        if (script) {
+            clearTimeout(tref);
+            script.parentNode.removeChild(script);
+            script.onreadystatechange = script.onerror =
+                script.onload = script.onclick = null;
+            script = null;
+            callback(frame);
+            callback = null;
+        }
     };
     script.id = 'a' + utils.random_string(8);
     script.src = url;
     script.type = 'text/javascript';
     script.charset = 'UTF-8';
-    script.onerror = function(e) {
-        close_script({status:1001, reason:"Onerror triggered on script"},
-                     'close');
+    script.onerror = function() {
+        close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (onerror)"));
     };
     script.onload = function(e) {
-        close_script({status:1001, reason:"Onload triggered on script"},
-                     'close');
+        close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (onload)"));
     };
     script.onreadystatechange = function(e) {
-        if (script.readyState == 'loaded' || script.readyState == 'complete') {
-            if (typeof script !== 'undefined' && script.htmlFor && script.onclick) {
+        if (/loaded|closed/.test(script.readyState)) {
+            if (script && script.htmlFor && script.onclick) {
                 try {
+                    // In IE, actually execute the script.
                     script.onclick();
                 } catch (x) {}
             }
-            if (typeof script !== 'undefined') {
-                close_script({status:1001, reason:"Onreadystatechange triggered on script"},
-                             'close');
+            if (script) {
+                close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (onreadystatechange)"));
             }
         }
     };
@@ -160,21 +144,18 @@ var jsonPGenericReceiver = function(url, callback) {
             script2 = _document.createElement('script');
             script2.text = "try{document.getElementById('"+script.id+"').onerror();}catch(x){};";
             script.async = script2.async = false;
-        } else {
-            // konqueror. fallback to a stupid timer, 5 seconds shall be plenty.
-            setTimeout(function(){
-                           if (script && script.onerror) {
-                               script.onerror();
-                           }
-                       }, 5000);
         }
     } else {
         script.async = true;
     }
+    // Fallback mostly for Konqueror - stupid timer, 5 seconds shall be plenty.
+    tref = setTimeout(function(){
+                          close_script(utils.closeFrame(1006, "JSONP script loaded abnormally (timeout)"));
+                      }, 5000);
 
     var head = _document.getElementsByTagName('head')[0];
     head.insertBefore(script, head.firstChild);
-    if (script2){
+    if (script2) {
         head.insertBefore(script2, head.firstChild);
     }
     return close_script;
diff --git a/lib/trans-websocket.js b/lib/trans-websocket.js
index a3fef09..d2ce5b5 100644
--- a/lib/trans-websocket.js
+++ b/lib/trans-websocket.js
@@ -8,13 +8,12 @@ var WebSocketTransport = SockJS.websocket = function(ri, trans_url) {
     }
     that.ri = ri;
     that.url = url;
-    var ws = that.ws = new WebSocket(that.url);
-    ws.onopen = function(e){that.ri._didOpen();};
-    ws.onmessage = function(e){that.ri._didMessage(e.data);};
-    ws.onclose = function(e){
-        ws.onopen = ws.onmessage = ws.onclose = null;
-        that.ws = undefined;
-        that.ri._didClose(1001, "Socket closed");
+    that.ws = new WebSocket(that.url);
+    that.ws.onmessage = function(e) {
+        that.ri._didMessage(e.data);
+    };
+    that.ws.onclose = function() {
+        that.ri._didClose(1006, "WebSocket connection broken");
     };
 };
 
@@ -22,8 +21,14 @@ WebSocketTransport.prototype.doSend = function(data) {
     this.ws.send(data);
 };
 
-WebSocketTransport.prototype.doClose = function() {
-    this.ws.close();
+WebSocketTransport.prototype.doCleanup = function() {
+    var that = this;
+    var ws = that.ws;
+    if (ws) {
+        ws.onmessage = ws.onclose = null;
+        ws.close();
+        that.ri = that.ws = null;
+    }
 };
 
 WebSocketTransport.enabled = function() {
diff --git a/lib/utils.js b/lib/utils.js
index 41ef971..d59da4a 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,11 +1,9 @@
 var utils = {};
 utils.random_string = function(letters, max) {
     var chars = 'abcdefghijklmnopqrstuvwxyz0123456789_';
-    if (typeof max === 'undefined') {
-        max = chars.length;
-    }
+    max = max || chars.length;
     var i, ret = [];
-    for(i=0; i<letters;i++) {
+    for(i=0; i < letters;i++) {
         ret.push( chars[Math.floor(Math.random() * max)] );
     }
     return ret.join('');
@@ -21,27 +19,34 @@ utils.random_number_string = function(max) {
 };
 
 utils.attachMessage = function(listener) {
+    utils.attachEvent('message', listener);
+};
+utils.attachEvent = function(event, listener) {
     if (typeof _window.addEventListener !== 'undefined') {
-        _window.addEventListener("message", listener, false);
+        _window.addEventListener(event, listener, false);
     } else {
         // IE quirks.
         // According to: http://stevesouders.com/misc/test-postmessage.php
         // the message gets delivered only to 'document', not 'window'.
-	    _document.attachEvent("onmessage", listener);
+	_document.attachEvent("on" + event, listener);
         // I get 'window' for ie8.
-	    _window.attachEvent("onmessage", listener);
+	_window.attachEvent("on" + event, listener);
     }
 };
 
 utils.detachMessage = function(listener) {
+    utils.detachEvent('message', listener);
+};
+utils.detachEvent = function(event, listener) {
     if (typeof _window.addEventListener !== 'undefined') {
-        _window.removeEventListener("message", listener, false);
+        _window.removeEventListener(event, listener, false);
     } else {
-        _document.detachEvent("onmessage", listener);
-	    _window.detachEvent("onmessage", listener);
+        _document.detachEvent("on" + event, listener);
+	_window.detachEvent("on" + event, listener);
     }
 };
 
+
 // Assuming that url looks like: http://asdasd:111/asd
 utils.getOrigin = function(url) {
     url += '/';
@@ -150,18 +155,32 @@ utils.createIframe = function (iframe_url, error_callback) {
     iframe.src = iframe_url;
     iframe.style.display = 'none';
     iframe.style.position = 'absolute';
-    iframe.onerror = onerror;
+    iframe.onerror = function(){onerror('onerror');};
     iframe.onload = function() {
         // `onload` is triggered before scripts on the iframe are
         // executed. Give it few seconds to actually load stuff.
         clearTimeout(tref);
-        tref = setTimeout(onerror, 2000);
+        tref = setTimeout(function(){onerror('onload timeout');}, 2000);
     };
     _document.body.appendChild(iframe);
-    tref = setTimeout(onerror, 5000);
+    tref = setTimeout(function(){onerror('timeout');}, 5000);
     return {
         iframe: iframe,
         cleanup: cleanup,
         loaded: unattach
     };
 };
+
+utils.closeFrame = function (status, reason) {
+    return 'c'+JSON.stringify([status, reason]);
+};
+
+utils.userSetStatus = function (status) {
+    return status === 1000 || (status >= 3000 && status <= 4999);
+};
+
+utils.log = function() {
+    if (_window.console && console.log) {
+        console.log.apply(console, arguments);
+    }
+};
diff --git a/tests-src/test-factory.coffee b/tests-src/test-factory.coffee
index 0aafc2b..a4a5dcb 100644
--- a/tests-src/test-factory.coffee
+++ b/tests-src/test-factory.coffee
@@ -115,23 +115,33 @@ factor_user_close = (protocol) ->
         expect(4)
         r = new SockJS(sockjs_url + '/echo', [protocol])
         ok(r)
+        counter = 0
         r.onopen = (e) ->
-            ok(true)
+            counter += 1
+            ok(counter is 1)
             r.close(3000, "User message")
+            ok(counter is 1)
+        r.onmessage = () ->
+            fail(true)
+            counter += 1
         r.onclose = (e) ->
-            equals(e.status, 3000)
-            equals(e.reason, "User message")
+            counter += 1
+            log('user_close ' + e.status + ' ' + e.reason)
+            ok(counter is 2)
             start()
 
 factor_server_close = (protocol) ->
     return ->
-        expect(3)
+        expect(4)
         r = new SockJS(sockjs_url + '/close', [protocol])
         ok(r)
         r.onopen = (e) ->
             ok(true)
+        r.onmessage = (e) ->
+            fail(true)
         r.onclose = (e) ->
-            equals(e.status, 1001)
+            equals(e.status, 3000)
+            equals(e.reason, "Go away!")
             start()
 
 test_invalid_url_404 = (protocol) ->
@@ -139,9 +149,13 @@ test_invalid_url_404 = (protocol) ->
         expect(2)
         r = new SockJS(sockjs_url + '/invalid_url', [protocol])
         ok(r)
+        counter =
         r.onopen = (e) ->
             fail(true)
+        r.onmessage = (e) ->
+            fail(true)
         r.onclose = (e) ->
+            log('404', e)
             equals(e.status, 2000)
             start()
 
@@ -153,6 +167,7 @@ test_invalid_url_500 = (protocol) ->
         r.onopen = (e) ->
             fail(true)
         r.onclose = (e) ->
+            log('500', e)
             equals(e.status, 2000)
             start()
 
@@ -164,5 +179,6 @@ test_invalid_url_port = (protocol) ->
         r.onopen = (e) ->
             fail(true)
         r.onclose = (e) ->
+            log('port', e)
             equals(e.status, 2000)
             start()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/sockjs-client.git



More information about the Pkg-javascript-commits mailing list