diff --git a/modules/javascript/pom.xml b/modules/javascript/pom.xml index cd47dd5a..2f5d0a20 100644 --- a/modules/javascript/pom.xml +++ b/modules/javascript/pom.xml @@ -3,14 +3,14 @@ org.atmosphere javascript-project - 2.0.5-SNAPSHOT + 2.0.11-SNAPSHOT ../../pom.xml 4.0.0 org.atmosphere.client javascript war - 2.0.5-SNAPSHOT + 2.0.11-SNAPSHOT javascript diff --git a/modules/javascript/src/main/webapp/javascript/atmosphere.js b/modules/javascript/src/main/webapp/javascript/atmosphere.js index eb1c51f9..4c29c969 100644 --- a/modules/javascript/src/main/webapp/javascript/atmosphere.js +++ b/modules/javascript/src/main/webapp/javascript/atmosphere.js @@ -28,7 +28,7 @@ "use strict"; - var version = "2.0.5-javascript", + var version = "2.0.10-javascript", atmosphere = {}, guid, requests = [], @@ -279,6 +279,8 @@ // Wait to be sure we have the full message before closing. if (_response.partialMessage === "" && (rq.transport === 'streaming') && (ajaxRequest.responseText.length > rq.maxStreamingLength)) { _response.messages = []; + rq.reconnectingOnLength = true; + rq.isReopen = true; _invokeClose(true); _disconnect(); _clearState(); @@ -305,9 +307,8 @@ var url = _request.url.replace(/([?&])_=[^&]*/, query); url = url + (url === _request.url ? (/\?/.test(_request.url) ? "&" : "?") + query : ""); - var rq = { - connected: false, + connected: false }; var closeR = new atmosphere.AtmosphereRequest(rq); closeR.attachHeadersAsQueryString = false; @@ -315,6 +316,7 @@ closeR.url = url; closeR.contentType = "text/plain"; closeR.transport = 'polling'; + closeR.async = false; _pushOnClose("", closeR); } } @@ -325,6 +327,10 @@ * @private */ function _close() { + if (_request.reconnectId) { + clearTimeout(_request.reconnectId); + delete _request.reconnectId; + } _request.reconnect = false; _abordingConnection = true; _response.request = _request; @@ -356,7 +362,7 @@ _activeRequest = null; } if (_websocket != null) { - if (_websocket.webSocketOpened) { + if (_websocket.canSendMessage) { _websocket.close(); } _websocket = null; @@ -917,7 +923,21 @@ }; script.onerror = function () { script.clean(); - _onError(0, "maxReconnectOnClose reached"); + rq.lastIndex = 0; + + if (rq.openId) { + clearTimeout(rq.openId); + } + + if (rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { + _open('re-connecting', rq.transport, rq); + _reconnect(_jqxhr, rq, request.reconnectInterval); + rq.openId = setTimeout(function() { + _triggerOpen(rq); + }, rq.reconnectInterval + 1000); + } else { + _onError(0, "maxReconnectOnClose reached"); + } }; head.insertBefore(script, head.firstChild); @@ -1019,7 +1039,7 @@ _response.transport = "sse"; - var location = _buildSSEUrl(_request.url); + var location = _buildSSEUrl(); if (_request.logLevel === 'debug') { atmosphere.util.debug("Invoking executeSSE"); @@ -1068,7 +1088,11 @@ } else { _open('re-opening', "sse", _request); } + } else if (_request.isReopen) { + _request.isReopen = false; + _open('re-opening', _request.transport, _request); } + sseOpened = true; if (_request.method === 'POST') { @@ -1093,10 +1117,10 @@ // https://github.com/remy/polyfills/blob/master/EventSource.js // Since we polling. - if (_sse.URL) { + /* if (_sse.URL) { _sse.interval = 100; - _sse.URL = _buildSSEUrl(_request.url); - } + _sse.URL = _buildSSEUrl(); + } */ if (!skipCallbackInvocation) { _invokeCallback(); @@ -1121,7 +1145,7 @@ if (_requestCount++ < _request.maxReconnectOnClose) { _open('re-connecting', _request.transport, _request); if (_request.reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _executeSSE(true); }, _request.reconnectInterval); } else { @@ -1197,18 +1221,22 @@ atmosphere.util.debug("Websocket successfully opened"); } + var reopening = webSocketOpened; + + if(_websocket != null) { + _websocket.canSendMessage = true; + } + if (!_request.enableProtocol) { - if (!webSocketOpened) { - _open('opening', "websocket", _request); - } else { + webSocketOpened = true; + if (reopening) { _open('re-opening', "websocket", _request); + } else { + _open('opening', "websocket", _request); } } - webSocketOpened = true; if (_websocket != null) { - _websocket.webSocketOpened = webSocketOpened; - if (_request.method === 'POST') { _response.state = "messageReceived"; _websocket.send(_request.data); @@ -1219,6 +1247,12 @@ _websocket.onmessage = function (message) { _timeout(_request); + // We only consider it opened if we get the handshake data + // https://github.com/Atmosphere/atmosphere-javascript/issues/74 + if (_request.enableProtocol) { + webSocketOpened = true; + } + _response.state = 'messageReceived'; _response.status = 200; @@ -1302,7 +1336,7 @@ if (_requestCount++ < _request.maxReconnectOnClose) { _open('re-connecting', _request.transport, _request); if (_request.reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _response.responseBody = ""; _response.messages = []; _executeWebSocket(true); @@ -1332,8 +1366,12 @@ } function _handleProtocol(request, message) { + // The first messages is always the uuid. var b = true; + + if (request.transport === 'polling') return b; + if (atmosphere.util.trim(message).length !== 0 && request.enableProtocol && request.firstMessage) { request.firstMessage = false; var messages = message.split(request.messageDelimiter); @@ -1393,7 +1431,7 @@ * @param response */ function _trackMessageSize(message, request, response) { - if (!_handleProtocol(_request, message)) + if (!_handleProtocol(request, message)) return true; if (message.length === 0) return true; @@ -1462,7 +1500,7 @@ _response.transport = _request.fallbackTransport; _request.fallbackTransport = 'none'; if (reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _execute(); }, reconnectInterval); } else { @@ -1590,6 +1628,13 @@ } }; + var disconnected = function () { + // Prevent onerror callback to be called + _response.errorHandled = true; + _clearState(); + reconnectF(); + }; + if (rq.force || (rq.reconnect && (rq.maxRequest === -1 || rq.requestCount++ < rq.maxRequest))) { rq.force = false; @@ -1620,8 +1665,8 @@ if (!_response.status) { _response.status = 500; } - _clearState(); if (!_response.errorHandled) { + _clearState(); reconnectF(); } }; @@ -1637,6 +1682,9 @@ var update = false; if (rq.transport === 'streaming' && rq.readyState > 2 && ajaxRequest.readyState === 4) { + if (rq.reconnectingOnLength) { + return; + } _clearState(); reconnectF(); return; @@ -1652,34 +1700,35 @@ _timeout(_request); if (rq.transport !== 'polling') { - if ((!rq.enableProtocol || !request.firstMessage) && ajaxRequest.readyState === 2) { - _triggerOpen(rq); - } - // MSIE 9 and lower status can be higher than 1000, Chrome can be 0 var status = 200; - if (ajaxRequest.readyState > 1) { + if (ajaxRequest.readyState === 4) { status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; } if (status >= 300 || status === 0) { - // Prevent onerror callback to be called - _response.errorHandled = true; - _clearState(); - reconnectF(); + disconnected(); return; } + + // Firefox incorrectly send statechange 0->2 when a reconnect attempt fails. The above checks ensure that onopen is not called for these + if ((!rq.enableProtocol || !request.firstMessage) && ajaxRequest.readyState === 2) { + _triggerOpen(rq); + } + } else if (ajaxRequest.readyState === 4) { update = true; } if (update) { var responseText = ajaxRequest.responseText; + _response.errorHandled = false; + // IE behave the same way when resuming long-polling or when the server goes down. if (atmosphere.util.trim(responseText).length === 0 && rq.transport === 'long-polling') { // For browser that aren't support onabort if (!ajaxRequest.hasData) { - reconnectF(); + disconnected(); } else { ajaxRequest.hasData = false; } @@ -1769,6 +1818,7 @@ _subscribed = true; } catch (e) { atmosphere.util.log(rq.logLevel, ["Unable to connect to " + rq.url]); + _onError(0, e); } } else { @@ -1843,15 +1893,21 @@ function _reconnect(ajaxRequest, request, reconnectInterval) { if (request.reconnect || (request.suspend && _subscribed)) { var status = 0; - if (ajaxRequest && ajaxRequest.readyState !== 0) { + if (ajaxRequest && ajaxRequest.readyState > 1) { status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; } _response.status = status === 0 ? 204 : status; _response.reason = status === 0 ? "Server resumed the connection or down." : "OK"; clearTimeout(request.id); + if (request.reconnectId) { + clearTimeout(request.reconnectId); + delete request.reconnectId; + } + if (reconnectInterval > 0) { - request.id = setTimeout(function () { + // For whatever reason, never cancel a reconnect timeout as it is mandatory to reconnect. + _request.reconnectId = setTimeout(function () { _executeRequest(request); }, reconnectInterval); } else { @@ -1916,7 +1972,7 @@ _clearState(); if (_requestCount++ < rq.maxReconnectOnClose) { if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _open('re-connecting', request.transport, request); _ieXDR(rq); }, rq.reconnectInterval); @@ -2103,7 +2159,7 @@ _invokeClose(true); _open('re-connecting', rq.transport, rq); if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _ieStreaming(rq); }, rq.reconnectInterval); } else { @@ -2119,7 +2175,7 @@ _open('re-connecting', rq.transport, rq); if (_requestCount++ < rq.maxReconnectOnClose) { if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _ieStreaming(rq); }, rq.reconnectInterval); } else { @@ -2182,6 +2238,7 @@ rq.reconnect = false; rq.force = true; rq.suspend = false; + rq.timeout = 1000; _executeRequest(rq); } @@ -2302,7 +2359,7 @@ * */ function _pushWebSocket(message) { - var msg = _getStringMessage(message); + var msg = atmosphere.util.isBinary(message) ? message : _getStringMessage(message); var data; try { if (_request.dispatchUrl != null) { @@ -2311,7 +2368,7 @@ data = msg; } - if (!_websocket.webSocketOpened) { + if (!_websocket.canSendMessage) { atmosphere.util.error("WebSocket not connected."); return; } @@ -2350,33 +2407,35 @@ } function _readHeaders(xdr, request) { - if (!request.readResponsesHeaders && !request.enableProtocol) { - request.lastTimestamp = atmosphere.util.now(); - request.uuid = guid; - return; - } - - try { - var tempDate = xdr.getResponseHeader('X-Cache-Date'); - if (tempDate && tempDate != null && tempDate.length > 0) { - request.lastTimestamp = tempDate.split(" ").pop(); + if (!request.readResponsesHeaders) { + if (!request.enableProtocol) { + request.lastTimestamp = atmosphere.util.now(); + request.uuid = guid; } + } + else { + try { + var tempDate = xdr.getResponseHeader('X-Cache-Date'); + if (tempDate && tempDate != null && tempDate.length > 0) { + request.lastTimestamp = tempDate.split(" ").pop(); + } - var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id'); - if (tempUUID && tempUUID != null) { - request.uuid = tempUUID.split(" ").pop(); - } + var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id'); + if (tempUUID && tempUUID != null) { + request.uuid = tempUUID.split(" ").pop(); + } - // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735 - if (request.headers) { - atmosphere.util.each(_request.headers, function (name) { - var v = xdr.getResponseHeader(name); - if (v) { - _response.headers[name] = v; - } - }); + // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735 + if (request.headers) { + atmosphere.util.each(_request.headers, function (name) { + var v = xdr.getResponseHeader(name); + if (v) { + _response.headers[name] = v; + } + }); + } + } catch (e) { } - } catch (e) { } } @@ -2398,6 +2457,7 @@ f.onError(response); break; case "opening": + delete _request.closed; if (typeof (f.onOpen) !== 'undefined') f.onOpen(response); break; @@ -2414,6 +2474,7 @@ f.onClientTimeout(_request); break; case "re-opening": + delete _request.closed; if (typeof (f.onReopen) !== 'undefined') f.onReopen(_request, response); break; @@ -2649,8 +2710,8 @@ }, isBinary: function (data) { - var string = Object.prototype.toString.call(data); - return string === "[object Blob]" || string === "[object ArrayBuffer]"; + // True if data is an instance of Blob, ArrayBuffer or ArrayBufferView + return /^\[object\s(?:Blob|ArrayBuffer|.+Array)\]$/.test(Object.prototype.toString.call(data)); }, isFunction: function (fn) { @@ -2982,9 +3043,13 @@ }); // Pressing ESC key in Firefox kills the connection + // for your information, this is fixed in Firefox 20 + // https://bugzilla.mozilla.org/show_bug.cgi?id=614304 atmosphere.util.on(window, "keypress", function (event) { - if (event.which === 27) { - event.preventDefault(); + if (event.charCode === 27 || event.keyCode === 27) { + if (event.preventDefault) { + event.preventDefault(); + } } }); diff --git a/modules/jquery/pom.xml b/modules/jquery/pom.xml index ed8bd1f1..7e6d6351 100755 --- a/modules/jquery/pom.xml +++ b/modules/jquery/pom.xml @@ -3,14 +3,14 @@ org.atmosphere javascript-project - 2.0.5-SNAPSHOT + 2.0.11-SNAPSHOT ../../pom.xml 4.0.0 org.atmosphere.client jquery war - 2.0.5-SNAPSHOT + 2.0.11-SNAPSHOT jquery diff --git a/modules/jquery/src/main/webapp/jquery/jquery.atmosphere.js b/modules/jquery/src/main/webapp/jquery/jquery.atmosphere.js index a1f7a752..77297444 100644 --- a/modules/jquery/src/main/webapp/jquery/jquery.atmosphere.js +++ b/modules/jquery/src/main/webapp/jquery/jquery.atmosphere.js @@ -54,7 +54,7 @@ jQuery.atmosphere = function () { }; return { - version: "2.0.5-jquery", + version: "2.0.10-jquery", uuid : 0, requests: [], callbacks: [], @@ -787,8 +787,17 @@ jQuery.atmosphere = function () { dataType: "jsonp", error: function (jqXHR, textStatus, errorThrown) { _response.error = true; - if (jqXHR.status < 300) { - _reconnect(_jqxhr, rq, 0); + + if (rq.openId) { + clearTimeout(rq.openId); + } + + if (rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { + _open('re-connecting', rq.transport, rq); + _reconnect(_jqxhr, rq, rq.reconnectInterval); + rq.openId = setTimeout(function() { + _triggerOpen(rq); + }, rq.reconnectInterval + 1000); } else { _onError(jqXHR.status, errorThrown); } @@ -1001,6 +1010,9 @@ jQuery.atmosphere = function () { } else { _open('re-opening', "sse", _request); } + } else if (_request.isReopen) { + _request.isReopen = false; + _open('re-opening', _request.transport, _request); } sseOpened = true; @@ -1045,7 +1057,7 @@ jQuery.atmosphere = function () { if (_requestCount++ < _request.maxReconnectOnClose) { _open('re-connecting', _request.transport, _request); if (_request.reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _executeSSE(true); }, _request.reconnectInterval); } else { @@ -1120,18 +1132,22 @@ jQuery.atmosphere = function () { jQuery.atmosphere.debug("Websocket successfully opened"); } + var reopening = webSocketOpened; + + if(_websocket != null) { + _websocket.canSendMessage = true; + } + if (!_request.enableProtocol) { - if (!webSocketOpened) { - _open('opening', "websocket", _request); - } else { + webSocketOpened = true; + if (reopening) { _open('re-opening', "websocket", _request); + } else { + _open('opening', "websocket", _request); } } - webSocketOpened = true; if (_websocket != null) { - _websocket.webSocketOpened = webSocketOpened; - if (_request.method === 'POST') { _response.state = "messageReceived"; _websocket.send(_request.data); @@ -1142,6 +1158,12 @@ jQuery.atmosphere = function () { _websocket.onmessage = function (message) { _timeout(_request); + // We only consider it opened if we get the handshake data + // https://github.com/Atmosphere/atmosphere-javascript/issues/74 + if (_request.enableProtocol) { + webSocketOpened = true; + } + _response.state = 'messageReceived'; _response.status = 200; @@ -1225,7 +1247,7 @@ jQuery.atmosphere = function () { if (_requestCount++ < _request.maxReconnectOnClose) { _open('re-connecting', _request.transport, _request); if (_request.reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _response.responseBody = ""; _response.messages = []; _executeWebSocket(true); @@ -1257,6 +1279,9 @@ jQuery.atmosphere = function () { function _handleProtocol(request, message) { // The first messages is always the uuid. var b = true; + + if (request.transport === 'polling') return b; + if (jQuery.trim(message).length !== 0 && request.enableProtocol && request.firstMessage) { request.firstMessage = false; var messages = message.split(request.messageDelimiter); @@ -1317,7 +1342,7 @@ jQuery.atmosphere = function () { * @param response */ function _trackMessageSize(message, request, response) { - if (!_handleProtocol(_request, message)) + if (!_handleProtocol(request, message)) return true; if (message.length === 0) return true; @@ -1386,7 +1411,7 @@ jQuery.atmosphere = function () { _response.transport = _request.fallbackTransport; _request.fallbackTransport = 'none'; if (reconnectInterval > 0) { - _request.id = setTimeout(function () { + _request.reconnectId = setTimeout(function () { _execute(); }, reconnectInterval); } else { @@ -1519,6 +1544,13 @@ jQuery.atmosphere = function () { } }; + var disconnected = function () { + // Prevent onerror callback to be called + _response.errorHandled = true; + _clearState(); + reconnectF(); + }; + if (rq.reconnect && (rq.maxRequest === -1 || rq.requestCount++ < rq.maxRequest)) { var ajaxRequest = jQuery.ajaxSettings.xhr(); ajaxRequest.hasData = false; @@ -1547,8 +1579,8 @@ jQuery.atmosphere = function () { if (!_response.status) { _response.status = 500; } - _clearState(); if (!_response.errorHandled) { + _clearState(); reconnectF(); } }; @@ -1564,6 +1596,9 @@ jQuery.atmosphere = function () { var update = false; if (rq.transport === 'streaming' && rq.readyState > 2 && ajaxRequest.readyState === 4) { + if (rq.reconnectingOnLength) { + return; + } _clearState(); reconnectF(); return; @@ -1579,33 +1614,33 @@ jQuery.atmosphere = function () { _timeout(_request); if (rq.transport !== 'polling') { - if ((!rq.enableProtocol || !request.firstMessage) && ajaxRequest.readyState === 2) { - _triggerOpen(rq); - } // MSIE 9 and lower status can be higher than 1000, Chrome can be 0 var status = 200; - if (ajaxRequest.readyState > 1) { + if (ajaxRequest.readyState === 4) { status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; } if (status >= 300 || status === 0) { - // Prevent onerror callback to be called - _response.errorHandled = true; - _clearState(); - reconnectF(); + disconnected(); return; } + + // Firefox incorrectly send statechange 0->2 when a reconnect attempt fails. The above checks ensure that onopen is not called for these + if ((!rq.enableProtocol || !request.firstMessage) && ajaxRequest.readyState === 2) { + _triggerOpen(rq); + } } else if (ajaxRequest.readyState === 4) { update = true; } if (update) { var responseText = ajaxRequest.responseText; + _response.errorHandled = false; if (jQuery.trim(responseText.length).length === 0 && rq.transport === 'long-polling') { // For browser that aren't support onabort if (!ajaxRequest.hasData) { - reconnectF(); + disconnected(); } else { ajaxRequest.hasData = false; } @@ -1764,17 +1799,22 @@ jQuery.atmosphere = function () { function _reconnect(ajaxRequest, request, reconnectInterval) { if (request.reconnect || (request.suspend && _subscribed)) { var status = 0; - if (ajaxRequest.readyState !== 0) { + if (ajaxRequest.readyState > 1) { status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; } _response.status = status === 0 ? 204 : status; _response.reason = status === 0 ? "Server resumed the connection or down." : "OK"; - // Reconnect immedialtely + // Reconnect immediately clearTimeout(request.id); + if (request.reconnectId) { + clearTimeout(request.reconnectId); + delete request.reconnectId; + } + if (reconnectInterval > 0) { - request.id = setTimeout(function () { - _executeRequest(request); + setTimeout(function () { + _request.reconnectId = _executeRequest(request); }, reconnectInterval); } else { _executeRequest(request); @@ -1839,7 +1879,7 @@ jQuery.atmosphere = function () { _clearState(); if (_requestCount++ < rq.maxReconnectOnClose) { if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _open('re-connecting', request.transport, request); _ieXDR(rq); }, rq.reconnectInterval); @@ -2036,7 +2076,7 @@ jQuery.atmosphere = function () { _invokeClose(true); _open('re-connecting', rq.transport, rq); if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _ieStreaming(rq); }, rq.reconnectInterval); } else { @@ -2052,7 +2092,7 @@ jQuery.atmosphere = function () { _open('re-connecting', rq.transport, rq); if (_requestCount++ < rq.maxReconnectOnClose) { if (rq.reconnectInterval > 0) { - rq.id = setTimeout(function () { + rq.reconnectId = setTimeout(function () { _ieStreaming(rq); }, rq.reconnectInterval); } else { @@ -2229,7 +2269,7 @@ jQuery.atmosphere = function () { * */ function _pushWebSocket(message) { - var msg = _getStringMessage(message); + var msg = jQuery.atmosphere.isBinary(message) ? message : _getStringMessage(message); var data; try { if (_request.dispatchUrl != null) { @@ -2238,7 +2278,7 @@ jQuery.atmosphere = function () { data = msg; } - if (!_websocket.webSocketOpened) { + if (!_websocket.canSendMessage) { jQuery.atmosphere.error("WebSocket not connected."); return; } @@ -2250,7 +2290,7 @@ jQuery.atmosphere = function () { }; _clearState(); - _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending " + data); + _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending " + message); _pushAjaxMessage(message); } } @@ -2277,33 +2317,35 @@ jQuery.atmosphere = function () { } function _readHeaders(xdr, request) { - if (!request.readResponsesHeaders && !request.enableProtocol) { - request.lastTimestamp = jQuery.now(); - request.uuid = jQuery.atmosphere.guid(); - return; - } - - try { - var tempDate = xdr.getResponseHeader('X-Cache-Date'); - if (tempDate && tempDate != null && tempDate.length > 0) { - request.lastTimestamp = tempDate.split(" ").pop(); + if (!request.readResponsesHeaders) { + if (!request.enableProtocol) { + request.lastTimestamp = jQuery.now(); + request.uuid = jQuery.atmosphere.guid(); } + } + else { + try { + var tempDate = xdr.getResponseHeader('X-Cache-Date'); + if (tempDate && tempDate != null && tempDate.length > 0) { + request.lastTimestamp = tempDate.split(" ").pop(); + } - var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id'); - if (tempUUID && tempUUID != null) { - request.uuid = tempUUID.split(" ").pop(); - } + var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id'); + if (tempUUID && tempUUID != null) { + request.uuid = tempUUID.split(" ").pop(); + } - // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735 - if (request.headers) { - jQuery.each(_request.headers, function (name) { - var v = xdr.getResponseHeader(name); - if (v) { - _response.headers[name] = v; - } - }); + // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735 + if (request.headers) { + jQuery.each(_request.headers, function (name) { + var v = xdr.getResponseHeader(name); + if (v) { + _response.headers[name] = v; + } + }); + } + } catch (e) { } - } catch (e) { } } @@ -2325,6 +2367,7 @@ jQuery.atmosphere = function () { f.onError(response); break; case "opening": + delete _request.closed; if (typeof (f.onOpen) !== 'undefined') f.onOpen(response); break; @@ -2341,6 +2384,7 @@ jQuery.atmosphere = function () { f.onClientTimeout(_request); break; case "re-opening": + delete _request.closed; if (typeof (f.onReopen) !== 'undefined') f.onReopen(_request, response); break; @@ -2439,6 +2483,8 @@ jQuery.atmosphere = function () { // Wait to be sure we have the full message before closing. if (_response.partialMessage === "" && (rq.transport === 'streaming') && (ajaxRequest.responseText.length > rq.maxStreamingLength)) { _response.messages = []; + rq.reconnectingOnLength = true; + rq.isReopen = true; _invokeClose(true); _disconnect(); _clearState(); @@ -2469,12 +2515,14 @@ jQuery.atmosphere = function () { jQuery.ajax({ url: url, async: false, - timeout: _request.connectTimeout + timeout: _request.connectTimeout, + cache: false }); } else { jQuery.ajax({ url: url, - async: false + async: false, + cache: false }); } } @@ -2486,6 +2534,10 @@ jQuery.atmosphere = function () { * @private */ function _close() { + if (_request.reconnectId) { + clearTimeout(_request.reconnectId); + delete _request.reconnectId; + } _request.reconnect = false; _abordingConnection = true; _response.request = _request; @@ -2499,6 +2551,7 @@ jQuery.atmosphere = function () { } function _clearState() { + _response.partialMessage = ""; if (_request.id) { clearTimeout(_request.id); } @@ -2516,7 +2569,7 @@ jQuery.atmosphere = function () { _activeRequest = null; } if (_websocket != null) { - if (_websocket.webSocketOpened) { + if (_websocket.canSendMessage) { _websocket.close(); } _websocket = null; @@ -2783,6 +2836,12 @@ jQuery.atmosphere = function () { error: function () { jQuery.atmosphere.log('error', arguments); + }, + + // TODO extract to utils or something + isBinary: function (data) { + // True if data is an instance of Blob, ArrayBuffer or ArrayBufferView + return /^\[object\s(?:Blob|ArrayBuffer|.+Array)\]$/.test(Object.prototype.toString.call(data)); } }; }(); diff --git a/pom.xml b/pom.xml index b9a3fa7c..3a4560c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.atmosphere javascript-project javascript-project - 2.0.5-SNAPSHOT + 2.0.11-SNAPSHOT pom Javascript clients for Atmosphere