forked from mirrors/gecko-dev
Bug 1693495 - [devtools] Implement a beginning of "Network" commands, starting with sendHTTPRequest. r=devtools-reviewers,nchevobbe
Use new "commands" thunk argument. We were passing connector as argument whereas we could have fetched it from thunk arguments. This will help slowly convert Connector/NetMonitorAPI to a command. Differential Revision: https://phabricator.services.mozilla.com/D166055
This commit is contained in:
parent
00c3224b88
commit
b642d61aff
22 changed files with 178 additions and 44 deletions
|
|
@ -165,6 +165,7 @@ const extraBrowserTestPaths = [
|
|||
"devtools/client/styleeditor/test/",
|
||||
"devtools/shared/commands/inspected-window/tests/",
|
||||
"devtools/shared/commands/inspector/tests/",
|
||||
"devtools/shared/commands/network/tests/",
|
||||
"devtools/shared/commands/resource/tests/",
|
||||
"devtools/shared/commands/script/tests/",
|
||||
"devtools/shared/commands/target-configuration/tests/",
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ function toggleHTTPCustomRequestPanel() {
|
|||
/**
|
||||
* Send a new HTTP request using the data in the custom request form.
|
||||
*/
|
||||
function sendHTTPCustomRequest(connector, request) {
|
||||
return async ({ dispatch, getState }) => {
|
||||
function sendHTTPCustomRequest(request) {
|
||||
return async ({ dispatch, getState, connector, commands }) => {
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ function sendHTTPCustomRequest(connector, request) {
|
|||
data.body = request.requestPostData.postData?.text;
|
||||
}
|
||||
|
||||
const { channelId } = await connector.sendHTTPRequest(data);
|
||||
const { channelId } = await commands.networkCommand.sendHTTPRequest(data);
|
||||
|
||||
const newRequest = getRequestByChannelId(getState(), channelId);
|
||||
// If the new custom request is available already select the request, else
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ function cloneSelectedRequest() {
|
|||
/**
|
||||
* Send a new HTTP request using the data in the custom request form.
|
||||
*/
|
||||
function sendCustomRequest(connector, requestId = null) {
|
||||
return async ({ dispatch, getState }) => {
|
||||
function sendCustomRequest(requestId = null) {
|
||||
return async ({ dispatch, getState, connector, commands }) => {
|
||||
let request;
|
||||
if (requestId) {
|
||||
request = getRequestById(getState(), requestId);
|
||||
|
|
@ -123,13 +123,11 @@ function sendCustomRequest(connector, requestId = null) {
|
|||
data.body = request.requestPostData.postData.text;
|
||||
}
|
||||
|
||||
// @backward-compat { version 85 } Introduced `channelId` to eventually
|
||||
// replace `actor`.
|
||||
const { channelId, actor } = await connector.sendHTTPRequest(data);
|
||||
const { channelId } = await commands.networkCommand.sendHTTPRequest(data);
|
||||
|
||||
dispatch({
|
||||
type: SEND_CUSTOM_REQUEST,
|
||||
id: channelId || actor,
|
||||
id: channelId,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ NetMonitorAPI.prototype = {
|
|||
this.store.dispatch(Actions.batchFlush());
|
||||
// Send custom request with same url, headers and body as the request
|
||||
// with the given requestId.
|
||||
this.store.dispatch(Actions.sendCustomRequest(this.connector, requestId));
|
||||
this.store.dispatch(Actions.sendCustomRequest(requestId));
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -369,8 +369,7 @@ module.exports = connect(
|
|||
(dispatch, props) => ({
|
||||
removeSelectedCustomRequest: () =>
|
||||
dispatch(Actions.removeSelectedCustomRequest()),
|
||||
sendCustomRequest: () =>
|
||||
dispatch(Actions.sendCustomRequest(props.connector)),
|
||||
sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
|
||||
updateRequest: (id, data, batch) =>
|
||||
dispatch(Actions.updateRequest(id, data, batch)),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -507,6 +507,6 @@ module.exports = connect(
|
|||
state => ({ request: getClickedRequest(state) }),
|
||||
(dispatch, props) => ({
|
||||
sendCustomRequest: request =>
|
||||
dispatch(Actions.sendHTTPCustomRequest(props.connector, request)),
|
||||
dispatch(Actions.sendHTTPCustomRequest(request)),
|
||||
})
|
||||
)(HTTPCustomRequestPanel);
|
||||
|
|
|
|||
|
|
@ -845,7 +845,6 @@ module.exports = connect(
|
|||
openHTTPCustomRequestTab: () =>
|
||||
dispatch(Actions.openHTTPCustomRequest(true)),
|
||||
cloneRequest: id => dispatch(Actions.cloneRequest(id)),
|
||||
sendCustomRequest: () =>
|
||||
dispatch(Actions.sendCustomRequest(props.connector)),
|
||||
sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
|
||||
})
|
||||
)(HeadersPanel);
|
||||
|
|
|
|||
|
|
@ -482,10 +482,9 @@ module.exports = connect(
|
|||
dispatch(Actions.openHTTPCustomRequest(true)),
|
||||
closeHTTPCustomRequestTab: () =>
|
||||
dispatch(Actions.openHTTPCustomRequest(false)),
|
||||
sendCustomRequest: () =>
|
||||
dispatch(Actions.sendCustomRequest(props.connector)),
|
||||
sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
|
||||
sendHTTPCustomRequest: request =>
|
||||
dispatch(Actions.sendHTTPCustomRequest(props.connector, request)),
|
||||
dispatch(Actions.sendHTTPCustomRequest(request)),
|
||||
openStatistics: open =>
|
||||
dispatch(Actions.openStatistics(props.connector, open)),
|
||||
openRequestBlockingAndAddUrl: url =>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class Connector {
|
|||
this.disconnect = this.disconnect.bind(this);
|
||||
this.willNavigate = this.willNavigate.bind(this);
|
||||
this.navigate = this.navigate.bind(this);
|
||||
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
|
||||
this.triggerActivity = this.triggerActivity.bind(this);
|
||||
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
|
||||
this.requestData = this.requestData.bind(this);
|
||||
|
|
@ -76,6 +75,7 @@ class Connector {
|
|||
this.getState = getState;
|
||||
this.toolbox = connection.toolbox;
|
||||
this.commands = this.toolbox.commands;
|
||||
this.networkCommand = this.commands.networkCommand;
|
||||
|
||||
// The owner object (NetMonitorAPI) received all events.
|
||||
this.owner = connection.owner;
|
||||
|
|
@ -344,19 +344,6 @@ class Connector {
|
|||
this.emitForTests(TEST_EVENTS.TIMELINE_EVENT, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a HTTP request data payload
|
||||
*
|
||||
* @param {object} data data payload would like to sent to backend
|
||||
*/
|
||||
async sendHTTPRequest(data) {
|
||||
const networkContentFront = await this.currentTarget.getFront(
|
||||
"networkContent"
|
||||
);
|
||||
const { channelId } = await networkContentFront.sendHTTPRequest(data);
|
||||
return { channelId };
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the list of blocked URLs
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ add_task(async function() {
|
|||
info("Starting test... ");
|
||||
|
||||
const { document, store, windowRequire, connector } = monitor.panelWin;
|
||||
const { sendHTTPRequest } = connector;
|
||||
|
||||
// Action should be processed synchronously in tests.
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
|
@ -50,7 +48,7 @@ add_task(async function() {
|
|||
},
|
||||
};
|
||||
const waitUntilRequestDisplayed = waitForNetworkEvents(monitor, 1);
|
||||
sendHTTPRequest(request);
|
||||
connector.networkCommand.sendHTTPRequest(request);
|
||||
await waitUntilRequestDisplayed;
|
||||
|
||||
info("selecting first request");
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ async function testOldEditAndResendPanel() {
|
|||
});
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, store, windowRequire, connector } = monitor.panelWin;
|
||||
const { document, store, windowRequire } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
const { getSelectedRequest, getSortedRequests } = windowRequire(
|
||||
"devtools/client/netmonitor/src/selectors/index"
|
||||
|
|
@ -214,7 +214,7 @@ async function testOldEditAndResendPanel() {
|
|||
|
||||
// send the new request
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
store.dispatch(Actions.sendCustomRequest(connector));
|
||||
store.dispatch(Actions.sendCustomRequest());
|
||||
await wait;
|
||||
|
||||
let sentItem;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ add_task(async function() {
|
|||
store.dispatch(Actions.cloneRequest(item.id));
|
||||
|
||||
info("Sending the cloned request (without change)");
|
||||
store.dispatch(Actions.sendCustomRequest(connector, item.id));
|
||||
store.dispatch(Actions.sendCustomRequest(item.id));
|
||||
|
||||
await waitUntil(
|
||||
() => getSortedRequests(store.getState()).length === length + 1
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ add_task(async function() {
|
|||
|
||||
const { store, windowRequire, connector } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
const { requestData, sendHTTPRequest } = connector;
|
||||
const { requestData } = connector;
|
||||
const { getSortedRequests } = windowRequire(
|
||||
"devtools/client/netmonitor/src/selectors/index"
|
||||
);
|
||||
|
|
@ -33,7 +33,7 @@ add_task(async function() {
|
|||
];
|
||||
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
sendHTTPRequest({
|
||||
connector.networkCommand.sendHTTPRequest({
|
||||
url: requestUrl,
|
||||
method: "POST",
|
||||
headers: requestHeaders,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ add_task(async function() {
|
|||
|
||||
const { store, windowRequire, connector } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
const { sendHTTPRequest } = connector;
|
||||
|
||||
const { getSortedRequests } = windowRequire(
|
||||
"devtools/client/netmonitor/src/selectors/index"
|
||||
|
|
@ -29,7 +28,7 @@ add_task(async function() {
|
|||
];
|
||||
|
||||
const originalRequest = waitForNetworkEvents(monitor, 1);
|
||||
sendHTTPRequest({
|
||||
connector.networkCommand.sendHTTPRequest({
|
||||
url: requestUrl,
|
||||
method: "GET",
|
||||
headers: requestHeaders,
|
||||
|
|
@ -49,7 +48,7 @@ add_task(async function() {
|
|||
|
||||
const clonedRequest = waitForNetworkEvents(monitor, 1);
|
||||
|
||||
store.dispatch(Actions.sendCustomRequest(connector, originalItem.id));
|
||||
store.dispatch(Actions.sendCustomRequest(originalItem.id));
|
||||
|
||||
await clonedRequest;
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ function NetworkEventMessage({
|
|||
getLongString: grip => {
|
||||
return serviceContainer.getLongString(grip);
|
||||
},
|
||||
sendHTTPRequest: () => {},
|
||||
triggerActivity: () => {},
|
||||
requestData: (requestId, dataType) => {
|
||||
return serviceContainer.requestData(requestId, dataType);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const Commands = {
|
|||
inspectedWindowCommand:
|
||||
"devtools/shared/commands/inspected-window/inspected-window-command",
|
||||
inspectorCommand: "devtools/shared/commands/inspector/inspector-command",
|
||||
networkCommand: "devtools/shared/commands/network/network-command",
|
||||
resourceCommand: "devtools/shared/commands/resource/resource-command",
|
||||
rootResourceCommand:
|
||||
"devtools/shared/commands/root-resource/root-resource-command",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
DIRS += [
|
||||
"inspected-window",
|
||||
"inspector",
|
||||
"network",
|
||||
"resource",
|
||||
"root-resource",
|
||||
"script",
|
||||
|
|
|
|||
10
devtools/shared/commands/network/moz.build
Normal file
10
devtools/shared/commands/network/moz.build
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
"network-command.js",
|
||||
)
|
||||
|
||||
if CONFIG["MOZ_BUILD_APP"] != "mobile/android":
|
||||
BROWSER_CHROME_MANIFESTS += ["tests/browser.ini"]
|
||||
42
devtools/shared/commands/network/network-command.js
Normal file
42
devtools/shared/commands/network/network-command.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
class NetworkCommand {
|
||||
/**
|
||||
* This class helps listen, inspect and control network requests.
|
||||
*
|
||||
* @param {DescriptorFront} descriptorFront
|
||||
* The context to inspect identified by this descriptor.
|
||||
* @param {WatcherFront} watcherFront
|
||||
* If available, a reference to the related Watcher Front.
|
||||
* @param {Object} commands
|
||||
* The commands object with all interfaces defined from devtools/shared/commands/
|
||||
*/
|
||||
constructor({ descriptorFront, watcherFront, commands }) {
|
||||
this.commands = commands;
|
||||
this.descriptorFront = descriptorFront;
|
||||
this.watcherFront = watcherFront;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a HTTP request data payload
|
||||
*
|
||||
* @param {object} data data payload would like to sent to backend
|
||||
*/
|
||||
async sendHTTPRequest(data) {
|
||||
// By default use the top-level target, but we might at some point
|
||||
// allow using another target.
|
||||
const networkContentFront = await this.commands.targetCommand.targetFront.getFront(
|
||||
"networkContent"
|
||||
);
|
||||
const { channelId } = await networkContentFront.sendHTTPRequest(data);
|
||||
return { channelId };
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
}
|
||||
|
||||
module.exports = NetworkCommand;
|
||||
10
devtools/shared/commands/network/tests/browser.ini
Normal file
10
devtools/shared/commands/network/tests/browser.ini
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
!/devtools/client/shared/test/highlighter-test-actor.js
|
||||
head.js
|
||||
|
||||
[browser_network_command_sendHTTPRequest.js]
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test the NetworkCommand's sendHTTPRequest
|
||||
|
||||
add_task(async function() {
|
||||
info("Test NetworkCommand.sendHTTPRequest");
|
||||
const tab = await addTab("data:text/html,foo");
|
||||
const commands = await CommandsFactory.forTab(tab);
|
||||
|
||||
// We have to ensure TargetCommand is initialized to have access to the top level target
|
||||
// from NetworkCommand.sendHTTPRequest
|
||||
await commands.targetCommand.startListening();
|
||||
|
||||
const { networkCommand } = commands;
|
||||
|
||||
const httpServer = createTestHTTPServer();
|
||||
const onRequest = new Promise(resolve => {
|
||||
httpServer.registerPathHandler(
|
||||
"/http-request.html",
|
||||
(request, response) => {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.write("Response body");
|
||||
resolve(request);
|
||||
}
|
||||
);
|
||||
});
|
||||
const url = `http://localhost:${httpServer.identity.primaryPort}/http-request.html`;
|
||||
|
||||
info("Call NetworkCommand.sendHTTPRequest");
|
||||
const { resourceCommand } = commands;
|
||||
const { onResource } = await resourceCommand.waitForNextResource(
|
||||
resourceCommand.TYPES.NETWORK_EVENT
|
||||
);
|
||||
const { channelId } = await networkCommand.sendHTTPRequest({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: [{ name: "Request", value: "Header" }],
|
||||
body: "Hello",
|
||||
cause: {
|
||||
loadingDocumentUri: "https://example.com",
|
||||
stacktraceAvailable: true,
|
||||
type: "xhr",
|
||||
},
|
||||
});
|
||||
ok(channelId, "Received a channel id in response");
|
||||
const resource = await onResource;
|
||||
is(
|
||||
resource.resourceId,
|
||||
channelId,
|
||||
"NETWORK_EVENT resource channelId is the same as the one returned by sendHTTPRequest"
|
||||
);
|
||||
|
||||
const request = await onRequest;
|
||||
is(request.method, "POST", "Request method is correct");
|
||||
is(request.getHeader("Request"), "Header", "The custom header was passed");
|
||||
is(fetchRequestBody(request), "Hello", "The request POST's body is correct");
|
||||
|
||||
await commands.destroy();
|
||||
});
|
||||
|
||||
const BinaryInputStream = Components.Constructor(
|
||||
"@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream"
|
||||
);
|
||||
|
||||
function fetchRequestBody(request) {
|
||||
let body = "";
|
||||
const bodyStream = new BinaryInputStream(request.bodyInputStream);
|
||||
let avail = 0;
|
||||
while ((avail = bodyStream.available()) > 0) {
|
||||
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
|
||||
}
|
||||
return body;
|
||||
}
|
||||
13
devtools/shared/commands/network/tests/head.js
Normal file
13
devtools/shared/commands/network/tests/head.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* import-globals-from ../../../../client/shared/test/shared-head.js */
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
|
||||
this
|
||||
);
|
||||
Loading…
Reference in a new issue