quickblox 2.17.2-logger → 2.17.4-logger
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -2
- package/quickblox.js +36571 -38627
- package/quickblox.min.js +1 -1
- package/src/libs/strophe/strophe.common.js +6668 -0
- package/src/libs/strophe/strophe.esm.js +6660 -0
- package/src/libs/strophe/strophe.umd.js +6873 -0
- package/src/libs/strophe/strophe.umd.min.js +1 -0
- package/src/modules/chat/qbChat.js +9 -0
- package/src/modules/webrtc/qbWebRTCSignalingProcessor.js +2 -1
- package/src/modules/webrtc/qbWebRTCSignalingProvider.js +2 -2
- package/src/qbConfig.js +1 -1
- package/src/qbStrophe.js +2 -1
- package/strophejs-1.4.0/.eslintrc.json +264 -0
- package/strophejs-1.4.0/.gitattributes +1 -0
- package/strophejs-1.4.0/CHANGELOG.md +250 -0
- package/strophejs-1.4.0/LICENSE.txt +19 -0
- package/strophejs-1.4.0/Makefile +92 -0
- package/strophejs-1.4.0/README.md +45 -0
- package/strophejs-1.4.0/RELEASE_CHECKLIST.md +16 -0
- package/strophejs-1.4.0/contrib/discojs/README.txt +42 -0
- package/strophejs-1.4.0/contrib/discojs/css/disco.css +16 -0
- package/strophejs-1.4.0/contrib/discojs/index.html +47 -0
- package/strophejs-1.4.0/contrib/discojs/punjab.tac +18 -0
- package/strophejs-1.4.0/contrib/discojs/scripts/basic.js +102 -0
- package/strophejs-1.4.0/contrib/discojs/scripts/disco.js +60 -0
- package/strophejs-1.4.0/docs.css +797 -0
- package/strophejs-1.4.0/examples/amd.html +21 -0
- package/strophejs-1.4.0/examples/attach/README +37 -0
- package/strophejs-1.4.0/examples/attach/__init__.py +0 -0
- package/strophejs-1.4.0/examples/attach/attacher/__init__.py +0 -0
- package/strophejs-1.4.0/examples/attach/attacher/views.py +18 -0
- package/strophejs-1.4.0/examples/attach/boshclient.py +158 -0
- package/strophejs-1.4.0/examples/attach/manage.py +11 -0
- package/strophejs-1.4.0/examples/attach/settings.py +85 -0
- package/strophejs-1.4.0/examples/attach/templates/attacher/index.html +88 -0
- package/strophejs-1.4.0/examples/attach/urls.py +19 -0
- package/strophejs-1.4.0/examples/basic.html +23 -0
- package/strophejs-1.4.0/examples/basic.js +73 -0
- package/strophejs-1.4.0/examples/echobot.html +25 -0
- package/strophejs-1.4.0/examples/echobot.js +79 -0
- package/strophejs-1.4.0/examples/main.js +59 -0
- package/strophejs-1.4.0/examples/prebind.html +39 -0
- package/strophejs-1.4.0/examples/prebind.js +103 -0
- package/strophejs-1.4.0/examples/restore.html +24 -0
- package/strophejs-1.4.0/examples/restore.js +71 -0
- package/strophejs-1.4.0/package-lock.json +8634 -0
- package/strophejs-1.4.0/package.json +84 -0
- package/strophejs-1.4.0/rollup.config.js +76 -0
- package/strophejs-1.4.0/src/bosh.js +916 -0
- package/strophejs-1.4.0/src/core.js +3535 -0
- package/strophejs-1.4.0/src/md5.js +204 -0
- package/strophejs-1.4.0/src/sha1.js +172 -0
- package/strophejs-1.4.0/src/shared-connection-worker.js +114 -0
- package/strophejs-1.4.0/src/shims.js +123 -0
- package/strophejs-1.4.0/src/strophe.js +14 -0
- package/strophejs-1.4.0/src/utils.js +63 -0
- package/strophejs-1.4.0/src/websocket.js +561 -0
- package/strophejs-1.4.0/src/worker-websocket.js +152 -0
- package/strophejs-1.4.0/tests/index.html +21 -0
- package/strophejs-1.4.0/tests/main.js +49 -0
- package/strophejs-1.4.0/tests/tests.js +929 -0
- package/strophejs-1.6.1/.eslintrc.json +264 -0
- package/strophejs-1.6.1/.gitattributes +1 -0
- package/strophejs-1.6.1/.nvmrc +1 -0
- package/strophejs-1.6.1/CHANGELOG.md +288 -0
- package/strophejs-1.6.1/LICENSE.txt +19 -0
- package/strophejs-1.6.1/Makefile +92 -0
- package/strophejs-1.6.1/README.md +46 -0
- package/strophejs-1.6.1/RELEASE_CHECKLIST.md +18 -0
- package/strophejs-1.6.1/babel.config.json +10 -0
- package/strophejs-1.6.1/contrib/discojs/README.txt +42 -0
- package/strophejs-1.6.1/contrib/discojs/css/disco.css +16 -0
- package/strophejs-1.6.1/contrib/discojs/index.html +47 -0
- package/strophejs-1.6.1/contrib/discojs/punjab.tac +18 -0
- package/strophejs-1.6.1/contrib/discojs/scripts/basic.js +102 -0
- package/strophejs-1.6.1/contrib/discojs/scripts/disco.js +60 -0
- package/strophejs-1.6.1/docs.css +797 -0
- package/strophejs-1.6.1/examples/amd.html +21 -0
- package/strophejs-1.6.1/examples/attach/README +37 -0
- package/strophejs-1.6.1/examples/attach/__init__.py +0 -0
- package/strophejs-1.6.1/examples/attach/attacher/__init__.py +0 -0
- package/strophejs-1.6.1/examples/attach/attacher/views.py +18 -0
- package/strophejs-1.6.1/examples/attach/boshclient.py +158 -0
- package/strophejs-1.6.1/examples/attach/manage.py +11 -0
- package/strophejs-1.6.1/examples/attach/settings.py +85 -0
- package/strophejs-1.6.1/examples/attach/templates/attacher/index.html +88 -0
- package/strophejs-1.6.1/examples/attach/urls.py +19 -0
- package/strophejs-1.6.1/examples/basic.html +23 -0
- package/strophejs-1.6.1/examples/basic.js +73 -0
- package/strophejs-1.6.1/examples/echobot.html +25 -0
- package/strophejs-1.6.1/examples/echobot.js +79 -0
- package/strophejs-1.6.1/examples/main.js +59 -0
- package/strophejs-1.6.1/examples/prebind.html +39 -0
- package/strophejs-1.6.1/examples/prebind.js +103 -0
- package/strophejs-1.6.1/examples/restore.html +24 -0
- package/strophejs-1.6.1/examples/restore.js +71 -0
- package/strophejs-1.6.1/package-lock.json +18461 -0
- package/strophejs-1.6.1/package.json +87 -0
- package/strophejs-1.6.1/rollup.config.js +70 -0
- package/strophejs-1.6.1/src/bosh.js +916 -0
- package/strophejs-1.6.1/src/builder.js +239 -0
- package/strophejs-1.6.1/src/constants.js +155 -0
- package/strophejs-1.6.1/src/core.js +2377 -0
- package/strophejs-1.6.1/src/sasl-anon.js +17 -0
- package/strophejs-1.6.1/src/sasl-external.js +27 -0
- package/strophejs-1.6.1/src/sasl-oauthbearer.js +30 -0
- package/strophejs-1.6.1/src/sasl-plain.js +32 -0
- package/strophejs-1.6.1/src/sasl-sha1.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha256.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha384.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha512.js +24 -0
- package/strophejs-1.6.1/src/sasl-xoauth2.js +27 -0
- package/strophejs-1.6.1/src/sasl.js +143 -0
- package/strophejs-1.6.1/src/scram.js +182 -0
- package/strophejs-1.6.1/src/shared-connection-worker.js +114 -0
- package/strophejs-1.6.1/src/shims.js +122 -0
- package/strophejs-1.6.1/src/strophe.js +15 -0
- package/strophejs-1.6.1/src/utils.js +626 -0
- package/strophejs-1.6.1/src/websocket.js +556 -0
- package/strophejs-1.6.1/src/worker-websocket.js +149 -0
- package/strophejs-1.6.1/tests.js +993 -0
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This program is distributed under the terms of the MIT license.
|
|
3
|
+
Please see the LICENSE file for details.
|
|
4
|
+
|
|
5
|
+
Copyright 2006-2008, OGG, LLC
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* global ActiveXObject */
|
|
9
|
+
|
|
10
|
+
import { DOMParser } from './shims'
|
|
11
|
+
import { $build, Strophe } from './core';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/** PrivateClass: Strophe.Request
|
|
15
|
+
* _Private_ helper class that provides a cross implementation abstraction
|
|
16
|
+
* for a BOSH related XMLHttpRequest.
|
|
17
|
+
*
|
|
18
|
+
* The Strophe.Request class is used internally to encapsulate BOSH request
|
|
19
|
+
* information. It is not meant to be used from user's code.
|
|
20
|
+
*/
|
|
21
|
+
Strophe.Request = class Request {
|
|
22
|
+
|
|
23
|
+
/** PrivateConstructor: Strophe.Request
|
|
24
|
+
* Create and initialize a new Strophe.Request object.
|
|
25
|
+
*
|
|
26
|
+
* Parameters:
|
|
27
|
+
* (XMLElement) elem - The XML data to be sent in the request.
|
|
28
|
+
* (Function) func - The function that will be called when the
|
|
29
|
+
* XMLHttpRequest readyState changes.
|
|
30
|
+
* (Integer) rid - The BOSH rid attribute associated with this request.
|
|
31
|
+
* (Integer) sends - The number of times this same request has been sent.
|
|
32
|
+
*/
|
|
33
|
+
constructor (elem, func, rid, sends) {
|
|
34
|
+
this.id = ++Strophe._requestId;
|
|
35
|
+
this.xmlData = elem;
|
|
36
|
+
this.data = Strophe.serialize(elem);
|
|
37
|
+
// save original function in case we need to make a new request
|
|
38
|
+
// from this one.
|
|
39
|
+
this.origFunc = func;
|
|
40
|
+
this.func = func;
|
|
41
|
+
this.rid = rid;
|
|
42
|
+
this.date = NaN;
|
|
43
|
+
this.sends = sends || 0;
|
|
44
|
+
this.abort = false;
|
|
45
|
+
this.dead = null;
|
|
46
|
+
|
|
47
|
+
this.age = function () {
|
|
48
|
+
if (!this.date) { return 0; }
|
|
49
|
+
const now = new Date();
|
|
50
|
+
return (now - this.date) / 1000;
|
|
51
|
+
};
|
|
52
|
+
this.timeDead = function () {
|
|
53
|
+
if (!this.dead) { return 0; }
|
|
54
|
+
const now = new Date();
|
|
55
|
+
return (now - this.dead) / 1000;
|
|
56
|
+
};
|
|
57
|
+
this.xhr = this._newXHR();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** PrivateFunction: getResponse
|
|
61
|
+
* Get a response from the underlying XMLHttpRequest.
|
|
62
|
+
*
|
|
63
|
+
* This function attempts to get a response from the request and checks
|
|
64
|
+
* for errors.
|
|
65
|
+
*
|
|
66
|
+
* Throws:
|
|
67
|
+
* "parsererror" - A parser error occured.
|
|
68
|
+
* "bad-format" - The entity has sent XML that cannot be processed.
|
|
69
|
+
*
|
|
70
|
+
* Returns:
|
|
71
|
+
* The DOM element tree of the response.
|
|
72
|
+
*/
|
|
73
|
+
getResponse () {
|
|
74
|
+
let node = null;
|
|
75
|
+
if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {
|
|
76
|
+
node = this.xhr.responseXML.documentElement;
|
|
77
|
+
if (node.tagName === "parsererror") {
|
|
78
|
+
Strophe.error("invalid response received");
|
|
79
|
+
Strophe.error("responseText: " + this.xhr.responseText);
|
|
80
|
+
Strophe.error("responseXML: " +
|
|
81
|
+
Strophe.serialize(this.xhr.responseXML));
|
|
82
|
+
throw new Error("parsererror");
|
|
83
|
+
}
|
|
84
|
+
} else if (this.xhr.responseText) {
|
|
85
|
+
// In React Native, we may get responseText but no responseXML. We can try to parse it manually.
|
|
86
|
+
Strophe.debug("Got responseText but no responseXML; attempting to parse it with DOMParser...");
|
|
87
|
+
node = new DOMParser().parseFromString(this.xhr.responseText, 'application/xml').documentElement;
|
|
88
|
+
if (!node) {
|
|
89
|
+
throw new Error('Parsing produced null node');
|
|
90
|
+
} else if (node.querySelector('parsererror')) {
|
|
91
|
+
Strophe.error("invalid response received: " + node.querySelector('parsererror').textContent);
|
|
92
|
+
Strophe.error("responseText: " + this.xhr.responseText);
|
|
93
|
+
const error = new Error();
|
|
94
|
+
error.name = Strophe.ErrorCondition.BAD_FORMAT;
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return node;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** PrivateFunction: _newXHR
|
|
102
|
+
* _Private_ helper function to create XMLHttpRequests.
|
|
103
|
+
*
|
|
104
|
+
* This function creates XMLHttpRequests across all implementations.
|
|
105
|
+
*
|
|
106
|
+
* Returns:
|
|
107
|
+
* A new XMLHttpRequest.
|
|
108
|
+
*/
|
|
109
|
+
_newXHR () {
|
|
110
|
+
let xhr = null;
|
|
111
|
+
if (window.XMLHttpRequest) {
|
|
112
|
+
xhr = new XMLHttpRequest();
|
|
113
|
+
if (xhr.overrideMimeType) {
|
|
114
|
+
xhr.overrideMimeType("text/xml; charset=utf-8");
|
|
115
|
+
}
|
|
116
|
+
} else if (window.ActiveXObject) {
|
|
117
|
+
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
|
118
|
+
}
|
|
119
|
+
// use Function.bind() to prepend ourselves as an argument
|
|
120
|
+
xhr.onreadystatechange = this.func.bind(null, this);
|
|
121
|
+
return xhr;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/** Class: Strophe.Bosh
|
|
126
|
+
* _Private_ helper class that handles BOSH Connections
|
|
127
|
+
*
|
|
128
|
+
* The Strophe.Bosh class is used internally by Strophe.Connection
|
|
129
|
+
* to encapsulate BOSH sessions. It is not meant to be used from user's code.
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
/** File: bosh.js
|
|
133
|
+
* A JavaScript library to enable BOSH in Strophejs.
|
|
134
|
+
*
|
|
135
|
+
* this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)
|
|
136
|
+
* to emulate a persistent, stateful, two-way connection to an XMPP server.
|
|
137
|
+
* More information on BOSH can be found in XEP 124.
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
/** PrivateConstructor: Strophe.Bosh
|
|
141
|
+
* Create and initialize a Strophe.Bosh object.
|
|
142
|
+
*
|
|
143
|
+
* Parameters:
|
|
144
|
+
* (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.
|
|
145
|
+
*
|
|
146
|
+
* Returns:
|
|
147
|
+
* A new Strophe.Bosh object.
|
|
148
|
+
*/
|
|
149
|
+
Strophe.Bosh = class Bosh {
|
|
150
|
+
|
|
151
|
+
constructor (connection) {
|
|
152
|
+
this._conn = connection;
|
|
153
|
+
/* request id for body tags */
|
|
154
|
+
this.rid = Math.floor(Math.random() * 4294967295);
|
|
155
|
+
/* The current session ID. */
|
|
156
|
+
this.sid = null;
|
|
157
|
+
|
|
158
|
+
// default BOSH values
|
|
159
|
+
this.hold = 1;
|
|
160
|
+
this.wait = 60;
|
|
161
|
+
this.window = 5;
|
|
162
|
+
this.errors = 0;
|
|
163
|
+
this.inactivity = null;
|
|
164
|
+
|
|
165
|
+
this.lastResponseHeaders = null;
|
|
166
|
+
this._requests = [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** PrivateFunction: _buildBody
|
|
170
|
+
* _Private_ helper function to generate the <body/> wrapper for BOSH.
|
|
171
|
+
*
|
|
172
|
+
* Returns:
|
|
173
|
+
* A Strophe.Builder with a <body/> element.
|
|
174
|
+
*/
|
|
175
|
+
_buildBody () {
|
|
176
|
+
const bodyWrap = $build('body', {
|
|
177
|
+
'rid': this.rid++,
|
|
178
|
+
'xmlns': Strophe.NS.HTTPBIND
|
|
179
|
+
});
|
|
180
|
+
if (this.sid !== null) {
|
|
181
|
+
bodyWrap.attrs({'sid': this.sid});
|
|
182
|
+
}
|
|
183
|
+
if (this._conn.options.keepalive && this._conn._sessionCachingSupported()) {
|
|
184
|
+
this._cacheSession();
|
|
185
|
+
}
|
|
186
|
+
return bodyWrap;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** PrivateFunction: _reset
|
|
190
|
+
* Reset the connection.
|
|
191
|
+
*
|
|
192
|
+
* This function is called by the reset function of the Strophe Connection
|
|
193
|
+
*/
|
|
194
|
+
_reset () {
|
|
195
|
+
this.rid = Math.floor(Math.random() * 4294967295);
|
|
196
|
+
this.sid = null;
|
|
197
|
+
this.errors = 0;
|
|
198
|
+
if (this._conn._sessionCachingSupported()) {
|
|
199
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this._conn.nextValidRid(this.rid);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** PrivateFunction: _connect
|
|
206
|
+
* _Private_ function that initializes the BOSH connection.
|
|
207
|
+
*
|
|
208
|
+
* Creates and sends the Request that initializes the BOSH connection.
|
|
209
|
+
*/
|
|
210
|
+
_connect (wait, hold, route) {
|
|
211
|
+
this.wait = wait || this.wait;
|
|
212
|
+
this.hold = hold || this.hold;
|
|
213
|
+
this.errors = 0;
|
|
214
|
+
|
|
215
|
+
const body = this._buildBody().attrs({
|
|
216
|
+
"to": this._conn.domain,
|
|
217
|
+
"xml:lang": "en",
|
|
218
|
+
"wait": this.wait,
|
|
219
|
+
"hold": this.hold,
|
|
220
|
+
"content": "text/xml; charset=utf-8",
|
|
221
|
+
"ver": "1.6",
|
|
222
|
+
"xmpp:version": "1.0",
|
|
223
|
+
"xmlns:xmpp": Strophe.NS.BOSH
|
|
224
|
+
});
|
|
225
|
+
if (route){
|
|
226
|
+
body.attrs({'route': route});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const _connect_cb = this._conn._connect_cb;
|
|
230
|
+
this._requests.push(
|
|
231
|
+
new Strophe.Request(
|
|
232
|
+
body.tree(),
|
|
233
|
+
this._onRequestStateChange.bind(this, _connect_cb.bind(this._conn)),
|
|
234
|
+
body.tree().getAttribute("rid")
|
|
235
|
+
)
|
|
236
|
+
);
|
|
237
|
+
this._throttledRequestHandler();
|
|
238
|
+
this._conn.clientLogger('_connect method was called with BOSH protocol');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** PrivateFunction: _attach
|
|
242
|
+
* Attach to an already created and authenticated BOSH session.
|
|
243
|
+
*
|
|
244
|
+
* This function is provided to allow Strophe to attach to BOSH
|
|
245
|
+
* sessions which have been created externally, perhaps by a Web
|
|
246
|
+
* application. This is often used to support auto-login type features
|
|
247
|
+
* without putting user credentials into the page.
|
|
248
|
+
*
|
|
249
|
+
* Parameters:
|
|
250
|
+
* (String) jid - The full JID that is bound by the session.
|
|
251
|
+
* (String) sid - The SID of the BOSH session.
|
|
252
|
+
* (String) rid - The current RID of the BOSH session. This RID
|
|
253
|
+
* will be used by the next request.
|
|
254
|
+
* (Function) callback The connect callback function.
|
|
255
|
+
* (Integer) wait - The optional HTTPBIND wait value. This is the
|
|
256
|
+
* time the server will wait before returning an empty result for
|
|
257
|
+
* a request. The default setting of 60 seconds is recommended.
|
|
258
|
+
* Other settings will require tweaks to the Strophe.TIMEOUT value.
|
|
259
|
+
* (Integer) hold - The optional HTTPBIND hold value. This is the
|
|
260
|
+
* number of connections the server will hold at one time. This
|
|
261
|
+
* should almost always be set to 1 (the default).
|
|
262
|
+
* (Integer) wind - The optional HTTBIND window value. This is the
|
|
263
|
+
* allowed range of request ids that are valid. The default is 5.
|
|
264
|
+
*/
|
|
265
|
+
_attach (jid, sid, rid, callback, wait, hold, wind) {
|
|
266
|
+
this._conn.jid = jid;
|
|
267
|
+
this.sid = sid;
|
|
268
|
+
this.rid = rid;
|
|
269
|
+
|
|
270
|
+
this._conn.connect_callback = callback;
|
|
271
|
+
this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);
|
|
272
|
+
this._conn.authenticated = true;
|
|
273
|
+
this._conn.connected = true;
|
|
274
|
+
|
|
275
|
+
this.wait = wait || this.wait;
|
|
276
|
+
this.hold = hold || this.hold;
|
|
277
|
+
this.window = wind || this.window;
|
|
278
|
+
|
|
279
|
+
this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** PrivateFunction: _restore
|
|
283
|
+
* Attempt to restore a cached BOSH session
|
|
284
|
+
*
|
|
285
|
+
* Parameters:
|
|
286
|
+
* (String) jid - The full JID that is bound by the session.
|
|
287
|
+
* This parameter is optional but recommended, specifically in cases
|
|
288
|
+
* where prebinded BOSH sessions are used where it's important to know
|
|
289
|
+
* that the right session is being restored.
|
|
290
|
+
* (Function) callback The connect callback function.
|
|
291
|
+
* (Integer) wait - The optional HTTPBIND wait value. This is the
|
|
292
|
+
* time the server will wait before returning an empty result for
|
|
293
|
+
* a request. The default setting of 60 seconds is recommended.
|
|
294
|
+
* Other settings will require tweaks to the Strophe.TIMEOUT value.
|
|
295
|
+
* (Integer) hold - The optional HTTPBIND hold value. This is the
|
|
296
|
+
* number of connections the server will hold at one time. This
|
|
297
|
+
* should almost always be set to 1 (the default).
|
|
298
|
+
* (Integer) wind - The optional HTTBIND window value. This is the
|
|
299
|
+
* allowed range of request ids that are valid. The default is 5.
|
|
300
|
+
*/
|
|
301
|
+
_restore (jid, callback, wait, hold, wind) {
|
|
302
|
+
const session = JSON.parse(window.sessionStorage.getItem('strophe-bosh-session'));
|
|
303
|
+
if (typeof session !== "undefined" &&
|
|
304
|
+
session !== null &&
|
|
305
|
+
session.rid &&
|
|
306
|
+
session.sid &&
|
|
307
|
+
session.jid &&
|
|
308
|
+
( typeof jid === "undefined" ||
|
|
309
|
+
jid === null ||
|
|
310
|
+
Strophe.getBareJidFromJid(session.jid) === Strophe.getBareJidFromJid(jid) ||
|
|
311
|
+
// If authcid is null, then it's an anonymous login, so
|
|
312
|
+
// we compare only the domains:
|
|
313
|
+
((Strophe.getNodeFromJid(jid) === null) && (Strophe.getDomainFromJid(session.jid) === jid))
|
|
314
|
+
)
|
|
315
|
+
) {
|
|
316
|
+
this._conn.restored = true;
|
|
317
|
+
this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind);
|
|
318
|
+
} else {
|
|
319
|
+
const error = new Error("_restore: no restoreable session.");
|
|
320
|
+
error.name = "StropheSessionError";
|
|
321
|
+
throw error;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** PrivateFunction: _cacheSession
|
|
326
|
+
* _Private_ handler for the beforeunload event.
|
|
327
|
+
*
|
|
328
|
+
* This handler is used to process the Bosh-part of the initial request.
|
|
329
|
+
* Parameters:
|
|
330
|
+
* (Strophe.Request) bodyWrap - The received stanza.
|
|
331
|
+
*/
|
|
332
|
+
_cacheSession () {
|
|
333
|
+
if (this._conn.authenticated) {
|
|
334
|
+
if (this._conn.jid && this.rid && this.sid) {
|
|
335
|
+
window.sessionStorage.setItem('strophe-bosh-session', JSON.stringify({
|
|
336
|
+
'jid': this._conn.jid,
|
|
337
|
+
'rid': this.rid,
|
|
338
|
+
'sid': this.sid
|
|
339
|
+
}));
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** PrivateFunction: _connect_cb
|
|
347
|
+
* _Private_ handler for initial connection request.
|
|
348
|
+
*
|
|
349
|
+
* This handler is used to process the Bosh-part of the initial request.
|
|
350
|
+
* Parameters:
|
|
351
|
+
* (Strophe.Request) bodyWrap - The received stanza.
|
|
352
|
+
*/
|
|
353
|
+
_connect_cb (bodyWrap) {
|
|
354
|
+
const typ = bodyWrap.getAttribute("type");
|
|
355
|
+
if (typ !== null && typ === "terminate") {
|
|
356
|
+
// an error occurred
|
|
357
|
+
let cond = bodyWrap.getAttribute("condition");
|
|
358
|
+
Strophe.error("BOSH-Connection failed: " + cond);
|
|
359
|
+
const conflict = bodyWrap.getElementsByTagName("conflict");
|
|
360
|
+
if (cond !== null) {
|
|
361
|
+
if (cond === "remote-stream-error" && conflict.length > 0) {
|
|
362
|
+
cond = "conflict";
|
|
363
|
+
}
|
|
364
|
+
this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
|
|
365
|
+
} else {
|
|
366
|
+
this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
|
|
367
|
+
}
|
|
368
|
+
this._conn._doDisconnect(cond);
|
|
369
|
+
return Strophe.Status.CONNFAIL;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// check to make sure we don't overwrite these if _connect_cb is
|
|
373
|
+
// called multiple times in the case of missing stream:features
|
|
374
|
+
if (!this.sid) {
|
|
375
|
+
this.sid = bodyWrap.getAttribute("sid");
|
|
376
|
+
}
|
|
377
|
+
const wind = bodyWrap.getAttribute('requests');
|
|
378
|
+
if (wind) { this.window = parseInt(wind, 10); }
|
|
379
|
+
const hold = bodyWrap.getAttribute('hold');
|
|
380
|
+
if (hold) { this.hold = parseInt(hold, 10); }
|
|
381
|
+
const wait = bodyWrap.getAttribute('wait');
|
|
382
|
+
if (wait) { this.wait = parseInt(wait, 10); }
|
|
383
|
+
const inactivity = bodyWrap.getAttribute('inactivity');
|
|
384
|
+
if (inactivity) { this.inactivity = parseInt(inactivity, 10); }
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** PrivateFunction: _disconnect
|
|
388
|
+
* _Private_ part of Connection.disconnect for Bosh
|
|
389
|
+
*
|
|
390
|
+
* Parameters:
|
|
391
|
+
* (Request) pres - This stanza will be sent before disconnecting.
|
|
392
|
+
*/
|
|
393
|
+
_disconnect (pres) {
|
|
394
|
+
this._sendTerminate(pres);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** PrivateFunction: _doDisconnect
|
|
398
|
+
* _Private_ function to disconnect.
|
|
399
|
+
*
|
|
400
|
+
* Resets the SID and RID.
|
|
401
|
+
*/
|
|
402
|
+
_doDisconnect () {
|
|
403
|
+
this.sid = null;
|
|
404
|
+
this.rid = Math.floor(Math.random() * 4294967295);
|
|
405
|
+
if (this._conn._sessionCachingSupported()) {
|
|
406
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
this._conn.nextValidRid(this.rid);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** PrivateFunction: _emptyQueue
|
|
413
|
+
* _Private_ function to check if the Request queue is empty.
|
|
414
|
+
*
|
|
415
|
+
* Returns:
|
|
416
|
+
* True, if there are no Requests queued, False otherwise.
|
|
417
|
+
*/
|
|
418
|
+
_emptyQueue () {
|
|
419
|
+
return this._requests.length === 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** PrivateFunction: _callProtocolErrorHandlers
|
|
423
|
+
* _Private_ function to call error handlers registered for HTTP errors.
|
|
424
|
+
*
|
|
425
|
+
* Parameters:
|
|
426
|
+
* (Strophe.Request) req - The request that is changing readyState.
|
|
427
|
+
*/
|
|
428
|
+
_callProtocolErrorHandlers (req) {
|
|
429
|
+
const reqStatus = Bosh._getRequestStatus(req);
|
|
430
|
+
const err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus];
|
|
431
|
+
if (err_callback) {
|
|
432
|
+
err_callback.call(this, reqStatus);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** PrivateFunction: _hitError
|
|
437
|
+
* _Private_ function to handle the error count.
|
|
438
|
+
*
|
|
439
|
+
* Requests are resent automatically until their error count reaches
|
|
440
|
+
* 5. Each time an error is encountered, this function is called to
|
|
441
|
+
* increment the count and disconnect if the count is too high.
|
|
442
|
+
*
|
|
443
|
+
* Parameters:
|
|
444
|
+
* (Integer) reqStatus - The request status.
|
|
445
|
+
*/
|
|
446
|
+
_hitError (reqStatus) {
|
|
447
|
+
this.errors++;
|
|
448
|
+
Strophe.warn("request errored, status: " + reqStatus +
|
|
449
|
+
", number of errors: " + this.errors);
|
|
450
|
+
if (this.errors > 4) {
|
|
451
|
+
this._conn._onDisconnectTimeout();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** PrivateFunction: _no_auth_received
|
|
456
|
+
*
|
|
457
|
+
* Called on stream start/restart when no stream:features
|
|
458
|
+
* has been received and sends a blank poll request.
|
|
459
|
+
*/
|
|
460
|
+
_no_auth_received (callback) {
|
|
461
|
+
Strophe.warn("Server did not yet offer a supported authentication "+
|
|
462
|
+
"mechanism. Sending a blank poll request.");
|
|
463
|
+
if (callback) {
|
|
464
|
+
callback = callback.bind(this._conn);
|
|
465
|
+
} else {
|
|
466
|
+
callback = this._conn._connect_cb.bind(this._conn);
|
|
467
|
+
}
|
|
468
|
+
const body = this._buildBody();
|
|
469
|
+
this._requests.push(
|
|
470
|
+
new Strophe.Request(
|
|
471
|
+
body.tree(),
|
|
472
|
+
this._onRequestStateChange.bind(this, callback),
|
|
473
|
+
body.tree().getAttribute("rid")
|
|
474
|
+
)
|
|
475
|
+
);
|
|
476
|
+
this._throttledRequestHandler();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** PrivateFunction: _onDisconnectTimeout
|
|
480
|
+
* _Private_ timeout handler for handling non-graceful disconnection.
|
|
481
|
+
*
|
|
482
|
+
* Cancels all remaining Requests and clears the queue.
|
|
483
|
+
*/
|
|
484
|
+
_onDisconnectTimeout () {
|
|
485
|
+
this._abortAllRequests();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** PrivateFunction: _abortAllRequests
|
|
489
|
+
* _Private_ helper function that makes sure all pending requests are aborted.
|
|
490
|
+
*/
|
|
491
|
+
_abortAllRequests () {
|
|
492
|
+
while (this._requests.length > 0) {
|
|
493
|
+
const req = this._requests.pop();
|
|
494
|
+
req.abort = true;
|
|
495
|
+
req.xhr.abort();
|
|
496
|
+
req.xhr.onreadystatechange = function () {};
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** PrivateFunction: _onIdle
|
|
501
|
+
* _Private_ handler called by Strophe.Connection._onIdle
|
|
502
|
+
*
|
|
503
|
+
* Sends all queued Requests or polls with empty Request if there are none.
|
|
504
|
+
*/
|
|
505
|
+
_onIdle () {
|
|
506
|
+
const data = this._conn._data;
|
|
507
|
+
// if no requests are in progress, poll
|
|
508
|
+
if (this._conn.authenticated && this._requests.length === 0 &&
|
|
509
|
+
data.length === 0 && !this._conn.disconnecting) {
|
|
510
|
+
Strophe.debug("no requests during idle cycle, sending blank request");
|
|
511
|
+
data.push(null);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (this._conn.paused) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if (this._requests.length < 2 && data.length > 0) {
|
|
519
|
+
const body = this._buildBody();
|
|
520
|
+
for (let i=0; i<data.length; i++) {
|
|
521
|
+
if (data[i] !== null) {
|
|
522
|
+
if (data[i] === "restart") {
|
|
523
|
+
body.attrs({
|
|
524
|
+
"to": this._conn.domain,
|
|
525
|
+
"xml:lang": "en",
|
|
526
|
+
"xmpp:restart": "true",
|
|
527
|
+
"xmlns:xmpp": Strophe.NS.BOSH
|
|
528
|
+
});
|
|
529
|
+
} else {
|
|
530
|
+
body.cnode(data[i]).up();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
delete this._conn._data;
|
|
535
|
+
this._conn._data = [];
|
|
536
|
+
this._requests.push(
|
|
537
|
+
new Strophe.Request(
|
|
538
|
+
body.tree(),
|
|
539
|
+
this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)),
|
|
540
|
+
body.tree().getAttribute("rid")
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
this._throttledRequestHandler();
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (this._requests.length > 0) {
|
|
547
|
+
const time_elapsed = this._requests[0].age();
|
|
548
|
+
if (this._requests[0].dead !== null) {
|
|
549
|
+
if (this._requests[0].timeDead() >
|
|
550
|
+
Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {
|
|
551
|
+
this._throttledRequestHandler();
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {
|
|
555
|
+
Strophe.warn("Request " +
|
|
556
|
+
this._requests[0].id +
|
|
557
|
+
" timed out, over " + Math.floor(Strophe.TIMEOUT * this.wait) +
|
|
558
|
+
" seconds since last activity");
|
|
559
|
+
this._throttledRequestHandler();
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/** PrivateFunction: _getRequestStatus
|
|
565
|
+
*
|
|
566
|
+
* Returns the HTTP status code from a Strophe.Request
|
|
567
|
+
*
|
|
568
|
+
* Parameters:
|
|
569
|
+
* (Strophe.Request) req - The Strophe.Request instance.
|
|
570
|
+
* (Integer) def - The default value that should be returned if no
|
|
571
|
+
* status value was found.
|
|
572
|
+
*/
|
|
573
|
+
static _getRequestStatus (req, def) {
|
|
574
|
+
let reqStatus;
|
|
575
|
+
if (req.xhr.readyState === 4) {
|
|
576
|
+
try {
|
|
577
|
+
reqStatus = req.xhr.status;
|
|
578
|
+
} catch (e) {
|
|
579
|
+
// ignore errors from undefined status attribute. Works
|
|
580
|
+
// around a browser bug
|
|
581
|
+
Strophe.error(
|
|
582
|
+
"Caught an error while retrieving a request's status, " +
|
|
583
|
+
"reqStatus: " + reqStatus);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (typeof(reqStatus) === "undefined") {
|
|
587
|
+
reqStatus = typeof def === 'number' ? def : 0;
|
|
588
|
+
}
|
|
589
|
+
return reqStatus;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** PrivateFunction: _onRequestStateChange
|
|
593
|
+
* _Private_ handler for Strophe.Request state changes.
|
|
594
|
+
*
|
|
595
|
+
* This function is called when the XMLHttpRequest readyState changes.
|
|
596
|
+
* It contains a lot of error handling logic for the many ways that
|
|
597
|
+
* requests can fail, and calls the request callback when requests
|
|
598
|
+
* succeed.
|
|
599
|
+
*
|
|
600
|
+
* Parameters:
|
|
601
|
+
* (Function) func - The handler for the request.
|
|
602
|
+
* (Strophe.Request) req - The request that is changing readyState.
|
|
603
|
+
*/
|
|
604
|
+
_onRequestStateChange (func, req) {
|
|
605
|
+
Strophe.debug("request id "+req.id+"."+req.sends+
|
|
606
|
+
" state changed to "+req.xhr.readyState);
|
|
607
|
+
if (req.abort) {
|
|
608
|
+
req.abort = false;
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (req.xhr.readyState !== 4) {
|
|
612
|
+
// The request is not yet complete
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
const reqStatus = Bosh._getRequestStatus(req);
|
|
616
|
+
this.lastResponseHeaders = req.xhr.getAllResponseHeaders();
|
|
617
|
+
if (this._conn.disconnecting && reqStatus >= 400) {
|
|
618
|
+
this._hitError(reqStatus);
|
|
619
|
+
this._callProtocolErrorHandlers(req);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const valid_request = reqStatus > 0 && reqStatus < 500;
|
|
624
|
+
const too_many_retries = req.sends > this._conn.maxRetries;
|
|
625
|
+
if (valid_request || too_many_retries) {
|
|
626
|
+
// remove from internal queue
|
|
627
|
+
this._removeRequest(req);
|
|
628
|
+
Strophe.debug("request id "+req.id+" should now be removed");
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (reqStatus === 200) {
|
|
632
|
+
// request succeeded
|
|
633
|
+
const reqIs0 = (this._requests[0] === req);
|
|
634
|
+
const reqIs1 = (this._requests[1] === req);
|
|
635
|
+
// if request 1 finished, or request 0 finished and request
|
|
636
|
+
// 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
|
|
637
|
+
// restart the other - both will be in the first spot, as the
|
|
638
|
+
// completed request has been removed from the queue already
|
|
639
|
+
if (reqIs1 ||
|
|
640
|
+
(reqIs0 && this._requests.length > 0 &&
|
|
641
|
+
this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
|
|
642
|
+
this._restartRequest(0);
|
|
643
|
+
}
|
|
644
|
+
this._conn.nextValidRid(Number(req.rid) + 1);
|
|
645
|
+
Strophe.debug("request id "+req.id+"."+req.sends+" got 200");
|
|
646
|
+
func(req); // call handler
|
|
647
|
+
this.errors = 0;
|
|
648
|
+
} else if (reqStatus === 0 ||
|
|
649
|
+
(reqStatus >= 400 && reqStatus < 600) ||
|
|
650
|
+
reqStatus >= 12000) {
|
|
651
|
+
// request failed
|
|
652
|
+
Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");
|
|
653
|
+
this._hitError(reqStatus);
|
|
654
|
+
this._callProtocolErrorHandlers(req);
|
|
655
|
+
if (reqStatus >= 400 && reqStatus < 500) {
|
|
656
|
+
this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING, null);
|
|
657
|
+
this._conn._doDisconnect();
|
|
658
|
+
}
|
|
659
|
+
} else {
|
|
660
|
+
Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (!valid_request && !too_many_retries) {
|
|
664
|
+
this._throttledRequestHandler();
|
|
665
|
+
} else if (too_many_retries && !this._conn.connected) {
|
|
666
|
+
this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "giving-up");
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** PrivateFunction: _processRequest
|
|
671
|
+
* _Private_ function to process a request in the queue.
|
|
672
|
+
*
|
|
673
|
+
* This function takes requests off the queue and sends them and
|
|
674
|
+
* restarts dead requests.
|
|
675
|
+
*
|
|
676
|
+
* Parameters:
|
|
677
|
+
* (Integer) i - The index of the request in the queue.
|
|
678
|
+
*/
|
|
679
|
+
_processRequest (i) {
|
|
680
|
+
let req = this._requests[i];
|
|
681
|
+
const reqStatus = Bosh._getRequestStatus(req, -1);
|
|
682
|
+
|
|
683
|
+
// make sure we limit the number of retries
|
|
684
|
+
if (req.sends > this._conn.maxRetries) {
|
|
685
|
+
this._conn._onDisconnectTimeout();
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const time_elapsed = req.age();
|
|
689
|
+
const primary_timeout = (!isNaN(time_elapsed) && time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait));
|
|
690
|
+
const secondary_timeout = (req.dead !== null && req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait));
|
|
691
|
+
const server_error = (req.xhr.readyState === 4 && (reqStatus < 1 || reqStatus >= 500));
|
|
692
|
+
|
|
693
|
+
if (primary_timeout || secondary_timeout || server_error) {
|
|
694
|
+
if (secondary_timeout) {
|
|
695
|
+
Strophe.error(`Request ${this._requests[i].id} timed out (secondary), restarting`);
|
|
696
|
+
}
|
|
697
|
+
req.abort = true;
|
|
698
|
+
req.xhr.abort();
|
|
699
|
+
// setting to null fails on IE6, so set to empty function
|
|
700
|
+
req.xhr.onreadystatechange = function () {};
|
|
701
|
+
this._requests[i] = new Strophe.Request(req.xmlData, req.origFunc, req.rid, req.sends);
|
|
702
|
+
req = this._requests[i];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (req.xhr.readyState === 0) {
|
|
706
|
+
Strophe.debug("request id "+req.id+"."+req.sends+" posting");
|
|
707
|
+
|
|
708
|
+
try {
|
|
709
|
+
const content_type = this._conn.options.contentType || "text/xml; charset=utf-8";
|
|
710
|
+
req.xhr.open("POST", this._conn.service, this._conn.options.sync ? false : true);
|
|
711
|
+
if (typeof req.xhr.setRequestHeader !== 'undefined') {
|
|
712
|
+
// IE9 doesn't have setRequestHeader
|
|
713
|
+
req.xhr.setRequestHeader("Content-Type", content_type);
|
|
714
|
+
}
|
|
715
|
+
if (this._conn.options.withCredentials) {
|
|
716
|
+
req.xhr.withCredentials = true;
|
|
717
|
+
}
|
|
718
|
+
} catch (e2) {
|
|
719
|
+
Strophe.error("XHR open failed: " + e2.toString());
|
|
720
|
+
if (!this._conn.connected) {
|
|
721
|
+
this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "bad-service");
|
|
722
|
+
}
|
|
723
|
+
this._conn.disconnect();
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Fires the XHR request -- may be invoked immediately
|
|
728
|
+
// or on a gradually expanding retry window for reconnects
|
|
729
|
+
const sendFunc = () => {
|
|
730
|
+
req.date = new Date();
|
|
731
|
+
if (this._conn.options.customHeaders){
|
|
732
|
+
const headers = this._conn.options.customHeaders;
|
|
733
|
+
for (const header in headers) {
|
|
734
|
+
if (Object.prototype.hasOwnProperty.call(headers, header)) {
|
|
735
|
+
req.xhr.setRequestHeader(header, headers[header]);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
req.xhr.send(req.data);
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
// Implement progressive backoff for reconnects --
|
|
743
|
+
// First retry (send === 1) should also be instantaneous
|
|
744
|
+
if (req.sends > 1) {
|
|
745
|
+
// Using a cube of the retry number creates a nicely
|
|
746
|
+
// expanding retry window
|
|
747
|
+
const backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait),
|
|
748
|
+
Math.pow(req.sends, 3)) * 1000;
|
|
749
|
+
setTimeout(function() {
|
|
750
|
+
// XXX: setTimeout should be called only with function expressions (23974bc1)
|
|
751
|
+
sendFunc();
|
|
752
|
+
}, backoff);
|
|
753
|
+
} else {
|
|
754
|
+
sendFunc();
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
req.sends++;
|
|
758
|
+
|
|
759
|
+
if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {
|
|
760
|
+
if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {
|
|
761
|
+
this._conn.xmlOutput(req.xmlData.childNodes[0]);
|
|
762
|
+
} else {
|
|
763
|
+
this._conn.xmlOutput(req.xmlData);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {
|
|
767
|
+
this._conn.rawOutput(req.data);
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
Strophe.debug("_processRequest: " +
|
|
771
|
+
(i === 0 ? "first" : "second") +
|
|
772
|
+
" request has readyState of " +
|
|
773
|
+
req.xhr.readyState);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/** PrivateFunction: _removeRequest
|
|
778
|
+
* _Private_ function to remove a request from the queue.
|
|
779
|
+
*
|
|
780
|
+
* Parameters:
|
|
781
|
+
* (Strophe.Request) req - The request to remove.
|
|
782
|
+
*/
|
|
783
|
+
_removeRequest (req) {
|
|
784
|
+
Strophe.debug("removing request");
|
|
785
|
+
for (let i=this._requests.length - 1; i>=0; i--) {
|
|
786
|
+
if (req === this._requests[i]) {
|
|
787
|
+
this._requests.splice(i, 1);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
// IE6 fails on setting to null, so set to empty function
|
|
791
|
+
req.xhr.onreadystatechange = function () {};
|
|
792
|
+
this._throttledRequestHandler();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/** PrivateFunction: _restartRequest
|
|
796
|
+
* _Private_ function to restart a request that is presumed dead.
|
|
797
|
+
*
|
|
798
|
+
* Parameters:
|
|
799
|
+
* (Integer) i - The index of the request in the queue.
|
|
800
|
+
*/
|
|
801
|
+
_restartRequest (i) {
|
|
802
|
+
const req = this._requests[i];
|
|
803
|
+
if (req.dead === null) {
|
|
804
|
+
req.dead = new Date();
|
|
805
|
+
}
|
|
806
|
+
this._processRequest(i);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/** PrivateFunction: _reqToData
|
|
810
|
+
* _Private_ function to get a stanza out of a request.
|
|
811
|
+
*
|
|
812
|
+
* Tries to extract a stanza out of a Request Object.
|
|
813
|
+
* When this fails the current connection will be disconnected.
|
|
814
|
+
*
|
|
815
|
+
* Parameters:
|
|
816
|
+
* (Object) req - The Request.
|
|
817
|
+
*
|
|
818
|
+
* Returns:
|
|
819
|
+
* The stanza that was passed.
|
|
820
|
+
*/
|
|
821
|
+
_reqToData (req) {
|
|
822
|
+
try {
|
|
823
|
+
return req.getResponse();
|
|
824
|
+
} catch (e) {
|
|
825
|
+
if (e.message !== "parsererror") { throw e; }
|
|
826
|
+
this._conn.disconnect("strophe-parsererror");
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/** PrivateFunction: _sendTerminate
|
|
831
|
+
* _Private_ function to send initial disconnect sequence.
|
|
832
|
+
*
|
|
833
|
+
* This is the first step in a graceful disconnect. It sends
|
|
834
|
+
* the BOSH server a terminate body and includes an unavailable
|
|
835
|
+
* presence if authentication has completed.
|
|
836
|
+
*/
|
|
837
|
+
_sendTerminate (pres) {
|
|
838
|
+
Strophe.debug("_sendTerminate was called");
|
|
839
|
+
const body = this._buildBody().attrs({type: "terminate"});
|
|
840
|
+
if (pres) {
|
|
841
|
+
body.cnode(pres.tree());
|
|
842
|
+
}
|
|
843
|
+
const req = new Strophe.Request(
|
|
844
|
+
body.tree(),
|
|
845
|
+
this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)),
|
|
846
|
+
body.tree().getAttribute("rid")
|
|
847
|
+
);
|
|
848
|
+
this._requests.push(req);
|
|
849
|
+
this._throttledRequestHandler();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/** PrivateFunction: _send
|
|
853
|
+
* _Private_ part of the Connection.send function for BOSH
|
|
854
|
+
*
|
|
855
|
+
* Just triggers the RequestHandler to send the messages that are in the queue
|
|
856
|
+
*/
|
|
857
|
+
_send () {
|
|
858
|
+
clearTimeout(this._conn._idleTimeout);
|
|
859
|
+
this._throttledRequestHandler();
|
|
860
|
+
this._conn._idleTimeout = setTimeout(() => this._conn._onIdle(), 100);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/** PrivateFunction: _sendRestart
|
|
864
|
+
*
|
|
865
|
+
* Send an xmpp:restart stanza.
|
|
866
|
+
*/
|
|
867
|
+
_sendRestart () {
|
|
868
|
+
this._throttledRequestHandler();
|
|
869
|
+
clearTimeout(this._conn._idleTimeout);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/** PrivateFunction: _throttledRequestHandler
|
|
873
|
+
* _Private_ function to throttle requests to the connection window.
|
|
874
|
+
*
|
|
875
|
+
* This function makes sure we don't send requests so fast that the
|
|
876
|
+
* request ids overflow the connection window in the case that one
|
|
877
|
+
* request died.
|
|
878
|
+
*/
|
|
879
|
+
_throttledRequestHandler () {
|
|
880
|
+
if (!this._requests) {
|
|
881
|
+
Strophe.debug("_throttledRequestHandler called with " +
|
|
882
|
+
"undefined requests");
|
|
883
|
+
} else {
|
|
884
|
+
Strophe.debug("_throttledRequestHandler called with " +
|
|
885
|
+
this._requests.length + " requests");
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
if (!this._requests || this._requests.length === 0) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
if (this._requests.length > 0) {
|
|
893
|
+
this._processRequest(0);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if (this._requests.length > 1 &&
|
|
897
|
+
Math.abs(this._requests[0].rid -
|
|
898
|
+
this._requests[1].rid) < this.window) {
|
|
899
|
+
this._processRequest(1);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
/** Variable: strip
|
|
906
|
+
*
|
|
907
|
+
* BOSH-Connections will have all stanzas wrapped in a <body> tag when
|
|
908
|
+
* passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.
|
|
909
|
+
* To strip this tag, User code can set <Strophe.Bosh.strip> to "body":
|
|
910
|
+
*
|
|
911
|
+
* > Strophe.Bosh.prototype.strip = "body";
|
|
912
|
+
*
|
|
913
|
+
* This will enable stripping of the body tag in both
|
|
914
|
+
* <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.
|
|
915
|
+
*/
|
|
916
|
+
Strophe.Bosh.prototype.strip = null;
|