зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1309866) for too many intermittent test failures after landing a=backout
Backed out changeset 30baf39ed89f (bug 1309866) Backed out changeset e0e09f7f22a3 (bug 1309866) Backed out changeset 75d37553b7cd (bug 1309866)
This commit is contained in:
Родитель
4c42b01cc8
Коммит
9e952ef90e
|
@ -14,7 +14,8 @@ devtools.jar:
|
||||||
content/projecteditor/chrome/content/projecteditor-test.xul (projecteditor/chrome/content/projecteditor-test.xul)
|
content/projecteditor/chrome/content/projecteditor-test.xul (projecteditor/chrome/content/projecteditor-test.xul)
|
||||||
content/projecteditor/chrome/content/projecteditor-loader.js (projecteditor/chrome/content/projecteditor-loader.js)
|
content/projecteditor/chrome/content/projecteditor-loader.js (projecteditor/chrome/content/projecteditor-loader.js)
|
||||||
content/netmonitor/netmonitor.xul (netmonitor/netmonitor.xul)
|
content/netmonitor/netmonitor.xul (netmonitor/netmonitor.xul)
|
||||||
content/netmonitor/netmonitor.js (netmonitor/netmonitor.js)
|
content/netmonitor/netmonitor-controller.js (netmonitor/netmonitor-controller.js)
|
||||||
|
content/netmonitor/netmonitor-view.js (netmonitor/netmonitor-view.js)
|
||||||
content/webconsole/webconsole.xul (webconsole/webconsole.xul)
|
content/webconsole/webconsole.xul (webconsole/webconsole.xul)
|
||||||
* content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul)
|
* content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul)
|
||||||
content/scratchpad/scratchpad.js (scratchpad/scratchpad.js)
|
content/scratchpad/scratchpad.js (scratchpad/scratchpad.js)
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
/* 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 {
|
|
||||||
BATCH_ACTIONS,
|
|
||||||
BATCH_ENABLE,
|
|
||||||
BATCH_RESET,
|
|
||||||
} = require("../constants");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process multiple actions at once as part of one dispatch, and produce only one
|
|
||||||
* state update at the end. This action is not processed by any reducer, but by a
|
|
||||||
* special store enhancer.
|
|
||||||
*/
|
|
||||||
function batchActions(actions) {
|
|
||||||
return {
|
|
||||||
type: BATCH_ACTIONS,
|
|
||||||
actions
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function batchEnable(enabled) {
|
|
||||||
return {
|
|
||||||
type: BATCH_ENABLE,
|
|
||||||
enabled
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function batchReset() {
|
|
||||||
return {
|
|
||||||
type: BATCH_RESET,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
batchActions,
|
|
||||||
batchEnable,
|
|
||||||
batchReset,
|
|
||||||
};
|
|
|
@ -42,12 +42,12 @@ function enableFilterTypeOnly(filter) {
|
||||||
/**
|
/**
|
||||||
* Set filter text.
|
* Set filter text.
|
||||||
*
|
*
|
||||||
* @param {string} text - A filter text is going to be set
|
* @param {string} url - A filter text is going to be set
|
||||||
*/
|
*/
|
||||||
function setFilterText(text) {
|
function setFilterText(url) {
|
||||||
return {
|
return {
|
||||||
type: SET_FILTER_TEXT,
|
type: SET_FILTER_TEXT,
|
||||||
text,
|
url,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const batching = require("./batching");
|
|
||||||
const filters = require("./filters");
|
const filters = require("./filters");
|
||||||
const requests = require("./requests");
|
const requests = require("./requests");
|
||||||
const selection = require("./selection");
|
|
||||||
const sort = require("./sort");
|
|
||||||
const timingMarkers = require("./timing-markers");
|
|
||||||
const ui = require("./ui");
|
const ui = require("./ui");
|
||||||
|
|
||||||
Object.assign(exports,
|
module.exports = Object.assign({}, filters, requests, ui);
|
||||||
batching,
|
|
||||||
filters,
|
|
||||||
requests,
|
|
||||||
selection,
|
|
||||||
sort,
|
|
||||||
timingMarkers,
|
|
||||||
ui
|
|
||||||
);
|
|
||||||
|
|
|
@ -3,12 +3,8 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'batching.js',
|
|
||||||
'filters.js',
|
'filters.js',
|
||||||
'index.js',
|
'index.js',
|
||||||
'requests.js',
|
'requests.js',
|
||||||
'selection.js',
|
|
||||||
'sort.js',
|
|
||||||
'timing-markers.js',
|
|
||||||
'ui.js',
|
'ui.js',
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,61 +5,21 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ADD_REQUEST,
|
UPDATE_REQUESTS,
|
||||||
UPDATE_REQUEST,
|
|
||||||
CLONE_SELECTED_REQUEST,
|
|
||||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
|
||||||
CLEAR_REQUESTS,
|
|
||||||
} = require("../constants");
|
} = require("../constants");
|
||||||
|
|
||||||
function addRequest(id, data, batch) {
|
|
||||||
return {
|
|
||||||
type: ADD_REQUEST,
|
|
||||||
id,
|
|
||||||
data,
|
|
||||||
meta: { batch },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRequest(id, data, batch) {
|
|
||||||
return {
|
|
||||||
type: UPDATE_REQUEST,
|
|
||||||
id,
|
|
||||||
data,
|
|
||||||
meta: { batch },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone the currently selected request, set the "isCustom" attribute.
|
* Update request items
|
||||||
* Used by the "Edit and Resend" feature.
|
*
|
||||||
|
* @param {array} requests - visible request items
|
||||||
*/
|
*/
|
||||||
function cloneSelectedRequest() {
|
function updateRequests(items) {
|
||||||
return {
|
return {
|
||||||
type: CLONE_SELECTED_REQUEST
|
type: UPDATE_REQUESTS,
|
||||||
};
|
items,
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a request from the list. Supports removing only cloned requests with a
|
|
||||||
* "isCustom" attribute. Other requests never need to be removed.
|
|
||||||
*/
|
|
||||||
function removeSelectedCustomRequest() {
|
|
||||||
return {
|
|
||||||
type: REMOVE_SELECTED_CUSTOM_REQUEST
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearRequests() {
|
|
||||||
return {
|
|
||||||
type: CLEAR_REQUESTS
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
addRequest,
|
updateRequests,
|
||||||
updateRequest,
|
|
||||||
cloneSelectedRequest,
|
|
||||||
removeSelectedCustomRequest,
|
|
||||||
clearRequests,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* 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 { getDisplayedRequests } = require("../selectors/index");
|
|
||||||
const { SELECT_REQUEST, PRESELECT_REQUEST } = require("../constants");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a new request with a given id is added in future, select it immediately.
|
|
||||||
* Used by the "Edit and Resend" feature, where we know in advance the ID of the
|
|
||||||
* request, at a time when it wasn't sent yet.
|
|
||||||
*/
|
|
||||||
function preselectRequest(id) {
|
|
||||||
return {
|
|
||||||
type: PRESELECT_REQUEST,
|
|
||||||
id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select request with a given id.
|
|
||||||
*/
|
|
||||||
function selectRequest(id) {
|
|
||||||
return {
|
|
||||||
type: SELECT_REQUEST,
|
|
||||||
id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the selection up to down according to the "delta" parameter. Possible values:
|
|
||||||
* - Number: positive or negative, move up or down by specified distance
|
|
||||||
* - "PAGE_UP" | "PAGE_DOWN" (String): page up or page down
|
|
||||||
* - +Infinity | -Infinity: move to the start or end of the list
|
|
||||||
*/
|
|
||||||
function selectDelta(delta) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const requests = getDisplayedRequests(state);
|
|
||||||
|
|
||||||
if (requests.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selIndex = requests.findIndex(r => r.id === state.requests.selectedId);
|
|
||||||
|
|
||||||
if (delta === "PAGE_DOWN") {
|
|
||||||
delta = Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
|
|
||||||
} else if (delta === "PAGE_UP") {
|
|
||||||
delta = -Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newIndex = Math.min(Math.max(0, selIndex + delta), requests.size - 1);
|
|
||||||
const newItem = requests.get(newIndex);
|
|
||||||
dispatch(selectRequest(newItem.id));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
preselectRequest,
|
|
||||||
selectRequest,
|
|
||||||
selectDelta,
|
|
||||||
};
|
|
|
@ -1,18 +0,0 @@
|
||||||
/* 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 { SORT_BY } = require("../constants");
|
|
||||||
|
|
||||||
function sortBy(sortType) {
|
|
||||||
return {
|
|
||||||
type: SORT_BY,
|
|
||||||
sortType
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
sortBy
|
|
||||||
};
|
|
|
@ -1,19 +0,0 @@
|
||||||
/* 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 { ADD_TIMING_MARKER, CLEAR_TIMING_MARKERS } = require("../constants");
|
|
||||||
|
|
||||||
exports.addTimingMarker = (marker) => {
|
|
||||||
return {
|
|
||||||
type: ADD_TIMING_MARKER,
|
|
||||||
marker
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.clearTimingMarkers = () => {
|
|
||||||
return {
|
|
||||||
type: CLEAR_TIMING_MARKERS
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
const {
|
const {
|
||||||
OPEN_SIDEBAR,
|
OPEN_SIDEBAR,
|
||||||
WATERFALL_RESIZE,
|
TOGGLE_SIDEBAR,
|
||||||
} = require("../constants");
|
} = require("../constants");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,21 +25,12 @@ function openSidebar(open) {
|
||||||
* Toggle sidebar open state.
|
* Toggle sidebar open state.
|
||||||
*/
|
*/
|
||||||
function toggleSidebar() {
|
function toggleSidebar() {
|
||||||
return (dispatch, getState) => dispatch(openSidebar(!getState().ui.sidebarOpen));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waterfall width has changed (likely on window resize). Update the UI.
|
|
||||||
*/
|
|
||||||
function resizeWaterfall(width) {
|
|
||||||
return {
|
return {
|
||||||
type: WATERFALL_RESIZE,
|
type: TOGGLE_SIDEBAR,
|
||||||
width
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
openSidebar,
|
openSidebar,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
resizeWaterfall,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* globals NetMonitorView */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { DOM } = require("devtools/client/shared/vendor/react");
|
const { DOM } = require("devtools/client/shared/vendor/react");
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
||||||
const { L10N } = require("../l10n");
|
const { L10N } = require("../l10n");
|
||||||
const Actions = require("../actions/index");
|
|
||||||
|
|
||||||
const { button } = DOM;
|
const { button } = DOM;
|
||||||
|
|
||||||
|
@ -15,18 +15,15 @@ const { button } = DOM;
|
||||||
* Clear button component
|
* Clear button component
|
||||||
* A type of tool button is responsible for cleaning network requests.
|
* A type of tool button is responsible for cleaning network requests.
|
||||||
*/
|
*/
|
||||||
function ClearButton({ onClick }) {
|
function ClearButton() {
|
||||||
return button({
|
return button({
|
||||||
id: "requests-menu-clear-button",
|
id: "requests-menu-clear-button",
|
||||||
className: "devtools-button devtools-clear-icon",
|
className: "devtools-button devtools-clear-icon",
|
||||||
title: L10N.getStr("netmonitor.toolbar.clear"),
|
title: L10N.getStr("netmonitor.toolbar.clear"),
|
||||||
onClick,
|
onClick: () => {
|
||||||
|
NetMonitorView.RequestsMenu.clear();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(
|
module.exports = ClearButton;
|
||||||
undefined,
|
|
||||||
dispatch => ({
|
|
||||||
onClick: () => dispatch(Actions.clearRequests())
|
|
||||||
})
|
|
||||||
)(ClearButton);
|
|
||||||
|
|
|
@ -5,12 +5,6 @@
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'clear-button.js',
|
'clear-button.js',
|
||||||
'filter-buttons.js',
|
'filter-buttons.js',
|
||||||
'request-list-content.js',
|
|
||||||
'request-list-empty.js',
|
|
||||||
'request-list-header.js',
|
|
||||||
'request-list-item.js',
|
|
||||||
'request-list-tooltip.js',
|
|
||||||
'request-list.js',
|
|
||||||
'search-box.js',
|
'search-box.js',
|
||||||
'summary-button.js',
|
'summary-button.js',
|
||||||
'toggle-button.js',
|
'toggle-button.js',
|
||||||
|
|
|
@ -1,255 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
/* globals NetMonitorView */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { Task } = require("devtools/shared/task");
|
|
||||||
const { createClass, createFactory, DOM } = require("devtools/client/shared/vendor/react");
|
|
||||||
const { div } = DOM;
|
|
||||||
const Actions = require("../actions/index");
|
|
||||||
const RequestListItem = createFactory(require("./request-list-item"));
|
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
||||||
const { setTooltipImageContent,
|
|
||||||
setTooltipStackTraceContent } = require("./request-list-tooltip");
|
|
||||||
const { getDisplayedRequests,
|
|
||||||
getWaterfallScale } = require("../selectors/index");
|
|
||||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
|
||||||
|
|
||||||
// tooltip show/hide delay in ms
|
|
||||||
const REQUESTS_TOOLTIP_TOGGLE_DELAY = 500;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the actual contents of the request list.
|
|
||||||
*/
|
|
||||||
const RequestListContent = createClass({
|
|
||||||
displayName: "RequestListContent",
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
// Set the CSS variables for waterfall scaling
|
|
||||||
this.setScalingStyles();
|
|
||||||
|
|
||||||
// Install event handler for displaying a tooltip
|
|
||||||
this.props.tooltip.startTogglingOnHover(this.refs.contentEl, this.onHover, {
|
|
||||||
toggleDelay: REQUESTS_TOOLTIP_TOGGLE_DELAY,
|
|
||||||
interactive: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Install event handler to hide the tooltip on scroll
|
|
||||||
this.refs.contentEl.addEventListener("scroll", this.onScroll, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUpdate() {
|
|
||||||
// Check if the list is scrolled to bottom, before UI update
|
|
||||||
this.shouldScrollBottom = this.isScrolledToBottom();
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
// Update the CSS variables for waterfall scaling after props change
|
|
||||||
this.setScalingStyles();
|
|
||||||
|
|
||||||
// Keep the list scrolled to bottom if a new row was added
|
|
||||||
if (this.shouldScrollBottom) {
|
|
||||||
let node = this.refs.contentEl;
|
|
||||||
node.scrollTop = node.scrollHeight;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.refs.contentEl.removeEventListener("scroll", this.onScroll, true);
|
|
||||||
|
|
||||||
// Uninstall the tooltip event handler
|
|
||||||
this.props.tooltip.stopTogglingOnHover();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the CSS variables for waterfall scaling. If React supported setting CSS
|
|
||||||
* variables as part of the "style" property of a DOM element, we would use that.
|
|
||||||
*
|
|
||||||
* However, React doesn't support this, so we need to use a hack and update the
|
|
||||||
* DOM element directly: https://github.com/facebook/react/issues/6411
|
|
||||||
*/
|
|
||||||
setScalingStyles(prevProps) {
|
|
||||||
const { scale } = this.props;
|
|
||||||
if (scale == this.currentScale) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentScale = scale;
|
|
||||||
|
|
||||||
const { style } = this.refs.contentEl;
|
|
||||||
style.removeProperty("--timings-scale");
|
|
||||||
style.removeProperty("--timings-rev-scale");
|
|
||||||
style.setProperty("--timings-scale", scale);
|
|
||||||
style.setProperty("--timings-rev-scale", 1 / scale);
|
|
||||||
},
|
|
||||||
|
|
||||||
isScrolledToBottom() {
|
|
||||||
const { contentEl } = this.refs;
|
|
||||||
const lastChildEl = contentEl.lastElementChild;
|
|
||||||
|
|
||||||
if (!lastChildEl) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastChildRect = lastChildEl.getBoundingClientRect();
|
|
||||||
let contentRect = contentEl.getBoundingClientRect();
|
|
||||||
|
|
||||||
return (lastChildRect.height + lastChildRect.top) <= contentRect.bottom;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The predicate used when deciding whether a popup should be shown
|
|
||||||
* over a request item or not.
|
|
||||||
*
|
|
||||||
* @param nsIDOMNode target
|
|
||||||
* The element node currently being hovered.
|
|
||||||
* @param object tooltip
|
|
||||||
* The current tooltip instance.
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
onHover: Task.async(function* (target, tooltip) {
|
|
||||||
let itemEl = target.closest(".request-list-item");
|
|
||||||
if (!itemEl) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let itemId = itemEl.dataset.id;
|
|
||||||
if (!itemId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let requestItem = this.props.displayedRequests.find(r => r.id == itemId);
|
|
||||||
if (!requestItem) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestItem.responseContent && target.closest(".requests-menu-icon-and-file")) {
|
|
||||||
return setTooltipImageContent(tooltip, itemEl, requestItem);
|
|
||||||
} else if (requestItem.cause && target.closest(".requests-menu-cause-stack")) {
|
|
||||||
return setTooltipStackTraceContent(tooltip, requestItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scroll listener for the requests menu view.
|
|
||||||
*/
|
|
||||||
onScroll() {
|
|
||||||
this.props.tooltip.hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for keyboard events. For arrow up/down, page up/down, home/end,
|
|
||||||
* move the selection up or down.
|
|
||||||
*/
|
|
||||||
onKeyDown(e) {
|
|
||||||
let delta;
|
|
||||||
|
|
||||||
switch (e.keyCode) {
|
|
||||||
case KeyCodes.DOM_VK_UP:
|
|
||||||
case KeyCodes.DOM_VK_LEFT:
|
|
||||||
delta = -1;
|
|
||||||
break;
|
|
||||||
case KeyCodes.DOM_VK_DOWN:
|
|
||||||
case KeyCodes.DOM_VK_RIGHT:
|
|
||||||
delta = +1;
|
|
||||||
break;
|
|
||||||
case KeyCodes.DOM_VK_PAGE_UP:
|
|
||||||
delta = "PAGE_UP";
|
|
||||||
break;
|
|
||||||
case KeyCodes.DOM_VK_PAGE_DOWN:
|
|
||||||
delta = "PAGE_DOWN";
|
|
||||||
break;
|
|
||||||
case KeyCodes.DOM_VK_HOME:
|
|
||||||
delta = -Infinity;
|
|
||||||
break;
|
|
||||||
case KeyCodes.DOM_VK_END:
|
|
||||||
delta = +Infinity;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delta) {
|
|
||||||
// Prevent scrolling when pressing navigation keys.
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
this.props.onSelectDelta(delta);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If selection has just changed (by keyboard navigation), don't keep the list
|
|
||||||
* scrolled to bottom, but allow scrolling up with the selection.
|
|
||||||
*/
|
|
||||||
onFocusedNodeChange() {
|
|
||||||
this.shouldScrollBottom = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a focused item was unmounted, transfer the focus to the container element.
|
|
||||||
*/
|
|
||||||
onFocusedNodeUnmount() {
|
|
||||||
if (this.refs.contentEl) {
|
|
||||||
this.refs.contentEl.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { selectedRequestId,
|
|
||||||
displayedRequests,
|
|
||||||
firstRequestStartedMillis,
|
|
||||||
onItemMouseDown,
|
|
||||||
onItemContextMenu,
|
|
||||||
onSecurityIconClick } = this.props;
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{
|
|
||||||
ref: "contentEl",
|
|
||||||
className: "requests-menu-contents",
|
|
||||||
tabIndex: 0,
|
|
||||||
onKeyDown: this.onKeyDown,
|
|
||||||
},
|
|
||||||
displayedRequests.map((item, index) => RequestListItem({
|
|
||||||
key: item.id,
|
|
||||||
item,
|
|
||||||
index,
|
|
||||||
isSelected: item.id === selectedRequestId,
|
|
||||||
firstRequestStartedMillis,
|
|
||||||
onMouseDown: e => onItemMouseDown(e, item.id),
|
|
||||||
onContextMenu: e => onItemContextMenu(e, item.id),
|
|
||||||
onSecurityIconClick: e => onSecurityIconClick(e, item),
|
|
||||||
onFocusedNodeChange: this.onFocusedNodeChange,
|
|
||||||
onFocusedNodeUnmount: this.onFocusedNodeUnmount,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = connect(
|
|
||||||
state => ({
|
|
||||||
displayedRequests: getDisplayedRequests(state),
|
|
||||||
selectedRequestId: state.requests.selectedId,
|
|
||||||
scale: getWaterfallScale(state),
|
|
||||||
firstRequestStartedMillis: state.requests.firstStartedMillis,
|
|
||||||
tooltip: NetMonitorView.RequestsMenu.tooltip,
|
|
||||||
}),
|
|
||||||
dispatch => ({
|
|
||||||
onItemMouseDown: (e, item) => dispatch(Actions.selectRequest(item)),
|
|
||||||
onItemContextMenu: (e, item) => {
|
|
||||||
e.preventDefault();
|
|
||||||
NetMonitorView.RequestsMenu.contextMenu.open(e);
|
|
||||||
},
|
|
||||||
onSelectDelta: (delta) => dispatch(Actions.selectDelta(delta)),
|
|
||||||
/**
|
|
||||||
* A handler that opens the security tab in the details view if secure or
|
|
||||||
* broken security indicator is clicked.
|
|
||||||
*/
|
|
||||||
onSecurityIconClick: (e, item) => {
|
|
||||||
const { securityState } = item;
|
|
||||||
if (securityState && securityState !== "insecure") {
|
|
||||||
// Choose the security tab.
|
|
||||||
NetMonitorView.NetworkDetails.widget.selectedIndex = 5;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
)(RequestListContent);
|
|
|
@ -1,65 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
/* globals NetMonitorView */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
|
||||||
const { L10N } = require("../l10n");
|
|
||||||
const { div, span, button } = DOM;
|
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UI displayed when the request list is empty. Contains instructions on reloading
|
|
||||||
* the page and on triggering performance analysis of the page.
|
|
||||||
*/
|
|
||||||
const RequestListEmptyNotice = createClass({
|
|
||||||
displayName: "RequestListEmptyNotice",
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
onReloadClick: PropTypes.func.isRequired,
|
|
||||||
onPerfClick: PropTypes.func.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return div(
|
|
||||||
{
|
|
||||||
id: "requests-menu-empty-notice",
|
|
||||||
className: "request-list-empty-notice",
|
|
||||||
},
|
|
||||||
div({ id: "notice-reload-message" },
|
|
||||||
span(null, L10N.getStr("netmonitor.reloadNotice1")),
|
|
||||||
button(
|
|
||||||
{
|
|
||||||
id: "requests-menu-reload-notice-button",
|
|
||||||
className: "devtools-toolbarbutton",
|
|
||||||
"data-standalone": true,
|
|
||||||
onClick: this.props.onReloadClick,
|
|
||||||
},
|
|
||||||
L10N.getStr("netmonitor.reloadNotice2")
|
|
||||||
),
|
|
||||||
span(null, L10N.getStr("netmonitor.reloadNotice3"))
|
|
||||||
),
|
|
||||||
div({ id: "notice-perf-message" },
|
|
||||||
span(null, L10N.getStr("netmonitor.perfNotice1")),
|
|
||||||
button({
|
|
||||||
id: "requests-menu-perf-notice-button",
|
|
||||||
title: L10N.getStr("netmonitor.perfNotice3"),
|
|
||||||
className: "devtools-button",
|
|
||||||
"data-standalone": true,
|
|
||||||
onClick: this.props.onPerfClick,
|
|
||||||
}),
|
|
||||||
span(null, L10N.getStr("netmonitor.perfNotice2"))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = connect(
|
|
||||||
undefined,
|
|
||||||
dispatch => ({
|
|
||||||
onPerfClick: e => NetMonitorView.toggleFrontendMode(),
|
|
||||||
onReloadClick: e => NetMonitorView.reloadPage(),
|
|
||||||
})
|
|
||||||
)(RequestListEmptyNotice);
|
|
|
@ -1,197 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* globals document */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
|
||||||
const { div, button } = DOM;
|
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
||||||
const { L10N } = require("../l10n");
|
|
||||||
const { getWaterfallScale } = require("../selectors/index");
|
|
||||||
const Actions = require("../actions/index");
|
|
||||||
const WaterfallBackground = require("../waterfall-background");
|
|
||||||
|
|
||||||
// ms
|
|
||||||
const REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE = 5;
|
|
||||||
// px
|
|
||||||
const REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN = 60;
|
|
||||||
|
|
||||||
const REQUEST_TIME_DECIMALS = 2;
|
|
||||||
|
|
||||||
const HEADERS = [
|
|
||||||
{ name: "status", label: "status3" },
|
|
||||||
{ name: "method" },
|
|
||||||
{ name: "file", boxName: "icon-and-file" },
|
|
||||||
{ name: "domain", boxName: "security-and-domain" },
|
|
||||||
{ name: "cause" },
|
|
||||||
{ name: "type" },
|
|
||||||
{ name: "transferred" },
|
|
||||||
{ name: "size" },
|
|
||||||
{ name: "waterfall" }
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the request list header with sorting arrows for columns.
|
|
||||||
* Displays tick marks in the waterfall column header.
|
|
||||||
* Also draws the waterfall background canvas and updates it when needed.
|
|
||||||
*/
|
|
||||||
const RequestListHeader = createClass({
|
|
||||||
displayName: "RequestListHeader",
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
sort: PropTypes.object,
|
|
||||||
scale: PropTypes.number,
|
|
||||||
waterfallWidth: PropTypes.number,
|
|
||||||
onHeaderClick: PropTypes.func.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.background = new WaterfallBackground(document);
|
|
||||||
this.background.draw(this.props);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.background.draw(this.props);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.background.destroy();
|
|
||||||
this.background = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { sort, scale, waterfallWidth, onHeaderClick } = this.props;
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ id: "requests-menu-toolbar", className: "devtools-toolbar" },
|
|
||||||
div({ id: "toolbar-labels" },
|
|
||||||
HEADERS.map(header => {
|
|
||||||
const name = header.name;
|
|
||||||
const boxName = header.boxName || name;
|
|
||||||
const label = L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
|
||||||
|
|
||||||
let sorted, sortedTitle;
|
|
||||||
const active = sort.type == name ? true : undefined;
|
|
||||||
if (active) {
|
|
||||||
sorted = sort.ascending ? "ascending" : "descending";
|
|
||||||
sortedTitle = L10N.getStr(sort.ascending
|
|
||||||
? "networkMenu.sortedAsc"
|
|
||||||
: "networkMenu.sortedDesc");
|
|
||||||
}
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{
|
|
||||||
id: `requests-menu-${boxName}-header-box`,
|
|
||||||
key: name,
|
|
||||||
className: `requests-menu-header requests-menu-${boxName}`,
|
|
||||||
// Used to style the next column.
|
|
||||||
"data-active": active,
|
|
||||||
},
|
|
||||||
button(
|
|
||||||
{
|
|
||||||
id: `requests-menu-${name}-button`,
|
|
||||||
className: `requests-menu-header-button requests-menu-${name}`,
|
|
||||||
"data-sorted": sorted,
|
|
||||||
title: sortedTitle,
|
|
||||||
onClick: () => onHeaderClick(name),
|
|
||||||
},
|
|
||||||
name == "waterfall" ? WaterfallLabel(waterfallWidth, scale, label)
|
|
||||||
: div({ className: "button-text" }, label),
|
|
||||||
div({ className: "button-icon" })
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the waterfall header - timing tick marks with the right spacing
|
|
||||||
*/
|
|
||||||
function waterfallDivisionLabels(waterfallWidth, scale) {
|
|
||||||
let labels = [];
|
|
||||||
|
|
||||||
// Build new millisecond tick labels...
|
|
||||||
let timingStep = REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE;
|
|
||||||
let scaledStep = scale * timingStep;
|
|
||||||
|
|
||||||
// Ignore any divisions that would end up being too close to each other.
|
|
||||||
while (scaledStep < REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN) {
|
|
||||||
scaledStep *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert one label for each division on the current scale.
|
|
||||||
for (let x = 0; x < waterfallWidth; x += scaledStep) {
|
|
||||||
let millisecondTime = x / scale;
|
|
||||||
|
|
||||||
let normalizedTime = millisecondTime;
|
|
||||||
let divisionScale = "millisecond";
|
|
||||||
|
|
||||||
// If the division is greater than 1 minute.
|
|
||||||
if (normalizedTime > 60000) {
|
|
||||||
normalizedTime /= 60000;
|
|
||||||
divisionScale = "minute";
|
|
||||||
} else if (normalizedTime > 1000) {
|
|
||||||
// If the division is greater than 1 second.
|
|
||||||
normalizedTime /= 1000;
|
|
||||||
divisionScale = "second";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Showing too many decimals is bad UX.
|
|
||||||
if (divisionScale == "millisecond") {
|
|
||||||
normalizedTime |= 0;
|
|
||||||
} else {
|
|
||||||
normalizedTime = L10N.numberWithDecimals(normalizedTime, REQUEST_TIME_DECIMALS);
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = (x + scaledStep | 0) - (x | 0);
|
|
||||||
// Adjust the first marker for the borders
|
|
||||||
if (x == 0) {
|
|
||||||
width -= 2;
|
|
||||||
}
|
|
||||||
// Last marker doesn't need a width specified at all
|
|
||||||
if (x + scaledStep >= waterfallWidth) {
|
|
||||||
width = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
labels.push(div(
|
|
||||||
{
|
|
||||||
key: labels.length,
|
|
||||||
className: "requests-menu-timings-division",
|
|
||||||
"data-division-scale": divisionScale,
|
|
||||||
style: { width }
|
|
||||||
},
|
|
||||||
L10N.getFormatStr("networkMenu." + divisionScale, normalizedTime)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return labels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function WaterfallLabel(waterfallWidth, scale, label) {
|
|
||||||
let className = "button-text requests-menu-waterfall-label-wrapper";
|
|
||||||
|
|
||||||
if (scale != null) {
|
|
||||||
label = waterfallDivisionLabels(waterfallWidth, scale);
|
|
||||||
className += " requests-menu-waterfall-visible";
|
|
||||||
}
|
|
||||||
|
|
||||||
return div({ className }, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = connect(
|
|
||||||
state => ({
|
|
||||||
sort: state.sort,
|
|
||||||
scale: getWaterfallScale(state),
|
|
||||||
waterfallWidth: state.ui.waterfallWidth,
|
|
||||||
firstRequestStartedMillis: state.requests.firstStartedMillis,
|
|
||||||
timingMarkers: state.timingMarkers,
|
|
||||||
}),
|
|
||||||
dispatch => ({
|
|
||||||
onHeaderClick: type => dispatch(Actions.sortBy(type)),
|
|
||||||
})
|
|
||||||
)(RequestListHeader);
|
|
|
@ -1,346 +0,0 @@
|
||||||
/* 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, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
|
||||||
const { div, span, img } = DOM;
|
|
||||||
const { L10N } = require("../l10n");
|
|
||||||
const { getFormattedSize } = require("../utils/format-utils");
|
|
||||||
const { getAbbreviatedMimeType } = require("../request-utils");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render one row in the request list.
|
|
||||||
*/
|
|
||||||
const RequestListItem = createClass({
|
|
||||||
displayName: "RequestListItem",
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
item: PropTypes.object.isRequired,
|
|
||||||
index: PropTypes.number.isRequired,
|
|
||||||
isSelected: PropTypes.bool.isRequired,
|
|
||||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
|
||||||
onContextMenu: PropTypes.func.isRequired,
|
|
||||||
onMouseDown: PropTypes.func.isRequired,
|
|
||||||
onSecurityIconClick: PropTypes.func.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.isSelected) {
|
|
||||||
this.refs.el.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return !relevantPropsEqual(this.props.item, nextProps.item)
|
|
||||||
|| this.props.index !== nextProps.index
|
|
||||||
|| this.props.isSelected !== nextProps.isSelected
|
|
||||||
|| this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis;
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (!prevProps.isSelected && this.props.isSelected) {
|
|
||||||
this.refs.el.focus();
|
|
||||||
if (this.props.onFocusedNodeChange) {
|
|
||||||
this.props.onFocusedNodeChange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
// If this node is being destroyed and has focus, transfer the focus manually
|
|
||||||
// to the parent tree component. Otherwise, the focus will get lost and keyboard
|
|
||||||
// navigation in the tree will stop working. This is a workaround for a XUL bug.
|
|
||||||
// See bugs 1259228 and 1152441 for details.
|
|
||||||
// DE-XUL: Remove this hack once all usages are only in HTML documents.
|
|
||||||
if (this.props.isSelected) {
|
|
||||||
this.refs.el.blur();
|
|
||||||
if (this.props.onFocusedNodeUnmount) {
|
|
||||||
this.props.onFocusedNodeUnmount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
item,
|
|
||||||
index,
|
|
||||||
isSelected,
|
|
||||||
firstRequestStartedMillis,
|
|
||||||
onContextMenu,
|
|
||||||
onMouseDown,
|
|
||||||
onSecurityIconClick
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
let classList = [ "request-list-item" ];
|
|
||||||
if (isSelected) {
|
|
||||||
classList.push("selected");
|
|
||||||
}
|
|
||||||
classList.push(index % 2 ? "odd" : "even");
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{
|
|
||||||
ref: "el",
|
|
||||||
className: classList.join(" "),
|
|
||||||
"data-id": item.id,
|
|
||||||
tabIndex: 0,
|
|
||||||
onContextMenu,
|
|
||||||
onMouseDown,
|
|
||||||
},
|
|
||||||
StatusColumn(item),
|
|
||||||
MethodColumn(item),
|
|
||||||
FileColumn(item),
|
|
||||||
DomainColumn(item, onSecurityIconClick),
|
|
||||||
CauseColumn(item),
|
|
||||||
TypeColumn(item),
|
|
||||||
TransferredSizeColumn(item),
|
|
||||||
ContentSizeColumn(item),
|
|
||||||
WaterfallColumn(item, firstRequestStartedMillis)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by shouldComponentUpdate: compare two items, and compare only properties
|
|
||||||
* relevant for rendering the RequestListItem. Other properties (like request and
|
|
||||||
* response headers, cookies, bodies) are ignored. These are very useful for the
|
|
||||||
* sidebar details, but not here.
|
|
||||||
*/
|
|
||||||
const RELEVANT_ITEM_PROPS = [
|
|
||||||
"status",
|
|
||||||
"statusText",
|
|
||||||
"fromCache",
|
|
||||||
"fromServiceWorker",
|
|
||||||
"method",
|
|
||||||
"url",
|
|
||||||
"responseContentDataUri",
|
|
||||||
"remoteAddress",
|
|
||||||
"securityState",
|
|
||||||
"cause",
|
|
||||||
"mimeType",
|
|
||||||
"contentSize",
|
|
||||||
"transferredSize",
|
|
||||||
"startedMillis",
|
|
||||||
"totalTime",
|
|
||||||
"eventTimings",
|
|
||||||
];
|
|
||||||
|
|
||||||
function relevantPropsEqual(item1, item2) {
|
|
||||||
return item1 === item2 || RELEVANT_ITEM_PROPS.every(p => item1[p] === item2[p]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function StatusColumn(item) {
|
|
||||||
const { status, statusText, fromCache, fromServiceWorker } = item;
|
|
||||||
|
|
||||||
let code, title;
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
if (fromCache) {
|
|
||||||
code = "cached";
|
|
||||||
} else if (fromServiceWorker) {
|
|
||||||
code = "service worker";
|
|
||||||
} else {
|
|
||||||
code = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusText) {
|
|
||||||
title = `${status} ${statusText}`;
|
|
||||||
if (fromCache) {
|
|
||||||
title += " (cached)";
|
|
||||||
}
|
|
||||||
if (fromServiceWorker) {
|
|
||||||
title += " (service worker)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return div({ className: "requests-menu-subitem requests-menu-status", title },
|
|
||||||
div({ className: "requests-menu-status-icon", "data-code": code }),
|
|
||||||
span({ className: "subitem-label requests-menu-status-code" }, status)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MethodColumn(item) {
|
|
||||||
const { method } = item;
|
|
||||||
return div({ className: "requests-menu-subitem requests-menu-method-box" },
|
|
||||||
span({ className: "subitem-label requests-menu-method" }, method)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FileColumn(item) {
|
|
||||||
const { urlDetails, responseContentDataUri } = item;
|
|
||||||
|
|
||||||
return div({ className: "requests-menu-subitem requests-menu-icon-and-file" },
|
|
||||||
img({
|
|
||||||
className: "requests-menu-icon",
|
|
||||||
src: responseContentDataUri,
|
|
||||||
hidden: !responseContentDataUri,
|
|
||||||
"data-type": responseContentDataUri ? "thumbnail" : undefined
|
|
||||||
}),
|
|
||||||
div(
|
|
||||||
{
|
|
||||||
className: "subitem-label requests-menu-file",
|
|
||||||
title: urlDetails.unicodeUrl
|
|
||||||
},
|
|
||||||
urlDetails.baseNameWithQuery
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function DomainColumn(item, onSecurityIconClick) {
|
|
||||||
const { urlDetails, remoteAddress, securityState } = item;
|
|
||||||
|
|
||||||
let iconClassList = [ "requests-security-state-icon" ];
|
|
||||||
let iconTitle;
|
|
||||||
if (urlDetails.isLocal) {
|
|
||||||
iconClassList.push("security-state-local");
|
|
||||||
iconTitle = L10N.getStr("netmonitor.security.state.secure");
|
|
||||||
} else if (securityState) {
|
|
||||||
iconClassList.push(`security-state-${securityState}`);
|
|
||||||
iconTitle = L10N.getStr(`netmonitor.security.state.${securityState}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = urlDetails.host + (remoteAddress ? ` (${remoteAddress})` : "");
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ className: "requests-menu-subitem requests-menu-security-and-domain" },
|
|
||||||
div({
|
|
||||||
className: iconClassList.join(" "),
|
|
||||||
title: iconTitle,
|
|
||||||
onClick: onSecurityIconClick,
|
|
||||||
}),
|
|
||||||
span({ className: "subitem-label requests-menu-domain", title }, urlDetails.host)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CauseColumn(item) {
|
|
||||||
const { cause } = item;
|
|
||||||
|
|
||||||
let causeType = "";
|
|
||||||
let causeUri = undefined;
|
|
||||||
let causeHasStack = false;
|
|
||||||
|
|
||||||
if (cause) {
|
|
||||||
causeType = cause.type;
|
|
||||||
causeUri = cause.loadingDocumentUri;
|
|
||||||
causeHasStack = cause.stacktrace && cause.stacktrace.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ className: "requests-menu-subitem requests-menu-cause", title: causeUri },
|
|
||||||
span({ className: "requests-menu-cause-stack", hidden: !causeHasStack }, "JS"),
|
|
||||||
span({ className: "subitem-label" }, causeType)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
|
||||||
"ecmascript": "js",
|
|
||||||
"javascript": "js",
|
|
||||||
"x-javascript": "js"
|
|
||||||
};
|
|
||||||
|
|
||||||
function TypeColumn(item) {
|
|
||||||
const { mimeType } = item;
|
|
||||||
let abbrevType;
|
|
||||||
if (mimeType) {
|
|
||||||
abbrevType = getAbbreviatedMimeType(mimeType);
|
|
||||||
abbrevType = CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ className: "requests-menu-subitem requests-menu-type", title: mimeType },
|
|
||||||
span({ className: "subitem-label" }, abbrevType)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TransferredSizeColumn(item) {
|
|
||||||
const { transferredSize, fromCache, fromServiceWorker } = item;
|
|
||||||
|
|
||||||
let text;
|
|
||||||
let className = "subitem-label";
|
|
||||||
if (fromCache) {
|
|
||||||
text = L10N.getStr("networkMenu.sizeCached");
|
|
||||||
className += " theme-comment";
|
|
||||||
} else if (fromServiceWorker) {
|
|
||||||
text = L10N.getStr("networkMenu.sizeServiceWorker");
|
|
||||||
className += " theme-comment";
|
|
||||||
} else if (typeof transferredSize == "number") {
|
|
||||||
text = getFormattedSize(transferredSize);
|
|
||||||
} else if (transferredSize === null) {
|
|
||||||
text = L10N.getStr("networkMenu.sizeUnavailable");
|
|
||||||
}
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ className: "requests-menu-subitem requests-menu-transferred", title: text },
|
|
||||||
span({ className }, text)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContentSizeColumn(item) {
|
|
||||||
const { contentSize } = item;
|
|
||||||
|
|
||||||
let text;
|
|
||||||
if (typeof contentSize == "number") {
|
|
||||||
text = getFormattedSize(contentSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return div(
|
|
||||||
{ className: "requests-menu-subitem subitem-label requests-menu-size", title: text },
|
|
||||||
span({ className: "subitem-label" }, text)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of properties of the timing info we want to create boxes for
|
|
||||||
const TIMING_KEYS = ["blocked", "dns", "connect", "send", "wait", "receive"];
|
|
||||||
|
|
||||||
function timingBoxes(item) {
|
|
||||||
const { eventTimings, totalTime, fromCache, fromServiceWorker } = item;
|
|
||||||
let boxes = [];
|
|
||||||
|
|
||||||
if (fromCache || fromServiceWorker) {
|
|
||||||
return boxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventTimings) {
|
|
||||||
// Add a set of boxes representing timing information.
|
|
||||||
for (let key of TIMING_KEYS) {
|
|
||||||
let width = eventTimings.timings[key];
|
|
||||||
|
|
||||||
// Don't render anything if it surely won't be visible.
|
|
||||||
// One millisecond == one unscaled pixel.
|
|
||||||
if (width > 0) {
|
|
||||||
boxes.push(div({
|
|
||||||
key,
|
|
||||||
className: "requests-menu-timings-box " + key,
|
|
||||||
style: { width }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof totalTime == "number") {
|
|
||||||
let text = L10N.getFormatStr("networkMenu.totalMS", totalTime);
|
|
||||||
boxes.push(div({
|
|
||||||
key: "total",
|
|
||||||
className: "requests-menu-timings-total",
|
|
||||||
title: text
|
|
||||||
}, text));
|
|
||||||
}
|
|
||||||
|
|
||||||
return boxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
function WaterfallColumn(item, firstRequestStartedMillis) {
|
|
||||||
const startedDeltaMillis = item.startedMillis - firstRequestStartedMillis;
|
|
||||||
const paddingInlineStart = `${startedDeltaMillis}px`;
|
|
||||||
|
|
||||||
return div({ className: "requests-menu-subitem requests-menu-waterfall" },
|
|
||||||
div(
|
|
||||||
{ className: "requests-menu-timings", style: { paddingInlineStart } },
|
|
||||||
timingBoxes(item)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = RequestListItem;
|
|
|
@ -1,107 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* globals gNetwork, NetMonitorController */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { Task } = require("devtools/shared/task");
|
|
||||||
const { formDataURI } = require("../request-utils");
|
|
||||||
const { WEBCONSOLE_L10N } = require("../l10n");
|
|
||||||
const { setImageTooltip,
|
|
||||||
getImageDimensions } = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
|
|
||||||
|
|
||||||
// px
|
|
||||||
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400;
|
|
||||||
// px
|
|
||||||
const REQUESTS_TOOLTIP_STACK_TRACE_WIDTH = 600;
|
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
||||||
|
|
||||||
const setTooltipImageContent = Task.async(function* (tooltip, itemEl, requestItem) {
|
|
||||||
let { mimeType, text, encoding } = requestItem.responseContent.content;
|
|
||||||
|
|
||||||
if (!mimeType || !mimeType.includes("image/")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let string = yield gNetwork.getString(text);
|
|
||||||
let src = formDataURI(mimeType, encoding, string);
|
|
||||||
let maxDim = REQUESTS_TOOLTIP_IMAGE_MAX_DIM;
|
|
||||||
let { naturalWidth, naturalHeight } = yield getImageDimensions(tooltip.doc, src);
|
|
||||||
let options = { maxDim, naturalWidth, naturalHeight };
|
|
||||||
setImageTooltip(tooltip, tooltip.doc, src, options);
|
|
||||||
|
|
||||||
return itemEl.querySelector(".requests-menu-icon");
|
|
||||||
});
|
|
||||||
|
|
||||||
const setTooltipStackTraceContent = Task.async(function* (tooltip, requestItem) {
|
|
||||||
let {stacktrace} = requestItem.cause;
|
|
||||||
|
|
||||||
if (!stacktrace || stacktrace.length == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let doc = tooltip.doc;
|
|
||||||
let el = doc.createElementNS(HTML_NS, "div");
|
|
||||||
el.className = "stack-trace-tooltip devtools-monospace";
|
|
||||||
|
|
||||||
for (let f of stacktrace) {
|
|
||||||
let { functionName, filename, lineNumber, columnNumber, asyncCause } = f;
|
|
||||||
|
|
||||||
if (asyncCause) {
|
|
||||||
// if there is asyncCause, append a "divider" row into the trace
|
|
||||||
let asyncFrameEl = doc.createElementNS(HTML_NS, "div");
|
|
||||||
asyncFrameEl.className = "stack-frame stack-frame-async";
|
|
||||||
asyncFrameEl.textContent =
|
|
||||||
WEBCONSOLE_L10N.getFormatStr("stacktrace.asyncStack", asyncCause);
|
|
||||||
el.appendChild(asyncFrameEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a source name in format "url -> url"
|
|
||||||
let sourceUrl = filename.split(" -> ").pop();
|
|
||||||
|
|
||||||
let frameEl = doc.createElementNS(HTML_NS, "div");
|
|
||||||
frameEl.className = "stack-frame stack-frame-call";
|
|
||||||
|
|
||||||
let funcEl = doc.createElementNS(HTML_NS, "span");
|
|
||||||
funcEl.className = "stack-frame-function-name";
|
|
||||||
funcEl.textContent =
|
|
||||||
functionName || WEBCONSOLE_L10N.getStr("stacktrace.anonymousFunction");
|
|
||||||
frameEl.appendChild(funcEl);
|
|
||||||
|
|
||||||
let sourceEl = doc.createElementNS(HTML_NS, "span");
|
|
||||||
sourceEl.className = "stack-frame-source-name";
|
|
||||||
frameEl.appendChild(sourceEl);
|
|
||||||
|
|
||||||
let sourceInnerEl = doc.createElementNS(HTML_NS, "span");
|
|
||||||
sourceInnerEl.className = "stack-frame-source-name-inner";
|
|
||||||
sourceEl.appendChild(sourceInnerEl);
|
|
||||||
|
|
||||||
sourceInnerEl.textContent = sourceUrl;
|
|
||||||
sourceInnerEl.title = sourceUrl;
|
|
||||||
|
|
||||||
let lineEl = doc.createElementNS(HTML_NS, "span");
|
|
||||||
lineEl.className = "stack-frame-line";
|
|
||||||
lineEl.textContent = `:${lineNumber}:${columnNumber}`;
|
|
||||||
sourceInnerEl.appendChild(lineEl);
|
|
||||||
|
|
||||||
frameEl.addEventListener("click", () => {
|
|
||||||
// hide the tooltip immediately, not after delay
|
|
||||||
tooltip.hide();
|
|
||||||
NetMonitorController.viewSourceInDebugger(filename, lineNumber);
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
el.appendChild(frameEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
tooltip.setContent(el, {width: REQUESTS_TOOLTIP_STACK_TRACE_WIDTH});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
setTooltipImageContent,
|
|
||||||
setTooltipStackTraceContent,
|
|
||||||
};
|
|
|
@ -1,34 +0,0 @@
|
||||||
/* 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 { createFactory, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
|
||||||
const { div } = DOM;
|
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
||||||
const RequestListHeader = createFactory(require("./request-list-header"));
|
|
||||||
const RequestListEmptyNotice = createFactory(require("./request-list-empty"));
|
|
||||||
const RequestListContent = createFactory(require("./request-list-content"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the request list - header, empty text, the actual content with rows
|
|
||||||
*/
|
|
||||||
const RequestList = function ({ isEmpty }) {
|
|
||||||
return div({ className: "request-list-container" },
|
|
||||||
RequestListHeader(),
|
|
||||||
isEmpty ? RequestListEmptyNotice() : RequestListContent()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
RequestList.displayName = "RequestList";
|
|
||||||
|
|
||||||
RequestList.propTypes = {
|
|
||||||
isEmpty: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = connect(
|
|
||||||
state => ({
|
|
||||||
isEmpty: state.requests.requests.isEmpty()
|
|
||||||
})
|
|
||||||
)(RequestList);
|
|
|
@ -14,7 +14,7 @@ const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||||
const { PluralForm } = require("devtools/shared/plural-form");
|
const { PluralForm } = require("devtools/shared/plural-form");
|
||||||
const { L10N } = require("../l10n");
|
const { L10N } = require("../l10n");
|
||||||
const { getDisplayedRequestsSummary } = require("../selectors/index");
|
const { getSummary } = require("../selectors/index");
|
||||||
|
|
||||||
const { button, span } = DOM;
|
const { button, span } = DOM;
|
||||||
|
|
||||||
|
@ -22,12 +22,14 @@ function SummaryButton({
|
||||||
summary,
|
summary,
|
||||||
triggerSummary,
|
triggerSummary,
|
||||||
}) {
|
}) {
|
||||||
let { count, bytes, millis } = summary;
|
let { count, totalBytes, totalMillis } = summary;
|
||||||
const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
||||||
PluralForm.get(count, L10N.getStr("networkMenu.summary"))
|
PluralForm.get(count, L10N.getStr("networkMenu.summary"))
|
||||||
.replace("#1", count)
|
.replace("#1", count)
|
||||||
.replace("#2", L10N.numberWithDecimals(bytes / 1024, CONTENT_SIZE_DECIMALS))
|
.replace("#2", L10N.numberWithDecimals(totalBytes / 1024,
|
||||||
.replace("#3", L10N.numberWithDecimals(millis / 1000, REQUEST_TIME_DECIMALS));
|
CONTENT_SIZE_DECIMALS))
|
||||||
|
.replace("#3", L10N.numberWithDecimals(totalMillis / 1000,
|
||||||
|
REQUEST_TIME_DECIMALS));
|
||||||
|
|
||||||
return button({
|
return button({
|
||||||
id: "requests-menu-network-summary-button",
|
id: "requests-menu-network-summary-button",
|
||||||
|
@ -45,7 +47,7 @@ SummaryButton.propTypes = {
|
||||||
|
|
||||||
module.exports = connect(
|
module.exports = connect(
|
||||||
(state) => ({
|
(state) => ({
|
||||||
summary: getDisplayedRequestsSummary(state),
|
summary: getSummary(state),
|
||||||
}),
|
}),
|
||||||
(dispatch) => ({
|
(dispatch) => ({
|
||||||
triggerSummary: () => {
|
triggerSummary: () => {
|
||||||
|
|
|
@ -2,20 +2,21 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* globals NetMonitorView */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||||
const { L10N } = require("../l10n");
|
const { L10N } = require("../l10n");
|
||||||
const Actions = require("../actions/index");
|
const Actions = require("../actions/index");
|
||||||
const { isSidebarToggleButtonDisabled } = require("../selectors/index");
|
|
||||||
|
|
||||||
const { button } = DOM;
|
const { button } = DOM;
|
||||||
|
|
||||||
function ToggleButton({
|
function ToggleButton({
|
||||||
disabled,
|
disabled,
|
||||||
open,
|
open,
|
||||||
onToggle,
|
triggerSidebar,
|
||||||
}) {
|
}) {
|
||||||
let className = ["devtools-button"];
|
let className = ["devtools-button"];
|
||||||
if (!open) {
|
if (!open) {
|
||||||
|
@ -31,21 +32,34 @@ function ToggleButton({
|
||||||
title,
|
title,
|
||||||
disabled,
|
disabled,
|
||||||
tabIndex: "0",
|
tabIndex: "0",
|
||||||
onMouseDown: onToggle,
|
onMouseDown: triggerSidebar,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ToggleButton.propTypes = {
|
ToggleButton.propTypes = {
|
||||||
disabled: PropTypes.bool.isRequired,
|
disabled: PropTypes.bool.isRequired,
|
||||||
onToggle: PropTypes.func.isRequired,
|
triggerSidebar: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = connect(
|
module.exports = connect(
|
||||||
(state) => ({
|
(state) => ({
|
||||||
disabled: isSidebarToggleButtonDisabled(state),
|
disabled: state.requests.items.length === 0,
|
||||||
open: state.ui.sidebarOpen,
|
open: state.ui.sidebar.open,
|
||||||
}),
|
}),
|
||||||
(dispatch) => ({
|
(dispatch) => ({
|
||||||
onToggle: () => dispatch(Actions.toggleSidebar())
|
triggerSidebar: () => {
|
||||||
|
dispatch(Actions.toggleSidebar());
|
||||||
|
|
||||||
|
let requestsMenu = NetMonitorView.RequestsMenu;
|
||||||
|
let selectedIndex = requestsMenu.selectedIndex;
|
||||||
|
|
||||||
|
// Make sure there's a selection if the button is pressed, to avoid
|
||||||
|
// showing an empty network details pane.
|
||||||
|
if (selectedIndex == -1 && requestsMenu.itemCount) {
|
||||||
|
requestsMenu.selectedIndex = 0;
|
||||||
|
} else {
|
||||||
|
requestsMenu.selectedIndex = -1;
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
)(ToggleButton);
|
)(ToggleButton);
|
||||||
|
|
|
@ -11,40 +11,12 @@ const general = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionTypes = {
|
const actionTypes = {
|
||||||
BATCH_ACTIONS: "BATCH_ACTIONS",
|
|
||||||
BATCH_ENABLE: "BATCH_ENABLE",
|
|
||||||
ADD_TIMING_MARKER: "ADD_TIMING_MARKER",
|
|
||||||
CLEAR_TIMING_MARKERS: "CLEAR_TIMING_MARKERS",
|
|
||||||
ADD_REQUEST: "ADD_REQUEST",
|
|
||||||
UPDATE_REQUEST: "UPDATE_REQUEST",
|
|
||||||
CLEAR_REQUESTS: "CLEAR_REQUESTS",
|
|
||||||
CLONE_SELECTED_REQUEST: "CLONE_SELECTED_REQUEST",
|
|
||||||
REMOVE_SELECTED_CUSTOM_REQUEST: "REMOVE_SELECTED_CUSTOM_REQUEST",
|
|
||||||
SELECT_REQUEST: "SELECT_REQUEST",
|
|
||||||
PRESELECT_REQUEST: "PRESELECT_REQUEST",
|
|
||||||
SORT_BY: "SORT_BY",
|
|
||||||
TOGGLE_FILTER_TYPE: "TOGGLE_FILTER_TYPE",
|
TOGGLE_FILTER_TYPE: "TOGGLE_FILTER_TYPE",
|
||||||
ENABLE_FILTER_TYPE_ONLY: "ENABLE_FILTER_TYPE_ONLY",
|
ENABLE_FILTER_TYPE_ONLY: "ENABLE_FILTER_TYPE_ONLY",
|
||||||
SET_FILTER_TEXT: "SET_FILTER_TEXT",
|
SET_FILTER_TEXT: "SET_FILTER_TEXT",
|
||||||
OPEN_SIDEBAR: "OPEN_SIDEBAR",
|
OPEN_SIDEBAR: "OPEN_SIDEBAR",
|
||||||
WATERFALL_RESIZE: "WATERFALL_RESIZE",
|
TOGGLE_SIDEBAR: "TOGGLE_SIDEBAR",
|
||||||
|
UPDATE_REQUESTS: "UPDATE_REQUESTS",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Descriptions for what this frontend is currently doing.
|
module.exports = Object.assign({}, general, actionTypes);
|
||||||
const ACTIVITY_TYPE = {
|
|
||||||
// Standing by and handling requests normally.
|
|
||||||
NONE: 0,
|
|
||||||
|
|
||||||
// Forcing the target to reload with cache enabled or disabled.
|
|
||||||
RELOAD: {
|
|
||||||
WITH_CACHE_ENABLED: 1,
|
|
||||||
WITH_CACHE_DISABLED: 2,
|
|
||||||
WITH_CACHE_DEFAULT: 3
|
|
||||||
},
|
|
||||||
|
|
||||||
// Enabling or disabling the cache without triggering a reload.
|
|
||||||
ENABLE_CACHE: 3,
|
|
||||||
DISABLE_CACHE: 4
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Object.assign({ ACTIVITY_TYPE }, general, actionTypes);
|
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Task } = require("devtools/shared/task");
|
const { Task } = require("devtools/shared/task");
|
||||||
const { writeHeaderText,
|
const {
|
||||||
getKeyWithEvent,
|
writeHeaderText,
|
||||||
getUrlQuery,
|
getKeyWithEvent,
|
||||||
parseQueryString } = require("./request-utils");
|
getUrlQuery,
|
||||||
const Actions = require("./actions/index");
|
parseQueryString,
|
||||||
|
} = require("./request-utils");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions handling the custom request view.
|
* Functions handling the custom request view.
|
||||||
|
@ -75,41 +76,37 @@ CustomRequestView.prototype = {
|
||||||
*/
|
*/
|
||||||
onUpdate: function (field) {
|
onUpdate: function (field) {
|
||||||
let selectedItem = NetMonitorView.RequestsMenu.selectedItem;
|
let selectedItem = NetMonitorView.RequestsMenu.selectedItem;
|
||||||
let store = NetMonitorView.RequestsMenu.store;
|
|
||||||
let value;
|
let value;
|
||||||
|
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case "method":
|
case "method":
|
||||||
value = $("#custom-method-value").value.trim();
|
value = $("#custom-method-value").value.trim();
|
||||||
store.dispatch(Actions.updateRequest(selectedItem.id, { method: value }));
|
selectedItem.attachment.method = value;
|
||||||
break;
|
break;
|
||||||
case "url":
|
case "url":
|
||||||
value = $("#custom-url-value").value;
|
value = $("#custom-url-value").value;
|
||||||
this.updateCustomQuery(value);
|
this.updateCustomQuery(value);
|
||||||
store.dispatch(Actions.updateRequest(selectedItem.id, { url: value }));
|
selectedItem.attachment.url = value;
|
||||||
break;
|
break;
|
||||||
case "query":
|
case "query":
|
||||||
let query = $("#custom-query-value").value;
|
let query = $("#custom-query-value").value;
|
||||||
this.updateCustomUrl(query);
|
this.updateCustomUrl(query);
|
||||||
|
field = "url";
|
||||||
value = $("#custom-url-value").value;
|
value = $("#custom-url-value").value;
|
||||||
store.dispatch(Actions.updateRequest(selectedItem.id, { url: value }));
|
selectedItem.attachment.url = value;
|
||||||
break;
|
break;
|
||||||
case "body":
|
case "body":
|
||||||
value = $("#custom-postdata-value").value;
|
value = $("#custom-postdata-value").value;
|
||||||
store.dispatch(Actions.updateRequest(selectedItem.id, {
|
selectedItem.attachment.requestPostData = { postData: { text: value } };
|
||||||
requestPostData: {
|
|
||||||
postData: { text: value }
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
break;
|
break;
|
||||||
case "headers":
|
case "headers":
|
||||||
let headersText = $("#custom-headers-value").value;
|
let headersText = $("#custom-headers-value").value;
|
||||||
value = parseHeadersText(headersText);
|
value = parseHeadersText(headersText);
|
||||||
store.dispatch(Actions.updateRequest(selectedItem.id, {
|
selectedItem.attachment.requestHeaders = { headers: value };
|
||||||
requestHeaders: { headers: value }
|
|
||||||
}));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetMonitorView.RequestsMenu.updateMenuView(selectedItem, field, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,7 +161,7 @@ function parseHeadersText(text) {
|
||||||
* Parse readable text list of a query string.
|
* Parse readable text list of a query string.
|
||||||
*
|
*
|
||||||
* @param string text
|
* @param string text
|
||||||
* Text of query string representation
|
* Text of query string represetation
|
||||||
* @return array
|
* @return array
|
||||||
* Array of query params {name, value}
|
* Array of query params {name, value}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* import-globals-from ./netmonitor-controller.js */
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
/* globals window, dumpn, $, NetMonitorView, gNetwork */
|
/* globals dumpn, $, NetMonitorView, gNetwork */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const promise = require("promise");
|
const promise = require("promise");
|
||||||
const EventEmitter = require("devtools/shared/event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const Editor = require("devtools/client/sourceeditor/editor");
|
|
||||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||||
const { Task } = require("devtools/shared/task");
|
const { Task } = require("devtools/shared/task");
|
||||||
const { ToolSidebar } = require("devtools/client/framework/sidebar");
|
const { ToolSidebar } = require("devtools/client/framework/sidebar");
|
||||||
|
@ -267,6 +267,10 @@ DetailsView.prototype = {
|
||||||
// Tab is selected but not dirty. We're done here.
|
// Tab is selected but not dirty. We're done here.
|
||||||
populated[tab] = true;
|
populated[tab] = true;
|
||||||
window.emit(EVENTS.TAB_UPDATED);
|
window.emit(EVENTS.TAB_UPDATED);
|
||||||
|
|
||||||
|
if (NetMonitorController.isConnected()) {
|
||||||
|
NetMonitorView.RequestsMenu.ensureSelectedItemIsVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (viewState.dirty[tab]) {
|
} else if (viewState.dirty[tab]) {
|
||||||
// Tab is dirty but no longer selected. Don't refresh it now, it'll be
|
// Tab is dirty but no longer selected. Don't refresh it now, it'll be
|
||||||
|
@ -324,7 +328,7 @@ DetailsView.prototype = {
|
||||||
} else {
|
} else {
|
||||||
code = data.status;
|
code = data.status;
|
||||||
}
|
}
|
||||||
$("#headers-summary-status-circle").setAttribute("data-code", code);
|
$("#headers-summary-status-circle").setAttribute("code", code);
|
||||||
$("#headers-summary-status-value").setAttribute("value",
|
$("#headers-summary-status-value").setAttribute("value",
|
||||||
data.status + " " + data.statusText);
|
data.status + " " + data.statusText);
|
||||||
$("#headers-summary-status").removeAttribute("hidden");
|
$("#headers-summary-status").removeAttribute("hidden");
|
||||||
|
|
|
@ -63,7 +63,9 @@ HarBuilder.prototype = {
|
||||||
let log = this.buildLog();
|
let log = this.buildLog();
|
||||||
|
|
||||||
// Build entries.
|
// Build entries.
|
||||||
for (let file of this._options.items) {
|
let items = this._options.items;
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
let file = items[i].attachment;
|
||||||
log.entries.push(this.buildEntry(log, file));
|
log.entries.push(this.buildEntry(log, file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,9 @@ HarCollector.prototype = {
|
||||||
this.files.set(actor, file);
|
this.files.set(actor, file);
|
||||||
|
|
||||||
// Mimic the Net panel data structure
|
// Mimic the Net panel data structure
|
||||||
this.items.push(file);
|
this.items.push({
|
||||||
|
attachment: file
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onNetworkEventUpdate: function (type, packet) {
|
onNetworkEventUpdate: function (type, packet) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ function* throttleUploadTest(actuallyThrottle) {
|
||||||
|
|
||||||
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
|
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
|
||||||
|
|
||||||
let { NetMonitorController, NetMonitorView } = monitor.panelWin;
|
let { NetMonitorView } = monitor.panelWin;
|
||||||
let { RequestsMenu } = NetMonitorView;
|
let { RequestsMenu } = NetMonitorView;
|
||||||
|
|
||||||
const size = 4096;
|
const size = 4096;
|
||||||
|
@ -32,7 +32,7 @@ function* throttleUploadTest(actuallyThrottle) {
|
||||||
uploadBPSMax: uploadSize,
|
uploadBPSMax: uploadSize,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let client = NetMonitorController.webConsoleClient;
|
let client = monitor._controller.webConsoleClient;
|
||||||
|
|
||||||
info("sending throttle request");
|
info("sending throttle request");
|
||||||
let deferred = promise.defer();
|
let deferred = promise.defer();
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
/* 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 { BATCH_ACTIONS, BATCH_ENABLE, BATCH_RESET } = require("../constants");
|
|
||||||
|
|
||||||
// ms
|
|
||||||
const REQUESTS_REFRESH_RATE = 50;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Middleware that watches for actions with a "batch = true" value in their meta field.
|
|
||||||
* These actions are queued and dispatched as one batch after a timeout.
|
|
||||||
* Special actions that are handled by this middleware:
|
|
||||||
* - BATCH_ENABLE can be used to enable and disable the batching.
|
|
||||||
* - BATCH_RESET discards the actions that are currently in the queue.
|
|
||||||
*/
|
|
||||||
function batchingMiddleware(store) {
|
|
||||||
return next => {
|
|
||||||
let queuedActions = [];
|
|
||||||
let enabled = true;
|
|
||||||
let flushTask = null;
|
|
||||||
|
|
||||||
return action => {
|
|
||||||
if (action.type === BATCH_ENABLE) {
|
|
||||||
return setEnabled(action.enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === BATCH_RESET) {
|
|
||||||
return resetQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.meta && action.meta.batch) {
|
|
||||||
if (!enabled) {
|
|
||||||
next(action);
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
queuedActions.push(action);
|
|
||||||
|
|
||||||
if (!flushTask) {
|
|
||||||
flushTask = new DelayedTask(flushActions, REQUESTS_REFRESH_RATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return flushTask.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(action);
|
|
||||||
};
|
|
||||||
|
|
||||||
function setEnabled(value) {
|
|
||||||
enabled = value;
|
|
||||||
|
|
||||||
// If disabling the batching, flush the actions that have been queued so far
|
|
||||||
if (!enabled && flushTask) {
|
|
||||||
flushTask.runNow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetQueue() {
|
|
||||||
queuedActions = [];
|
|
||||||
|
|
||||||
if (flushTask) {
|
|
||||||
flushTask.cancel();
|
|
||||||
flushTask = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function flushActions() {
|
|
||||||
const actions = queuedActions;
|
|
||||||
queuedActions = [];
|
|
||||||
|
|
||||||
next({
|
|
||||||
type: BATCH_ACTIONS,
|
|
||||||
actions,
|
|
||||||
});
|
|
||||||
|
|
||||||
flushTask = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a delayed task that calls the specified task function after a delay.
|
|
||||||
*/
|
|
||||||
function DelayedTask(taskFn, delay) {
|
|
||||||
this._promise = new Promise((resolve, reject) => {
|
|
||||||
this.runTask = (cancel) => {
|
|
||||||
if (cancel) {
|
|
||||||
reject("Task cancelled");
|
|
||||||
} else {
|
|
||||||
taskFn();
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
this.runTask = null;
|
|
||||||
};
|
|
||||||
this.timeout = setTimeout(this.runTask, delay);
|
|
||||||
}).catch(console.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
DelayedTask.prototype = {
|
|
||||||
/**
|
|
||||||
* Return a promise that is resolved after the task is performed or canceled.
|
|
||||||
*/
|
|
||||||
get promise() {
|
|
||||||
return this._promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the execution of the task.
|
|
||||||
*/
|
|
||||||
cancel() {
|
|
||||||
clearTimeout(this.timeout);
|
|
||||||
if (this.runTask) {
|
|
||||||
this.runTask(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the scheduled task immediately, without waiting for the timeout.
|
|
||||||
* Resolves the promise correctly.
|
|
||||||
*/
|
|
||||||
runNow() {
|
|
||||||
clearTimeout(this.timeout);
|
|
||||||
if (this.runTask) {
|
|
||||||
this.runTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = batchingMiddleware;
|
|
|
@ -1,7 +0,0 @@
|
||||||
# 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(
|
|
||||||
'batching.js',
|
|
||||||
)
|
|
|
@ -6,10 +6,8 @@ DIRS += [
|
||||||
'actions',
|
'actions',
|
||||||
'components',
|
'components',
|
||||||
'har',
|
'har',
|
||||||
'middleware',
|
|
||||||
'reducers',
|
'reducers',
|
||||||
'selectors',
|
'selectors'
|
||||||
'utils',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
|
@ -19,8 +17,6 @@ DevToolsModules(
|
||||||
'events.js',
|
'events.js',
|
||||||
'filter-predicates.js',
|
'filter-predicates.js',
|
||||||
'l10n.js',
|
'l10n.js',
|
||||||
'netmonitor-controller.js',
|
|
||||||
'netmonitor-view.js',
|
|
||||||
'panel.js',
|
'panel.js',
|
||||||
'performance-statistics-view.js',
|
'performance-statistics-view.js',
|
||||||
'prefs.js',
|
'prefs.js',
|
||||||
|
@ -31,7 +27,6 @@ DevToolsModules(
|
||||||
'sort-predicates.js',
|
'sort-predicates.js',
|
||||||
'store.js',
|
'store.js',
|
||||||
'toolbar-view.js',
|
'toolbar-view.js',
|
||||||
'waterfall-background.js',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||||
|
|
|
@ -3,10 +3,37 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
/* globals window, NetMonitorView, gStore, dumpn */
|
/* globals window, document, NetMonitorView, gStore, Actions */
|
||||||
|
/* exported loader */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var { utils: Cu } = Components;
|
||||||
|
|
||||||
|
// Descriptions for what this frontend is currently doing.
|
||||||
|
const ACTIVITY_TYPE = {
|
||||||
|
// Standing by and handling requests normally.
|
||||||
|
NONE: 0,
|
||||||
|
|
||||||
|
// Forcing the target to reload with cache enabled or disabled.
|
||||||
|
RELOAD: {
|
||||||
|
WITH_CACHE_ENABLED: 1,
|
||||||
|
WITH_CACHE_DISABLED: 2,
|
||||||
|
WITH_CACHE_DEFAULT: 3
|
||||||
|
},
|
||||||
|
|
||||||
|
// Enabling or disabling the cache without triggering a reload.
|
||||||
|
ENABLE_CACHE: 3,
|
||||||
|
DISABLE_CACHE: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
var BrowserLoaderModule = {};
|
||||||
|
Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
|
||||||
|
var { loader, require } = BrowserLoaderModule.BrowserLoader({
|
||||||
|
baseURI: "resource://devtools/client/netmonitor/",
|
||||||
|
window
|
||||||
|
});
|
||||||
|
|
||||||
const promise = require("promise");
|
const promise = require("promise");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
@ -14,22 +41,20 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const Editor = require("devtools/client/sourceeditor/editor");
|
const Editor = require("devtools/client/sourceeditor/editor");
|
||||||
const {TimelineFront} = require("devtools/shared/fronts/timeline");
|
const {TimelineFront} = require("devtools/shared/fronts/timeline");
|
||||||
const {Task} = require("devtools/shared/task");
|
const {Task} = require("devtools/shared/task");
|
||||||
const { ACTIVITY_TYPE } = require("./constants");
|
const {Prefs} = require("./prefs");
|
||||||
const { EVENTS } = require("./events");
|
const {EVENTS} = require("./events");
|
||||||
const { configureStore } = require("./store");
|
|
||||||
const Actions = require("./actions/index");
|
const Actions = require("./actions/index");
|
||||||
const { getDisplayedRequestById } = require("./selectors/index");
|
|
||||||
const { Prefs } = require("./prefs");
|
|
||||||
|
|
||||||
XPCOMUtils.defineConstant(window, "EVENTS", EVENTS);
|
XPCOMUtils.defineConstant(this, "EVENTS", EVENTS);
|
||||||
XPCOMUtils.defineConstant(window, "ACTIVITY_TYPE", ACTIVITY_TYPE);
|
XPCOMUtils.defineConstant(this, "ACTIVITY_TYPE", ACTIVITY_TYPE);
|
||||||
XPCOMUtils.defineConstant(window, "Editor", Editor);
|
XPCOMUtils.defineConstant(this, "Editor", Editor);
|
||||||
XPCOMUtils.defineConstant(window, "Prefs", Prefs);
|
XPCOMUtils.defineConstant(this, "Prefs", Prefs);
|
||||||
XPCOMUtils.defineLazyModuleGetter(window, "Chart",
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Chart",
|
||||||
"resource://devtools/client/shared/widgets/Chart.jsm");
|
"resource://devtools/client/shared/widgets/Chart.jsm");
|
||||||
|
|
||||||
// Initialize the global Redux store
|
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
||||||
window.gStore = configureStore();
|
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object defining the network monitor controller components.
|
* Object defining the network monitor controller components.
|
||||||
|
@ -66,7 +91,6 @@ var NetMonitorController = {
|
||||||
}
|
}
|
||||||
this._shutdown = promise.defer();
|
this._shutdown = promise.defer();
|
||||||
{
|
{
|
||||||
gStore.dispatch(Actions.batchReset());
|
|
||||||
NetMonitorView.destroy();
|
NetMonitorView.destroy();
|
||||||
this.TargetEventsHandler.disconnect();
|
this.TargetEventsHandler.disconnect();
|
||||||
this.NetworkEventsHandler.disconnect();
|
this.NetworkEventsHandler.disconnect();
|
||||||
|
@ -263,18 +287,19 @@ var NetMonitorController = {
|
||||||
let deferred = promise.defer();
|
let deferred = promise.defer();
|
||||||
let request = null;
|
let request = null;
|
||||||
let inspector = function () {
|
let inspector = function () {
|
||||||
request = getDisplayedRequestById(gStore.getState(), requestId);
|
let predicate = i => i.value === requestId;
|
||||||
|
request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
|
||||||
if (!request) {
|
if (!request) {
|
||||||
// Reset filters so that the request is visible.
|
// Reset filters so that the request is visible.
|
||||||
gStore.dispatch(Actions.toggleFilterType("all"));
|
gStore.dispatch(Actions.toggleFilterType("all"));
|
||||||
request = getDisplayedRequestById(gStore.getState(), requestId);
|
request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request was found, select it. Otherwise this function will be
|
// If the request was found, select it. Otherwise this function will be
|
||||||
// called again once new requests arrive.
|
// called again once new requests arrive.
|
||||||
if (request) {
|
if (request) {
|
||||||
window.off(EVENTS.REQUEST_ADDED, inspector);
|
window.off(EVENTS.REQUEST_ADDED, inspector);
|
||||||
gStore.dispatch(Actions.selectRequest(request.id));
|
NetMonitorView.RequestsMenu.selectedItem = request;
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -373,14 +398,14 @@ TargetEventsHandler.prototype = {
|
||||||
// Reset UI.
|
// Reset UI.
|
||||||
if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) {
|
if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) {
|
||||||
NetMonitorView.RequestsMenu.reset();
|
NetMonitorView.RequestsMenu.reset();
|
||||||
} else {
|
NetMonitorView.Sidebar.toggle(false);
|
||||||
// If the log is persistent, just clear all accumulated timing markers.
|
|
||||||
gStore.dispatch(Actions.clearTimingMarkers());
|
|
||||||
}
|
}
|
||||||
// Switch to the default network traffic inspector view.
|
// Switch to the default network traffic inspector view.
|
||||||
if (NetMonitorController.getCurrentActivity() == ACTIVITY_TYPE.NONE) {
|
if (NetMonitorController.getCurrentActivity() == ACTIVITY_TYPE.NONE) {
|
||||||
NetMonitorView.showNetworkInspectorView();
|
NetMonitorView.showNetworkInspectorView();
|
||||||
}
|
}
|
||||||
|
// Clear any accumulated markers.
|
||||||
|
NetMonitorController.NetworkEventsHandler.clearMarkers();
|
||||||
|
|
||||||
window.emit(EVENTS.TARGET_WILL_NAVIGATE);
|
window.emit(EVENTS.TARGET_WILL_NAVIGATE);
|
||||||
break;
|
break;
|
||||||
|
@ -404,6 +429,8 @@ TargetEventsHandler.prototype = {
|
||||||
* Functions handling target network events.
|
* Functions handling target network events.
|
||||||
*/
|
*/
|
||||||
function NetworkEventsHandler() {
|
function NetworkEventsHandler() {
|
||||||
|
this._markers = [];
|
||||||
|
|
||||||
this._onNetworkEvent = this._onNetworkEvent.bind(this);
|
this._onNetworkEvent = this._onNetworkEvent.bind(this);
|
||||||
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
||||||
this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this);
|
this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this);
|
||||||
|
@ -429,6 +456,19 @@ NetworkEventsHandler.prototype = {
|
||||||
return NetMonitorController.timelineFront;
|
return NetMonitorController.timelineFront;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get firstDocumentDOMContentLoadedTimestamp() {
|
||||||
|
let marker = this._markers.filter(e => {
|
||||||
|
return e.name == "document::DOMContentLoaded";
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
return marker ? marker.unixTime / 1000 : -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
get firstDocumentLoadTimestamp() {
|
||||||
|
let marker = this._markers.filter(e => e.name == "document::Load")[0];
|
||||||
|
return marker ? marker.unixTime / 1000 : -1;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the current target client.
|
* Connect to the current target client.
|
||||||
*/
|
*/
|
||||||
|
@ -485,7 +525,7 @@ NetworkEventsHandler.prototype = {
|
||||||
*/
|
*/
|
||||||
_onDocLoadingMarker: function (marker) {
|
_onDocLoadingMarker: function (marker) {
|
||||||
window.emit(EVENTS.TIMELINE_EVENT, marker);
|
window.emit(EVENTS.TIMELINE_EVENT, marker);
|
||||||
gStore.dispatch(Actions.addTimingMarker(marker));
|
this._markers.push(marker);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -507,7 +547,8 @@ NetworkEventsHandler.prototype = {
|
||||||
} = networkInfo;
|
} = networkInfo;
|
||||||
|
|
||||||
NetMonitorView.RequestsMenu.addRequest(
|
NetMonitorView.RequestsMenu.addRequest(
|
||||||
actor, {startedDateTime, method, url, isXHR, cause, fromCache, fromServiceWorker}
|
actor, startedDateTime, method, url, isXHR, cause, fromCache,
|
||||||
|
fromServiceWorker
|
||||||
);
|
);
|
||||||
window.emit(EVENTS.NETWORK_EVENT, actor);
|
window.emit(EVENTS.NETWORK_EVENT, actor);
|
||||||
},
|
},
|
||||||
|
@ -596,7 +637,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestHeaders: function (response) {
|
_onRequestHeaders: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
requestHeaders: response
|
requestHeaders: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
|
window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -610,7 +651,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestCookies: function (response) {
|
_onRequestCookies: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
requestCookies: response
|
requestCookies: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
|
window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -624,7 +665,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestPostData: function (response) {
|
_onRequestPostData: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
requestPostData: response
|
requestPostData: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
|
window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -638,7 +679,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onSecurityInfo: function (response) {
|
_onSecurityInfo: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
securityInfo: response.securityInfo
|
securityInfo: response.securityInfo
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
|
window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -652,7 +693,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseHeaders: function (response) {
|
_onResponseHeaders: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
responseHeaders: response
|
responseHeaders: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
|
window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -666,7 +707,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseCookies: function (response) {
|
_onResponseCookies: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
responseCookies: response
|
responseCookies: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
|
window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -680,7 +721,7 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseContent: function (response) {
|
_onResponseContent: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
responseContent: response
|
responseContent: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
|
window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -694,11 +735,18 @@ NetworkEventsHandler.prototype = {
|
||||||
_onEventTimings: function (response) {
|
_onEventTimings: function (response) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
NetMonitorView.RequestsMenu.updateRequest(response.from, {
|
||||||
eventTimings: response
|
eventTimings: response
|
||||||
}).then(() => {
|
}, () => {
|
||||||
window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
|
window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all accumulated markers.
|
||||||
|
*/
|
||||||
|
clearMarkers: function () {
|
||||||
|
this._markers.length = 0;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the full text of a LongString.
|
* Fetches the full text of a LongString.
|
||||||
*
|
*
|
||||||
|
@ -715,10 +763,19 @@ NetworkEventsHandler.prototype = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this is document is in RTL mode.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
XPCOMUtils.defineLazyGetter(window, "isRTL", function () {
|
||||||
|
return window.getComputedStyle(document.documentElement, null)
|
||||||
|
.direction == "rtl";
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenient way of emitting events from the panel window.
|
* Convenient way of emitting events from the panel window.
|
||||||
*/
|
*/
|
||||||
EventEmitter.decorate(window);
|
EventEmitter.decorate(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preliminary setup for the NetMonitorController object.
|
* Preliminary setup for the NetMonitorController object.
|
||||||
|
@ -738,4 +795,14 @@ Object.defineProperties(window, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.NetMonitorController = NetMonitorController;
|
/**
|
||||||
|
* Helper method for debugging.
|
||||||
|
* @param string
|
||||||
|
*/
|
||||||
|
function dumpn(str) {
|
||||||
|
if (wantLogging) {
|
||||||
|
dump("NET-FRONTEND: " + str + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||||
|
|
|
@ -2,25 +2,25 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* import-globals-from ./netmonitor-controller.js */
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
/* globals $, gStore, NetMonitorController, dumpn */
|
/* globals Prefs, setInterval, setTimeout, clearInterval, clearTimeout, btoa */
|
||||||
|
/* exported $, $all */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { testing: isTesting } = require("devtools/shared/flags");
|
const { testing: isTesting } = require("devtools/shared/flags");
|
||||||
const promise = require("promise");
|
|
||||||
const Editor = require("devtools/client/sourceeditor/editor");
|
|
||||||
const { Task } = require("devtools/shared/task");
|
|
||||||
const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers");
|
const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers");
|
||||||
|
const { configureStore } = require("./store");
|
||||||
const { RequestsMenuView } = require("./requests-menu-view");
|
const { RequestsMenuView } = require("./requests-menu-view");
|
||||||
const { CustomRequestView } = require("./custom-request-view");
|
const { CustomRequestView } = require("./custom-request-view");
|
||||||
const { ToolbarView } = require("./toolbar-view");
|
const { ToolbarView } = require("./toolbar-view");
|
||||||
const { SidebarView } = require("./sidebar-view");
|
const { SidebarView } = require("./sidebar-view");
|
||||||
const { DetailsView } = require("./details-view");
|
const { DetailsView } = require("./details-view");
|
||||||
const { PerformanceStatisticsView } = require("./performance-statistics-view");
|
const { PerformanceStatisticsView } = require("./performance-statistics-view");
|
||||||
const { ACTIVITY_TYPE } = require("./constants");
|
|
||||||
const Actions = require("./actions/index");
|
// Initialize the global redux variables
|
||||||
const { Prefs } = require("./prefs");
|
var gStore = configureStore();
|
||||||
|
|
||||||
// ms
|
// ms
|
||||||
const WDA_DEFAULT_VERIFY_INTERVAL = 50;
|
const WDA_DEFAULT_VERIFY_INTERVAL = 50;
|
||||||
|
@ -80,6 +80,12 @@ var NetMonitorView = {
|
||||||
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
|
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
|
||||||
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
|
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
|
||||||
this.toggleDetailsPane({ visible: false });
|
this.toggleDetailsPane({ visible: false });
|
||||||
|
|
||||||
|
// Disable the performance statistics mode.
|
||||||
|
if (!Prefs.statistics) {
|
||||||
|
$("#request-menu-context-perf").hidden = true;
|
||||||
|
$("#notice-perf-message").hidden = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +169,7 @@ var NetMonitorView = {
|
||||||
*/
|
*/
|
||||||
showNetworkInspectorView: function () {
|
showNetworkInspectorView: function () {
|
||||||
this._body.selectedPanel = $("#network-inspector-view");
|
this._body.selectedPanel = $("#network-inspector-view");
|
||||||
|
this.RequestsMenu._flushWaterfallViews(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,7 +192,7 @@ var NetMonitorView = {
|
||||||
// • The response content size and request total time are necessary for
|
// • The response content size and request total time are necessary for
|
||||||
// populating the statistics view.
|
// populating the statistics view.
|
||||||
// • The response mime type is used for categorization.
|
// • The response mime type is used for categorization.
|
||||||
yield whenDataAvailable(requestsView.store, [
|
yield whenDataAvailable(requestsView, [
|
||||||
"responseHeaders", "status", "contentSize", "mimeType", "totalTime"
|
"responseHeaders", "status", "contentSize", "mimeType", "totalTime"
|
||||||
]);
|
]);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -193,9 +200,8 @@ var NetMonitorView = {
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const requests = requestsView.store.getState().requests.requests;
|
statisticsView.createPrimedCacheChart(requestsView.items);
|
||||||
statisticsView.createPrimedCacheChart(requests);
|
statisticsView.createEmptyCacheChart(requestsView.items);
|
||||||
statisticsView.createEmptyCacheChart(requests);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -235,39 +241,44 @@ var NetMonitorView = {
|
||||||
_editorPromises: new Map()
|
_editorPromises: new Map()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOM query helper.
|
||||||
|
* TODO: Move it into "dom-utils.js" module and "require" it when needed.
|
||||||
|
*/
|
||||||
|
var $ = (selector, target = document) => target.querySelector(selector);
|
||||||
|
var $all = (selector, target = document) => target.querySelectorAll(selector);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure certain properties are available on all objects in a data store.
|
* Makes sure certain properties are available on all objects in a data store.
|
||||||
*
|
*
|
||||||
* @param Store dataStore
|
* @param array dataStore
|
||||||
* A Redux store for which to check the availability of properties.
|
* The request view object from which to fetch the item list.
|
||||||
* @param array mandatoryFields
|
* @param array mandatoryFields
|
||||||
* A list of strings representing properties of objects in dataStore.
|
* A list of strings representing properties of objects in dataStore.
|
||||||
* @return object
|
* @return object
|
||||||
* A promise resolved when all objects in dataStore contain the
|
* A promise resolved when all objects in dataStore contain the
|
||||||
* properties defined in mandatoryFields.
|
* properties defined in mandatoryFields.
|
||||||
*/
|
*/
|
||||||
function whenDataAvailable(dataStore, mandatoryFields) {
|
function whenDataAvailable(requestsView, mandatoryFields) {
|
||||||
return new Promise((resolve, reject) => {
|
let deferred = promise.defer();
|
||||||
let interval = setInterval(() => {
|
|
||||||
const { requests } = dataStore.getState().requests;
|
|
||||||
const allFieldsPresent = !requests.isEmpty() && requests.every(
|
|
||||||
item => mandatoryFields.every(
|
|
||||||
field => item.get(field) !== undefined
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (allFieldsPresent) {
|
let interval = setInterval(() => {
|
||||||
clearInterval(interval);
|
const { attachments } = requestsView;
|
||||||
clearTimeout(timer);
|
if (attachments.length > 0 && attachments.every(item => {
|
||||||
resolve();
|
return mandatoryFields.every(field => field in item);
|
||||||
}
|
})) {
|
||||||
}, WDA_DEFAULT_VERIFY_INTERVAL);
|
|
||||||
|
|
||||||
let timer = setTimeout(() => {
|
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
reject(new Error("Timed out while waiting for data"));
|
clearTimeout(timer);
|
||||||
}, WDA_DEFAULT_GIVE_UP_TIMEOUT);
|
deferred.resolve();
|
||||||
});
|
}
|
||||||
|
}, WDA_DEFAULT_VERIFY_INTERVAL);
|
||||||
|
|
||||||
|
let timer = setTimeout(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
deferred.reject(new Error("Timed out while waiting for data"));
|
||||||
|
}, WDA_DEFAULT_GIVE_UP_TIMEOUT);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -279,5 +290,3 @@ NetMonitorView.NetworkDetails = new DetailsView();
|
||||||
NetMonitorView.RequestsMenu = new RequestsMenuView();
|
NetMonitorView.RequestsMenu = new RequestsMenuView();
|
||||||
NetMonitorView.CustomRequest = new CustomRequestView();
|
NetMonitorView.CustomRequest = new CustomRequestView();
|
||||||
NetMonitorView.PerformanceStatistics = new PerformanceStatisticsView();
|
NetMonitorView.PerformanceStatistics = new PerformanceStatisticsView();
|
||||||
|
|
||||||
exports.NetMonitorView = NetMonitorView;
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* globals window, document, NetMonitorController, NetMonitorView */
|
|
||||||
/* exported Netmonitor, NetMonitorController, NetMonitorView, $, $all, dumpn */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const Cu = Components.utils;
|
|
||||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
|
||||||
const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
|
|
||||||
|
|
||||||
function Netmonitor(toolbox) {
|
|
||||||
const { require } = BrowserLoader({
|
|
||||||
baseURI: "resource://devtools/client/netmonitor/",
|
|
||||||
window,
|
|
||||||
commonLibRequire: toolbox.browserRequire,
|
|
||||||
});
|
|
||||||
|
|
||||||
window.windowRequire = require;
|
|
||||||
|
|
||||||
const { NetMonitorController } = require("./netmonitor-controller.js");
|
|
||||||
const { NetMonitorView } = require("./netmonitor-view.js");
|
|
||||||
|
|
||||||
window.NetMonitorController = NetMonitorController;
|
|
||||||
window.NetMonitorView = NetMonitorView;
|
|
||||||
|
|
||||||
NetMonitorController._toolbox = toolbox;
|
|
||||||
NetMonitorController._target = toolbox.target;
|
|
||||||
}
|
|
||||||
|
|
||||||
Netmonitor.prototype = {
|
|
||||||
init() {
|
|
||||||
return window.NetMonitorController.startupNetMonitor();
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
return window.NetMonitorController.shutdownNetMonitor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DOM query helper.
|
|
||||||
* TODO: Move it into "dom-utils.js" module and "require" it when needed.
|
|
||||||
*/
|
|
||||||
var $ = (selector, target = document) => target.querySelector(selector);
|
|
||||||
var $all = (selector, target = document) => target.querySelectorAll(selector);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method for debugging.
|
|
||||||
* @param string
|
|
||||||
*/
|
|
||||||
function dumpn(str) {
|
|
||||||
if (wantLogging) {
|
|
||||||
dump("NET-FRONTEND: " + str + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
<script type="application/javascript;version=1.8"
|
<script type="application/javascript;version=1.8"
|
||||||
src="chrome://devtools/content/shared/theme-switching.js"/>
|
src="chrome://devtools/content/shared/theme-switching.js"/>
|
||||||
<script type="text/javascript" src="netmonitor.js"/>
|
<script type="text/javascript" src="netmonitor-controller.js"/>
|
||||||
|
<script type="text/javascript" src="netmonitor-view.js"/>
|
||||||
|
|
||||||
<deck id="body"
|
<deck id="body"
|
||||||
class="theme-sidebar"
|
class="theme-sidebar"
|
||||||
|
@ -25,10 +26,188 @@
|
||||||
<hbox id="network-table-and-sidebar"
|
<hbox id="network-table-and-sidebar"
|
||||||
class="devtools-responsive-container"
|
class="devtools-responsive-container"
|
||||||
flex="1">
|
flex="1">
|
||||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
<vbox id="network-table" flex="1" class="devtools-main-content">
|
||||||
id="network-table"
|
<toolbar id="requests-menu-toolbar"
|
||||||
class="devtools-main-content">
|
class="devtools-toolbar"
|
||||||
</html:div>
|
align="center">
|
||||||
|
<hbox id="toolbar-labels" flex="1">
|
||||||
|
<hbox id="requests-menu-status-header-box"
|
||||||
|
class="requests-menu-header requests-menu-status"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-status-button"
|
||||||
|
class="requests-menu-header-button requests-menu-status"
|
||||||
|
data-key="status"
|
||||||
|
data-localization="label=netmonitor.toolbar.status3"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-method-header-box"
|
||||||
|
class="requests-menu-header requests-menu-method"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-method-button"
|
||||||
|
class="requests-menu-header-button requests-menu-method"
|
||||||
|
data-key="method"
|
||||||
|
data-localization="label=netmonitor.toolbar.method"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-icon-and-file-header-box"
|
||||||
|
class="requests-menu-header requests-menu-icon-and-file"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-file-button"
|
||||||
|
class="requests-menu-header-button requests-menu-file"
|
||||||
|
data-key="file"
|
||||||
|
data-localization="label=netmonitor.toolbar.file"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-domain-header-box"
|
||||||
|
class="requests-menu-header requests-menu-security-and-domain"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-domain-button"
|
||||||
|
class="requests-menu-header-button requests-menu-security-and-domain"
|
||||||
|
data-key="domain"
|
||||||
|
data-localization="label=netmonitor.toolbar.domain"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-cause-header-box"
|
||||||
|
class="requests-menu-header requests-menu-cause"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-cause-button"
|
||||||
|
class="requests-menu-header-button requests-menu-cause"
|
||||||
|
data-key="cause"
|
||||||
|
data-localization="label=netmonitor.toolbar.cause"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-type-header-box"
|
||||||
|
class="requests-menu-header requests-menu-type"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-type-button"
|
||||||
|
class="requests-menu-header-button requests-menu-type"
|
||||||
|
data-key="type"
|
||||||
|
data-localization="label=netmonitor.toolbar.type"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-transferred-header-box"
|
||||||
|
class="requests-menu-header requests-menu-transferred"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-transferred-button"
|
||||||
|
class="requests-menu-header-button requests-menu-transferred"
|
||||||
|
data-key="transferred"
|
||||||
|
data-localization="label=netmonitor.toolbar.transferred"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-size-header-box"
|
||||||
|
class="requests-menu-header requests-menu-size"
|
||||||
|
align="center">
|
||||||
|
<button id="requests-menu-size-button"
|
||||||
|
class="requests-menu-header-button requests-menu-size"
|
||||||
|
data-key="size"
|
||||||
|
data-localization="label=netmonitor.toolbar.size"
|
||||||
|
crop="end"
|
||||||
|
flex="1">
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="requests-menu-waterfall-header-box"
|
||||||
|
class="requests-menu-header requests-menu-waterfall"
|
||||||
|
align="center"
|
||||||
|
flex="1">
|
||||||
|
<button id="requests-menu-waterfall-button"
|
||||||
|
class="requests-menu-header-button requests-menu-waterfall"
|
||||||
|
data-key="waterfall"
|
||||||
|
pack="start"
|
||||||
|
data-localization="label=netmonitor.toolbar.waterfall"
|
||||||
|
flex="1">
|
||||||
|
<image id="requests-menu-waterfall-image"/>
|
||||||
|
<box id="requests-menu-waterfall-label-wrapper">
|
||||||
|
<label id="requests-menu-waterfall-label"
|
||||||
|
class="plain requests-menu-waterfall"
|
||||||
|
data-localization="value=netmonitor.toolbar.waterfall"/>
|
||||||
|
</box>
|
||||||
|
</button>
|
||||||
|
</hbox>
|
||||||
|
</hbox>
|
||||||
|
</toolbar>
|
||||||
|
|
||||||
|
<vbox id="requests-menu-empty-notice"
|
||||||
|
class="side-menu-widget-empty-text">
|
||||||
|
<hbox id="notice-reload-message" align="center">
|
||||||
|
<label data-localization="content=netmonitor.reloadNotice1"/>
|
||||||
|
<button id="requests-menu-reload-notice-button"
|
||||||
|
class="devtools-toolbarbutton"
|
||||||
|
standalone="true"
|
||||||
|
data-localization="label=netmonitor.reloadNotice2"/>
|
||||||
|
<label data-localization="content=netmonitor.reloadNotice3"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox id="notice-perf-message" align="center">
|
||||||
|
<label data-localization="content=netmonitor.perfNotice1"/>
|
||||||
|
<button id="requests-menu-perf-notice-button"
|
||||||
|
class="devtools-toolbarbutton"
|
||||||
|
standalone="true"
|
||||||
|
data-localization="tooltiptext=netmonitor.perfNotice3"/>
|
||||||
|
<label data-localization="content=netmonitor.perfNotice2"/>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
|
|
||||||
|
<vbox id="requests-menu-contents" flex="1">
|
||||||
|
<hbox id="requests-menu-item-template" hidden="true">
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-status"
|
||||||
|
align="center">
|
||||||
|
<box class="requests-menu-status-icon"/>
|
||||||
|
<label class="plain requests-menu-status-code"
|
||||||
|
crop="end"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-method-box"
|
||||||
|
align="center">
|
||||||
|
<label class="plain requests-menu-method"
|
||||||
|
crop="end"
|
||||||
|
flex="1"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-icon-and-file"
|
||||||
|
align="center">
|
||||||
|
<image class="requests-menu-icon" hidden="true"/>
|
||||||
|
<label class="plain requests-menu-file"
|
||||||
|
crop="end"
|
||||||
|
flex="1"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-security-and-domain"
|
||||||
|
align="center">
|
||||||
|
<image class="requests-security-state-icon" />
|
||||||
|
<label class="plain requests-menu-domain"
|
||||||
|
crop="end"
|
||||||
|
flex="1"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-cause" align="center">
|
||||||
|
<label class="requests-menu-cause-stack" value="JS" hidden="true"/>
|
||||||
|
<label class="plain requests-menu-cause-label" flex="1" crop="end"/>
|
||||||
|
</hbox>
|
||||||
|
<label class="plain requests-menu-subitem requests-menu-type"
|
||||||
|
crop="end"/>
|
||||||
|
<label class="plain requests-menu-subitem requests-menu-transferred"
|
||||||
|
crop="end"/>
|
||||||
|
<label class="plain requests-menu-subitem requests-menu-size"
|
||||||
|
crop="end"/>
|
||||||
|
<hbox class="requests-menu-subitem requests-menu-waterfall"
|
||||||
|
align="center"
|
||||||
|
flex="1">
|
||||||
|
<hbox class="requests-menu-timings"
|
||||||
|
align="center">
|
||||||
|
<label class="plain requests-menu-timings-total"/>
|
||||||
|
</hbox>
|
||||||
|
</hbox>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
|
</vbox>
|
||||||
|
|
||||||
<splitter id="network-inspector-view-splitter"
|
<splitter id="network-inspector-view-splitter"
|
||||||
class="devtools-side-splitter"/>
|
class="devtools-side-splitter"/>
|
||||||
|
|
|
@ -14,7 +14,10 @@ function NetMonitorPanel(iframeWindow, toolbox) {
|
||||||
this.panelDoc = iframeWindow.document;
|
this.panelDoc = iframeWindow.document;
|
||||||
this._toolbox = toolbox;
|
this._toolbox = toolbox;
|
||||||
|
|
||||||
this._netmonitor = new iframeWindow.Netmonitor(toolbox);
|
this._view = this.panelWin.NetMonitorView;
|
||||||
|
this._controller = this.panelWin.NetMonitorController;
|
||||||
|
this._controller._target = this.target;
|
||||||
|
this._controller._toolbox = this._toolbox;
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
EventEmitter.decorate(this);
|
||||||
}
|
}
|
||||||
|
@ -43,8 +46,7 @@ NetMonitorPanel.prototype = {
|
||||||
yield this.target.makeRemote();
|
yield this.target.makeRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
yield this._netmonitor.init();
|
yield this._controller.startupNetMonitor();
|
||||||
|
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
|
|
||||||
|
@ -65,7 +67,7 @@ NetMonitorPanel.prototype = {
|
||||||
let deferred = promise.defer();
|
let deferred = promise.defer();
|
||||||
this._destroying = deferred.promise;
|
this._destroying = deferred.promise;
|
||||||
|
|
||||||
yield this._netmonitor.destroy();
|
yield this._controller.shutdownNetMonitor();
|
||||||
this.emit("destroyed");
|
this.emit("destroyed");
|
||||||
|
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
|
|
|
@ -2,21 +2,16 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* import-globals-from ./netmonitor-controller.js */
|
||||||
/* globals $, window, document, NetMonitorView */
|
/* globals $ */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
const {PluralForm} = require("devtools/shared/plural-form");
|
const {PluralForm} = require("devtools/shared/plural-form");
|
||||||
const {Filters} = require("./filter-predicates");
|
const {Filters} = require("./filter-predicates");
|
||||||
const {L10N} = require("./l10n");
|
const {L10N} = require("./l10n");
|
||||||
const {EVENTS} = require("./events");
|
|
||||||
const Actions = require("./actions/index");
|
const Actions = require("./actions/index");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Chart",
|
|
||||||
"resource://devtools/client/shared/widgets/Chart.jsm");
|
|
||||||
|
|
||||||
const REQUEST_TIME_DECIMALS = 2;
|
const REQUEST_TIME_DECIMALS = 2;
|
||||||
const CONTENT_SIZE_DECIMALS = 2;
|
const CONTENT_SIZE_DECIMALS = 2;
|
||||||
|
|
||||||
|
@ -177,7 +172,7 @@ PerformanceStatisticsView.prototype = {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (let requestItem of items) {
|
for (let requestItem of items) {
|
||||||
let details = requestItem;
|
let details = requestItem.attachment;
|
||||||
let type;
|
let type;
|
||||||
|
|
||||||
if (Filters.html(details)) {
|
if (Filters.html(details)) {
|
||||||
|
@ -242,8 +237,11 @@ function responseIsFresh({ responseHeaders, status }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = responseHeaders.headers;
|
let list = responseHeaders.headers;
|
||||||
let cacheControl = list.find(e => e.name.toLowerCase() == "cache-control");
|
let cacheControl = list.filter(e => {
|
||||||
let expires = list.find(e => e.name.toLowerCase() == "expires");
|
return e.name.toLowerCase() == "cache-control";
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
let expires = list.filter(e => e.name.toLowerCase() == "expires")[0];
|
||||||
|
|
||||||
// Check the "Cache-Control" header for a maximum age value.
|
// Check the "Cache-Control" header for a maximum age value.
|
||||||
if (cacheControl) {
|
if (cacheControl) {
|
||||||
|
|
|
@ -13,5 +13,6 @@ const {PrefsHelper} = require("devtools/client/shared/prefs");
|
||||||
exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
||||||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||||
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
||||||
|
statistics: ["Bool", "statistics"],
|
||||||
filters: ["Json", "filters"]
|
filters: ["Json", "filters"]
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* 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 { BATCH_ACTIONS } = require("../constants");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A reducer to handle batched actions. For each action in the BATCH_ACTIONS array,
|
|
||||||
* the reducer is called successively on the array of batched actions, resulting in
|
|
||||||
* only one state update.
|
|
||||||
*/
|
|
||||||
function batchingReducer(nextReducer) {
|
|
||||||
return function reducer(state, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case BATCH_ACTIONS:
|
|
||||||
return action.actions.reduce(reducer, state);
|
|
||||||
default:
|
|
||||||
return nextReducer(state, action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = batchingReducer;
|
|
|
@ -27,7 +27,7 @@ const FilterTypes = I.Record({
|
||||||
|
|
||||||
const Filters = I.Record({
|
const Filters = I.Record({
|
||||||
types: new FilterTypes({ all: true }),
|
types: new FilterTypes({ all: true }),
|
||||||
text: "",
|
url: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleFilterType(state, action) {
|
function toggleFilterType(state, action) {
|
||||||
|
@ -72,7 +72,7 @@ function filters(state = new Filters(), action) {
|
||||||
case ENABLE_FILTER_TYPE_ONLY:
|
case ENABLE_FILTER_TYPE_ONLY:
|
||||||
return state.set("types", enableFilterTypeOnly(state.types, action));
|
return state.set("types", enableFilterTypeOnly(state.types, action));
|
||||||
case SET_FILTER_TEXT:
|
case SET_FILTER_TEXT:
|
||||||
return state.set("text", action.text);
|
return state.set("url", action.url);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { combineReducers } = require("devtools/client/shared/vendor/redux");
|
const { combineReducers } = require("devtools/client/shared/vendor/redux");
|
||||||
const batchingReducer = require("./batching");
|
|
||||||
const requests = require("./requests");
|
|
||||||
const sort = require("./sort");
|
|
||||||
const filters = require("./filters");
|
const filters = require("./filters");
|
||||||
const timingMarkers = require("./timing-markers");
|
const requests = require("./requests");
|
||||||
const ui = require("./ui");
|
const ui = require("./ui");
|
||||||
|
|
||||||
module.exports = batchingReducer(
|
module.exports = combineReducers({
|
||||||
combineReducers({
|
filters,
|
||||||
requests,
|
requests,
|
||||||
sort,
|
ui,
|
||||||
filters,
|
});
|
||||||
timingMarkers,
|
|
||||||
ui,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
|
@ -3,11 +3,8 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'batching.js',
|
|
||||||
'filters.js',
|
'filters.js',
|
||||||
'index.js',
|
'index.js',
|
||||||
'requests.js',
|
'requests.js',
|
||||||
'sort.js',
|
|
||||||
'timing-markers.js',
|
|
||||||
'ui.js',
|
'ui.js',
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,242 +5,25 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const I = require("devtools/client/shared/vendor/immutable");
|
const I = require("devtools/client/shared/vendor/immutable");
|
||||||
const { getUrlDetails } = require("../request-utils");
|
|
||||||
const {
|
const {
|
||||||
ADD_REQUEST,
|
UPDATE_REQUESTS,
|
||||||
UPDATE_REQUEST,
|
|
||||||
CLEAR_REQUESTS,
|
|
||||||
SELECT_REQUEST,
|
|
||||||
PRESELECT_REQUEST,
|
|
||||||
CLONE_SELECTED_REQUEST,
|
|
||||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
|
||||||
OPEN_SIDEBAR
|
|
||||||
} = require("../constants");
|
} = require("../constants");
|
||||||
|
|
||||||
const Request = I.Record({
|
|
||||||
id: null,
|
|
||||||
// Set to true in case of a request that's being edited as part of "edit and resend"
|
|
||||||
isCustom: false,
|
|
||||||
// Request properties - at the beginning, they are unknown and are gradually filled in
|
|
||||||
startedMillis: undefined,
|
|
||||||
method: undefined,
|
|
||||||
url: undefined,
|
|
||||||
urlDetails: undefined,
|
|
||||||
remotePort: undefined,
|
|
||||||
remoteAddress: undefined,
|
|
||||||
isXHR: undefined,
|
|
||||||
cause: undefined,
|
|
||||||
fromCache: undefined,
|
|
||||||
fromServiceWorker: undefined,
|
|
||||||
status: undefined,
|
|
||||||
statusText: undefined,
|
|
||||||
httpVersion: undefined,
|
|
||||||
securityState: undefined,
|
|
||||||
securityInfo: undefined,
|
|
||||||
mimeType: undefined,
|
|
||||||
contentSize: undefined,
|
|
||||||
transferredSize: undefined,
|
|
||||||
totalTime: undefined,
|
|
||||||
eventTimings: undefined,
|
|
||||||
headersSize: undefined,
|
|
||||||
requestHeaders: undefined,
|
|
||||||
requestHeadersFromUploadStream: undefined,
|
|
||||||
requestCookies: undefined,
|
|
||||||
requestPostData: undefined,
|
|
||||||
responseHeaders: undefined,
|
|
||||||
responseCookies: undefined,
|
|
||||||
responseContent: undefined,
|
|
||||||
responseContentDataUri: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const Requests = I.Record({
|
const Requests = I.Record({
|
||||||
// The request list
|
items: [],
|
||||||
requests: I.List(),
|
|
||||||
// Selection state
|
|
||||||
selectedId: null,
|
|
||||||
preselectedId: null,
|
|
||||||
// Auxiliary fields to hold requests stats
|
|
||||||
firstStartedMillis: +Infinity,
|
|
||||||
lastEndedMillis: -Infinity,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const UPDATE_PROPS = [
|
function updateRequests(state, action) {
|
||||||
"method",
|
return state.set("items", action.items || state.items);
|
||||||
"url",
|
}
|
||||||
"remotePort",
|
|
||||||
"remoteAddress",
|
|
||||||
"status",
|
|
||||||
"statusText",
|
|
||||||
"httpVersion",
|
|
||||||
"securityState",
|
|
||||||
"securityInfo",
|
|
||||||
"mimeType",
|
|
||||||
"contentSize",
|
|
||||||
"transferredSize",
|
|
||||||
"totalTime",
|
|
||||||
"eventTimings",
|
|
||||||
"headersSize",
|
|
||||||
"requestHeaders",
|
|
||||||
"requestHeadersFromUploadStream",
|
|
||||||
"requestCookies",
|
|
||||||
"requestPostData",
|
|
||||||
"responseHeaders",
|
|
||||||
"responseCookies",
|
|
||||||
"responseContent",
|
|
||||||
"responseContentDataUri"
|
|
||||||
];
|
|
||||||
|
|
||||||
function requestsReducer(state = new Requests(), action) {
|
function requests(state = new Requests(), action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADD_REQUEST: {
|
case UPDATE_REQUESTS:
|
||||||
return state.withMutations(st => {
|
return updateRequests(state, action);
|
||||||
let newRequest = new Request(Object.assign(
|
|
||||||
{ id: action.id },
|
|
||||||
action.data,
|
|
||||||
{ urlDetails: getUrlDetails(action.data.url) }
|
|
||||||
));
|
|
||||||
st.requests = st.requests.push(newRequest);
|
|
||||||
|
|
||||||
// Update the started/ended timestamps
|
|
||||||
let { startedMillis } = action.data;
|
|
||||||
if (startedMillis < st.firstStartedMillis) {
|
|
||||||
st.firstStartedMillis = startedMillis;
|
|
||||||
}
|
|
||||||
if (startedMillis > st.lastEndedMillis) {
|
|
||||||
st.lastEndedMillis = startedMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the request if it was preselected and there is no other selection
|
|
||||||
if (st.preselectedId && st.preselectedId === action.id) {
|
|
||||||
st.selectedId = st.selectedId || st.preselectedId;
|
|
||||||
st.preselectedId = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
case UPDATE_REQUEST: {
|
|
||||||
let { requests, lastEndedMillis } = state;
|
|
||||||
|
|
||||||
let updateIdx = requests.findIndex(r => r.id === action.id);
|
|
||||||
if (updateIdx === -1) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
requests = requests.update(updateIdx, r => r.withMutations(request => {
|
|
||||||
for (let [key, value] of Object.entries(action.data)) {
|
|
||||||
if (!UPDATE_PROPS.includes(key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
request[key] = value;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case "url":
|
|
||||||
// Compute the additional URL details
|
|
||||||
request.urlDetails = getUrlDetails(value);
|
|
||||||
break;
|
|
||||||
case "responseContent":
|
|
||||||
// If there's no mime type available when the response content
|
|
||||||
// is received, assume text/plain as a fallback.
|
|
||||||
if (!request.mimeType) {
|
|
||||||
request.mimeType = "text/plain";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "totalTime":
|
|
||||||
const endedMillis = request.startedMillis + value;
|
|
||||||
lastEndedMillis = Math.max(lastEndedMillis, endedMillis);
|
|
||||||
break;
|
|
||||||
case "requestPostData":
|
|
||||||
request.requestHeadersFromUploadStream = {
|
|
||||||
headers: [],
|
|
||||||
headersSize: 0,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return state.withMutations(st => {
|
|
||||||
st.requests = requests;
|
|
||||||
st.lastEndedMillis = lastEndedMillis;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
case CLEAR_REQUESTS: {
|
|
||||||
return new Requests();
|
|
||||||
}
|
|
||||||
case SELECT_REQUEST: {
|
|
||||||
return state.set("selectedId", action.id);
|
|
||||||
}
|
|
||||||
case PRESELECT_REQUEST: {
|
|
||||||
return state.set("preselectedId", action.id);
|
|
||||||
}
|
|
||||||
case CLONE_SELECTED_REQUEST: {
|
|
||||||
let { requests, selectedId } = state;
|
|
||||||
|
|
||||||
if (!selectedId) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
let clonedIdx = requests.findIndex(r => r.id === selectedId);
|
|
||||||
if (clonedIdx === -1) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
let clonedRequest = requests.get(clonedIdx);
|
|
||||||
let newRequest = new Request({
|
|
||||||
id: clonedRequest.id + "-clone",
|
|
||||||
method: clonedRequest.method,
|
|
||||||
url: clonedRequest.url,
|
|
||||||
urlDetails: clonedRequest.urlDetails,
|
|
||||||
requestHeaders: clonedRequest.requestHeaders,
|
|
||||||
requestPostData: clonedRequest.requestPostData,
|
|
||||||
isCustom: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Insert the clone right after the original. This ensures that the requests
|
|
||||||
// are always sorted next to each other, even when multiple requests are
|
|
||||||
// equal according to the sorting criteria.
|
|
||||||
requests = requests.insert(clonedIdx + 1, newRequest);
|
|
||||||
|
|
||||||
return state.withMutations(st => {
|
|
||||||
st.requests = requests;
|
|
||||||
st.selectedId = newRequest.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
case REMOVE_SELECTED_CUSTOM_REQUEST: {
|
|
||||||
let { requests, selectedId } = state;
|
|
||||||
|
|
||||||
if (!selectedId) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
let removedRequest = requests.find(r => r.id === selectedId);
|
|
||||||
|
|
||||||
// Only custom requests can be removed
|
|
||||||
if (!removedRequest || !removedRequest.isCustom) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.withMutations(st => {
|
|
||||||
st.requests = requests.filter(r => r !== removedRequest);
|
|
||||||
st.selectedId = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
case OPEN_SIDEBAR: {
|
|
||||||
if (!action.open) {
|
|
||||||
return state.set("selectedId", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.selectedId && !state.requests.isEmpty()) {
|
|
||||||
return state.set("selectedId", state.requests.get(0).id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = requestsReducer;
|
module.exports = requests;
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/* 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 I = require("devtools/client/shared/vendor/immutable");
|
|
||||||
const { SORT_BY } = require("../constants");
|
|
||||||
|
|
||||||
const Sort = I.Record({
|
|
||||||
// null means: sort by "waterfall", but don't highlight the table header
|
|
||||||
type: null,
|
|
||||||
ascending: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
function sortReducer(state = new Sort(), action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case SORT_BY: {
|
|
||||||
return state.withMutations(st => {
|
|
||||||
if (action.sortType == st.type) {
|
|
||||||
st.ascending = !st.ascending;
|
|
||||||
} else {
|
|
||||||
st.type = action.sortType;
|
|
||||||
st.ascending = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = sortReducer;
|
|
|
@ -1,54 +0,0 @@
|
||||||
/* 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 I = require("devtools/client/shared/vendor/immutable");
|
|
||||||
const { ADD_TIMING_MARKER,
|
|
||||||
CLEAR_TIMING_MARKERS,
|
|
||||||
CLEAR_REQUESTS } = require("../constants");
|
|
||||||
|
|
||||||
const TimingMarkers = I.Record({
|
|
||||||
firstDocumentDOMContentLoadedTimestamp: -1,
|
|
||||||
firstDocumentLoadTimestamp: -1,
|
|
||||||
});
|
|
||||||
|
|
||||||
function addTimingMarker(state, action) {
|
|
||||||
if (action.marker.name == "document::DOMContentLoaded" &&
|
|
||||||
state.firstDocumentDOMContentLoadedTimestamp == -1) {
|
|
||||||
return state.set("firstDocumentDOMContentLoadedTimestamp",
|
|
||||||
action.marker.unixTime / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.marker.name == "document::Load" &&
|
|
||||||
state.firstDocumentLoadTimestamp == -1) {
|
|
||||||
return state.set("firstDocumentLoadTimestamp",
|
|
||||||
action.marker.unixTime / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearTimingMarkers(state) {
|
|
||||||
return state.withMutations(st => {
|
|
||||||
st.remove("firstDocumentDOMContentLoadedTimestamp");
|
|
||||||
st.remove("firstDocumentLoadTimestamp");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function timingMarkers(state = new TimingMarkers(), action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case ADD_TIMING_MARKER:
|
|
||||||
return addTimingMarker(state, action);
|
|
||||||
|
|
||||||
case CLEAR_REQUESTS:
|
|
||||||
case CLEAR_TIMING_MARKERS:
|
|
||||||
return clearTimingMarkers(state);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = timingMarkers;
|
|
|
@ -7,31 +7,31 @@
|
||||||
const I = require("devtools/client/shared/vendor/immutable");
|
const I = require("devtools/client/shared/vendor/immutable");
|
||||||
const {
|
const {
|
||||||
OPEN_SIDEBAR,
|
OPEN_SIDEBAR,
|
||||||
WATERFALL_RESIZE,
|
TOGGLE_SIDEBAR,
|
||||||
} = require("../constants");
|
} = require("../constants");
|
||||||
|
|
||||||
|
const Sidebar = I.Record({
|
||||||
|
open: false,
|
||||||
|
});
|
||||||
|
|
||||||
const UI = I.Record({
|
const UI = I.Record({
|
||||||
sidebarOpen: false,
|
sidebar: new Sidebar(),
|
||||||
waterfallWidth: 300,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function openSidebar(state, action) {
|
function openSidebar(state, action) {
|
||||||
return state.set("sidebarOpen", action.open);
|
return state.setIn(["sidebar", "open"], action.open);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe bounds for waterfall width (px)
|
function toggleSidebar(state, action) {
|
||||||
const REQUESTS_WATERFALL_SAFE_BOUNDS = 90;
|
return state.setIn(["sidebar", "open"], !state.sidebar.open);
|
||||||
|
|
||||||
function resizeWaterfall(state, action) {
|
|
||||||
return state.set("waterfallWidth", action.width - REQUESTS_WATERFALL_SAFE_BOUNDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui(state = new UI(), action) {
|
function ui(state = new UI(), action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case OPEN_SIDEBAR:
|
case OPEN_SIDEBAR:
|
||||||
return openSidebar(state, action);
|
return openSidebar(state, action);
|
||||||
case WATERFALL_RESIZE:
|
case TOGGLE_SIDEBAR:
|
||||||
return resizeWaterfall(state, action);
|
return toggleSidebar(state, action);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-copy-url-params",
|
id: "request-menu-context-copy-url-params",
|
||||||
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
||||||
visible: !!(selectedItem && getUrlQuery(selectedItem.url)),
|
visible: !!(selectedItem && getUrlQuery(selectedItem.attachment.url)),
|
||||||
click: () => this.copyUrlParams(),
|
click: () => this.copyUrlParams(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-copy-post-data",
|
id: "request-menu-context-copy-post-data",
|
||||||
label: L10N.getStr("netmonitor.context.copyPostData"),
|
label: L10N.getStr("netmonitor.context.copyPostData"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
|
||||||
visible: !!(selectedItem && selectedItem.requestPostData),
|
visible: !!(selectedItem && selectedItem.attachment.requestPostData),
|
||||||
click: () => this.copyPostData(),
|
click: () => this.copyPostData(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-copy-as-curl",
|
id: "request-menu-context-copy-as-curl",
|
||||||
label: L10N.getStr("netmonitor.context.copyAsCurl"),
|
label: L10N.getStr("netmonitor.context.copyAsCurl"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
|
||||||
visible: !!selectedItem,
|
visible: !!(selectedItem && selectedItem.attachment),
|
||||||
click: () => this.copyAsCurl(),
|
click: () => this.copyAsCurl(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-copy-request-headers",
|
id: "request-menu-context-copy-request-headers",
|
||||||
label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
|
label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
|
||||||
visible: !!(selectedItem && selectedItem.requestHeaders),
|
visible: !!(selectedItem && selectedItem.attachment.requestHeaders),
|
||||||
click: () => this.copyRequestHeaders(),
|
click: () => this.copyRequestHeaders(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "response-menu-context-copy-response-headers",
|
id: "response-menu-context-copy-response-headers",
|
||||||
label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
|
label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
|
||||||
visible: !!(selectedItem && selectedItem.responseHeaders),
|
visible: !!(selectedItem && selectedItem.attachment.responseHeaders),
|
||||||
click: () => this.copyResponseHeaders(),
|
click: () => this.copyResponseHeaders(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -104,9 +104,9 @@ RequestListContextMenu.prototype = {
|
||||||
label: L10N.getStr("netmonitor.context.copyResponse"),
|
label: L10N.getStr("netmonitor.context.copyResponse"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
|
||||||
visible: !!(selectedItem &&
|
visible: !!(selectedItem &&
|
||||||
selectedItem.responseContent &&
|
selectedItem.attachment.responseContent &&
|
||||||
selectedItem.responseContent.content.text &&
|
selectedItem.attachment.responseContent.content.text &&
|
||||||
selectedItem.responseContent.content.text.length !== 0),
|
selectedItem.attachment.responseContent.content.text.length !== 0),
|
||||||
click: () => this.copyResponse(),
|
click: () => this.copyResponse(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -115,8 +115,9 @@ RequestListContextMenu.prototype = {
|
||||||
label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
|
label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
|
||||||
visible: !!(selectedItem &&
|
visible: !!(selectedItem &&
|
||||||
selectedItem.responseContent &&
|
selectedItem.attachment.responseContent &&
|
||||||
selectedItem.responseContent.content.mimeType.includes("image/")),
|
selectedItem.attachment.responseContent.content
|
||||||
|
.mimeType.includes("image/")),
|
||||||
click: () => this.copyImageAsDataUri(),
|
click: () => this.copyImageAsDataUri(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-copy-all-as-har",
|
id: "request-menu-context-copy-all-as-har",
|
||||||
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
|
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
|
||||||
visible: this.items.size > 0,
|
visible: !!this.items.length,
|
||||||
click: () => this.copyAllAsHar(),
|
click: () => this.copyAllAsHar(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ RequestListContextMenu.prototype = {
|
||||||
id: "request-menu-context-save-all-as-har",
|
id: "request-menu-context-save-all-as-har",
|
||||||
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
|
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"),
|
||||||
visible: this.items.size > 0,
|
visible: !!this.items.length,
|
||||||
click: () => this.saveAllAsHar(),
|
click: () => this.saveAllAsHar(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -151,7 +152,8 @@ RequestListContextMenu.prototype = {
|
||||||
label: L10N.getStr("netmonitor.context.editAndResend"),
|
label: L10N.getStr("netmonitor.context.editAndResend"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
|
||||||
visible: !!(NetMonitorController.supportsCustomRequest &&
|
visible: !!(NetMonitorController.supportsCustomRequest &&
|
||||||
selectedItem && !selectedItem.isCustom),
|
selectedItem &&
|
||||||
|
!selectedItem.attachment.isCustom),
|
||||||
click: () => NetMonitorView.RequestsMenu.cloneSelectedRequest(),
|
click: () => NetMonitorView.RequestsMenu.cloneSelectedRequest(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -185,14 +187,15 @@ RequestListContextMenu.prototype = {
|
||||||
*/
|
*/
|
||||||
openRequestInTab() {
|
openRequestInTab() {
|
||||||
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
||||||
win.openUILinkIn(this.selectedItem.url, "tab", { relatedToCurrent: true });
|
let { url } = this.selectedItem.attachment;
|
||||||
|
win.openUILinkIn(url, "tab", { relatedToCurrent: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy the request url from the currently selected item.
|
* Copy the request url from the currently selected item.
|
||||||
*/
|
*/
|
||||||
copyUrl() {
|
copyUrl() {
|
||||||
clipboardHelper.copyString(this.selectedItem.url);
|
clipboardHelper.copyString(this.selectedItem.attachment.url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,7 +203,7 @@ RequestListContextMenu.prototype = {
|
||||||
* selected item.
|
* selected item.
|
||||||
*/
|
*/
|
||||||
copyUrlParams() {
|
copyUrlParams() {
|
||||||
let { url } = this.selectedItem;
|
let { url } = this.selectedItem.attachment;
|
||||||
let params = getUrlQuery(url).split("&");
|
let params = getUrlQuery(url).split("&");
|
||||||
let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
|
let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
|
||||||
clipboardHelper.copyString(string);
|
clipboardHelper.copyString(string);
|
||||||
|
@ -211,7 +214,7 @@ RequestListContextMenu.prototype = {
|
||||||
* the currently selected item.
|
* the currently selected item.
|
||||||
*/
|
*/
|
||||||
copyPostData: Task.async(function* () {
|
copyPostData: Task.async(function* () {
|
||||||
let selected = this.selectedItem;
|
let selected = this.selectedItem.attachment;
|
||||||
|
|
||||||
// Try to extract any form data parameters.
|
// Try to extract any form data parameters.
|
||||||
let formDataSections = yield getFormDataSections(
|
let formDataSections = yield getFormDataSections(
|
||||||
|
@ -248,7 +251,7 @@ RequestListContextMenu.prototype = {
|
||||||
* Copy a cURL command from the currently selected item.
|
* Copy a cURL command from the currently selected item.
|
||||||
*/
|
*/
|
||||||
copyAsCurl: Task.async(function* () {
|
copyAsCurl: Task.async(function* () {
|
||||||
let selected = this.selectedItem;
|
let selected = this.selectedItem.attachment;
|
||||||
|
|
||||||
// Create a sanitized object for the Curl command generator.
|
// Create a sanitized object for the Curl command generator.
|
||||||
let data = {
|
let data = {
|
||||||
|
@ -278,7 +281,8 @@ RequestListContextMenu.prototype = {
|
||||||
* Copy the raw request headers from the currently selected item.
|
* Copy the raw request headers from the currently selected item.
|
||||||
*/
|
*/
|
||||||
copyRequestHeaders() {
|
copyRequestHeaders() {
|
||||||
let rawHeaders = this.selectedItem.requestHeaders.rawHeaders.trim();
|
let selected = this.selectedItem.attachment;
|
||||||
|
let rawHeaders = selected.requestHeaders.rawHeaders.trim();
|
||||||
if (Services.appinfo.OS !== "WINNT") {
|
if (Services.appinfo.OS !== "WINNT") {
|
||||||
rawHeaders = rawHeaders.replace(/\r/g, "");
|
rawHeaders = rawHeaders.replace(/\r/g, "");
|
||||||
}
|
}
|
||||||
|
@ -289,7 +293,8 @@ RequestListContextMenu.prototype = {
|
||||||
* Copy the raw response headers from the currently selected item.
|
* Copy the raw response headers from the currently selected item.
|
||||||
*/
|
*/
|
||||||
copyResponseHeaders() {
|
copyResponseHeaders() {
|
||||||
let rawHeaders = this.selectedItem.responseHeaders.rawHeaders.trim();
|
let selected = this.selectedItem.attachment;
|
||||||
|
let rawHeaders = selected.responseHeaders.rawHeaders.trim();
|
||||||
if (Services.appinfo.OS !== "WINNT") {
|
if (Services.appinfo.OS !== "WINNT") {
|
||||||
rawHeaders = rawHeaders.replace(/\r/g, "");
|
rawHeaders = rawHeaders.replace(/\r/g, "");
|
||||||
}
|
}
|
||||||
|
@ -300,7 +305,8 @@ RequestListContextMenu.prototype = {
|
||||||
* Copy image as data uri.
|
* Copy image as data uri.
|
||||||
*/
|
*/
|
||||||
copyImageAsDataUri() {
|
copyImageAsDataUri() {
|
||||||
const { mimeType, text, encoding } = this.selectedItem.responseContent.content;
|
let selected = this.selectedItem.attachment;
|
||||||
|
let { mimeType, text, encoding } = selected.responseContent.content;
|
||||||
|
|
||||||
gNetwork.getString(text).then(string => {
|
gNetwork.getString(text).then(string => {
|
||||||
let data = formDataURI(mimeType, encoding, string);
|
let data = formDataURI(mimeType, encoding, string);
|
||||||
|
@ -312,7 +318,8 @@ RequestListContextMenu.prototype = {
|
||||||
* Copy response data as a string.
|
* Copy response data as a string.
|
||||||
*/
|
*/
|
||||||
copyResponse() {
|
copyResponse() {
|
||||||
const { text } = this.selectedItem.responseContent.content;
|
let selected = this.selectedItem.attachment;
|
||||||
|
let text = selected.responseContent.content.text;
|
||||||
|
|
||||||
gNetwork.getString(text).then(string => {
|
gNetwork.getString(text).then(string => {
|
||||||
clipboardHelper.copyString(string);
|
clipboardHelper.copyString(string);
|
||||||
|
@ -341,7 +348,8 @@ RequestListContextMenu.prototype = {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getString: gNetwork.getString.bind(gNetwork),
|
getString: gNetwork.getString.bind(gNetwork),
|
||||||
items: this.items,
|
view: NetMonitorView.RequestsMenu,
|
||||||
|
items: NetMonitorView.RequestsMenu.items,
|
||||||
title: title
|
title: title
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ const getFormDataSections = Task.async(function* (headers, uploadHeaders, postDa
|
||||||
getString) {
|
getString) {
|
||||||
let formDataSections = [];
|
let formDataSections = [];
|
||||||
|
|
||||||
let requestHeaders = headers.headers;
|
let { headers: requestHeaders } = headers;
|
||||||
let payloadHeaders = uploadHeaders ? uploadHeaders.headers : [];
|
let { headers: payloadHeaders } = uploadHeaders;
|
||||||
let allHeaders = [...payloadHeaders, ...requestHeaders];
|
let allHeaders = [...payloadHeaders, ...requestHeaders];
|
||||||
|
|
||||||
let contentTypeHeader = allHeaders.find(e => {
|
let contentTypeHeader = allHeaders.find(e => {
|
||||||
|
@ -188,37 +188,6 @@ function getUrlHost(url) {
|
||||||
return decodeUnicodeUrl((new URL(url)).host);
|
return decodeUnicodeUrl((new URL(url)).host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract several details fields from a URL at once.
|
|
||||||
*/
|
|
||||||
function getUrlDetails(url) {
|
|
||||||
let baseNameWithQuery = getUrlBaseNameWithQuery(url);
|
|
||||||
let host = getUrlHost(url);
|
|
||||||
let hostname = getUrlHostName(url);
|
|
||||||
let unicodeUrl = decodeUnicodeUrl(url);
|
|
||||||
|
|
||||||
// Mark local hosts specially, where "local" is as defined in the W3C
|
|
||||||
// spec for secure contexts.
|
|
||||||
// http://www.w3.org/TR/powerful-features/
|
|
||||||
//
|
|
||||||
// * If the name falls under 'localhost'
|
|
||||||
// * If the name is an IPv4 address within 127.0.0.0/8
|
|
||||||
// * If the name is an IPv6 address within ::1/128
|
|
||||||
//
|
|
||||||
// IPv6 parsing is a little sloppy; it assumes that the address has
|
|
||||||
// been validated before it gets here.
|
|
||||||
let isLocal = hostname.match(/(.+\.)?localhost$/) ||
|
|
||||||
hostname.match(/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}/) ||
|
|
||||||
hostname.match(/\[[0:]+1\]/);
|
|
||||||
|
|
||||||
return {
|
|
||||||
baseNameWithQuery,
|
|
||||||
host,
|
|
||||||
unicodeUrl,
|
|
||||||
isLocal
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a url's query string into its components
|
* Parse a url's query string into its components
|
||||||
*
|
*
|
||||||
|
@ -284,7 +253,6 @@ module.exports = {
|
||||||
getUrlBaseNameWithQuery,
|
getUrlBaseNameWithQuery,
|
||||||
getUrlHostName,
|
getUrlHostName,
|
||||||
getUrlHost,
|
getUrlHost,
|
||||||
getUrlDetails,
|
|
||||||
parseQueryString,
|
parseQueryString,
|
||||||
loadCauseString,
|
loadCauseString,
|
||||||
};
|
};
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,13 +0,0 @@
|
||||||
/* 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";
|
|
||||||
|
|
||||||
function getActiveFilters(state) {
|
|
||||||
return state.filters.types.toSeq().filter(checked => checked).keySeq().toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getActiveFilters
|
|
||||||
};
|
|
|
@ -4,12 +4,60 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const filters = require("./filters");
|
const { createSelector } = require("devtools/client/shared/vendor/reselect");
|
||||||
const requests = require("./requests");
|
|
||||||
const ui = require("./ui");
|
|
||||||
|
|
||||||
Object.assign(exports,
|
/**
|
||||||
filters,
|
* Gets the total number of bytes representing the cumulated content size of
|
||||||
requests,
|
* a set of requests. Returns 0 for an empty set.
|
||||||
ui
|
*
|
||||||
|
* @param {array} items - an array of request items
|
||||||
|
* @return {number} total bytes of requests
|
||||||
|
*/
|
||||||
|
function getTotalBytesOfRequests(items) {
|
||||||
|
if (!items.length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = 0;
|
||||||
|
items.forEach((item) => {
|
||||||
|
let size = item.attachment.contentSize;
|
||||||
|
result += (typeof size == "number") ? size : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total milliseconds for all requests. Returns null for an
|
||||||
|
* empty set.
|
||||||
|
*
|
||||||
|
* @param {array} items - an array of request items
|
||||||
|
* @return {object} total milliseconds for all requests
|
||||||
|
*/
|
||||||
|
function getTotalMillisOfRequests(items) {
|
||||||
|
if (!items.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldest = items.reduce((prev, curr) =>
|
||||||
|
prev.attachment.startedMillis < curr.attachment.startedMillis ?
|
||||||
|
prev : curr);
|
||||||
|
const newest = items.reduce((prev, curr) =>
|
||||||
|
prev.attachment.startedMillis > curr.attachment.startedMillis ?
|
||||||
|
prev : curr);
|
||||||
|
|
||||||
|
return newest.attachment.endedMillis - oldest.attachment.startedMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSummary = createSelector(
|
||||||
|
(state) => state.requests.items,
|
||||||
|
(requests) => ({
|
||||||
|
count: requests.length,
|
||||||
|
totalBytes: getTotalBytesOfRequests(requests),
|
||||||
|
totalMillis: getTotalMillisOfRequests(requests),
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getSummary,
|
||||||
|
};
|
||||||
|
|
|
@ -3,8 +3,5 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'filters.js',
|
'index.js'
|
||||||
'index.js',
|
|
||||||
'requests.js',
|
|
||||||
'ui.js',
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
/* 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 { createSelector } = require("devtools/client/shared/vendor/reselect");
|
|
||||||
const { Filters, isFreetextMatch } = require("../filter-predicates");
|
|
||||||
const { Sorters } = require("../sort-predicates");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given requests is a clone, find and return the original request if it is.
|
|
||||||
* Cloned requests are sorted by comparing the original ones.
|
|
||||||
*/
|
|
||||||
function getOrigRequest(requests, req) {
|
|
||||||
if (!req.id.endsWith("-clone")) {
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
const origId = req.id.replace(/-clone$/, "");
|
|
||||||
return requests.find(r => r.id === origId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFilterFn = createSelector(
|
|
||||||
state => state.filters,
|
|
||||||
filters => r => {
|
|
||||||
const matchesType = filters.types.some((enabled, filter) => {
|
|
||||||
return enabled && Filters[filter] && Filters[filter](r);
|
|
||||||
});
|
|
||||||
return matchesType && isFreetextMatch(r, filters.text);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const getSortFn = createSelector(
|
|
||||||
state => state.requests.requests,
|
|
||||||
state => state.sort,
|
|
||||||
(requests, sort) => {
|
|
||||||
let dataSorter = Sorters[sort.type || "waterfall"];
|
|
||||||
|
|
||||||
function sortWithClones(a, b) {
|
|
||||||
// If one request is a clone of the other, sort them next to each other
|
|
||||||
if (a.id == b.id + "-clone") {
|
|
||||||
return +1;
|
|
||||||
} else if (a.id + "-clone" == b.id) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, get the original requests and compare them
|
|
||||||
return dataSorter(
|
|
||||||
getOrigRequest(requests, a),
|
|
||||||
getOrigRequest(requests, b)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ascending = sort.ascending ? +1 : -1;
|
|
||||||
return (a, b) => ascending * sortWithClones(a, b, dataSorter);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const getSortedRequests = createSelector(
|
|
||||||
state => state.requests.requests,
|
|
||||||
getSortFn,
|
|
||||||
(requests, sortFn) => requests.sort(sortFn)
|
|
||||||
);
|
|
||||||
|
|
||||||
const getDisplayedRequests = createSelector(
|
|
||||||
state => state.requests.requests,
|
|
||||||
getFilterFn,
|
|
||||||
getSortFn,
|
|
||||||
(requests, filterFn, sortFn) => requests.filter(filterFn).sort(sortFn)
|
|
||||||
);
|
|
||||||
|
|
||||||
const getDisplayedRequestsSummary = createSelector(
|
|
||||||
getDisplayedRequests,
|
|
||||||
state => state.requests.lastEndedMillis - state.requests.firstStartedMillis,
|
|
||||||
(requests, totalMillis) => {
|
|
||||||
if (requests.size == 0) {
|
|
||||||
return { count: 0, bytes: 0, millis: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalBytes = requests.reduce((total, item) => {
|
|
||||||
if (typeof item.contentSize == "number") {
|
|
||||||
total += item.contentSize;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return {
|
|
||||||
count: requests.size,
|
|
||||||
bytes: totalBytes,
|
|
||||||
millis: totalMillis,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function getRequestById(state, id) {
|
|
||||||
return state.requests.requests.find(r => r.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDisplayedRequestById(state, id) {
|
|
||||||
return getDisplayedRequests(state).find(r => r.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSelectedRequest(state) {
|
|
||||||
if (!state.requests.selectedId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRequestById(state, state.requests.selectedId);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getSortedRequests,
|
|
||||||
getDisplayedRequests,
|
|
||||||
getDisplayedRequestsSummary,
|
|
||||||
getRequestById,
|
|
||||||
getDisplayedRequestById,
|
|
||||||
getSelectedRequest,
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
/* 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 { getDisplayedRequests } = require("./requests");
|
|
||||||
|
|
||||||
function isSidebarToggleButtonDisabled(state) {
|
|
||||||
return getDisplayedRequests(state).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
const EPSILON = 0.001;
|
|
||||||
|
|
||||||
function getWaterfallScale(state) {
|
|
||||||
const { requests, timingMarkers, ui } = state;
|
|
||||||
|
|
||||||
if (requests.firstStartedMillis == +Infinity) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastEventMillis = Math.max(requests.lastEndedMillis,
|
|
||||||
timingMarkers.firstDocumentDOMContentLoadedTimestamp,
|
|
||||||
timingMarkers.firstDocumentLoadTimestamp);
|
|
||||||
const longestWidth = lastEventMillis - requests.firstStartedMillis;
|
|
||||||
return Math.min(Math.max(ui.waterfallWidth / longestWidth, EPSILON), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
isSidebarToggleButtonDisabled,
|
|
||||||
getWaterfallScale,
|
|
||||||
};
|
|
|
@ -2,7 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* globals window, dumpn, $, NetMonitorView */
|
/* import-globals-from ./netmonitor-controller.js */
|
||||||
|
/* globals dumpn, $, NetMonitorView */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ SidebarView.prototype = {
|
||||||
*/
|
*/
|
||||||
toggle: function (visibleFlag) {
|
toggle: function (visibleFlag) {
|
||||||
NetMonitorView.toggleDetailsPane({ visible: visibleFlag });
|
NetMonitorView.toggleDetailsPane({ visible: visibleFlag });
|
||||||
|
NetMonitorView.RequestsMenu._flushWaterfallViews(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,7 @@ const {
|
||||||
getAbbreviatedMimeType,
|
getAbbreviatedMimeType,
|
||||||
getUrlBaseNameWithQuery,
|
getUrlBaseNameWithQuery,
|
||||||
getUrlHost,
|
getUrlHost,
|
||||||
|
loadCauseString,
|
||||||
} = require("./request-utils");
|
} = require("./request-utils");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,8 +60,8 @@ function domain(first, second) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cause(first, second) {
|
function cause(first, second) {
|
||||||
let firstCause = first.cause.type;
|
let firstCause = loadCauseString(first.cause.type);
|
||||||
let secondCause = second.cause.type;
|
let secondCause = loadCauseString(second.cause.type);
|
||||||
if (firstCause == secondCause) {
|
if (firstCause == secondCause) {
|
||||||
return first.startedMillis - second.startedMillis;
|
return first.startedMillis - second.startedMillis;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,11 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { createStore, applyMiddleware } = require("devtools/client/shared/vendor/redux");
|
const createStore = require("devtools/client/shared/redux/create-store");
|
||||||
const { thunk } = require("devtools/client/shared/redux/middleware/thunk");
|
const reducers = require("./reducers/index");
|
||||||
const batching = require("./middleware/batching");
|
|
||||||
const rootReducer = require("./reducers/index");
|
|
||||||
|
|
||||||
function configureStore() {
|
function configureStore() {
|
||||||
return createStore(
|
return createStore()(reducers);
|
||||||
rootReducer,
|
|
||||||
applyMiddleware(
|
|
||||||
thunk,
|
|
||||||
batching
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.configureStore = configureStore;
|
exports.configureStore = configureStore;
|
||||||
|
|
|
@ -54,6 +54,7 @@ support-files =
|
||||||
skip-if = (toolkit == "cocoa" && e10s) # bug 1252254
|
skip-if = (toolkit == "cocoa" && e10s) # bug 1252254
|
||||||
[browser_net_api-calls.js]
|
[browser_net_api-calls.js]
|
||||||
[browser_net_autoscroll.js]
|
[browser_net_autoscroll.js]
|
||||||
|
skip-if = true # Bug 1309191 - replace with rewritten version in React
|
||||||
[browser_net_cached-status.js]
|
[browser_net_cached-status.js]
|
||||||
[browser_net_cause.js]
|
[browser_net_cause.js]
|
||||||
[browser_net_cause_redirect.js]
|
[browser_net_cause_redirect.js]
|
||||||
|
@ -88,7 +89,7 @@ subsuite = clipboard
|
||||||
[browser_net_cyrillic-01.js]
|
[browser_net_cyrillic-01.js]
|
||||||
[browser_net_cyrillic-02.js]
|
[browser_net_cyrillic-02.js]
|
||||||
[browser_net_details-no-duplicated-content.js]
|
[browser_net_details-no-duplicated-content.js]
|
||||||
skip-if = true # Test broken in React version, is too low-level
|
skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
|
||||||
[browser_net_frame.js]
|
[browser_net_frame.js]
|
||||||
[browser_net_filter-01.js]
|
[browser_net_filter-01.js]
|
||||||
[browser_net_filter-02.js]
|
[browser_net_filter-02.js]
|
||||||
|
@ -139,7 +140,6 @@ skip-if = true # Bug 1258809
|
||||||
skip-if = true # Bug 1258809
|
skip-if = true # Bug 1258809
|
||||||
[browser_net_simple-request.js]
|
[browser_net_simple-request.js]
|
||||||
[browser_net_sort-01.js]
|
[browser_net_sort-01.js]
|
||||||
skip-if = true # Redundant for React/Redux version
|
|
||||||
[browser_net_sort-02.js]
|
[browser_net_sort-02.js]
|
||||||
[browser_net_sort-03.js]
|
[browser_net_sort-03.js]
|
||||||
[browser_net_statistics-01.js]
|
[browser_net_statistics-01.js]
|
||||||
|
@ -149,6 +149,5 @@ skip-if = true # Redundant for React/Redux version
|
||||||
[browser_net_streaming-response.js]
|
[browser_net_streaming-response.js]
|
||||||
[browser_net_throttle.js]
|
[browser_net_throttle.js]
|
||||||
[browser_net_timeline_ticks.js]
|
[browser_net_timeline_ticks.js]
|
||||||
skip-if = true # TODO: fix the test
|
|
||||||
[browser_net_timing-division.js]
|
[browser_net_timing-division.js]
|
||||||
[browser_net_persistent_logs.js]
|
[browser_net_persistent_logs.js]
|
||||||
|
|
|
@ -8,15 +8,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let Actions = require("devtools/client/netmonitor/actions/index");
|
|
||||||
|
|
||||||
let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
|
let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
|
||||||
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
||||||
requestLongerTimeout(2);
|
requestLongerTimeout(2);
|
||||||
|
|
||||||
let { NetMonitorView, gStore } = monitor.panelWin;
|
let { NetMonitorView } = monitor.panelWin;
|
||||||
let { RequestsMenu } = NetMonitorView;
|
let { RequestsMenu } = NetMonitorView;
|
||||||
|
|
||||||
RequestsMenu.lazyUpdate = false;
|
RequestsMenu.lazyUpdate = false;
|
||||||
|
@ -39,19 +37,24 @@ add_task(function* () {
|
||||||
|
|
||||||
check(-1, false);
|
check(-1, false);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+Infinity));
|
RequestsMenu.focusLastVisibleItem();
|
||||||
check(1, true);
|
check(1, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-Infinity));
|
RequestsMenu.focusFirstVisibleItem();
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+1));
|
RequestsMenu.focusNextItem();
|
||||||
check(1, true);
|
check(1, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-1));
|
RequestsMenu.focusPrevItem();
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+10));
|
RequestsMenu.focusItemAtDelta(+1);
|
||||||
check(1, true);
|
check(1, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-10));
|
RequestsMenu.focusItemAtDelta(-1);
|
||||||
|
check(0, true);
|
||||||
|
|
||||||
|
RequestsMenu.focusItemAtDelta(+10);
|
||||||
|
check(1, true);
|
||||||
|
RequestsMenu.focusItemAtDelta(-10);
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
wait = waitForNetworkEvents(monitor, 18);
|
wait = waitForNetworkEvents(monitor, 18);
|
||||||
|
@ -60,25 +63,25 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+Infinity));
|
RequestsMenu.focusLastVisibleItem();
|
||||||
check(19, true);
|
check(19, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-Infinity));
|
RequestsMenu.focusFirstVisibleItem();
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+1));
|
RequestsMenu.focusNextItem();
|
||||||
check(1, true);
|
check(1, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-1));
|
RequestsMenu.focusPrevItem();
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+10));
|
RequestsMenu.focusItemAtDelta(+10);
|
||||||
check(10, true);
|
check(10, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-10));
|
RequestsMenu.focusItemAtDelta(-10);
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
gStore.dispatch(Actions.selectDelta(+100));
|
RequestsMenu.focusItemAtDelta(+100);
|
||||||
check(19, true);
|
check(19, true);
|
||||||
gStore.dispatch(Actions.selectDelta(-100));
|
RequestsMenu.focusItemAtDelta(-100);
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
return teardown(monitor);
|
yield teardown(monitor);
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,8 +35,6 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
$(".requests-menu-contents").focus();
|
|
||||||
|
|
||||||
check(-1, false);
|
check(-1, false);
|
||||||
|
|
||||||
EventUtils.sendKey("DOWN", window);
|
EventUtils.sendKey("DOWN", window);
|
||||||
|
@ -125,7 +123,7 @@ add_task(function* () {
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||||
check(-1, false);
|
check(-1, false);
|
||||||
|
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $(".request-list-item"));
|
EventUtils.sendMouseEvent({ type: "mousedown" }, $(".side-menu-widget-item"));
|
||||||
check(0, true);
|
check(0, true);
|
||||||
|
|
||||||
yield teardown(monitor);
|
yield teardown(monitor);
|
||||||
|
|
|
@ -32,7 +32,7 @@ add_task(function* () {
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
REQUEST_URIS.forEach(function (uri, index) {
|
REQUEST_URIS.forEach(function (uri, index) {
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(index), "GET", uri);
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(index), "GET", uri);
|
||||||
});
|
});
|
||||||
|
|
||||||
yield teardown(monitor);
|
yield teardown(monitor);
|
||||||
|
|
|
@ -10,25 +10,22 @@ add_task(function* () {
|
||||||
requestLongerTimeout(2);
|
requestLongerTimeout(2);
|
||||||
|
|
||||||
let { monitor } = yield initNetMonitor(INFINITE_GET_URL);
|
let { monitor } = yield initNetMonitor(INFINITE_GET_URL);
|
||||||
let { $ } = monitor.panelWin;
|
let win = monitor.panelWin;
|
||||||
|
let topNode = win.document.getElementById("requests-menu-contents");
|
||||||
// Wait until the first request makes the empty notice disappear
|
let requestsContainer = topNode.getElementsByTagName("scrollbox")[0];
|
||||||
yield waitForRequestListToAppear();
|
ok(!!requestsContainer, "Container element exists as expected.");
|
||||||
|
|
||||||
let requestsContainer = $(".requests-menu-contents");
|
|
||||||
ok(requestsContainer, "Container element exists as expected.");
|
|
||||||
|
|
||||||
// (1) Check that the scroll position is maintained at the bottom
|
// (1) Check that the scroll position is maintained at the bottom
|
||||||
// when the requests overflow the vertical size of the container.
|
// when the requests overflow the vertical size of the container.
|
||||||
yield waitForRequestsToOverflowContainer();
|
yield waitForRequestsToOverflowContainer();
|
||||||
yield waitForScroll();
|
yield waitForScroll();
|
||||||
ok(true, "Scrolled to bottom on overflow.");
|
ok(scrolledToBottom(requestsContainer), "Scrolled to bottom on overflow.");
|
||||||
|
|
||||||
// (2) Now set the scroll position to the first item and check
|
// (2) Now set the scroll position somewhere in the middle and check
|
||||||
// that additional requests do not change the scroll position.
|
// that additional requests do not change the scroll position.
|
||||||
let firstNode = requestsContainer.firstChild;
|
let children = requestsContainer.childNodes;
|
||||||
firstNode.scrollIntoView();
|
let middleNode = children.item(children.length / 2);
|
||||||
yield waitSomeTime();
|
middleNode.scrollIntoView();
|
||||||
ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom.");
|
ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom.");
|
||||||
// save for comparison later
|
// save for comparison later
|
||||||
let scrollTop = requestsContainer.scrollTop;
|
let scrollTop = requestsContainer.scrollTop;
|
||||||
|
@ -42,7 +39,7 @@ add_task(function* () {
|
||||||
ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom.");
|
ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom.");
|
||||||
yield waitForNetworkEvents(monitor, 8);
|
yield waitForNetworkEvents(monitor, 8);
|
||||||
yield waitForScroll();
|
yield waitForScroll();
|
||||||
ok(true, "Still scrolled to bottom.");
|
ok(scrolledToBottom(requestsContainer), "Still scrolled to bottom.");
|
||||||
|
|
||||||
// (4) Now select an item in the list and check that additional requests
|
// (4) Now select an item in the list and check that additional requests
|
||||||
// do not change the scroll position.
|
// do not change the scroll position.
|
||||||
|
@ -52,20 +49,12 @@ add_task(function* () {
|
||||||
is(requestsContainer.scrollTop, 0, "Did not scroll.");
|
is(requestsContainer.scrollTop, 0, "Did not scroll.");
|
||||||
|
|
||||||
// Done: clean up.
|
// Done: clean up.
|
||||||
return teardown(monitor);
|
yield teardown(monitor);
|
||||||
|
|
||||||
function waitForRequestListToAppear() {
|
|
||||||
info("Waiting until the empty notice disappears and is replaced with the list");
|
|
||||||
return waitUntil(() => !!$(".requests-menu-contents"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function* waitForRequestsToOverflowContainer() {
|
function* waitForRequestsToOverflowContainer() {
|
||||||
info("Waiting for enough requests to overflow the container");
|
|
||||||
while (true) {
|
while (true) {
|
||||||
info("Waiting for one network request");
|
|
||||||
yield waitForNetworkEvents(monitor, 1);
|
yield waitForNetworkEvents(monitor, 1);
|
||||||
if (requestsContainer.scrollHeight > requestsContainer.clientHeight) {
|
if (requestsContainer.scrollHeight > requestsContainer.clientHeight) {
|
||||||
info("The list is long enough, returning");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +70,6 @@ add_task(function* () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForScroll() {
|
function waitForScroll() {
|
||||||
info("Waiting for the list to scroll to bottom");
|
return monitor._view.RequestsMenu.widget.once("scroll-to-bottom");
|
||||||
return waitUntil(() => scrolledToBottom(requestsContainer));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", HTTPS_CONTENT_TYPE_SJS + "?fmt=br", {
|
"GET", HTTPS_CONTENT_TYPE_SJS + "?fmt=br", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "Connected",
|
statusText: "Connected",
|
||||||
|
|
|
@ -93,8 +93,7 @@ add_task(function* () {
|
||||||
let item = RequestsMenu.getItemAtIndex(index);
|
let item = RequestsMenu.getItemAtIndex(index);
|
||||||
|
|
||||||
info("Verifying request #" + index);
|
info("Verifying request #" + index);
|
||||||
yield verifyRequestItemTarget(RequestsMenu, item,
|
yield verifyRequestItemTarget(item, request.method, request.uri, request.details);
|
||||||
request.method, request.uri, request.details);
|
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ const EXPECTED_REQUESTS = [
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: CAUSE_URL,
|
url: CAUSE_URL,
|
||||||
causeType: "document",
|
causeType: "document",
|
||||||
causeUri: null,
|
causeUri: "",
|
||||||
// The document load has internal privileged JS code on the stack
|
// The document load has internal privileged JS code on the stack
|
||||||
stack: true
|
stack: true
|
||||||
},
|
},
|
||||||
|
@ -103,11 +103,11 @@ add_task(function* () {
|
||||||
let { method, url, causeType, causeUri, stack } = spec;
|
let { method, url, causeType, causeUri, stack } = spec;
|
||||||
|
|
||||||
let requestItem = RequestsMenu.getItemAtIndex(i);
|
let requestItem = RequestsMenu.getItemAtIndex(i);
|
||||||
verifyRequestItemTarget(RequestsMenu, requestItem,
|
verifyRequestItemTarget(requestItem,
|
||||||
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
||||||
);
|
);
|
||||||
|
|
||||||
let { stacktrace } = requestItem.cause;
|
let { stacktrace } = requestItem.attachment.cause;
|
||||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||||
|
|
||||||
if (stack) {
|
if (stack) {
|
||||||
|
@ -137,7 +137,9 @@ add_task(function* () {
|
||||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-cause-button"));
|
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-cause-button"));
|
||||||
let expectedOrder = EXPECTED_REQUESTS.map(r => r.causeType).sort();
|
let expectedOrder = EXPECTED_REQUESTS.map(r => r.causeType).sort();
|
||||||
expectedOrder.forEach((expectedCause, i) => {
|
expectedOrder.forEach((expectedCause, i) => {
|
||||||
const cause = RequestsMenu.getItemAtIndex(i).cause.type;
|
let { target } = RequestsMenu.getItemAtIndex(i);
|
||||||
|
let causeLabel = target.querySelector(".requests-menu-cause-label");
|
||||||
|
let cause = causeLabel.getAttribute("value");
|
||||||
is(cause, expectedCause, `The request #${i} has the expected cause after sorting`);
|
is(cause, expectedCause, `The request #${i} has the expected cause after sorting`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ add_task(function* () {
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
EXPECTED_REQUESTS.forEach(({status, hasStack}, i) => {
|
EXPECTED_REQUESTS.forEach(({status, hasStack}, i) => {
|
||||||
let item = RequestsMenu.getItemAtIndex(i);
|
let { attachment } = RequestsMenu.getItemAtIndex(i);
|
||||||
|
|
||||||
is(item.status, status, `Request #${i} has the expected status`);
|
is(attachment.status, status, `Request #${i} has the expected status`);
|
||||||
|
|
||||||
let { stacktrace } = item.cause;
|
let { stacktrace } = attachment.cause;
|
||||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||||
|
|
||||||
if (hasStack) {
|
if (hasStack) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=xml", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=xml", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
@ -33,7 +33,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(1),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
@ -42,7 +42,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(2),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
@ -51,7 +51,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(3),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
@ -60,7 +60,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(4),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
|
||||||
status: 404,
|
status: 404,
|
||||||
statusText: "Not Found",
|
statusText: "Not Found",
|
||||||
|
@ -69,7 +69,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(5),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
|
||||||
"GET", TEST_IMAGE, {
|
"GET", TEST_IMAGE, {
|
||||||
fuzzyUrl: true,
|
fuzzyUrl: true,
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -79,7 +79,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(6),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=gzip", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=gzip", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -23,7 +23,7 @@ add_task(function* () {
|
||||||
let requestItem = RequestsMenu.getItemAtIndex(0);
|
let requestItem = RequestsMenu.getItemAtIndex(0);
|
||||||
RequestsMenu.selectedItem = requestItem;
|
RequestsMenu.selectedItem = requestItem;
|
||||||
|
|
||||||
let { method, httpVersion, status, statusText } = requestItem;
|
let { method, httpVersion, status, statusText } = requestItem.attachment;
|
||||||
|
|
||||||
const EXPECTED_REQUEST_HEADERS = [
|
const EXPECTED_REQUEST_HEADERS = [
|
||||||
`${method} ${SIMPLE_URL} ${httpVersion}`,
|
`${method} ${SIMPLE_URL} ${httpVersion}`,
|
||||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* () {
|
||||||
|
|
||||||
yield waitForClipboardPromise(function setup() {
|
yield waitForClipboardPromise(function setup() {
|
||||||
RequestsMenu.contextMenu.copyUrl();
|
RequestsMenu.contextMenu.copyUrl();
|
||||||
}, requestItem.url);
|
}, requestItem.attachment.url);
|
||||||
|
|
||||||
yield teardown(monitor);
|
yield teardown(monitor);
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,8 +25,7 @@ add_task(function* () {
|
||||||
|
|
||||||
info("Checking the preflight and flight methods");
|
info("Checking the preflight and flight methods");
|
||||||
["OPTIONS", "POST"].forEach((method, i) => {
|
["OPTIONS", "POST"].forEach((method, i) => {
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(i),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i), method, requestUrl);
|
||||||
method, requestUrl);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
yield teardown(monitor);
|
yield teardown(monitor);
|
||||||
|
|
|
@ -31,19 +31,19 @@ add_task(function* () {
|
||||||
multipartForm: RequestsMenu.getItemAtIndex(3)
|
multipartForm: RequestsMenu.getItemAtIndex(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = yield createCurlData(requests.get, gNetwork);
|
let data = yield createCurlData(requests.get.attachment, gNetwork);
|
||||||
testFindHeader(data);
|
testFindHeader(data);
|
||||||
|
|
||||||
data = yield createCurlData(requests.post, gNetwork);
|
data = yield createCurlData(requests.post.attachment, gNetwork);
|
||||||
testIsUrlEncodedRequest(data);
|
testIsUrlEncodedRequest(data);
|
||||||
testWritePostDataTextParams(data);
|
testWritePostDataTextParams(data);
|
||||||
|
|
||||||
data = yield createCurlData(requests.multipart, gNetwork);
|
data = yield createCurlData(requests.multipart.attachment, gNetwork);
|
||||||
testIsMultipartRequest(data);
|
testIsMultipartRequest(data);
|
||||||
testGetMultipartBoundary(data);
|
testGetMultipartBoundary(data);
|
||||||
testRemoveBinaryDataFromMultipartText(data);
|
testRemoveBinaryDataFromMultipartText(data);
|
||||||
|
|
||||||
data = yield createCurlData(requests.multipartForm, gNetwork);
|
data = yield createCurlData(requests.multipartForm.attachment, gNetwork);
|
||||||
testGetHeadersFromMultipartText(data);
|
testGetHeadersFromMultipartText(data);
|
||||||
|
|
||||||
if (Services.appinfo.OS != "WINNT") {
|
if (Services.appinfo.OS != "WINNT") {
|
||||||
|
|
|
@ -22,7 +22,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=txt", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=txt", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "DA DA DA"
|
statusText: "DA DA DA"
|
||||||
|
|
|
@ -21,7 +21,7 @@ add_task(function* () {
|
||||||
tab.linkedBrowser.reload();
|
tab.linkedBrowser.reload();
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CYRILLIC_URL, {
|
"GET", CYRILLIC_URL, {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK"
|
statusText: "OK"
|
||||||
|
|
|
@ -28,109 +28,8 @@ const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = REQUESTS_WITH_MEDIA_AND_FLASH.conca
|
||||||
{ url: "sjs_content-type-test-server.sjs?fmt=ws" },
|
{ url: "sjs_content-type-test-server.sjs?fmt=ws" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const EXPECTED_REQUESTS = [
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=html",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "html",
|
|
||||||
fullMimeType: "text/html; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=css",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "css",
|
|
||||||
fullMimeType: "text/css; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=js",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "js",
|
|
||||||
fullMimeType: "application/javascript; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=font",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "woff",
|
|
||||||
fullMimeType: "font/woff"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=image",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "png",
|
|
||||||
fullMimeType: "image/png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=audio",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "ogg",
|
|
||||||
fullMimeType: "audio/ogg"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=video",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "webm",
|
|
||||||
fullMimeType: "video/webm"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=flash",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "x-shockwave-flash",
|
|
||||||
fullMimeType: "application/x-shockwave-flash"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=ws",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 101,
|
|
||||||
statusText: "Switching Protocols",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let Actions = require("devtools/client/netmonitor/actions/index");
|
let Actions = require("devtools/client/netmonitor/actions/index");
|
||||||
|
|
||||||
let { monitor } = yield initNetMonitor(FILTERING_URL);
|
let { monitor } = yield initNetMonitor(FILTERING_URL);
|
||||||
let { gStore } = monitor.panelWin;
|
let { gStore } = monitor.panelWin;
|
||||||
|
|
||||||
|
@ -281,25 +180,85 @@ add_task(function* () {
|
||||||
is(NetMonitorView.detailsPaneHidden, false,
|
is(NetMonitorView.detailsPaneHidden, false,
|
||||||
"The details pane should still be visible after filtering.");
|
"The details pane should still be visible after filtering.");
|
||||||
|
|
||||||
const items = RequestsMenu.items;
|
is(RequestsMenu.items.length, visibility.length,
|
||||||
const visibleItems = RequestsMenu.visibleItems;
|
|
||||||
|
|
||||||
is(items.size, visibility.length,
|
|
||||||
"There should be a specific amount of items in the requests menu.");
|
"There should be a specific amount of items in the requests menu.");
|
||||||
is(visibleItems.size, visibility.filter(e => e).length,
|
is(RequestsMenu.visibleItems.length, visibility.filter(e => e).length,
|
||||||
"There should be a specific amount of visible items in the requests menu.");
|
"There should be a specific amount of visbile items in the requests menu.");
|
||||||
|
|
||||||
for (let i = 0; i < visibility.length; i++) {
|
for (let i = 0; i < visibility.length; i++) {
|
||||||
let itemId = items.get(i).id;
|
is(RequestsMenu.getItemAtIndex(i).target.hidden, !visibility[i],
|
||||||
let shouldBeVisible = !!visibility[i];
|
"The item at index " + i + " doesn't have the correct hidden state.");
|
||||||
let isThere = visibleItems.some(r => r.id == itemId);
|
|
||||||
is(isThere, shouldBeVisible,
|
|
||||||
`The item at index ${i} has visibility=${shouldBeVisible}`);
|
|
||||||
|
|
||||||
if (shouldBeVisible) {
|
|
||||||
let { method, url, data } = EXPECTED_REQUESTS[i];
|
|
||||||
verifyRequestItemTarget(RequestsMenu, items.get(i), method, url, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=html", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "html",
|
||||||
|
fullMimeType: "text/html; charset=utf-8"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "css",
|
||||||
|
fullMimeType: "text/css; charset=utf-8"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "js",
|
||||||
|
fullMimeType: "application/javascript; charset=utf-8"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=font", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "woff",
|
||||||
|
fullMimeType: "font/woff"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=image", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "png",
|
||||||
|
fullMimeType: "image/png"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=audio", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "ogg",
|
||||||
|
fullMimeType: "audio/ogg"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=video", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "webm",
|
||||||
|
fullMimeType: "video/webm"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(7),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=flash", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "x-shockwave-flash",
|
||||||
|
fullMimeType: "application/x-shockwave-flash"
|
||||||
|
});
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(8),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=ws", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 101,
|
||||||
|
statusText: "Switching Protocols",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,106 +29,6 @@ const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = REQUESTS_WITH_MEDIA_AND_FLASH.conca
|
||||||
{ url: "sjs_content-type-test-server.sjs?fmt=ws" },
|
{ url: "sjs_content-type-test-server.sjs?fmt=ws" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const EXPECTED_REQUESTS = [
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=html",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "html",
|
|
||||||
fullMimeType: "text/html; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=css",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "css",
|
|
||||||
fullMimeType: "text/css; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=js",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "js",
|
|
||||||
fullMimeType: "application/javascript; charset=utf-8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=font",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "woff",
|
|
||||||
fullMimeType: "font/woff"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=image",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "png",
|
|
||||||
fullMimeType: "image/png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=audio",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "ogg",
|
|
||||||
fullMimeType: "audio/ogg"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=video",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "webm",
|
|
||||||
fullMimeType: "video/webm"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=flash",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: "OK",
|
|
||||||
type: "x-shockwave-flash",
|
|
||||||
fullMimeType: "application/x-shockwave-flash"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
url: CONTENT_TYPE_SJS + "?fmt=ws",
|
|
||||||
data: {
|
|
||||||
fuzzyUrl: true,
|
|
||||||
status: 101,
|
|
||||||
statusText: "Switching Protocols",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let { monitor } = yield initNetMonitor(FILTERING_URL);
|
let { monitor } = yield initNetMonitor(FILTERING_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
@ -198,29 +98,103 @@ add_task(function* () {
|
||||||
is(NetMonitorView.detailsPaneHidden, false,
|
is(NetMonitorView.detailsPaneHidden, false,
|
||||||
"The details pane should still be visible after filtering.");
|
"The details pane should still be visible after filtering.");
|
||||||
|
|
||||||
const items = RequestsMenu.items;
|
is(RequestsMenu.items.length, visibility.length,
|
||||||
const visibleItems = RequestsMenu.visibleItems;
|
|
||||||
|
|
||||||
is(items.size, visibility.length,
|
|
||||||
"There should be a specific amount of items in the requests menu.");
|
"There should be a specific amount of items in the requests menu.");
|
||||||
is(visibleItems.size, visibility.filter(e => e).length,
|
is(RequestsMenu.visibleItems.length, visibility.filter(e => e).length,
|
||||||
"There should be a specific amount of visible items in the requests menu.");
|
"There should be a specific amount of visbile items in the requests menu.");
|
||||||
|
|
||||||
for (let i = 0; i < visibility.length; i++) {
|
for (let i = 0; i < visibility.length; i++) {
|
||||||
let itemId = items.get(i).id;
|
is(RequestsMenu.getItemAtIndex(i).target.hidden, !visibility[i],
|
||||||
let shouldBeVisible = !!visibility[i];
|
"The item at index " + i + " doesn't have the correct hidden state.");
|
||||||
let isThere = visibleItems.some(r => r.id == itemId);
|
|
||||||
is(isThere, shouldBeVisible,
|
|
||||||
`The item at index ${i} has visibility=${shouldBeVisible}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < EXPECTED_REQUESTS.length; i++) {
|
for (let i = 0; i < visibility.length; i += 9) {
|
||||||
let { method, url, data } = EXPECTED_REQUESTS[i];
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
for (let j = i; j < visibility.length; j += EXPECTED_REQUESTS.length) {
|
"GET", CONTENT_TYPE_SJS + "?fmt=html", {
|
||||||
if (visibility[j]) {
|
fuzzyUrl: true,
|
||||||
verifyRequestItemTarget(RequestsMenu, items.get(j), method, url, data);
|
status: 200,
|
||||||
}
|
statusText: "OK",
|
||||||
}
|
type: "html",
|
||||||
|
fullMimeType: "text/html; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 1; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "css",
|
||||||
|
fullMimeType: "text/css; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 2; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "js",
|
||||||
|
fullMimeType: "application/javascript; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 3; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=font", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "woff",
|
||||||
|
fullMimeType: "font/woff"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 4; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=image", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "png",
|
||||||
|
fullMimeType: "image/png"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 5; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=audio", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "ogg",
|
||||||
|
fullMimeType: "audio/ogg"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 6; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=video", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "webm",
|
||||||
|
fullMimeType: "video/webm"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 7; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=flash", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "x-shockwave-flash",
|
||||||
|
fullMimeType: "application/x-shockwave-flash"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 8; i < visibility.length; i += 9) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=ws", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 101,
|
||||||
|
statusText: "Switching Protocols"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -104,6 +104,82 @@ add_task(function* () {
|
||||||
is(RequestsMenu.items.length, order.length,
|
is(RequestsMenu.items.length, order.length,
|
||||||
"There should be a specific amount of items in the requests menu.");
|
"There should be a specific amount of items in the requests menu.");
|
||||||
is(RequestsMenu.visibleItems.length, visible,
|
is(RequestsMenu.visibleItems.length, visible,
|
||||||
"There should be a specific amount of visible items in the requests menu.");
|
"There should be a specific amount of visbile items in the requests menu.");
|
||||||
|
|
||||||
|
for (let i = 0; i < order.length; i++) {
|
||||||
|
is(RequestsMenu.getItemAtIndex(i), RequestsMenu.items[i],
|
||||||
|
"The requests menu items aren't ordered correctly. Misplaced item " + i + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=html", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "html",
|
||||||
|
fullMimeType: "text/html; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "css",
|
||||||
|
fullMimeType: "text/css; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len * 2]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "js",
|
||||||
|
fullMimeType: "application/javascript; charset=utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len * 3]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=font", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "woff",
|
||||||
|
fullMimeType: "font/woff"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len * 4]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=image", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "png",
|
||||||
|
fullMimeType: "image/png"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len * 5]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=audio", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "ogg",
|
||||||
|
fullMimeType: "audio/ogg"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0, len = order.length / 7; i < len; i++) {
|
||||||
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(order[i + len * 6]),
|
||||||
|
"GET", CONTENT_TYPE_SJS + "?fmt=video", {
|
||||||
|
fuzzyUrl: true,
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
type: "webm",
|
||||||
|
fullMimeType: "video/webm"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if the summary text displayed in the network requests menu footer is correct.
|
* Test if the summary text displayed in the network requests menu footer
|
||||||
|
* is correct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
|
@ -13,13 +14,13 @@ add_task(function* () {
|
||||||
let { tab, monitor } = yield initNetMonitor(FILTERING_URL);
|
let { tab, monitor } = yield initNetMonitor(FILTERING_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
|
||||||
let { $, NetMonitorView, gStore, windowRequire } = monitor.panelWin;
|
let { $, NetMonitorView, gStore } = monitor.panelWin;
|
||||||
let { RequestsMenu } = NetMonitorView;
|
let { RequestsMenu } = NetMonitorView;
|
||||||
|
|
||||||
let { getDisplayedRequestsSummary } =
|
let winRequire = monitor.panelWin.require;
|
||||||
windowRequire("devtools/client/netmonitor/selectors/index");
|
let { getSummary } = winRequire("devtools/client/netmonitor/selectors/index");
|
||||||
let { L10N } = windowRequire("devtools/client/netmonitor/l10n");
|
let { L10N } = winRequire("devtools/client/netmonitor/l10n");
|
||||||
let { PluralForm } = windowRequire("devtools/shared/plural-form");
|
let { PluralForm } = winRequire("devtools/shared/plural-form");
|
||||||
|
|
||||||
RequestsMenu.lazyUpdate = false;
|
RequestsMenu.lazyUpdate = false;
|
||||||
testStatus();
|
testStatus();
|
||||||
|
@ -45,27 +46,26 @@ add_task(function* () {
|
||||||
yield teardown(monitor);
|
yield teardown(monitor);
|
||||||
|
|
||||||
function testStatus() {
|
function testStatus() {
|
||||||
|
const { count, totalBytes, totalMillis } = getSummary(gStore.getState());
|
||||||
let value = $("#requests-menu-network-summary-button").textContent;
|
let value = $("#requests-menu-network-summary-button").textContent;
|
||||||
info("Current summary: " + value);
|
info("Current summary: " + value);
|
||||||
|
|
||||||
let state = gStore.getState();
|
let totalRequestsCount = RequestsMenu.itemCount;
|
||||||
let totalRequestsCount = state.requests.requests.size;
|
info("Current requests: " + count + " of " + totalRequestsCount + ".");
|
||||||
let requestsSummary = getDisplayedRequestsSummary(state);
|
|
||||||
info(`Current requests: ${requestsSummary.count} of ${totalRequestsCount}.`);
|
|
||||||
|
|
||||||
if (!totalRequestsCount || !requestsSummary.count) {
|
if (!totalRequestsCount || !count) {
|
||||||
is(value, L10N.getStr("networkMenu.empty"),
|
is(value, L10N.getStr("networkMenu.empty"),
|
||||||
"The current summary text is incorrect, expected an 'empty' label.");
|
"The current summary text is incorrect, expected an 'empty' label.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info(`Computed total bytes: ${requestsSummary.bytes}`);
|
info("Computed total bytes: " + totalBytes);
|
||||||
info(`Computed total millis: ${requestsSummary.millis}`);
|
info("Computed total millis: " + totalMillis);
|
||||||
|
|
||||||
is(value, PluralForm.get(requestsSummary.count, L10N.getStr("networkMenu.summary"))
|
is(value, PluralForm.get(count, L10N.getStr("networkMenu.summary"))
|
||||||
.replace("#1", requestsSummary.count)
|
.replace("#1", count)
|
||||||
.replace("#2", L10N.numberWithDecimals(requestsSummary.bytes / 1024, 2))
|
.replace("#2", L10N.numberWithDecimals((totalBytes || 0) / 1024, 2))
|
||||||
.replace("#3", L10N.numberWithDecimals(requestsSummary.millis / 1000, 2))
|
.replace("#3", L10N.numberWithDecimals((totalMillis || 0) / 1000, 2))
|
||||||
, "The current summary text is correct.");
|
, "The current summary text is incorrect.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ const EXPECTED_REQUESTS_TOP = [
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: TOP_URL,
|
url: TOP_URL,
|
||||||
causeType: "document",
|
causeType: "document",
|
||||||
causeUri: null,
|
causeUri: "",
|
||||||
stack: true
|
stack: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -176,8 +176,9 @@ add_task(function* () {
|
||||||
for (let i = 0; i < REQUEST_COUNT; i++) {
|
for (let i = 0; i < REQUEST_COUNT; i++) {
|
||||||
let requestItem = RequestsMenu.getItemAtIndex(i);
|
let requestItem = RequestsMenu.getItemAtIndex(i);
|
||||||
|
|
||||||
let itemUrl = requestItem.url;
|
let itemUrl = requestItem.attachment.url;
|
||||||
let itemCauseUri = requestItem.cause.loadingDocumentUri;
|
let itemCauseUri = requestItem.target.querySelector(".requests-menu-cause-label")
|
||||||
|
.getAttribute("tooltiptext");
|
||||||
let spec;
|
let spec;
|
||||||
if (itemUrl == SUB_URL || itemCauseUri == SUB_URL) {
|
if (itemUrl == SUB_URL || itemCauseUri == SUB_URL) {
|
||||||
spec = EXPECTED_REQUESTS_SUB[currentSub++];
|
spec = EXPECTED_REQUESTS_SUB[currentSub++];
|
||||||
|
@ -186,11 +187,11 @@ add_task(function* () {
|
||||||
}
|
}
|
||||||
let { method, url, causeType, causeUri, stack } = spec;
|
let { method, url, causeType, causeUri, stack } = spec;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, requestItem,
|
verifyRequestItemTarget(requestItem,
|
||||||
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
||||||
);
|
);
|
||||||
|
|
||||||
let { stacktrace } = requestItem.cause;
|
let { stacktrace } = requestItem.attachment.cause;
|
||||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||||
|
|
||||||
if (stack) {
|
if (stack) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(function* () {
|
||||||
info("Checking the image thumbnail when all items are shown.");
|
info("Checking the image thumbnail when all items are shown.");
|
||||||
checkImageThumbnail();
|
checkImageThumbnail();
|
||||||
|
|
||||||
gStore.dispatch(Actions.sortBy("size"));
|
RequestsMenu.sortBy("size");
|
||||||
info("Checking the image thumbnail when all items are sorted.");
|
info("Checking the image thumbnail when all items are sorted.");
|
||||||
checkImageThumbnail();
|
checkImageThumbnail();
|
||||||
|
|
||||||
|
@ -61,11 +61,11 @@ add_task(function* () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkImageThumbnail() {
|
function checkImageThumbnail() {
|
||||||
is($all(".requests-menu-icon[data-type=thumbnail]").length, 1,
|
is($all(".requests-menu-icon[type=thumbnail]").length, 1,
|
||||||
"There should be only one image request with a thumbnail displayed.");
|
"There should be only one image request with a thumbnail displayed.");
|
||||||
is($(".requests-menu-icon[data-type=thumbnail]").src, TEST_IMAGE_DATA_URI,
|
is($(".requests-menu-icon[type=thumbnail]").src, TEST_IMAGE_DATA_URI,
|
||||||
"The image requests-menu-icon thumbnail is displayed correctly.");
|
"The image requests-menu-icon thumbnail is displayed correctly.");
|
||||||
is($(".requests-menu-icon[data-type=thumbnail]").hidden, false,
|
is($(".requests-menu-icon[type=thumbnail]").hidden, false,
|
||||||
"The image requests-menu-icon thumbnail should not be hidden.");
|
"The image requests-menu-icon thumbnail should not be hidden.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,12 +26,12 @@ add_task(function* test() {
|
||||||
yield onThumbnail;
|
yield onThumbnail;
|
||||||
|
|
||||||
info("Checking the image thumbnail after a few requests were made...");
|
info("Checking the image thumbnail after a few requests were made...");
|
||||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.getItemAtIndex(0));
|
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[0]);
|
||||||
|
|
||||||
// Hide tooltip before next test, to avoid the situation that tooltip covers
|
// Hide tooltip before next test, to avoid the situation that tooltip covers
|
||||||
// the icon for the request of the next test.
|
// the icon for the request of the next test.
|
||||||
info("Checking the image thumbnail gets hidden...");
|
info("Checking the image thumbnail gets hidden...");
|
||||||
yield hideTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.getItemAtIndex(0));
|
yield hideTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[0]);
|
||||||
|
|
||||||
// +1 extra document reload
|
// +1 extra document reload
|
||||||
onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS + 1);
|
onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS + 1);
|
||||||
|
@ -44,10 +44,10 @@ add_task(function* test() {
|
||||||
yield onThumbnail;
|
yield onThumbnail;
|
||||||
|
|
||||||
info("Checking the image thumbnail after a reload.");
|
info("Checking the image thumbnail after a reload.");
|
||||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.getItemAtIndex(1));
|
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[1]);
|
||||||
|
|
||||||
info("Checking if the image thumbnail is hidden when mouse leaves the menu widget");
|
info("Checking if the image thumbnail is hidden when mouse leaves the menu widget");
|
||||||
let requestsMenuEl = $(".requests-menu-contents");
|
let requestsMenuEl = $("#requests-menu-contents");
|
||||||
let onHidden = RequestsMenu.tooltip.once("hidden");
|
let onHidden = RequestsMenu.tooltip.once("hidden");
|
||||||
EventUtils.synthesizeMouse(requestsMenuEl, 0, 0, {type: "mouseout"}, monitor.panelWin);
|
EventUtils.synthesizeMouse(requestsMenuEl, 0, 0, {type: "mouseout"}, monitor.panelWin);
|
||||||
yield onHidden;
|
yield onHidden;
|
||||||
|
@ -65,7 +65,7 @@ add_task(function* test() {
|
||||||
* with the expected content.
|
* with the expected content.
|
||||||
*/
|
*/
|
||||||
function* showTooltipAndVerify(tooltip, requestItem) {
|
function* showTooltipAndVerify(tooltip, requestItem) {
|
||||||
let anchor = $(".requests-menu-file", getItemTarget(RequestsMenu, requestItem));
|
let anchor = $(".requests-menu-file", requestItem.target);
|
||||||
yield showTooltipOn(tooltip, anchor);
|
yield showTooltipOn(tooltip, anchor);
|
||||||
|
|
||||||
info("Tooltip was successfully opened for the image request.");
|
info("Tooltip was successfully opened for the image request.");
|
||||||
|
@ -88,13 +88,13 @@ add_task(function* test() {
|
||||||
* Hide a tooltip on the {requestItem} and verify that it was closed.
|
* Hide a tooltip on the {requestItem} and verify that it was closed.
|
||||||
*/
|
*/
|
||||||
function* hideTooltipAndVerify(tooltip, requestItem) {
|
function* hideTooltipAndVerify(tooltip, requestItem) {
|
||||||
// Hovering over the "method" column hides the tooltip.
|
// Hovering method hides tooltip.
|
||||||
let anchor = $(".requests-menu-method", getItemTarget(RequestsMenu, requestItem));
|
let anchor = $(".requests-menu-method", requestItem.target);
|
||||||
|
|
||||||
let onTooltipHidden = tooltip.once("hidden");
|
let onHidden = tooltip.once("hidden");
|
||||||
let win = anchor.ownerDocument.defaultView;
|
let win = anchor.ownerDocument.defaultView;
|
||||||
EventUtils.synthesizeMouseAtCenter(anchor, {type: "mousemove"}, win);
|
EventUtils.synthesizeMouseAtCenter(anchor, {type: "mousemove"}, win);
|
||||||
yield onTooltipHidden;
|
yield onHidden;
|
||||||
|
|
||||||
info("Tooltip was successfully closed.");
|
info("Tooltip was successfully closed.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -22,7 +22,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json-malformed", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json-malformed", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json-custom-mime", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json-custom-mime", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json-text-mime", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json-text-mime", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp&jsonp=$_0123Fun", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp&jsonp=$_0123Fun", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
@ -34,7 +34,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(1),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp2&jsonp=$_4567Sad", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp2&jsonp=$_4567Sad", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -28,7 +28,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=html-long", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=html-long", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK"
|
statusText: "OK"
|
||||||
|
|
|
@ -59,11 +59,11 @@ add_task(function* () {
|
||||||
removeTab(tab);
|
removeTab(tab);
|
||||||
yield onDestroyed;
|
yield onDestroyed;
|
||||||
|
|
||||||
ok(!monitor.panelWin.NetMonitorController.client,
|
ok(!monitor._controller.client,
|
||||||
"There shouldn't be a client available after destruction.");
|
"There shouldn't be a client available after destruction.");
|
||||||
ok(!monitor.panelWin.NetMonitorController.tabClient,
|
ok(!monitor._controller.tabClient,
|
||||||
"There shouldn't be a tabClient available after destruction.");
|
"There shouldn't be a tabClient available after destruction.");
|
||||||
ok(!monitor.panelWin.NetMonitorController.webConsoleClient,
|
ok(!monitor._controller.webConsoleClient,
|
||||||
"There shouldn't be a webConsoleClient available after destruction.");
|
"There shouldn't be a webConsoleClient available after destruction.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(0),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
|
||||||
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=urlencoded", {
|
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=urlencoded", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "Och Aye",
|
statusText: "Och Aye",
|
||||||
|
@ -34,7 +34,7 @@ add_task(function* () {
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
|
||||||
time: true
|
time: true
|
||||||
});
|
});
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(1),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
|
||||||
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=multipart", {
|
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=multipart", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "Och Aye",
|
statusText: "Och Aye",
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let Actions = require("devtools/client/netmonitor/actions/index");
|
let Actions = require("devtools/client/netmonitor/actions/index");
|
||||||
let { getActiveFilters } = require("devtools/client/netmonitor/selectors/index");
|
|
||||||
|
|
||||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
|
||||||
|
@ -21,8 +19,8 @@ add_task(function* () {
|
||||||
// Use these getters instead of caching instances inside the panel win,
|
// Use these getters instead of caching instances inside the panel win,
|
||||||
// since the tool is reopened a bunch of times during this test
|
// since the tool is reopened a bunch of times during this test
|
||||||
// and the instances will differ.
|
// and the instances will differ.
|
||||||
|
let getView = () => monitor.panelWin.NetMonitorView;
|
||||||
let getStore = () => monitor.panelWin.gStore;
|
let getStore = () => monitor.panelWin.gStore;
|
||||||
let getState = () => getStore().getState();
|
|
||||||
|
|
||||||
let prefsToCheck = {
|
let prefsToCheck = {
|
||||||
filters: {
|
filters: {
|
||||||
|
@ -30,7 +28,7 @@ add_task(function* () {
|
||||||
newValue: ["html", "css"],
|
newValue: ["html", "css"],
|
||||||
// Getter used to retrieve the current value from the frontend, in order
|
// Getter used to retrieve the current value from the frontend, in order
|
||||||
// to verify that the pref was applied properly.
|
// to verify that the pref was applied properly.
|
||||||
validateValue: ($) => getActiveFilters(getState()),
|
validateValue: ($) => getView().RequestsMenu._activeFilters,
|
||||||
// Predicate used to modify the frontend when setting the new pref value,
|
// Predicate used to modify the frontend when setting the new pref value,
|
||||||
// before trying to validate the changes.
|
// before trying to validate the changes.
|
||||||
modifyFrontend: ($, value) => value.forEach(e =>
|
modifyFrontend: ($, value) => value.forEach(e =>
|
||||||
|
|
|
@ -31,7 +31,7 @@ add_task(function* () {
|
||||||
EventUtils.sendMouseEvent({ type: "click" },
|
EventUtils.sendMouseEvent({ type: "click" },
|
||||||
document.getElementById("toggle-raw-headers"));
|
document.getElementById("toggle-raw-headers"));
|
||||||
|
|
||||||
testShowRawHeaders(origItem);
|
testShowRawHeaders(origItem.attachment);
|
||||||
|
|
||||||
EventUtils.sendMouseEvent({ type: "click" },
|
EventUtils.sendMouseEvent({ type: "click" },
|
||||||
document.getElementById("toggle-raw-headers"));
|
document.getElementById("toggle-raw-headers"));
|
||||||
|
@ -46,12 +46,12 @@ add_task(function* () {
|
||||||
function testShowRawHeaders(data) {
|
function testShowRawHeaders(data) {
|
||||||
let requestHeaders = document.getElementById("raw-request-headers-textarea").value;
|
let requestHeaders = document.getElementById("raw-request-headers-textarea").value;
|
||||||
for (let header of data.requestHeaders.headers) {
|
for (let header of data.requestHeaders.headers) {
|
||||||
ok(requestHeaders.includes(header.name + ": " + header.value),
|
ok(requestHeaders.indexOf(header.name + ": " + header.value) >= 0,
|
||||||
"textarea contains request headers");
|
"textarea contains request headers");
|
||||||
}
|
}
|
||||||
let responseHeaders = document.getElementById("raw-response-headers-textarea").value;
|
let responseHeaders = document.getElementById("raw-response-headers-textarea").value;
|
||||||
for (let header of data.responseHeaders.headers) {
|
for (let header of data.responseHeaders.headers) {
|
||||||
ok(responseHeaders.includes(header.name + ": " + header.value),
|
ok(responseHeaders.indexOf(header.name + ": " + header.value) >= 0,
|
||||||
"textarea contains response headers");
|
"textarea contains response headers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
let { monitor } = yield initNetMonitor(SINGLE_GET_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
|
||||||
let { document, NetMonitorView } = monitor.panelWin;
|
let { document, NetMonitorView } = monitor.panelWin;
|
||||||
let { RequestsMenu } = NetMonitorView;
|
let { RequestsMenu } = NetMonitorView;
|
||||||
|
|
||||||
let wait = waitForNetworkEvents(monitor, 1);
|
let wait = waitForNetworkEvents(monitor, 2);
|
||||||
let button = document.querySelector("#requests-menu-reload-notice-button");
|
let button = document.querySelector("#requests-menu-reload-notice-button");
|
||||||
button.click();
|
button.click();
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
is(RequestsMenu.itemCount, 1, "The request menu should have one item after reloading");
|
is(RequestsMenu.itemCount, 2, "The request menu should have two items after reloading");
|
||||||
|
|
||||||
return teardown(monitor);
|
return teardown(monitor);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
let { monitor } = yield initNetMonitor(SINGLE_GET_URL);
|
||||||
info("Starting test... ");
|
info("Starting test... ");
|
||||||
|
|
||||||
let { document, EVENTS } = monitor.panelWin;
|
let { document, EVENTS } = monitor.panelWin;
|
||||||
|
@ -21,7 +21,7 @@ add_task(function* () {
|
||||||
markers.push(marker);
|
markers.push(marker);
|
||||||
});
|
});
|
||||||
|
|
||||||
yield waitForNetworkEvents(monitor, 1);
|
yield waitForNetworkEvents(monitor, 2);
|
||||||
yield waitUntil(() => markers.length == 2);
|
yield waitUntil(() => markers.length == 2);
|
||||||
|
|
||||||
ok(true, "Reloading finished");
|
ok(true, "Reloading finished");
|
||||||
|
|
|
@ -54,7 +54,7 @@ add_task(function* () {
|
||||||
return teardown(monitor);
|
return teardown(monitor);
|
||||||
|
|
||||||
function verifyRequest(offset) {
|
function verifyRequest(offset) {
|
||||||
verifyRequestItemTarget(RequestsMenu, RequestsMenu.getItemAtIndex(offset),
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(offset),
|
||||||
"GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
|
"GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "OK",
|
statusText: "OK",
|
||||||
|
|
|
@ -39,15 +39,13 @@ add_task(function* () {
|
||||||
RequestsMenu.cloneSelectedRequest();
|
RequestsMenu.cloneSelectedRequest();
|
||||||
yield onPopulated;
|
yield onPopulated;
|
||||||
|
|
||||||
testCustomForm(origItem);
|
testCustomForm(origItem.attachment);
|
||||||
|
|
||||||
let customItem = RequestsMenu.selectedItem;
|
let customItem = RequestsMenu.selectedItem;
|
||||||
testCustomItem(customItem, origItem);
|
testCustomItem(customItem, origItem);
|
||||||
|
|
||||||
// edit the custom request
|
// edit the custom request
|
||||||
yield editCustomForm();
|
yield editCustomForm();
|
||||||
// FIXME: reread the customItem, it's been replaced by a new object (immutable!)
|
|
||||||
customItem = RequestsMenu.selectedItem;
|
|
||||||
testCustomItemChanged(customItem, origItem);
|
testCustomItemChanged(customItem, origItem);
|
||||||
|
|
||||||
// send the new request
|
// send the new request
|
||||||
|
@ -56,20 +54,30 @@ add_task(function* () {
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
let sentItem = RequestsMenu.selectedItem;
|
let sentItem = RequestsMenu.selectedItem;
|
||||||
testSentRequest(sentItem, origItem);
|
testSentRequest(sentItem.attachment, origItem.attachment);
|
||||||
|
|
||||||
return teardown(monitor);
|
return teardown(monitor);
|
||||||
|
|
||||||
function testCustomItem(item, orig) {
|
function testCustomItem(item, orig) {
|
||||||
is(item.method, orig.method, "item is showing the same method as original request");
|
let method = item.target.querySelector(".requests-menu-method").value;
|
||||||
is(item.url, orig.url, "item is showing the same URL as original request");
|
let origMethod = orig.target.querySelector(".requests-menu-method").value;
|
||||||
|
is(method, origMethod, "menu item is showing the same method as original request");
|
||||||
|
|
||||||
|
let file = item.target.querySelector(".requests-menu-file").value;
|
||||||
|
let origFile = orig.target.querySelector(".requests-menu-file").value;
|
||||||
|
is(file, origFile, "menu item is showing the same file name as original request");
|
||||||
|
|
||||||
|
let domain = item.target.querySelector(".requests-menu-domain").value;
|
||||||
|
let origDomain = orig.target.querySelector(".requests-menu-domain").value;
|
||||||
|
is(domain, origDomain, "menu item is showing the same domain as original request");
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCustomItemChanged(item, orig) {
|
function testCustomItemChanged(item, orig) {
|
||||||
let url = item.url;
|
let file = item.target.querySelector(".requests-menu-file").value;
|
||||||
let expectedUrl = orig.url + "&" + ADD_QUERY;
|
let expectedFile = orig.target.querySelector(".requests-menu-file").value +
|
||||||
|
"&" + ADD_QUERY;
|
||||||
|
|
||||||
is(url, expectedUrl, "menu item is updated to reflect url entered in form");
|
is(file, expectedFile, "menu item is updated to reflect url entered in form");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -30,9 +30,9 @@ add_task(function* () {
|
||||||
|
|
||||||
// Check the requests that were sent
|
// Check the requests that were sent
|
||||||
for (let [i, method] of METHODS.entries()) {
|
for (let [i, method] of METHODS.entries()) {
|
||||||
let item = RequestsMenu.getItemAtIndex(i);
|
let { attachment } = RequestsMenu.getItemAtIndex(i);
|
||||||
is(item.method, method, `The ${method} request has the right method`);
|
is(attachment.method, method, `The ${method} request has the right method`);
|
||||||
is(item.url, requestUrl, `The ${method} request has the right URL`);
|
is(attachment.url, requestUrl, `The ${method} request has the right URL`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resend both requests without modification. Wait for resent OPTIONS, then POST.
|
// Resend both requests without modification. Wait for resent OPTIONS, then POST.
|
||||||
|
@ -61,7 +61,7 @@ add_task(function* () {
|
||||||
// Check the resent requests
|
// Check the resent requests
|
||||||
for (let [i, method] of METHODS.entries()) {
|
for (let [i, method] of METHODS.entries()) {
|
||||||
let index = i + 2;
|
let index = i + 2;
|
||||||
let item = RequestsMenu.getItemAtIndex(index);
|
let item = RequestsMenu.getItemAtIndex(index).attachment;
|
||||||
is(item.method, method, `The ${method} request has the right method`);
|
is(item.method, method, `The ${method} request has the right method`);
|
||||||
is(item.url, requestUrl, `The ${method} request has the right URL`);
|
is(item.url, requestUrl, `The ${method} request has the right URL`);
|
||||||
is(item.status, 200, `The ${method} response has the right status`);
|
is(item.status, 200, `The ${method} response has the right status`);
|
||||||
|
|
|
@ -35,21 +35,21 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
yield wait;
|
yield wait;
|
||||||
|
|
||||||
let item = RequestsMenu.getItemAtIndex(0);
|
let { attachment } = RequestsMenu.getItemAtIndex(0);
|
||||||
is(item.method, "POST", "The request has the right method");
|
is(attachment.method, "POST", "The request has the right method");
|
||||||
is(item.url, requestUrl, "The request has the right URL");
|
is(attachment.url, requestUrl, "The request has the right URL");
|
||||||
|
|
||||||
for (let { name, value } of item.requestHeaders.headers) {
|
for (let { name, value } of attachment.requestHeaders.headers) {
|
||||||
info(`Request header: ${name}: ${value}`);
|
info(`Request header: ${name}: ${value}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasRequestHeader(name, value) {
|
function hasRequestHeader(name, value) {
|
||||||
let { headers } = item.requestHeaders;
|
let { headers } = attachment.requestHeaders;
|
||||||
return headers.some(h => h.name === name && h.value === value);
|
return headers.some(h => h.name === name && h.value === value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasNotRequestHeader(name) {
|
function hasNotRequestHeader(name) {
|
||||||
let { headers } = item.requestHeaders;
|
let { headers } = attachment.requestHeaders;
|
||||||
return headers.every(h => h.name !== name);
|
return headers.every(h => h.name !== name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,13 @@ add_task(function* () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function* clickAndTestSecurityIcon() {
|
function* clickAndTestSecurityIcon() {
|
||||||
let item = RequestsMenu.getItemAtIndex(0);
|
let item = RequestsMenu.items[0];
|
||||||
let target = getItemTarget(RequestsMenu, item);
|
let icon = $(".requests-security-state-icon", item.target);
|
||||||
let icon = $(".requests-security-state-icon", target);
|
|
||||||
|
|
||||||
info("Clicking security icon of the first request and waiting for panel update.");
|
info("Clicking security icon of the first request and waiting for the " +
|
||||||
EventUtils.synthesizeMouseAtCenter(icon, {}, monitor.panelWin);
|
"panel to update.");
|
||||||
|
|
||||||
|
icon.click();
|
||||||
yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
|
yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
|
||||||
|
|
||||||
is(NetworkDetails.widget.selectedPanel, $("#security-tabpanel"),
|
is(NetworkDetails.widget.selectedPanel, $("#security-tabpanel"),
|
||||||
|
|
|
@ -22,13 +22,11 @@ add_task(function* () {
|
||||||
|
|
||||||
is(RequestsMenu.itemCount, 2, "There were two requests due to redirect.");
|
is(RequestsMenu.itemCount, 2, "There were two requests due to redirect.");
|
||||||
|
|
||||||
let initial = RequestsMenu.getItemAtIndex(0);
|
let initial = RequestsMenu.items[0];
|
||||||
let redirect = RequestsMenu.getItemAtIndex(1);
|
let redirect = RequestsMenu.items[1];
|
||||||
|
|
||||||
let initialSecurityIcon =
|
let initialSecurityIcon = $(".requests-security-state-icon", initial.target);
|
||||||
$(".requests-security-state-icon", getItemTarget(RequestsMenu, initial));
|
let redirectSecurityIcon = $(".requests-security-state-icon", redirect.target);
|
||||||
let redirectSecurityIcon =
|
|
||||||
$(".requests-security-state-icon", getItemTarget(RequestsMenu, redirect));
|
|
||||||
|
|
||||||
ok(initialSecurityIcon.classList.contains("security-state-insecure"),
|
ok(initialSecurityIcon.classList.contains("security-state-insecure"),
|
||||||
"Initial request was marked insecure.");
|
"Initial request was marked insecure.");
|
||||||
|
|
|
@ -24,13 +24,12 @@ add_task(function* () {
|
||||||
yield performRequests();
|
yield performRequests();
|
||||||
|
|
||||||
for (let item of RequestsMenu.items) {
|
for (let item of RequestsMenu.items) {
|
||||||
let target = getItemTarget(RequestsMenu, item);
|
let domain = $(".requests-menu-domain", item.target).value;
|
||||||
let domain = $(".requests-menu-domain", target).textContent;
|
|
||||||
|
|
||||||
info("Found a request to " + domain);
|
info("Found a request to " + domain);
|
||||||
ok(domain in EXPECTED_SECURITY_STATES, "Domain " + domain + " was expected.");
|
ok(domain in EXPECTED_SECURITY_STATES, "Domain " + domain + " was expected.");
|
||||||
|
|
||||||
let classes = $(".requests-security-state-icon", target).classList;
|
let classes = $(".requests-security-state-icon", item.target).classList;
|
||||||
let expectedClass = EXPECTED_SECURITY_STATES[domain];
|
let expectedClass = EXPECTED_SECURITY_STATES[domain];
|
||||||
|
|
||||||
info("Classes of security state icon are: " + classes);
|
info("Classes of security state icon are: " + classes);
|
||||||
|
|
|
@ -58,7 +58,7 @@ add_task(function* () {
|
||||||
info("Selecting the request.");
|
info("Selecting the request.");
|
||||||
RequestsMenu.selectedIndex = 0;
|
RequestsMenu.selectedIndex = 0;
|
||||||
|
|
||||||
is(RequestsMenu.selectedItem.securityState, undefined,
|
is(RequestsMenu.selectedItem.attachment.securityState, undefined,
|
||||||
"Security state has not yet arrived.");
|
"Security state has not yet arrived.");
|
||||||
is(tabEl.hidden, !testcase.visibleOnNewEvent,
|
is(tabEl.hidden, !testcase.visibleOnNewEvent,
|
||||||
"Security tab is " +
|
"Security tab is " +
|
||||||
|
@ -70,7 +70,7 @@ add_task(function* () {
|
||||||
info("Waiting for security information to arrive.");
|
info("Waiting for security information to arrive.");
|
||||||
yield onSecurityInfo;
|
yield onSecurityInfo;
|
||||||
|
|
||||||
ok(RequestsMenu.selectedItem.securityState,
|
ok(RequestsMenu.selectedItem.attachment.securityState,
|
||||||
"Security state arrived.");
|
"Security state arrived.");
|
||||||
is(tabEl.hidden, !testcase.visibleOnSecurityInfo,
|
is(tabEl.hidden, !testcase.visibleOnSecurityInfo,
|
||||||
"Security tab is " +
|
"Security tab is " +
|
||||||
|
|
|
@ -26,8 +26,8 @@ add_task(function* () {
|
||||||
|
|
||||||
is(RequestsMenu.itemCount, 1, "Only the reload should be recorded.");
|
is(RequestsMenu.itemCount, 1, "Only the reload should be recorded.");
|
||||||
let request = RequestsMenu.getItemAtIndex(0);
|
let request = RequestsMenu.getItemAtIndex(0);
|
||||||
is(request.method, "GET", "The method is correct.");
|
is(request.attachment.method, "GET", "The method is correct.");
|
||||||
is(request.status, "200", "The status is correct.");
|
is(request.attachment.status, "200", "The status is correct.");
|
||||||
|
|
||||||
yield removeTab(beaconTab);
|
yield removeTab(beaconTab);
|
||||||
return teardown(monitor);
|
return teardown(monitor);
|
||||||
|
|
|
@ -23,9 +23,9 @@ add_task(function* () {
|
||||||
|
|
||||||
is(RequestsMenu.itemCount, 1, "The beacon should be recorded.");
|
is(RequestsMenu.itemCount, 1, "The beacon should be recorded.");
|
||||||
let request = RequestsMenu.getItemAtIndex(0);
|
let request = RequestsMenu.getItemAtIndex(0);
|
||||||
is(request.method, "POST", "The method is correct.");
|
is(request.attachment.method, "POST", "The method is correct.");
|
||||||
ok(request.url.endsWith("beacon_request"), "The URL is correct.");
|
ok(request.attachment.url.endsWith("beacon_request"), "The URL is correct.");
|
||||||
is(request.status, "404", "The status is correct.");
|
is(request.attachment.status, "404", "The status is correct.");
|
||||||
|
|
||||||
return teardown(monitor);
|
return teardown(monitor);
|
||||||
});
|
});
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче