зеркало из https://github.com/mozilla/gecko-dev.git
Bug 832983 - Basic support for adding xhr breakpoints r=jlast
Differential Revision: https://phabricator.services.mozilla.com/D5662 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
eeaa237703
Коммит
efdb07ca38
|
@ -7,7 +7,7 @@
|
|||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { Cr } = require("chrome");
|
||||
const { Cr, Ci } = require("chrome");
|
||||
const { ActorPool, GeneratedLocation } = require("devtools/server/actors/common");
|
||||
const { createValueGrip } = require("devtools/server/actors/object/utils");
|
||||
const { longStringGrip } = require("devtools/server/actors/object/long-string");
|
||||
|
@ -64,6 +64,8 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this._parentClosed = false;
|
||||
this._scripts = null;
|
||||
this._pauseOnDOMEvents = null;
|
||||
this._xhrBreakpoints = [];
|
||||
this._observingNetwork = false;
|
||||
|
||||
this._options = {
|
||||
useSourceMaps: false,
|
||||
|
@ -92,7 +94,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this.objectGrip = this.objectGrip.bind(this);
|
||||
this.pauseObjectGrip = this.pauseObjectGrip.bind(this);
|
||||
this._onWindowReady = this._onWindowReady.bind(this);
|
||||
this._onOpeningRequest = this._onOpeningRequest.bind(this);
|
||||
EventEmitter.on(this._parent, "window-ready", this._onWindowReady);
|
||||
|
||||
// Set a wrappedJSObject property so |this| can be sent via the observer svc
|
||||
// for the xpcshell harness.
|
||||
this.wrappedJSObject = this;
|
||||
|
@ -228,6 +232,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
// things like breakpoints across connections.
|
||||
this._sourceActorStore = null;
|
||||
|
||||
this._xhrBreakpoints = [];
|
||||
this._updateNetworkObserver();
|
||||
|
||||
EventEmitter.off(this._parent, "window-ready", this._onWindowReady);
|
||||
this.sources.off("newSource", this.onNewSourceEvent);
|
||||
this.sources.off("updatedSource", this.onUpdatedSourceEvent);
|
||||
|
@ -317,6 +324,100 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
}
|
||||
},
|
||||
|
||||
_findXHRBreakpointIndex(p, m) {
|
||||
return this._xhrBreakpoints.findIndex(
|
||||
({ path, method }) => path === p && method === m);
|
||||
},
|
||||
|
||||
removeXHRBreakpoint: function(path, method) {
|
||||
const index = this._findXHRBreakpointIndex(path, method);
|
||||
|
||||
if (index >= 0) {
|
||||
this._xhrBreakpoints.splice(index, 1);
|
||||
}
|
||||
return this._updateNetworkObserver();
|
||||
},
|
||||
|
||||
setXHRBreakpoint: function(path, method) {
|
||||
// request.path is a string,
|
||||
// If requested url contains the path, then we pause.
|
||||
const index = this._findXHRBreakpointIndex(path, method);
|
||||
|
||||
if (index === -1) {
|
||||
this._xhrBreakpoints.push({ path, method });
|
||||
}
|
||||
return this._updateNetworkObserver();
|
||||
},
|
||||
|
||||
_updateNetworkObserver() {
|
||||
// Workers don't have access to `Services` and even if they did, network
|
||||
// requests are all dispatched to the main thread, so there would be
|
||||
// nothing here to listen for. We'll need to revisit implementing
|
||||
// XHR breakpoints for workers.
|
||||
if (isWorker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._xhrBreakpoints.length > 0 && !this._observingNetwork) {
|
||||
this._observingNetwork = true;
|
||||
Services.obs.addObserver(this._onOpeningRequest, "http-on-opening-request");
|
||||
} else if (this._xhrBreakpoints.length === 0 && this._observingNetwork) {
|
||||
this._observingNetwork = false;
|
||||
Services.obs.removeObserver(this._onOpeningRequest, "http-on-opening-request");
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_onOpeningRequest: function(subject) {
|
||||
if (this.skipBreakpoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
const url = channel.URI.asciiSpec;
|
||||
const requestMethod = channel.requestMethod;
|
||||
|
||||
let causeType = Ci.nsIContentPolicy.TYPE_OTHER;
|
||||
if (channel.loadInfo) {
|
||||
causeType = channel.loadInfo.externalContentPolicyType;
|
||||
}
|
||||
|
||||
const isXHR = (
|
||||
causeType === Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST ||
|
||||
causeType === Ci.nsIContentPolicy.TYPE_FETCH
|
||||
);
|
||||
|
||||
if (!isXHR) {
|
||||
// We currently break only if the request is either fetch or xhr
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldPause = false;
|
||||
for (const { path, method } of this._xhrBreakpoints) {
|
||||
if (method !== "ANY" && method !== requestMethod) {
|
||||
continue;
|
||||
}
|
||||
if (url.includes(path)) {
|
||||
shouldPause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPause) {
|
||||
const frame = this.dbg.getNewestFrame();
|
||||
|
||||
// If there is no frame, this request was dispatched by logic that isn't
|
||||
// primarily JS, so pausing the event loop wouldn't make sense.
|
||||
// This covers background requests like loading the initial page document,
|
||||
// or loading favicons. This also includes requests dispatched indirectly
|
||||
// from workers. We'll need to handle them separately in the future.
|
||||
if (frame) {
|
||||
this._pauseAndRespond(frame, { type: "XHR" });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onDetach: function(request) {
|
||||
this.destroy();
|
||||
this._state = "detached";
|
||||
|
|
|
@ -3,12 +3,31 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {generateActorSpec} = require("devtools/shared/protocol");
|
||||
const {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
|
||||
|
||||
const threadSpec = generateActorSpec({
|
||||
typeName: "context",
|
||||
|
||||
methods: {},
|
||||
methods: {
|
||||
setXHRBreakpoint: {
|
||||
request: {
|
||||
path: Arg(0, "string"),
|
||||
method: Arg(1, "string")
|
||||
},
|
||||
response: {
|
||||
value: RetVal("boolean")
|
||||
}
|
||||
},
|
||||
removeXHRBreakpoint: {
|
||||
request: {
|
||||
path: Arg(0, "string"),
|
||||
method: Arg(1, "string")
|
||||
},
|
||||
response: {
|
||||
value: RetVal("boolean")
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
exports.threadSpec = threadSpec;
|
||||
|
|
Загрузка…
Ссылка в новой задаче