@@ -24,6 +24,10 @@ class FrameTree {
24
24
this . _browsingContextGroup . __jugglerFrameTrees . add ( this ) ;
25
25
this . _scriptsToEvaluateOnNewDocument = new Map ( ) ;
26
26
27
+ this . _webSocketEventService = Cc [
28
+ "@mozilla.org/websocketevent/service;1"
29
+ ] . getService ( Ci . nsIWebSocketEventService ) ;
30
+
27
31
this . _bindings = new Map ( ) ;
28
32
this . _runtime = new Runtime ( false /* isWorker */ ) ;
29
33
this . _workers = new Map ( ) ;
@@ -200,7 +204,7 @@ class FrameTree {
200
204
201
205
if ( isStart ) {
202
206
// Starting a new navigation.
203
- frame . _pendingNavigationId = this . _channelId ( channel ) ;
207
+ frame . _pendingNavigationId = channelId ( channel ) ;
204
208
frame . _pendingNavigationURL = channel . URI . spec ;
205
209
this . emit ( FrameTree . Events . NavigationStarted , frame ) ;
206
210
} else if ( isTransferring || ( isStop && frame . _pendingNavigationId && ! status ) ) {
@@ -241,14 +245,6 @@ class FrameTree {
241
245
}
242
246
}
243
247
244
- _channelId ( channel ) {
245
- if ( channel instanceof Ci . nsIIdentChannel ) {
246
- const identChannel = channel . QueryInterface ( Ci . nsIIdentChannel ) ;
247
- return String ( identChannel . channelId ) ;
248
- }
249
- return helper . generateId ( ) ;
250
- }
251
-
252
248
_onDocShellCreated ( docShell ) {
253
249
// Bug 1142752: sometimes, the docshell appears to be immediately
254
250
// destroyed, bailout early to prevent random exceptions.
@@ -302,6 +298,11 @@ FrameTree.Events = {
302
298
GlobalObjectCreated : 'globalobjectcreated' ,
303
299
WorkerCreated : 'workercreated' ,
304
300
WorkerDestroyed : 'workerdestroyed' ,
301
+ WebSocketCreated : 'websocketcreated' ,
302
+ WebSocketOpened : 'websocketopened' ,
303
+ WebSocketClosed : 'websocketclosed' ,
304
+ WebSocketFrameReceived : 'websocketframereceived' ,
305
+ WebSocketFrameSent : 'websocketframesent' ,
305
306
NavigationStarted : 'navigationstarted' ,
306
307
NavigationCommitted : 'navigationcommitted' ,
307
308
NavigationAborted : 'navigationaborted' ,
@@ -332,6 +333,90 @@ class Frame {
332
333
333
334
this . _textInputProcessor = null ;
334
335
this . _executionContext = null ;
336
+
337
+ this . _webSocketListenerInnerWindowId = 0 ;
338
+ // WebSocketListener calls frameReceived event before webSocketOpened.
339
+ // To avoid this, serialize event reporting.
340
+ this . _webSocketInfos = new Map ( ) ;
341
+
342
+ const dispatchWebSocketFrameReceived = ( webSocketSerialID , frame ) => this . _frameTree . emit ( FrameTree . Events . WebSocketFrameReceived , {
343
+ frameId : this . _frameId ,
344
+ wsid : webSocketSerialID + '' ,
345
+ opcode : frame . opCode ,
346
+ data : frame . opCode !== 1 ? btoa ( frame . payload ) : frame . payload ,
347
+ } ) ;
348
+ this . _webSocketListener = {
349
+ QueryInterface : ChromeUtils . generateQI ( [ Ci . nsIWebSocketEventListener , ] ) ,
350
+
351
+ webSocketCreated : ( webSocketSerialID , uri , protocols ) => {
352
+ this . _frameTree . emit ( FrameTree . Events . WebSocketCreated , {
353
+ frameId : this . _frameId ,
354
+ wsid : webSocketSerialID + '' ,
355
+ requestURL : uri ,
356
+ } ) ;
357
+ this . _webSocketInfos . set ( webSocketSerialID , {
358
+ opened : false ,
359
+ pendingIncomingFrames : [ ] ,
360
+ } ) ;
361
+ } ,
362
+
363
+ webSocketOpened : ( webSocketSerialID , effectiveURI , protocols , extensions , httpChannelId ) => {
364
+ this . _frameTree . emit ( FrameTree . Events . WebSocketOpened , {
365
+ frameId : this . _frameId ,
366
+ requestId : httpChannelId + '' ,
367
+ wsid : webSocketSerialID + '' ,
368
+ effectiveURL : effectiveURI ,
369
+ } ) ;
370
+ const info = this . _webSocketInfos . get ( webSocketSerialID ) ;
371
+ info . opened = true ;
372
+ for ( const frame of info . pendingIncomingFrames )
373
+ dispatchWebSocketFrameReceived ( webSocketSerialID , frame ) ;
374
+ } ,
375
+
376
+ webSocketMessageAvailable : ( webSocketSerialID , data , messageType ) => {
377
+ // We don't use this event.
378
+ } ,
379
+
380
+ webSocketClosed : ( webSocketSerialID , wasClean , code , reason ) => {
381
+ this . _webSocketInfos . delete ( webSocketSerialID ) ;
382
+ let error = '' ;
383
+ if ( ! wasClean ) {
384
+ const keys = Object . keys ( Ci . nsIWebSocketChannel ) ;
385
+ for ( const key of keys ) {
386
+ if ( Ci . nsIWebSocketChannel [ key ] === code )
387
+ error = key ;
388
+ }
389
+ }
390
+ this . _frameTree . emit ( FrameTree . Events . WebSocketClosed , {
391
+ frameId : this . _frameId ,
392
+ wsid : webSocketSerialID + '' ,
393
+ error,
394
+ } ) ;
395
+ } ,
396
+
397
+ frameReceived : ( webSocketSerialID , frame ) => {
398
+ // Report only text and binary frames.
399
+ if ( frame . opCode !== 1 && frame . opCode !== 2 )
400
+ return ;
401
+ const info = this . _webSocketInfos . get ( webSocketSerialID ) ;
402
+ if ( info . opened )
403
+ dispatchWebSocketFrameReceived ( webSocketSerialID , frame ) ;
404
+ else
405
+ info . pendingIncomingFrames . push ( frame ) ;
406
+ } ,
407
+
408
+ frameSent : ( webSocketSerialID , frame ) => {
409
+ // Report only text and binary frames.
410
+ if ( frame . opCode !== 1 && frame . opCode !== 2 )
411
+ return ;
412
+ this . _frameTree . emit ( FrameTree . Events . WebSocketFrameSent , {
413
+ frameId : this . _frameId ,
414
+ wsid : webSocketSerialID + '' ,
415
+ opcode : frame . opCode ,
416
+ data : frame . opCode !== 1 ? btoa ( frame . payload ) : frame . payload ,
417
+ } ) ;
418
+ } ,
419
+ } ;
335
420
}
336
421
337
422
dispose ( ) {
@@ -354,6 +439,12 @@ class Frame {
354
439
}
355
440
356
441
_onGlobalObjectCleared ( ) {
442
+ const webSocketService = this . _frameTree . _webSocketEventService ;
443
+ if ( this . _webSocketListenerInnerWindowId )
444
+ webSocketService . removeListener ( this . _webSocketListenerInnerWindowId , this . _webSocketListener ) ;
445
+ this . _webSocketListenerInnerWindowId = this . domWindow ( ) . windowGlobalChild . innerWindowId ;
446
+ webSocketService . addListener ( this . _webSocketListenerInnerWindowId , this . _webSocketListener ) ;
447
+
357
448
if ( this . _executionContext )
358
449
this . _runtime . destroyExecutionContext ( this . _executionContext ) ;
359
450
this . _executionContext = this . _runtime . createExecutionContext ( this . domWindow ( ) , this . domWindow ( ) , {
@@ -473,6 +564,15 @@ class Worker {
473
564
}
474
565
}
475
566
567
+ function channelId ( channel ) {
568
+ if ( channel instanceof Ci . nsIIdentChannel ) {
569
+ const identChannel = channel . QueryInterface ( Ci . nsIIdentChannel ) ;
570
+ return String ( identChannel . channelId ) ;
571
+ }
572
+ return helper . generateId ( ) ;
573
+ }
574
+
575
+
476
576
var EXPORTED_SYMBOLS = [ 'FrameTree' ] ;
477
577
this . FrameTree = FrameTree ;
478
578
0 commit comments