1
1
import { Transport } from "../transport.js" ;
2
- import debugModule from "debug" ; // debug()
3
2
import { yeast } from "../contrib/yeast.js" ;
4
- import { encode } from "../contrib/parseqs.js" ;
5
- import { encodePayload , decodePayload , RawData } from "engine.io-parser" ;
6
- import {
7
- CookieJar ,
8
- createCookieJar ,
9
- XHR as XMLHttpRequest ,
10
- } from "./xmlhttprequest.js" ;
11
- import { Emitter } from "@socket.io/component-emitter" ;
12
- import { SocketOptions } from "../socket.js" ;
13
- import { installTimerFunctions , pick } from "../util.js" ;
14
- import { globalThisShim as globalThis } from "../globalThis.js" ;
3
+ import { encodePayload , decodePayload } from "engine.io-parser" ;
4
+ import debugModule from "debug" ; // debug()
15
5
16
6
const debug = debugModule ( "engine.io-client:polling" ) ; // debug()
17
7
18
- function empty ( ) { }
19
-
20
- const hasXHR2 = ( function ( ) {
21
- const xhr = new XMLHttpRequest ( {
22
- xdomain : false ,
23
- } ) ;
24
- return null != xhr . responseType ;
25
- } ) ( ) ;
26
-
27
- export class Polling extends Transport {
28
- private readonly xd : boolean ;
29
-
8
+ export abstract class Polling extends Transport {
30
9
private polling : boolean = false ;
31
- private pollXhr : any ;
32
- private cookieJar ?: CookieJar ;
33
-
34
- /**
35
- * XHR Polling constructor.
36
- *
37
- * @param {Object } opts
38
- * @package
39
- */
40
- constructor ( opts ) {
41
- super ( opts ) ;
42
-
43
- if ( typeof location !== "undefined" ) {
44
- const isSSL = "https:" === location . protocol ;
45
- let port = location . port ;
46
-
47
- // some user agents have empty `location.port`
48
- if ( ! port ) {
49
- port = isSSL ? "443" : "80" ;
50
- }
51
-
52
- this . xd =
53
- ( typeof location !== "undefined" &&
54
- opts . hostname !== location . hostname ) ||
55
- port !== opts . port ;
56
- }
57
- /**
58
- * XHR supports binary
59
- */
60
- const forceBase64 = opts && opts . forceBase64 ;
61
- this . supportsBinary = hasXHR2 && ! forceBase64 ;
62
-
63
- if ( this . opts . withCredentials ) {
64
- this . cookieJar = createCookieJar ( ) ;
65
- }
66
- }
67
10
68
11
override get name ( ) {
69
12
return "polling" ;
@@ -215,7 +158,7 @@ export class Polling extends Transport {
215
158
*
216
159
* @private
217
160
*/
218
- private uri ( ) {
161
+ protected uri ( ) {
219
162
const schema = this . opts . secure ? "https" : "http" ;
220
163
const query : { b64 ?: number ; sid ?: string } = this . query || { } ;
221
164
@@ -231,259 +174,6 @@ export class Polling extends Transport {
231
174
return this . createUri ( schema , query ) ;
232
175
}
233
176
234
- /**
235
- * Creates a request.
236
- *
237
- * @param {String } method
238
- * @private
239
- */
240
- request ( opts = { } ) {
241
- Object . assign ( opts , { xd : this . xd , cookieJar : this . cookieJar } , this . opts ) ;
242
- return new Request ( this . uri ( ) , opts ) ;
243
- }
244
-
245
- /**
246
- * Sends data.
247
- *
248
- * @param {String } data to send.
249
- * @param {Function } called upon flush.
250
- * @private
251
- */
252
- private doWrite ( data , fn ) {
253
- const req = this . request ( {
254
- method : "POST" ,
255
- data : data ,
256
- } ) ;
257
- req . on ( "success" , fn ) ;
258
- req . on ( "error" , ( xhrStatus , context ) => {
259
- this . onError ( "xhr post error" , xhrStatus , context ) ;
260
- } ) ;
261
- }
262
-
263
- /**
264
- * Starts a poll cycle.
265
- *
266
- * @private
267
- */
268
- private doPoll ( ) {
269
- debug ( "xhr poll" ) ;
270
- const req = this . request ( ) ;
271
- req . on ( "data" , this . onData . bind ( this ) ) ;
272
- req . on ( "error" , ( xhrStatus , context ) => {
273
- this . onError ( "xhr poll error" , xhrStatus , context ) ;
274
- } ) ;
275
- this . pollXhr = req ;
276
- }
277
- }
278
-
279
- interface RequestReservedEvents {
280
- success : ( ) => void ;
281
- data : ( data : RawData ) => void ;
282
- error : ( err : number | Error , context : unknown ) => void ; // context should be typed as XMLHttpRequest, but this type is not available on non-browser platforms
283
- }
284
-
285
- export class Request extends Emitter < { } , { } , RequestReservedEvents > {
286
- private readonly opts : { xd ; cookieJar : CookieJar } & SocketOptions ;
287
- private readonly method : string ;
288
- private readonly uri : string ;
289
- private readonly data : string | ArrayBuffer ;
290
-
291
- private xhr : any ;
292
- private setTimeoutFn : typeof setTimeout ;
293
- private index : number ;
294
-
295
- static requestsCount = 0 ;
296
- static requests = { } ;
297
-
298
- /**
299
- * Request constructor
300
- *
301
- * @param {Object } options
302
- * @package
303
- */
304
- constructor ( uri , opts ) {
305
- super ( ) ;
306
- installTimerFunctions ( this , opts ) ;
307
- this . opts = opts ;
308
-
309
- this . method = opts . method || "GET" ;
310
- this . uri = uri ;
311
- this . data = undefined !== opts . data ? opts . data : null ;
312
-
313
- this . create ( ) ;
314
- }
315
-
316
- /**
317
- * Creates the XHR object and sends the request.
318
- *
319
- * @private
320
- */
321
- private create ( ) {
322
- const opts = pick (
323
- this . opts ,
324
- "agent" ,
325
- "pfx" ,
326
- "key" ,
327
- "passphrase" ,
328
- "cert" ,
329
- "ca" ,
330
- "ciphers" ,
331
- "rejectUnauthorized" ,
332
- "autoUnref"
333
- ) ;
334
- opts . xdomain = ! ! this . opts . xd ;
335
-
336
- const xhr = ( this . xhr = new XMLHttpRequest ( opts ) ) ;
337
-
338
- try {
339
- debug ( "xhr open %s: %s" , this . method , this . uri ) ;
340
- xhr . open ( this . method , this . uri , true ) ;
341
- try {
342
- if ( this . opts . extraHeaders ) {
343
- xhr . setDisableHeaderCheck && xhr . setDisableHeaderCheck ( true ) ;
344
- for ( let i in this . opts . extraHeaders ) {
345
- if ( this . opts . extraHeaders . hasOwnProperty ( i ) ) {
346
- xhr . setRequestHeader ( i , this . opts . extraHeaders [ i ] ) ;
347
- }
348
- }
349
- }
350
- } catch ( e ) { }
351
-
352
- if ( "POST" === this . method ) {
353
- try {
354
- xhr . setRequestHeader ( "Content-type" , "text/plain;charset=UTF-8" ) ;
355
- } catch ( e ) { }
356
- }
357
-
358
- try {
359
- xhr . setRequestHeader ( "Accept" , "*/*" ) ;
360
- } catch ( e ) { }
361
-
362
- this . opts . cookieJar ?. addCookies ( xhr ) ;
363
-
364
- // ie6 check
365
- if ( "withCredentials" in xhr ) {
366
- xhr . withCredentials = this . opts . withCredentials ;
367
- }
368
-
369
- if ( this . opts . requestTimeout ) {
370
- xhr . timeout = this . opts . requestTimeout ;
371
- }
372
-
373
- xhr . onreadystatechange = ( ) => {
374
- if ( xhr . readyState === 3 ) {
375
- this . opts . cookieJar ?. parseCookies ( xhr ) ;
376
- }
377
-
378
- if ( 4 !== xhr . readyState ) return ;
379
- if ( 200 === xhr . status || 1223 === xhr . status ) {
380
- this . onLoad ( ) ;
381
- } else {
382
- // make sure the `error` event handler that's user-set
383
- // does not throw in the same tick and gets caught here
384
- this . setTimeoutFn ( ( ) => {
385
- this . onError ( typeof xhr . status === "number" ? xhr . status : 0 ) ;
386
- } , 0 ) ;
387
- }
388
- } ;
389
-
390
- debug ( "xhr data %s" , this . data ) ;
391
- xhr . send ( this . data ) ;
392
- } catch ( e ) {
393
- // Need to defer since .create() is called directly from the constructor
394
- // and thus the 'error' event can only be only bound *after* this exception
395
- // occurs. Therefore, also, we cannot throw here at all.
396
- this . setTimeoutFn ( ( ) => {
397
- this . onError ( e ) ;
398
- } , 0 ) ;
399
- return ;
400
- }
401
-
402
- if ( typeof document !== "undefined" ) {
403
- this . index = Request . requestsCount ++ ;
404
- Request . requests [ this . index ] = this ;
405
- }
406
- }
407
-
408
- /**
409
- * Called upon error.
410
- *
411
- * @private
412
- */
413
- private onError ( err : number | Error ) {
414
- this . emitReserved ( "error" , err , this . xhr ) ;
415
- this . cleanup ( true ) ;
416
- }
417
-
418
- /**
419
- * Cleans up house.
420
- *
421
- * @private
422
- */
423
- private cleanup ( fromError ?) {
424
- if ( "undefined" === typeof this . xhr || null === this . xhr ) {
425
- return ;
426
- }
427
- this . xhr . onreadystatechange = empty ;
428
-
429
- if ( fromError ) {
430
- try {
431
- this . xhr . abort ( ) ;
432
- } catch ( e ) { }
433
- }
434
-
435
- if ( typeof document !== "undefined" ) {
436
- delete Request . requests [ this . index ] ;
437
- }
438
-
439
- this . xhr = null ;
440
- }
441
-
442
- /**
443
- * Called upon load.
444
- *
445
- * @private
446
- */
447
- private onLoad ( ) {
448
- const data = this . xhr . responseText ;
449
- if ( data !== null ) {
450
- this . emitReserved ( "data" , data ) ;
451
- this . emitReserved ( "success" ) ;
452
- this . cleanup ( ) ;
453
- }
454
- }
455
-
456
- /**
457
- * Aborts the request.
458
- *
459
- * @package
460
- */
461
- public abort ( ) {
462
- this . cleanup ( ) ;
463
- }
464
- }
465
-
466
- /**
467
- * Aborts pending requests when unloading the window. This is needed to prevent
468
- * memory leaks (e.g. when using IE) and to ensure that no spurious error is
469
- * emitted.
470
- */
471
-
472
- if ( typeof document !== "undefined" ) {
473
- // @ts -ignore
474
- if ( typeof attachEvent === "function" ) {
475
- // @ts -ignore
476
- attachEvent ( "onunload" , unloadHandler ) ;
477
- } else if ( typeof addEventListener === "function" ) {
478
- const terminationEvent = "onpagehide" in globalThis ? "pagehide" : "unload" ;
479
- addEventListener ( terminationEvent , unloadHandler , false ) ;
480
- }
481
- }
482
-
483
- function unloadHandler ( ) {
484
- for ( let i in Request . requests ) {
485
- if ( Request . requests . hasOwnProperty ( i ) ) {
486
- Request . requests [ i ] . abort ( ) ;
487
- }
488
- }
177
+ abstract doPoll ( ) ;
178
+ abstract doWrite ( data : string , callback : ( ) => void ) ;
489
179
}
0 commit comments