зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1555631 - WebSocket frame payload preview. r=Honza,nchevobbe
Support WebSocket frame payload preview. Differential Revision: https://phabricator.services.mozilla.com/D38271 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
27b7855a32
Коммит
8f2fe89432
|
@ -237,6 +237,7 @@ devtools.jar:
|
|||
content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg)
|
||||
content/netmonitor/index.html (netmonitor/index.html)
|
||||
content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css)
|
||||
content/netmonitor/src/assets/styles/websockets.css (netmonitor/src/assets/styles/websockets.css)
|
||||
|
||||
# Application panel
|
||||
content/application/index.html (application/index.html)
|
||||
|
|
|
@ -731,6 +731,10 @@ netmonitor.ws.type.received=Received
|
|||
# %1$S is the formatted hour-minutes-seconds, %2$S is the milliseconds (zero-padded)
|
||||
netmonitor.ws.time.format=%1$S.%2$S
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.ws.rawData.header): This is the label displayed
|
||||
# in the messages panel identifying the raw data.
|
||||
netmonitor.ws.rawData.header=Raw Data (%S)
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.tab.headers): This is the label displayed
|
||||
# in the network details pane identifying the headers tab.
|
||||
netmonitor.tab.headers=Headers
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.ws-frame-list-empty-notice {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.empty-notice-element {
|
||||
padding-top: 12px;
|
||||
padding-left: 12px;
|
||||
|
@ -516,43 +512,6 @@
|
|||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
/* Frame type icon in the WebSockets Time column */
|
||||
|
||||
.ws-frames-list-type-icon {
|
||||
display: inline-block;
|
||||
/* align bottom of image 4px below the text baseline
|
||||
this tends to give a better result than "middle" */
|
||||
vertical-align: -4px;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.ws-frames-list-type-icon-sent {
|
||||
color: var(--green-70);
|
||||
}
|
||||
|
||||
.theme-dark .ws-frames-list-type-icon-sent {
|
||||
color: var(--green-50);
|
||||
}
|
||||
|
||||
.ws-frames-list-type-icon-received {
|
||||
color: var(--red-60);
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
.theme-dark .ws-frames-list-type-icon-received {
|
||||
color: var(--red-40);
|
||||
}
|
||||
|
||||
.ws-frame-list-item.selected .ws-frames-list-type-icon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Use lining numbers so that seconds and milliseconds align */
|
||||
.ws-frames-list-time {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Responsive web design support */
|
||||
|
||||
@media (max-width: 700px) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
@import "resource://devtools/client/shared/components/SidebarToggle.css";
|
||||
@import "resource://devtools/client/shared/components/splitter/SplitBox.css";
|
||||
@import "resource://devtools/client/shared/components/tree/TreeView.css";
|
||||
@import "resource://devtools/client/shared/components/Accordion.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/Tabs.css";
|
||||
@import "chrome://devtools/skin/components-frame.css";
|
||||
@import "chrome://devtools/content/shared/sourceeditor/codemirror/lib/codemirror.css";
|
||||
|
@ -21,6 +22,7 @@
|
|||
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatisticsPanel.css";
|
||||
@import "chrome://devtools/content/netmonitor/src/assets/styles/CustomRequestPanel.css";
|
||||
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatusCode.css";
|
||||
@import "chrome://devtools/content/netmonitor/src/assets/styles/websockets.css";
|
||||
|
||||
/* General */
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* Empty notice */
|
||||
|
||||
#messages-panel .ws-frame-list-empty-notice {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Frame type icon in the WebSockets Time column */
|
||||
|
||||
#messages-panel .ws-frames-list-type-icon {
|
||||
display: inline-block;
|
||||
/* align bottom of image 4px below the text baseline
|
||||
this tends to give a better result than "middle" */
|
||||
vertical-align: -4px;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
#messages-panel .ws-frames-list-type-icon-sent {
|
||||
color: var(--green-70);
|
||||
}
|
||||
|
||||
#messages-panel .theme-dark .ws-frames-list-type-icon-sent {
|
||||
color: var(--green-50);
|
||||
}
|
||||
|
||||
#messages-panel .ws-frames-list-type-icon-received {
|
||||
color: var(--red-60);
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
#messages-panel .theme-dark .ws-frames-list-type-icon-received {
|
||||
color: var(--red-40);
|
||||
}
|
||||
|
||||
#messages-panel .ws-frame-list-item.selected .ws-frames-list-type-icon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Use lining numbers so that seconds and milliseconds align */
|
||||
#messages-panel .ws-frames-list-time {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Styles related to the Accordion items in the FramePayload component */
|
||||
|
||||
#messages-panel .ws-frame-payload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#messages-panel .ws-frame-rawData-payload {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
padding: 4px 8px;
|
||||
padding-inline-start: 20px;
|
||||
font-family: var(--monospace-font-family);
|
||||
font-size: var(--theme-code-font-size);
|
||||
line-height: calc(15/11);
|
||||
}
|
||||
|
||||
#messages-panel #ws-frame-rawData-header,
|
||||
#messages-panel #ws-frame-formattedData-header {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
/* Styles related to JSONPreview */
|
||||
|
||||
#messages-panel .treeTable .objectBox {
|
||||
white-space: normal;
|
||||
overflow-wrap: break-word;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* 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 {
|
||||
Component,
|
||||
createFactory,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
// Components
|
||||
const TreeView = createFactory(
|
||||
require("devtools/client/shared/components/tree/TreeView")
|
||||
);
|
||||
loader.lazyGetter(this, "Rep", function() {
|
||||
return require("devtools/client/shared/components/reps/reps").REPS.Rep;
|
||||
});
|
||||
loader.lazyGetter(this, "MODE", function() {
|
||||
return require("devtools/client/shared/components/reps/reps").MODE;
|
||||
});
|
||||
|
||||
/**
|
||||
* Shows JSON in a custom tree format.
|
||||
*/
|
||||
class JSONPreview extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
// Custom value renderer
|
||||
renderValue: PropTypes.func,
|
||||
cropLimit: PropTypes.number,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.renderValueWithRep = this.renderValueWithRep.bind(this);
|
||||
}
|
||||
|
||||
renderValueWithRep(props) {
|
||||
const { member } = props;
|
||||
|
||||
// Hide strings with following conditions
|
||||
// 1. this row is a togglable section and content is object ('cause it shouldn't hide
|
||||
// when string or number)
|
||||
// 2. the `value` object has a `value` property, only happened in Cookies panel
|
||||
// Put 2 here to not dup this method
|
||||
if (
|
||||
(member.level === 0 && member.type === "object") ||
|
||||
(typeof member.value === "object" && member.value && member.value.value)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Rep(
|
||||
Object.assign(props, {
|
||||
// FIXME: A workaround for the issue in StringRep
|
||||
// Force StringRep to crop the text every time
|
||||
member: Object.assign({}, member, { open: false }),
|
||||
mode: MODE.TINY,
|
||||
cropLimit: this.props.cropLimit,
|
||||
noGrip: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return dom.div(
|
||||
{
|
||||
className: "tree-container",
|
||||
},
|
||||
TreeView({
|
||||
...this.props,
|
||||
renderValue: this.props.renderValue || this.renderValueWithRep,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = JSONPreview;
|
|
@ -19,7 +19,9 @@ const { FILTER_SEARCH_DELAY } = require("../constants");
|
|||
// Components
|
||||
const TreeViewClass = require("devtools/client/shared/components/tree/TreeView");
|
||||
const PropertiesViewContextMenu = require("../widgets/PropertiesViewContextMenu");
|
||||
const TreeView = createFactory(TreeViewClass);
|
||||
const JSONPreview = createFactory(
|
||||
require("devtools/client/netmonitor/src/components/JSONPreview")
|
||||
);
|
||||
|
||||
loader.lazyGetter(this, "SearchBox", function() {
|
||||
return createFactory(require("devtools/client/shared/components/SearchBox"));
|
||||
|
@ -36,13 +38,6 @@ loader.lazyGetter(this, "HTMLPreview", function() {
|
|||
return createFactory(require("./HtmlPreview"));
|
||||
});
|
||||
|
||||
loader.lazyGetter(this, "Rep", function() {
|
||||
return require("devtools/client/shared/components/reps/reps").REPS.Rep;
|
||||
});
|
||||
loader.lazyGetter(this, "MODE", function() {
|
||||
return require("devtools/client/shared/components/reps/reps").MODE;
|
||||
});
|
||||
|
||||
const { div, tr, td, pre } = dom;
|
||||
const AUTO_EXPAND_MAX_LEVEL = 7;
|
||||
const AUTO_EXPAND_MAX_NODES = 50;
|
||||
|
@ -95,7 +90,6 @@ class PropertiesView extends Component {
|
|||
this.getRowClass = this.getRowClass.bind(this);
|
||||
this.onFilter = this.onFilter.bind(this);
|
||||
this.renderRowWithExtras = this.renderRowWithExtras.bind(this);
|
||||
this.renderValueWithRep = this.renderValueWithRep.bind(this);
|
||||
this.shouldRenderSearchBox = this.shouldRenderSearchBox.bind(this);
|
||||
this.updateFilterText = this.updateFilterText.bind(this);
|
||||
}
|
||||
|
@ -176,33 +170,6 @@ class PropertiesView extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
renderValueWithRep(props) {
|
||||
const { member } = props;
|
||||
|
||||
// Hide strings with following conditions
|
||||
// 1. this row is a togglable section and content is object ('cause it shouldn't hide
|
||||
// when string or number)
|
||||
// 2. the `value` object has a `value` property, only happened in Cookies panel
|
||||
// Put 2 here to not dup this method
|
||||
if (
|
||||
(member.level === 0 && member.type === "object") ||
|
||||
(typeof member.value === "object" && member.value && member.value.value)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Rep(
|
||||
Object.assign(props, {
|
||||
// FIXME: A workaround for the issue in StringRep
|
||||
// Force StringRep to crop the text every time
|
||||
member: Object.assign({}, member, { open: false }),
|
||||
mode: MODE.TINY,
|
||||
cropLimit: this.props.cropLimit,
|
||||
noGrip: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
sectionIsSearchable(object, section) {
|
||||
return !(
|
||||
object[section][EDITOR_CONFIG_ID] || object[section][HTML_PREVIEW_ID]
|
||||
|
@ -251,34 +218,31 @@ class PropertiesView extends Component {
|
|||
placeholder: filterPlaceHolder,
|
||||
})
|
||||
),
|
||||
div(
|
||||
{ className: "tree-container" },
|
||||
TreeView({
|
||||
object,
|
||||
provider,
|
||||
columns: [
|
||||
{
|
||||
id: "value",
|
||||
width: "100%",
|
||||
},
|
||||
],
|
||||
decorator: decorator || {
|
||||
getRowClass: rowObject => this.getRowClass(rowObject, sectionNames),
|
||||
JSONPreview({
|
||||
object,
|
||||
provider,
|
||||
columns: [
|
||||
{
|
||||
id: "value",
|
||||
width: "100%",
|
||||
},
|
||||
enableInput,
|
||||
expandableStrings,
|
||||
useQuotes: false,
|
||||
expandedNodes: TreeViewClass.getExpandedNodes(object, {
|
||||
maxLevel: AUTO_EXPAND_MAX_LEVEL,
|
||||
maxNodes: AUTO_EXPAND_MAX_NODES,
|
||||
}),
|
||||
onFilter: props => this.onFilter(props, sectionNames),
|
||||
renderRow: renderRow || this.renderRowWithExtras,
|
||||
renderValue: renderValue || this.renderValueWithRep,
|
||||
openLink,
|
||||
onContextMenuRow: this.onContextMenuRow,
|
||||
})
|
||||
)
|
||||
],
|
||||
decorator: decorator || {
|
||||
getRowClass: rowObject => this.getRowClass(rowObject, sectionNames),
|
||||
},
|
||||
enableInput,
|
||||
expandableStrings,
|
||||
useQuotes: false,
|
||||
expandedNodes: TreeViewClass.getExpandedNodes(object, {
|
||||
maxLevel: AUTO_EXPAND_MAX_LEVEL,
|
||||
maxNodes: AUTO_EXPAND_MAX_NODES,
|
||||
}),
|
||||
onFilter: props => this.onFilter(props, sectionNames),
|
||||
renderRow: renderRow || this.renderRowWithExtras,
|
||||
renderValue,
|
||||
openLink,
|
||||
onContextMenuRow: this.onContextMenuRow,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ const {
|
|||
fetchNetworkUpdatePacket,
|
||||
formDataURI,
|
||||
getUrlBaseName,
|
||||
isJSON,
|
||||
} = require("../utils/request-utils");
|
||||
const { Filters } = require("../utils/filter-predicates");
|
||||
|
||||
|
@ -85,23 +86,6 @@ class ResponsePanel extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks that the response is base64 encoded by
|
||||
* comparing these 2 values:
|
||||
* 1. The original response
|
||||
* 2. The value of doing a base64 decode on the
|
||||
* response and then base64 encoding the result.
|
||||
* If the values are different or an error is thrown,
|
||||
* the method will return false.
|
||||
*/
|
||||
isBase64(response) {
|
||||
try {
|
||||
return btoa(atob(response)) == response;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle json, which we tentatively identify by checking the
|
||||
* MIME type for "json" after any word boundary. This works
|
||||
|
@ -111,12 +95,11 @@ class ResponsePanel extends Component {
|
|||
* it's json or not, to handle responses incorrectly labeled
|
||||
* as text/plain instead.
|
||||
*/
|
||||
isJSON(mimeType, response) {
|
||||
handleJSONResponse(mimeType, response) {
|
||||
const limit = Services.prefs.getIntPref(
|
||||
"devtools.netmonitor.responseBodyLimit"
|
||||
);
|
||||
const { request } = this.props;
|
||||
let json, error;
|
||||
|
||||
// Check if the response has been truncated, in which case no parse should
|
||||
// be attempted.
|
||||
|
@ -126,19 +109,7 @@ class ResponsePanel extends Component {
|
|||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(response);
|
||||
} catch (err) {
|
||||
if (this.isBase64(response)) {
|
||||
try {
|
||||
json = JSON.parse(atob(response));
|
||||
} catch (err64) {
|
||||
error = err;
|
||||
}
|
||||
} else {
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
let { json, error } = isJSON(response);
|
||||
|
||||
if (/\bjson/.test(mimeType) || json) {
|
||||
// Extract the actual json substring in case this might be a "JSONP".
|
||||
|
@ -226,7 +197,8 @@ class ResponsePanel extends Component {
|
|||
}
|
||||
|
||||
// Display Properties View
|
||||
const { json, jsonpCallback, error } = this.isJSON(mimeType, text) || {};
|
||||
const { json, jsonpCallback, error } =
|
||||
this.handleJSONResponse(mimeType, text) || {};
|
||||
const object = {};
|
||||
let sectionName;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ DevToolsModules(
|
|||
'DropHarHandler.js',
|
||||
'HeadersPanel.js',
|
||||
'HtmlPreview.js',
|
||||
'JSONPreview.js',
|
||||
'MonitorPanel.js',
|
||||
'NetworkDetailsPanel.js',
|
||||
'ParamsPanel.js',
|
||||
|
|
|
@ -4,11 +4,32 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const {
|
||||
Component,
|
||||
createFactory,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { div } = dom;
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { getFramePayload } = require("../../utils/request-utils");
|
||||
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n.js");
|
||||
const {
|
||||
getFramePayload,
|
||||
isJSON,
|
||||
} = require("devtools/client/netmonitor/src/utils/request-utils.js");
|
||||
const {
|
||||
getFormattedSize,
|
||||
} = require("devtools/client/netmonitor/src/utils/format-utils.js");
|
||||
|
||||
// Components
|
||||
const Accordion = createFactory(
|
||||
require("devtools/client/shared/components/Accordion")
|
||||
);
|
||||
const RawData = createFactory(require("./RawData"));
|
||||
loader.lazyGetter(this, "JSONPreview", function() {
|
||||
return createFactory(
|
||||
require("devtools/client/netmonitor/src/components/JSONPreview")
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Shows the full payload of a WebSocket frame.
|
||||
|
@ -27,6 +48,8 @@ class FramePayload extends Component {
|
|||
|
||||
this.state = {
|
||||
payload: "",
|
||||
isFormattedData: false,
|
||||
formattedData: {},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,8 +57,11 @@ class FramePayload extends Component {
|
|||
const { selectedFrame, connector } = this.props;
|
||||
getFramePayload(selectedFrame.payload, connector.getLongString).then(
|
||||
payload => {
|
||||
const { json } = isJSON(payload);
|
||||
this.setState({
|
||||
payload,
|
||||
isFormattedData: !!json,
|
||||
formattedData: json,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -45,15 +71,55 @@ class FramePayload extends Component {
|
|||
const { selectedFrame, connector } = nextProps;
|
||||
getFramePayload(selectedFrame.payload, connector.getLongString).then(
|
||||
payload => {
|
||||
const { json } = isJSON(payload);
|
||||
this.setState({
|
||||
payload,
|
||||
isFormattedData: !!json,
|
||||
formattedData: json,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return div({ className: "ws-frame-payload" }, this.state.payload);
|
||||
const items = [
|
||||
{
|
||||
className: "rawData",
|
||||
component: RawData({ payload: this.state.payload }),
|
||||
header: L10N.getFormatStrWithNumbers(
|
||||
"netmonitor.ws.rawData.header",
|
||||
getFormattedSize(this.state.payload.length)
|
||||
),
|
||||
labelledby: "ws-frame-rawData-header",
|
||||
opened: true,
|
||||
},
|
||||
];
|
||||
if (this.state.isFormattedData) {
|
||||
items.push({
|
||||
className: "formattedData",
|
||||
component: JSONPreview({
|
||||
object: this.state.formattedData,
|
||||
columns: [
|
||||
{
|
||||
id: "value",
|
||||
width: "100%",
|
||||
},
|
||||
],
|
||||
}),
|
||||
header: `JSON (${getFormattedSize(this.state.payload.length)})`,
|
||||
labelledby: "ws-frame-formattedData-header",
|
||||
opened: true,
|
||||
});
|
||||
}
|
||||
|
||||
return div(
|
||||
{
|
||||
className: "ws-frame-payload",
|
||||
},
|
||||
Accordion({
|
||||
items,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* 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 { Component } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
/**
|
||||
* Shows raw payload of a WebSocket frame.
|
||||
*/
|
||||
class RawData extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
payload: PropTypes.string.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { payload } = this.props;
|
||||
return dom.div(
|
||||
{
|
||||
className: "ws-frame-rawData-payload",
|
||||
},
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RawData;
|
|
@ -17,7 +17,7 @@ const {
|
|||
connect,
|
||||
} = require("devtools/client/shared/redux/visibility-handler-connect");
|
||||
const Actions = require("../../actions/index");
|
||||
|
||||
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
|
||||
const {
|
||||
getSelectedFrame,
|
||||
isSelectedFrameVisible,
|
||||
|
@ -71,6 +71,17 @@ class WebSocketsPanel extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { clientHeight } = findDOMNode(this.refs.endPanel) || {};
|
||||
|
||||
if (clientHeight) {
|
||||
Services.prefs.setIntPref(
|
||||
"devtools.netmonitor.ws.payload-preview-height",
|
||||
clientHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the filter text
|
||||
clearFilterText() {
|
||||
if (this.searchboxRef) {
|
||||
|
@ -81,9 +92,6 @@ class WebSocketsPanel extends Component {
|
|||
render() {
|
||||
const { frameDetailsOpen, connector, selectedFrame } = this.props;
|
||||
|
||||
const initialWidth = Services.prefs.getIntPref(
|
||||
"devtools.netmonitor.ws.payload-preview-width"
|
||||
);
|
||||
const initialHeight = Services.prefs.getIntPref(
|
||||
"devtools.netmonitor.ws.payload-preview-height"
|
||||
);
|
||||
|
@ -95,15 +103,15 @@ class WebSocketsPanel extends Component {
|
|||
}),
|
||||
SplitBox({
|
||||
className: "devtools-responsive-container",
|
||||
initialWidth: initialWidth,
|
||||
initialHeight: initialHeight,
|
||||
minSize: "50px",
|
||||
maxSize: "50%",
|
||||
maxSize: "80%",
|
||||
splitterSize: frameDetailsOpen ? 1 : 0,
|
||||
startPanel: FrameListContent({ connector }),
|
||||
endPanel:
|
||||
frameDetailsOpen &&
|
||||
FramePayload({
|
||||
ref: "endPanel",
|
||||
connector,
|
||||
selectedFrame,
|
||||
}),
|
||||
|
|
|
@ -14,6 +14,7 @@ DevToolsModules(
|
|||
'FrameListHeader.js',
|
||||
'FrameListItem.js',
|
||||
'FramePayload.js',
|
||||
'RawData.js',
|
||||
'StatusBar.js',
|
||||
'Toolbar.js',
|
||||
'WebSocketsPanel.js',
|
||||
|
|
|
@ -584,6 +584,49 @@ function processNetworkUpdates(update, request) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks that the response is base64 encoded by
|
||||
* comparing these 2 values:
|
||||
* 1. The original response
|
||||
* 2. The value of doing a base64 decode on the
|
||||
* response and then base64 encoding the result.
|
||||
* If the values are different or an error is thrown,
|
||||
* the method will return false.
|
||||
*/
|
||||
function isBase64(payload) {
|
||||
try {
|
||||
return btoa(atob(payload)) == payload;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the payload is of JSON type.
|
||||
*/
|
||||
function isJSON(payload) {
|
||||
let json, error;
|
||||
|
||||
try {
|
||||
json = JSON.parse(payload);
|
||||
} catch (err) {
|
||||
if (isBase64(payload)) {
|
||||
try {
|
||||
json = JSON.parse(atob(payload));
|
||||
} catch (err64) {
|
||||
error = err;
|
||||
}
|
||||
} else {
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
json,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
decodeUnicodeBase64,
|
||||
getFormDataSections,
|
||||
|
@ -612,4 +655,5 @@ module.exports = {
|
|||
processNetworkUpdates,
|
||||
propertiesEqual,
|
||||
ipToLong,
|
||||
isJSON,
|
||||
};
|
||||
|
|
|
@ -170,8 +170,7 @@ pref("devtools.netmonitor.visibleColumns",
|
|||
);
|
||||
pref("devtools.netmonitor.columnsData",
|
||||
'[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"url","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
|
||||
pref("devtools.netmonitor.ws.payload-preview-width", 550);
|
||||
pref("devtools.netmonitor.ws.payload-preview-height", 450);
|
||||
pref("devtools.netmonitor.ws.payload-preview-height", 128);
|
||||
|
||||
pref("devtools.netmonitor.response.ui.limit", 10240);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче