browser(firefox): instrument websockets (#4287)
This commit is contained in:
parent
914f6372ec
commit
18c3efe79e
|
|
@ -1,2 +1,2 @@
|
||||||
1197
|
1198
|
||||||
Changed: lushnikov@chromium.org Wed 28 Oct 2020 02:43:11 PM PDT
|
Changed: lushnikov@chromium.org Thu 29 Oct 2020 04:23:02 PM PDT
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@ class FrameTree {
|
||||||
this._browsingContextGroup.__jugglerFrameTrees.add(this);
|
this._browsingContextGroup.__jugglerFrameTrees.add(this);
|
||||||
this._scriptsToEvaluateOnNewDocument = new Map();
|
this._scriptsToEvaluateOnNewDocument = new Map();
|
||||||
|
|
||||||
|
this._webSocketEventService = Cc[
|
||||||
|
"@mozilla.org/websocketevent/service;1"
|
||||||
|
].getService(Ci.nsIWebSocketEventService);
|
||||||
|
|
||||||
this._bindings = new Map();
|
this._bindings = new Map();
|
||||||
this._runtime = new Runtime(false /* isWorker */);
|
this._runtime = new Runtime(false /* isWorker */);
|
||||||
this._workers = new Map();
|
this._workers = new Map();
|
||||||
|
|
@ -200,7 +204,7 @@ class FrameTree {
|
||||||
|
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
// Starting a new navigation.
|
// Starting a new navigation.
|
||||||
frame._pendingNavigationId = this._channelId(channel);
|
frame._pendingNavigationId = channelId(channel);
|
||||||
frame._pendingNavigationURL = channel.URI.spec;
|
frame._pendingNavigationURL = channel.URI.spec;
|
||||||
this.emit(FrameTree.Events.NavigationStarted, frame);
|
this.emit(FrameTree.Events.NavigationStarted, frame);
|
||||||
} else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) {
|
} else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) {
|
||||||
|
|
@ -241,14 +245,6 @@ class FrameTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_channelId(channel) {
|
|
||||||
if (channel instanceof Ci.nsIIdentChannel) {
|
|
||||||
const identChannel = channel.QueryInterface(Ci.nsIIdentChannel);
|
|
||||||
return String(identChannel.channelId);
|
|
||||||
}
|
|
||||||
return helper.generateId();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onDocShellCreated(docShell) {
|
_onDocShellCreated(docShell) {
|
||||||
// Bug 1142752: sometimes, the docshell appears to be immediately
|
// Bug 1142752: sometimes, the docshell appears to be immediately
|
||||||
// destroyed, bailout early to prevent random exceptions.
|
// destroyed, bailout early to prevent random exceptions.
|
||||||
|
|
@ -302,6 +298,11 @@ FrameTree.Events = {
|
||||||
GlobalObjectCreated: 'globalobjectcreated',
|
GlobalObjectCreated: 'globalobjectcreated',
|
||||||
WorkerCreated: 'workercreated',
|
WorkerCreated: 'workercreated',
|
||||||
WorkerDestroyed: 'workerdestroyed',
|
WorkerDestroyed: 'workerdestroyed',
|
||||||
|
WebSocketCreated: 'websocketcreated',
|
||||||
|
WebSocketOpened: 'websocketopened',
|
||||||
|
WebSocketClosed: 'websocketclosed',
|
||||||
|
WebSocketFrameReceived: 'websocketframereceived',
|
||||||
|
WebSocketFrameSent: 'websocketframesent',
|
||||||
NavigationStarted: 'navigationstarted',
|
NavigationStarted: 'navigationstarted',
|
||||||
NavigationCommitted: 'navigationcommitted',
|
NavigationCommitted: 'navigationcommitted',
|
||||||
NavigationAborted: 'navigationaborted',
|
NavigationAborted: 'navigationaborted',
|
||||||
|
|
@ -332,6 +333,90 @@ class Frame {
|
||||||
|
|
||||||
this._textInputProcessor = null;
|
this._textInputProcessor = null;
|
||||||
this._executionContext = null;
|
this._executionContext = null;
|
||||||
|
|
||||||
|
this._webSocketListenerInnerWindowId = 0;
|
||||||
|
// WebSocketListener calls frameReceived event before webSocketOpened.
|
||||||
|
// To avoid this, serialize event reporting.
|
||||||
|
this._webSocketInfos = new Map();
|
||||||
|
|
||||||
|
const dispatchWebSocketFrameReceived = (webSocketSerialID, frame) => this._frameTree.emit(FrameTree.Events.WebSocketFrameReceived, {
|
||||||
|
frameId: this._frameId,
|
||||||
|
wsid: webSocketSerialID + '',
|
||||||
|
opcode: frame.opCode,
|
||||||
|
data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload,
|
||||||
|
});
|
||||||
|
this._webSocketListener = {
|
||||||
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketEventListener, ]),
|
||||||
|
|
||||||
|
webSocketCreated: (webSocketSerialID, uri, protocols) => {
|
||||||
|
this._frameTree.emit(FrameTree.Events.WebSocketCreated, {
|
||||||
|
frameId: this._frameId,
|
||||||
|
wsid: webSocketSerialID + '',
|
||||||
|
requestURL: uri,
|
||||||
|
});
|
||||||
|
this._webSocketInfos.set(webSocketSerialID, {
|
||||||
|
opened: false,
|
||||||
|
pendingIncomingFrames: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
webSocketOpened: (webSocketSerialID, effectiveURI, protocols, extensions, httpChannelId) => {
|
||||||
|
this._frameTree.emit(FrameTree.Events.WebSocketOpened, {
|
||||||
|
frameId: this._frameId,
|
||||||
|
requestId: httpChannelId + '',
|
||||||
|
wsid: webSocketSerialID + '',
|
||||||
|
effectiveURL: effectiveURI,
|
||||||
|
});
|
||||||
|
const info = this._webSocketInfos.get(webSocketSerialID);
|
||||||
|
info.opened = true;
|
||||||
|
for (const frame of info.pendingIncomingFrames)
|
||||||
|
dispatchWebSocketFrameReceived(webSocketSerialID, frame);
|
||||||
|
},
|
||||||
|
|
||||||
|
webSocketMessageAvailable: (webSocketSerialID, data, messageType) => {
|
||||||
|
// We don't use this event.
|
||||||
|
},
|
||||||
|
|
||||||
|
webSocketClosed: (webSocketSerialID, wasClean, code, reason) => {
|
||||||
|
this._webSocketInfos.delete(webSocketSerialID);
|
||||||
|
let error = '';
|
||||||
|
if (!wasClean) {
|
||||||
|
const keys = Object.keys(Ci.nsIWebSocketChannel);
|
||||||
|
for (const key of keys) {
|
||||||
|
if (Ci.nsIWebSocketChannel[key] === code)
|
||||||
|
error = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._frameTree.emit(FrameTree.Events.WebSocketClosed, {
|
||||||
|
frameId: this._frameId,
|
||||||
|
wsid: webSocketSerialID + '',
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
frameReceived: (webSocketSerialID, frame) => {
|
||||||
|
// Report only text and binary frames.
|
||||||
|
if (frame.opCode !== 1 && frame.opCode !== 2)
|
||||||
|
return;
|
||||||
|
const info = this._webSocketInfos.get(webSocketSerialID);
|
||||||
|
if (info.opened)
|
||||||
|
dispatchWebSocketFrameReceived(webSocketSerialID, frame);
|
||||||
|
else
|
||||||
|
info.pendingIncomingFrames.push(frame);
|
||||||
|
},
|
||||||
|
|
||||||
|
frameSent: (webSocketSerialID, frame) => {
|
||||||
|
// Report only text and binary frames.
|
||||||
|
if (frame.opCode !== 1 && frame.opCode !== 2)
|
||||||
|
return;
|
||||||
|
this._frameTree.emit(FrameTree.Events.WebSocketFrameSent, {
|
||||||
|
frameId: this._frameId,
|
||||||
|
wsid: webSocketSerialID + '',
|
||||||
|
opcode: frame.opCode,
|
||||||
|
data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
|
|
@ -354,6 +439,12 @@ class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGlobalObjectCleared() {
|
_onGlobalObjectCleared() {
|
||||||
|
const webSocketService = this._frameTree._webSocketEventService;
|
||||||
|
if (this._webSocketListenerInnerWindowId)
|
||||||
|
webSocketService.removeListener(this._webSocketListenerInnerWindowId, this._webSocketListener);
|
||||||
|
this._webSocketListenerInnerWindowId = this.domWindow().windowGlobalChild.innerWindowId;
|
||||||
|
webSocketService.addListener(this._webSocketListenerInnerWindowId, this._webSocketListener);
|
||||||
|
|
||||||
if (this._executionContext)
|
if (this._executionContext)
|
||||||
this._runtime.destroyExecutionContext(this._executionContext);
|
this._runtime.destroyExecutionContext(this._executionContext);
|
||||||
this._executionContext = this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), {
|
this._executionContext = this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), {
|
||||||
|
|
@ -473,6 +564,15 @@ class Worker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function channelId(channel) {
|
||||||
|
if (channel instanceof Ci.nsIIdentChannel) {
|
||||||
|
const identChannel = channel.QueryInterface(Ci.nsIIdentChannel);
|
||||||
|
return String(identChannel.channelId);
|
||||||
|
}
|
||||||
|
return helper.generateId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ['FrameTree'];
|
var EXPORTED_SYMBOLS = ['FrameTree'];
|
||||||
this.FrameTree = FrameTree;
|
this.FrameTree = FrameTree;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,11 @@ class PageAgent {
|
||||||
helper.on(this._frameTree, 'pageready', () => this._browserPage.emit('pageReady', {})),
|
helper.on(this._frameTree, 'pageready', () => this._browserPage.emit('pageReady', {})),
|
||||||
helper.on(this._frameTree, 'workercreated', this._onWorkerCreated.bind(this)),
|
helper.on(this._frameTree, 'workercreated', this._onWorkerCreated.bind(this)),
|
||||||
helper.on(this._frameTree, 'workerdestroyed', this._onWorkerDestroyed.bind(this)),
|
helper.on(this._frameTree, 'workerdestroyed', this._onWorkerDestroyed.bind(this)),
|
||||||
|
helper.on(this._frameTree, 'websocketcreated', event => this._browserPage.emit('webSocketCreated', event)),
|
||||||
|
helper.on(this._frameTree, 'websocketopened', event => this._browserPage.emit('webSocketOpened', event)),
|
||||||
|
helper.on(this._frameTree, 'websocketframesent', event => this._browserPage.emit('webSocketFrameSent', event)),
|
||||||
|
helper.on(this._frameTree, 'websocketframereceived', event => this._browserPage.emit('webSocketFrameReceived', event)),
|
||||||
|
helper.on(this._frameTree, 'websocketclosed', event => this._browserPage.emit('webSocketClosed', event)),
|
||||||
helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'),
|
helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'),
|
||||||
this._runtime.events.onErrorFromWorker((domWindow, message, stack) => {
|
this._runtime.events.onErrorFromWorker((domWindow, message, stack) => {
|
||||||
const frame = this._frameTree.frameForDocShell(domWindow.docShell);
|
const frame = this._frameTree.frameForDocShell(domWindow.docShell);
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,12 @@ class PageHandler {
|
||||||
runtimeConsole: emitProtocolEvent('Runtime.console'),
|
runtimeConsole: emitProtocolEvent('Runtime.console'),
|
||||||
runtimeExecutionContextCreated: emitProtocolEvent('Runtime.executionContextCreated'),
|
runtimeExecutionContextCreated: emitProtocolEvent('Runtime.executionContextCreated'),
|
||||||
runtimeExecutionContextDestroyed: emitProtocolEvent('Runtime.executionContextDestroyed'),
|
runtimeExecutionContextDestroyed: emitProtocolEvent('Runtime.executionContextDestroyed'),
|
||||||
|
|
||||||
|
webSocketCreated: emitProtocolEvent('Page.webSocketCreated'),
|
||||||
|
webSocketOpened: emitProtocolEvent('Page.webSocketOpened'),
|
||||||
|
webSocketClosed: emitProtocolEvent('Page.webSocketClosed'),
|
||||||
|
webSocketFrameReceived: emitProtocolEvent('Page.webSocketFrameReceived'),
|
||||||
|
webSocketFrameSent: emitProtocolEvent('Page.webSocketFrameSent'),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -668,6 +668,34 @@ const Page = {
|
||||||
screencastId: t.String,
|
screencastId: t.String,
|
||||||
file: t.String,
|
file: t.String,
|
||||||
},
|
},
|
||||||
|
'webSocketCreated': {
|
||||||
|
frameId: t.String,
|
||||||
|
wsid: t.String,
|
||||||
|
requestURL: t.String,
|
||||||
|
},
|
||||||
|
'webSocketOpened': {
|
||||||
|
frameId: t.String,
|
||||||
|
requestId: t.String,
|
||||||
|
wsid: t.String,
|
||||||
|
effectiveURL: t.String,
|
||||||
|
},
|
||||||
|
'webSocketClosed': {
|
||||||
|
frameId: t.String,
|
||||||
|
wsid: t.String,
|
||||||
|
error: t.String,
|
||||||
|
},
|
||||||
|
'webSocketFrameSent': {
|
||||||
|
frameId: t.String,
|
||||||
|
wsid: t.String,
|
||||||
|
opcode: t.Number,
|
||||||
|
data: t.String,
|
||||||
|
},
|
||||||
|
'webSocketFrameReceived': {
|
||||||
|
frameId: t.String,
|
||||||
|
wsid: t.String,
|
||||||
|
opcode: t.Number,
|
||||||
|
data: t.String,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue