зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1360495 - Add response header columns in NetMonitor. r=Honza
--HG-- extra : rebase_source : eed0d9916453a3a5d2711026beaa9ce9085ae86a
This commit is contained in:
Родитель
021ccf02e1
Коммит
1a57567f72
|
@ -640,6 +640,11 @@ netmonitor.toolbar.resetColumns=Reset Columns
|
|||
# displayed in the network table header context menu for the timing submenu
|
||||
netmonitor.toolbar.timings=Timings
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.responseHeaders): This is the
|
||||
# label displayed in the network table header context menu for the
|
||||
# response headers submenu.
|
||||
netmonitor.toolbar.responseHeaders=Response Headers
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.summary.url): This is the label displayed
|
||||
# in the network details headers tab identifying the URL.
|
||||
netmonitor.summary.url=Request URL:
|
||||
|
|
|
@ -23,9 +23,9 @@ EventEmitter.decorate(window);
|
|||
|
||||
pref("devtools.netmonitor.enabled", true);
|
||||
pref("devtools.netmonitor.filters", "[\"all\"]");
|
||||
pref("devtools.netmonitor.hiddenColumns",
|
||||
"[\"cookies\",\"duration\",\"endTime\",\"latency\"," +
|
||||
"\"protocol\",\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\",\"startTime\"]"
|
||||
pref("devtools.netmonitor.visibleColumns",
|
||||
"[\"status\",\"method\",\"file\",\"domain\",\"cause\"," +
|
||||
"\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
pref("devtools.netmonitor.panes-network-details-width", 550);
|
||||
pref("devtools.netmonitor.panes-network-details-height", 450);
|
||||
|
|
|
@ -489,6 +489,9 @@ body,
|
|||
width: 8%;
|
||||
}
|
||||
|
||||
.requests-list-response-header {
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
.requests-list-domain.requests-list-column {
|
||||
text-align: start;
|
||||
|
|
|
@ -23,6 +23,7 @@ DevToolsModules(
|
|||
'request-list-column-method.js',
|
||||
'request-list-column-protocol.js',
|
||||
'request-list-column-remote-ip.js',
|
||||
'request-list-column-response-header.js',
|
||||
'request-list-column-response-time.js',
|
||||
'request-list-column-scheme.js',
|
||||
'request-list-column-set-cookies.js',
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* 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";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { getResponseHeader } = require("../utils/request-utils");
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
/**
|
||||
* Renders a response header column in the requests list. The actual
|
||||
* header to show is passed as a prop.
|
||||
*/
|
||||
const RequestListColumnResponseHeader = createClass({
|
||||
displayName: "RequestListColumnResponseHeader",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
header: PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const currHeader = getResponseHeader(this.props.item, this.props.header);
|
||||
const nextHeader = getResponseHeader(nextProps.item, nextProps.header);
|
||||
return currHeader !== nextHeader;
|
||||
},
|
||||
|
||||
render() {
|
||||
let header = getResponseHeader(this.props.item, this.props.header);
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-column requests-list-response-header",
|
||||
title: header
|
||||
},
|
||||
header
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnResponseHeader;
|
|
@ -89,7 +89,8 @@ const RequestListHeader = createClass({
|
|||
HEADERS.filter((header) => columns.get(header.name)).map((header) => {
|
||||
let name = header.name;
|
||||
let boxName = header.boxName || name;
|
||||
let label = L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
let label = header.noLocalization
|
||||
? name : L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
let sorted, sortedTitle;
|
||||
let active = sort.type == name ? true : undefined;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ const {
|
|||
} = require("devtools/client/shared/vendor/react");
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
const { RESPONSE_HEADERS } = require("../constants");
|
||||
|
||||
// Components
|
||||
const RequestListColumnCause = createFactory(require("./request-list-column-cause"));
|
||||
|
@ -25,6 +26,7 @@ const RequestListColumnLatency = createFactory(require("./request-list-column-la
|
|||
const RequestListColumnMethod = createFactory(require("./request-list-column-method"));
|
||||
const RequestListColumnProtocol = createFactory(require("./request-list-column-protocol"));
|
||||
const RequestListColumnRemoteIP = createFactory(require("./request-list-column-remote-ip"));
|
||||
const RequestListColumnResponseHeader = createFactory(require("./request-list-column-response-header"));
|
||||
const RequestListColumnResponseTime = createFactory(require("./request-list-column-response-time"));
|
||||
const RequestListColumnScheme = createFactory(require("./request-list-column-scheme"));
|
||||
const RequestListColumnSetCookies = createFactory(require("./request-list-column-set-cookies"));
|
||||
|
@ -163,6 +165,9 @@ const RequestListItem = createClass({
|
|||
RequestListColumnResponseTime({ item, firstRequestStartedMillis }),
|
||||
columns.get("duration") && RequestListColumnDuration({ item }),
|
||||
columns.get("latency") && RequestListColumnLatency({ item }),
|
||||
...RESPONSE_HEADERS.filter(header => columns.get(header)).map(
|
||||
header => RequestListColumnResponseHeader({ item, header }),
|
||||
),
|
||||
columns.get("waterfall") &&
|
||||
RequestListColumnWaterfall({ item, firstRequestStartedMillis,
|
||||
onWaterfallMouseDown }),
|
||||
|
|
|
@ -93,6 +93,18 @@ const EVENTS = {
|
|||
CONNECTED: "connected",
|
||||
};
|
||||
|
||||
const RESPONSE_HEADERS = [
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
"Content-Encoding",
|
||||
"Content-Length",
|
||||
"ETag",
|
||||
"Keep-Alive",
|
||||
"Last-Modified",
|
||||
"Server",
|
||||
"Vary"
|
||||
];
|
||||
|
||||
const HEADERS = [
|
||||
{
|
||||
name: "status",
|
||||
|
@ -180,6 +192,13 @@ const HEADERS = [
|
|||
canFilter: false,
|
||||
subMenu: "timings",
|
||||
},
|
||||
...RESPONSE_HEADERS
|
||||
.map(header => ({
|
||||
name: header,
|
||||
canFilter: false,
|
||||
subMenu: "responseHeaders",
|
||||
noLocalization: true
|
||||
})),
|
||||
{
|
||||
name: "waterfall",
|
||||
canFilter: false,
|
||||
|
@ -225,6 +244,7 @@ const general = {
|
|||
EVENTS,
|
||||
FILTER_SEARCH_DELAY: 200,
|
||||
HEADERS,
|
||||
RESPONSE_HEADERS,
|
||||
FILTER_FLAGS,
|
||||
SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE: 51200, // 50 KB in bytes
|
||||
REQUESTS_WATERFALL,
|
||||
|
|
|
@ -32,11 +32,11 @@ function prefsMiddleware(store) {
|
|||
break;
|
||||
case TOGGLE_COLUMN:
|
||||
case RESET_COLUMNS:
|
||||
let hiddenColumns = [...store.getState().ui.columns]
|
||||
.filter(([column, shown]) => !shown)
|
||||
let visibleColumns = [...store.getState().ui.columns]
|
||||
.filter(([column, shown]) => shown)
|
||||
.map(([column, shown]) => column);
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.hiddenColumns", JSON.stringify(hiddenColumns));
|
||||
"devtools.netmonitor.visibleColumns", JSON.stringify(visibleColumns));
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -11,6 +11,7 @@ const {
|
|||
OPEN_STATISTICS,
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
||||
RESET_COLUMNS,
|
||||
RESPONSE_HEADERS,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
SELECT_REQUEST,
|
||||
|
@ -18,7 +19,7 @@ const {
|
|||
WATERFALL_RESIZE,
|
||||
} = require("../constants");
|
||||
|
||||
const Columns = I.Record({
|
||||
const cols = {
|
||||
status: true,
|
||||
method: true,
|
||||
file: true,
|
||||
|
@ -38,7 +39,13 @@ const Columns = I.Record({
|
|||
duration: false,
|
||||
latency: false,
|
||||
waterfall: true,
|
||||
});
|
||||
};
|
||||
const Columns = I.Record(
|
||||
Object.assign(
|
||||
cols,
|
||||
RESPONSE_HEADERS.reduce((acc, header) => Object.assign(acc, { [header]: false }), {})
|
||||
)
|
||||
);
|
||||
|
||||
const UI = I.Record({
|
||||
columns: new Columns(),
|
||||
|
|
|
@ -16,6 +16,10 @@ const subMenuMap = HEADERS
|
|||
.filter((header) => header.hasOwnProperty("subMenu"))
|
||||
.reduce((acc, { name, subMenu }) => Object.assign(acc, { [name]: subMenu }), {});
|
||||
|
||||
const nonLocalizedHeaders = HEADERS
|
||||
.filter((header) => header.hasOwnProperty("noLocalization"))
|
||||
.map((header) => header.name);
|
||||
|
||||
class RequestListHeaderContextMenu {
|
||||
constructor({ toggleColumn, resetColumns }) {
|
||||
this.toggleColumn = toggleColumn;
|
||||
|
@ -37,13 +41,16 @@ class RequestListHeaderContextMenu {
|
|||
*/
|
||||
open(event = {}) {
|
||||
let menu = [];
|
||||
let subMenu = { timings: [] };
|
||||
let subMenu = { timings: [], responseHeaders: [] };
|
||||
let onlyOneColumn = this.visibleColumns.length === 1;
|
||||
|
||||
for (let [column, shown] of this.columns) {
|
||||
let label = nonLocalizedHeaders.includes(column)
|
||||
? stringMap[column] || column
|
||||
: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`);
|
||||
let entry = {
|
||||
id: `request-list-header-${column}-toggle`,
|
||||
label: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`),
|
||||
label,
|
||||
type: "checkbox",
|
||||
checked: shown,
|
||||
click: () => this.toggleColumn(column),
|
||||
|
@ -60,6 +67,10 @@ class RequestListHeaderContextMenu {
|
|||
label: L10N.getStr("netmonitor.toolbar.timings"),
|
||||
submenu: subMenu.timings,
|
||||
});
|
||||
menu.push({
|
||||
label: L10N.getStr("netmonitor.toolbar.responseHeaders"),
|
||||
submenu: subMenu.responseHeaders,
|
||||
});
|
||||
|
||||
menu.push({ type: "separator" });
|
||||
menu.push({
|
||||
|
|
|
@ -32,11 +32,11 @@ function configureStore() {
|
|||
});
|
||||
|
||||
let columns = new Columns();
|
||||
let hiddenColumns = getPref("devtools.netmonitor.hiddenColumns");
|
||||
let visibleColumns = getPref("devtools.netmonitor.visibleColumns");
|
||||
|
||||
for (let [col] of columns) {
|
||||
columns = columns.withMutations((state) => {
|
||||
state.set(col, !hiddenColumns.includes(col));
|
||||
state.set(col, visibleColumns.includes(col));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@ const { PrefsHelper } = require("devtools/client/shared/prefs");
|
|||
exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
||||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
||||
hiddenColumns: ["Json", "hiddenColumns"],
|
||||
visibleColumns: ["Json", "visibleColumns"],
|
||||
filters: ["Json", "filters"]
|
||||
});
|
||||
|
|
|
@ -356,6 +356,24 @@ function getFormattedProtocol(item) {
|
|||
return protocol.join("+");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a particular response header, or null if not
|
||||
* present.
|
||||
*/
|
||||
function getResponseHeader(item, header) {
|
||||
let { responseHeaders } = item;
|
||||
if (!responseHeaders || !responseHeaders.headers.length) {
|
||||
return null;
|
||||
}
|
||||
header = header.toLowerCase();
|
||||
for (let responseHeader of responseHeaders.headers) {
|
||||
if (responseHeader.name.toLowerCase() == header) {
|
||||
return responseHeader.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFormDataSections,
|
||||
fetchHeaders,
|
||||
|
@ -365,6 +383,7 @@ module.exports = {
|
|||
getAbbreviatedMimeType,
|
||||
getEndTime,
|
||||
getFormattedProtocol,
|
||||
getResponseHeader,
|
||||
getResponseTime,
|
||||
getStartTime,
|
||||
getUrlBaseName,
|
||||
|
|
|
@ -8,9 +8,11 @@ const {
|
|||
getAbbreviatedMimeType,
|
||||
getEndTime,
|
||||
getResponseTime,
|
||||
getResponseHeader,
|
||||
getStartTime,
|
||||
ipToLong,
|
||||
} = require("./request-utils");
|
||||
const { RESPONSE_HEADERS } = require("../constants");
|
||||
|
||||
/**
|
||||
* Predicates used when sorting items.
|
||||
|
@ -92,6 +94,16 @@ function latency(first, second) {
|
|||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
function compareHeader(header, first, second) {
|
||||
const result = compareValues(getResponseHeader(first, header) || "",
|
||||
getResponseHeader(second, header) || "");
|
||||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
const responseHeaders = RESPONSE_HEADERS
|
||||
.reduce((acc, header) => Object.assign(
|
||||
acc, {[header]: (first, second) => compareHeader(header, first, second)}), {});
|
||||
|
||||
function domain(first, second) {
|
||||
const firstDomain = first.urlDetails.host.toLowerCase();
|
||||
const secondDomain = second.urlDetails.host.toLowerCase();
|
||||
|
@ -150,7 +162,7 @@ function contentSize(first, second) {
|
|||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
exports.Sorters = {
|
||||
const sorters = {
|
||||
status,
|
||||
method,
|
||||
file,
|
||||
|
@ -171,3 +183,4 @@ exports.Sorters = {
|
|||
latency,
|
||||
waterfall,
|
||||
};
|
||||
exports.Sorters = Object.assign(sorters, responseHeaders);
|
||||
|
|
|
@ -18,6 +18,9 @@ add_task(function* () {
|
|||
.filter(([_, visible]) => visible);
|
||||
|
||||
if (visibleColumns.length === 1) {
|
||||
if (!shown) {
|
||||
continue;
|
||||
}
|
||||
yield testLastMenuItem(column);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,38 +4,36 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if hidden columns are properly saved
|
||||
* Tests if visible columns are properly saved
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
Services.prefs.setCharPref("devtools.netmonitor.hiddenColumns",
|
||||
'["status", "contentSize"]');
|
||||
Services.prefs.setCharPref("devtools.netmonitor.visibleColumns",
|
||||
'["status", "contentSize", "waterfall"]');
|
||||
|
||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, parent } = monitor.panelWin;
|
||||
|
||||
ok(!document.querySelector("#requests-list-status-button"),
|
||||
"Status column should be hidden");
|
||||
ok(!document.querySelector("#requests-list-contentSize-button"),
|
||||
"Content size column should be hidden");
|
||||
|
||||
yield showColumn("status");
|
||||
yield showColumn("contentSize");
|
||||
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns")
|
||||
.includes("contentSize"), "Pref should be synced for contentSize");
|
||||
ok(document.querySelector("#requests-list-status-button"),
|
||||
"Status column should be shown");
|
||||
ok(document.querySelector("#requests-list-contentSize-button"),
|
||||
"Content size column should be shown");
|
||||
|
||||
yield hideColumn("status");
|
||||
yield hideColumn("contentSize");
|
||||
|
||||
ok(Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.visibleColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.visibleColumns")
|
||||
.includes("contentSize"), "Pref should be synced for contentSize");
|
||||
|
||||
yield showColumn("status");
|
||||
|
||||
ok(Services.prefs.getCharPref("devtools.netmonitor.visibleColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
|
||||
function* hideColumn(column) {
|
||||
info(`Clicking context-menu item for ${column}`);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
|
|
|
@ -14,7 +14,7 @@ add_task(function* () {
|
|||
let { document, parent, windowRequire } = monitor.panelWin;
|
||||
let { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
|
||||
|
||||
let prefBefore = Prefs.hiddenColumns;
|
||||
let prefBefore = Prefs.visibleColumns;
|
||||
|
||||
hideColumn("status");
|
||||
hideColumn("waterfall");
|
||||
|
@ -24,7 +24,7 @@ add_task(function* () {
|
|||
|
||||
parent.document.querySelector("#request-list-header-reset-columns").click();
|
||||
|
||||
is(JSON.stringify(prefBefore), JSON.stringify(Prefs.hiddenColumns),
|
||||
is(JSON.stringify(prefBefore), JSON.stringify(Prefs.visibleColumns),
|
||||
"Reset columns item should reset columns pref");
|
||||
|
||||
function* hideColumn(column) {
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
*/
|
||||
|
||||
add_task(function* () {
|
||||
// Hide file, protocol, remoteip columns to make sure timing division
|
||||
// can render properly
|
||||
// Make sure timing division can render properly
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.hiddenColumns",
|
||||
"[\"file\",\"protocol\",\"remoteip\"]"
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
"[\"waterfall\"]"
|
||||
);
|
||||
|
||||
let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
|
|
|
@ -92,8 +92,14 @@ Services.prefs.setBoolPref("devtools.debugger.log", false);
|
|||
// Always reset some prefs to their original values after the test finishes.
|
||||
const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
|
||||
|
||||
// Reveal all hidden columns for test
|
||||
Services.prefs.setCharPref("devtools.netmonitor.hiddenColumns", "[]");
|
||||
// Reveal many columns for test
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
"[\"cause\",\"contentSize\",\"cookies\",\"domain\",\"duration\"," +
|
||||
"\"endTime\",\"file\",\"latency\",\"method\",\"protocol\"," +
|
||||
"\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\"," +
|
||||
"\"startTime\",\"status\",\"transferred\",\"type\",\"waterfall\"]"
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
info("finish() was called, cleaning up...");
|
||||
|
|
|
@ -160,8 +160,8 @@ pref("devtools.netmonitor.enabled", true);
|
|||
pref("devtools.netmonitor.panes-network-details-width", 550);
|
||||
pref("devtools.netmonitor.panes-network-details-height", 450);
|
||||
pref("devtools.netmonitor.filters", "[\"all\"]");
|
||||
pref("devtools.netmonitor.hiddenColumns",
|
||||
"[\"cookies\",\"duration\",\"endTime\",\"latency\",\"protocol\",\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\",\"startTime\"]"
|
||||
pref("devtools.netmonitor.visibleColumns",
|
||||
"[\"status\",\"method\",\"file\",\"domain\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
|
||||
// The default Network monitor HAR export setting
|
||||
|
|
Загрузка…
Ссылка в новой задаче